1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 20:38:08 +01:00
Files
wmaker/src/switchmenu.c
Rodolfo García Peñas (kix) 41da1b30db New file misc.h
This is the new file misc.h, with the function prototypes for misc.c.
This file is created using misc.c and removing the prototypes from funcs.h
2013-04-17 10:13:25 +01:00

427 lines
11 KiB
C

/*
* Window Maker window manager
*
* Copyright (c) 1997 Shige Abe
* Copyright (c) 1997-2003 Alfredo K. Kojima
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "wconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "WindowMaker.h"
#include "window.h"
#include "actions.h"
#include "client.h"
#include "misc.h"
#include "stacking.h"
#include "workspace.h"
#include "framewin.h"
#define IS_GNUSTEP_MENU(w) ((w)->wm_gnustep_attr && \
((w)->wm_gnustep_attr->flags & GSWindowLevelAttr) && \
((w)->wm_gnustep_attr->window_level == WMMainMenuWindowLevel || \
(w)->wm_gnustep_attr->window_level == WMSubmenuWindowLevel))
/********* Global Variables *******/
extern WPreferences wPreferences;
static int initialized = 0;
static void observer(void *self, WMNotification * notif);
static void wsobserver(void *self, WMNotification * notif);
/*
* FocusWindow
*
* - Needs to check if already in the right workspace before
* calling wChangeWorkspace?
*
* Order:
* Switch to correct workspace
* Unshade if shaded
* If iconified then deiconify else focus/raise.
*/
static void focusWindow(WMenu * menu, WMenuEntry * entry)
{
WWindow *wwin;
WScreen *scr;
int x, y, move = 0;
wwin = (WWindow *) entry->clientdata;
scr = wwin->screen_ptr;
wMakeWindowVisible(wwin);
x = wwin->frame_x;
y = wwin->frame_y;
/* bring window back to visible area */
move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width, wwin->frame->core->height);
if (move) {
wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
}
}
void InitializeSwitchMenu(void)
{
if (!initialized) {
initialized = 1;
WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
}
}
/*
*
* Open switch menu
*
*/
void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
{
WMenu *switchmenu = scr->switch_menu;
WWindow *wwin;
if (switchmenu) {
if (switchmenu->flags.mapped) {
if (!switchmenu->flags.buttoned) {
wMenuUnmap(switchmenu);
} else {
wRaiseFrame(switchmenu->frame->core);
if (keyboard)
wMenuMapAt(switchmenu, 0, 0, True);
else
wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
}
} else {
if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
y = y - switchmenu->frame->core->height / 2;
}
wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
}
return;
}
switchmenu = wMenuCreate(scr, _("Windows"), True);
scr->switch_menu = switchmenu;
wwin = scr->focused_window;
while (wwin) {
UpdateSwitchMenu(scr, wwin, ACTION_ADD);
wwin = wwin->prev;
}
if (switchmenu) {
int newx, newy;
if (!switchmenu->flags.realized)
wMenuRealize(switchmenu);
if (keyboard && x == 0 && y == 0) {
newx = newy = 0;
} else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
newx = x - switchmenu->frame->core->width / 2;
newy = y - switchmenu->frame->core->height / 2;
} else {
newx = x - switchmenu->frame->core->width / 2;
newy = y;
}
wMenuMapAt(switchmenu, newx, newy, keyboard);
}
}
static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
{
int idx;
if (menu->entry_no <= old_pos)
return -1;
#define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
if (old_pos >= 0) {
if (WS(old_pos) >= wwin->frame->workspace
&& (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
return old_pos;
}
}
#undef WS
for (idx = 0; idx < menu->entry_no; idx++) {
WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
if (!IS_OMNIPRESENT(tw)
&& tw->frame->workspace > wwin->frame->workspace) {
break;
}
}
return idx;
}
/*
* Update switch menu
*/
void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
{
WMenu *switchmenu = scr->switch_menu;
WMenuEntry *entry;
char title[MAX_MENU_TEXT_LENGTH + 6];
int len = sizeof(title);
int i;
int checkVisibility = 0;
if (!wwin->screen_ptr->switch_menu)
return;
/*
* This menu is updated under the following conditions:
*
* 1. When a window is created.
* 2. When a window is destroyed.
*
* 3. When a window changes it's title.
* 4. When a window changes its workspace.
*/
if (action == ACTION_ADD) {
char *t;
int idx;
if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
return;
}
if (wwin->frame->title)
snprintf(title, len, "%s", wwin->frame->title);
else
snprintf(title, len, "%s", DEF_WINDOW_TITLE);
t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
if (IS_OMNIPRESENT(wwin))
idx = -1;
else {
idx = menuIndexForWindow(switchmenu, wwin, -1);
}
entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
wfree(t);
entry->flags.indicator = 1;
entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
if (IS_OMNIPRESENT(wwin))
snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
else
snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
scr->workspaces[wwin->frame->workspace]->name);
if (wwin->flags.hidden) {
entry->flags.indicator_type = MI_HIDDEN;
entry->flags.indicator_on = 1;
} else if (wwin->flags.miniaturized) {
entry->flags.indicator_type = MI_MINIWINDOW;
entry->flags.indicator_on = 1;
} else if (wwin->flags.focused) {
entry->flags.indicator_type = MI_DIAMOND;
entry->flags.indicator_on = 1;
} else if (wwin->flags.shaded) {
entry->flags.indicator_type = MI_SHADED;
entry->flags.indicator_on = 1;
}
wMenuRealize(switchmenu);
checkVisibility = 1;
} else {
char *t;
for (i = 0; i < switchmenu->entry_no; i++) {
entry = switchmenu->entries[i];
/* this is the entry that was changed */
if (entry->clientdata == wwin) {
switch (action) {
case ACTION_REMOVE:
wMenuRemoveItem(switchmenu, i);
wMenuRealize(switchmenu);
checkVisibility = 1;
break;
case ACTION_CHANGE:
if (entry->text)
wfree(entry->text);
if (wwin->frame->title)
snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
else
snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
entry->text = t;
wMenuRealize(switchmenu);
checkVisibility = 1;
break;
case ACTION_CHANGE_WORKSPACE:
if (entry->rtext) {
int idx = -1;
char *t, *rt;
int it, ion;
if (IS_OMNIPRESENT(wwin)) {
snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
} else {
snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
"[%s]",
scr->workspaces[wwin->frame->workspace]->name);
}
rt = entry->rtext;
entry->rtext = NULL;
t = entry->text;
entry->text = NULL;
it = entry->flags.indicator_type;
ion = entry->flags.indicator_on;
if (!IS_OMNIPRESENT(wwin) && idx < 0) {
idx = menuIndexForWindow(switchmenu, wwin, i);
}
wMenuRemoveItem(switchmenu, i);
entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
wfree(t);
entry->rtext = rt;
entry->flags.indicator = 1;
entry->flags.indicator_type = it;
entry->flags.indicator_on = ion;
}
wMenuRealize(switchmenu);
checkVisibility = 1;
break;
case ACTION_CHANGE_STATE:
if (wwin->flags.hidden) {
entry->flags.indicator_type = MI_HIDDEN;
entry->flags.indicator_on = 1;
} else if (wwin->flags.miniaturized) {
entry->flags.indicator_type = MI_MINIWINDOW;
entry->flags.indicator_on = 1;
} else if (wwin->flags.shaded && !wwin->flags.focused) {
entry->flags.indicator_type = MI_SHADED;
entry->flags.indicator_on = 1;
} else {
entry->flags.indicator_on = wwin->flags.focused;
entry->flags.indicator_type = MI_DIAMOND;
}
break;
}
break;
}
}
}
if (checkVisibility) {
int tmp;
tmp = switchmenu->frame->top_width + 5;
/* if menu got unreachable, bring it to a visible place */
if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
switchmenu->frame_y, False);
}
}
wMenuPaint(switchmenu);
}
static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
{
WMenu *menu = scr->switch_menu;
int i;
WWindow *wwin;
if (!menu)
return;
for (i = 0; i < menu->entry_no; i++) {
wwin = (WWindow *) menu->entries[i]->clientdata;
if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
if (IS_OMNIPRESENT(wwin))
snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
else
snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
scr->workspaces[wwin->frame->workspace]->name);
menu->flags.realized = 0;
}
}
if (!menu->flags.realized)
wMenuRealize(menu);
}
static void observer(void *self, WMNotification * notif)
{
WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
const char *name = WMGetNotificationName(notif);
void *data = WMGetNotificationClientData(notif);
if (!wwin)
return;
if (strcmp(name, WMNManaged) == 0)
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
else if (strcmp(name, WMNUnmanaged) == 0)
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
else if (strcmp(name, WMNChangedWorkspace) == 0)
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
else if (strcmp(name, WMNChangedFocus) == 0)
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
else if (strcmp(name, WMNChangedName) == 0)
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
else if (strcmp(name, WMNChangedState) == 0) {
if (strcmp((char *)data, "omnipresent") == 0) {
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
} else {
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
}
}
}
static void wsobserver(void *self, WMNotification * notif)
{
WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
const char *name = WMGetNotificationName(notif);
void *data = WMGetNotificationClientData(notif);
if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
UpdateSwitchMenuWorkspace(scr, (uintptr_t)data);
} else if (strcmp(name, WMNWorkspaceChanged) == 0) {
}
}