Configure: Added proper check for Xmu library for WRaster
[wmaker-crm.git] / src / switchmenu.c
blobdb7a40e248014d3e8630cbb962c200d42cedcde6
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997 Shige Abe
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "wconfig.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdint.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
32 #include "WindowMaker.h"
33 #include "window.h"
34 #include "actions.h"
35 #include "client.h"
36 #include "misc.h"
37 #include "stacking.h"
38 #include "workspace.h"
39 #include "framewin.h"
40 #include "switchmenu.h"
42 #define IS_GNUSTEP_MENU(w) ((w)->wm_gnustep_attr && \
43 ((w)->wm_gnustep_attr->flags & GSWindowLevelAttr) && \
44 ((w)->wm_gnustep_attr->window_level == WMMainMenuWindowLevel || \
45 (w)->wm_gnustep_attr->window_level == WMSubmenuWindowLevel))
47 static int initialized = 0;
48 static void observer(void *self, WMNotification * notif);
49 static void wsobserver(void *self, WMNotification * notif);
52 * FocusWindow
54 * - Needs to check if already in the right workspace before
55 * calling wChangeWorkspace?
57 * Order:
58 * Switch to correct workspace
59 * Unshade if shaded
60 * If iconified then deiconify else focus/raise.
62 static void focusWindow(WMenu * menu, WMenuEntry * entry)
64 WWindow *wwin;
65 WScreen *scr;
66 int x, y, move = 0;
68 /* Parameter not used, but tell the compiler that it is ok */
69 (void) menu;
71 wwin = (WWindow *) entry->clientdata;
72 scr = wwin->screen_ptr;
74 wMakeWindowVisible(wwin);
76 x = wwin->frame_x;
77 y = wwin->frame_y;
79 /* bring window back to visible area */
80 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width, wwin->frame->core->height);
82 if (move) {
83 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
87 void InitializeSwitchMenu(void)
89 if (!initialized) {
90 initialized = 1;
92 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
93 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
94 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
95 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
96 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
97 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
98 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
100 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
101 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
107 * Open switch menu
110 void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
112 WMenu *switchmenu = scr->switch_menu;
113 WWindow *wwin;
115 if (switchmenu) {
116 if (switchmenu->flags.mapped) {
117 if (!switchmenu->flags.buttoned) {
118 wMenuUnmap(switchmenu);
119 } else {
120 wRaiseFrame(switchmenu->frame->core);
122 if (keyboard)
123 wMenuMapAt(switchmenu, 0, 0, True);
124 else
125 wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
127 } else {
128 if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
129 y = y - switchmenu->frame->core->height / 2;
131 wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
133 return;
135 switchmenu = wMenuCreate(scr, _("Windows"), True);
136 scr->switch_menu = switchmenu;
138 wwin = scr->focused_window;
139 while (wwin) {
140 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
142 wwin = wwin->prev;
145 if (switchmenu) {
146 int newx, newy;
148 if (!switchmenu->flags.realized)
149 wMenuRealize(switchmenu);
151 if (keyboard && x == 0 && y == 0) {
152 newx = newy = 0;
153 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
154 newx = x - switchmenu->frame->core->width / 2;
155 newy = y - switchmenu->frame->core->height / 2;
156 } else {
157 newx = x - switchmenu->frame->core->width / 2;
158 newy = y;
160 wMenuMapAt(switchmenu, newx, newy, keyboard);
164 static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
166 int idx;
168 if (menu->entry_no <= old_pos)
169 return -1;
171 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
172 if (old_pos >= 0) {
173 if (WS(old_pos) >= wwin->frame->workspace
174 && (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
175 return old_pos;
178 #undef WS
180 for (idx = 0; idx < menu->entry_no; idx++) {
181 WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
183 if (!IS_OMNIPRESENT(tw)
184 && tw->frame->workspace > wwin->frame->workspace) {
185 break;
189 return idx;
193 * Update switch menu
195 void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
197 WMenu *switchmenu = scr->switch_menu;
198 WMenuEntry *entry;
199 char title[MAX_MENU_TEXT_LENGTH + 6];
200 int len = sizeof(title);
201 int i;
202 int checkVisibility = 0;
204 if (!wwin->screen_ptr->switch_menu)
205 return;
207 * This menu is updated under the following conditions:
209 * 1. When a window is created.
210 * 2. When a window is destroyed.
212 * 3. When a window changes it's title.
213 * 4. When a window changes its workspace.
215 if (action == ACTION_ADD) {
216 char *t;
217 int idx;
219 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
220 return;
223 if (wwin->frame->title)
224 snprintf(title, len, "%s", wwin->frame->title);
225 else
226 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
227 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
229 if (IS_OMNIPRESENT(wwin))
230 idx = -1;
231 else {
232 idx = menuIndexForWindow(switchmenu, wwin, -1);
235 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
236 wfree(t);
238 entry->flags.indicator = 1;
239 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
240 if (IS_OMNIPRESENT(wwin))
241 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
242 else
243 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
244 w_global.workspace.array[wwin->frame->workspace]->name);
246 if (wwin->flags.hidden) {
247 entry->flags.indicator_type = MI_HIDDEN;
248 entry->flags.indicator_on = 1;
249 } else if (wwin->flags.miniaturized) {
250 entry->flags.indicator_type = MI_MINIWINDOW;
251 entry->flags.indicator_on = 1;
252 } else if (wwin->flags.focused) {
253 entry->flags.indicator_type = MI_DIAMOND;
254 entry->flags.indicator_on = 1;
255 } else if (wwin->flags.shaded) {
256 entry->flags.indicator_type = MI_SHADED;
257 entry->flags.indicator_on = 1;
260 wMenuRealize(switchmenu);
261 checkVisibility = 1;
262 } else {
263 char *t;
264 for (i = 0; i < switchmenu->entry_no; i++) {
265 entry = switchmenu->entries[i];
266 /* this is the entry that was changed */
267 if (entry->clientdata == wwin) {
268 switch (action) {
269 case ACTION_REMOVE:
270 wMenuRemoveItem(switchmenu, i);
271 wMenuRealize(switchmenu);
272 checkVisibility = 1;
273 break;
275 case ACTION_CHANGE:
276 if (entry->text)
277 wfree(entry->text);
279 if (wwin->frame->title)
280 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
281 else
282 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
284 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
285 entry->text = t;
287 wMenuRealize(switchmenu);
288 checkVisibility = 1;
289 break;
291 case ACTION_CHANGE_WORKSPACE:
292 if (entry->rtext) {
293 int idx = -1;
294 char *t, *rt;
295 int it, ion;
297 if (IS_OMNIPRESENT(wwin)) {
298 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
299 } else {
300 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
301 "[%s]",
302 w_global.workspace.array[wwin->frame->workspace]->name);
305 rt = entry->rtext;
306 entry->rtext = NULL;
307 t = entry->text;
308 entry->text = NULL;
310 it = entry->flags.indicator_type;
311 ion = entry->flags.indicator_on;
313 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
314 idx = menuIndexForWindow(switchmenu, wwin, i);
317 wMenuRemoveItem(switchmenu, i);
319 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
320 wfree(t);
321 entry->rtext = rt;
322 entry->flags.indicator = 1;
323 entry->flags.indicator_type = it;
324 entry->flags.indicator_on = ion;
326 wMenuRealize(switchmenu);
327 checkVisibility = 1;
328 break;
330 case ACTION_CHANGE_STATE:
331 if (wwin->flags.hidden) {
332 entry->flags.indicator_type = MI_HIDDEN;
333 entry->flags.indicator_on = 1;
334 } else if (wwin->flags.miniaturized) {
335 entry->flags.indicator_type = MI_MINIWINDOW;
336 entry->flags.indicator_on = 1;
337 } else if (wwin->flags.shaded && !wwin->flags.focused) {
338 entry->flags.indicator_type = MI_SHADED;
339 entry->flags.indicator_on = 1;
340 } else {
341 entry->flags.indicator_on = wwin->flags.focused;
342 entry->flags.indicator_type = MI_DIAMOND;
344 break;
346 break;
350 if (checkVisibility) {
351 int tmp;
353 tmp = switchmenu->frame->top_width + 5;
354 /* if menu got unreachable, bring it to a visible place */
355 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
356 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
357 switchmenu->frame_y, False);
360 wMenuPaint(switchmenu);
363 static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
365 WMenu *menu = scr->switch_menu;
366 int i;
367 WWindow *wwin;
369 if (!menu)
370 return;
372 for (i = 0; i < menu->entry_no; i++) {
373 wwin = (WWindow *) menu->entries[i]->clientdata;
375 if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
376 if (IS_OMNIPRESENT(wwin))
377 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
378 else
379 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
380 w_global.workspace.array[wwin->frame->workspace]->name);
381 menu->flags.realized = 0;
384 if (!menu->flags.realized)
385 wMenuRealize(menu);
388 static void observer(void *self, WMNotification * notif)
390 WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
391 const char *name = WMGetNotificationName(notif);
392 void *data = WMGetNotificationClientData(notif);
394 /* Parameter not used, but tell the compiler that it is ok */
395 (void) self;
397 if (!wwin)
398 return;
400 if (strcmp(name, WMNManaged) == 0)
401 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
402 else if (strcmp(name, WMNUnmanaged) == 0)
403 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
404 else if (strcmp(name, WMNChangedWorkspace) == 0)
405 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
406 else if (strcmp(name, WMNChangedFocus) == 0)
407 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
408 else if (strcmp(name, WMNChangedName) == 0)
409 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
410 else if (strcmp(name, WMNChangedState) == 0) {
411 if (strcmp((char *)data, "omnipresent") == 0) {
412 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
413 } else {
414 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
419 static void wsobserver(void *self, WMNotification * notif)
421 WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
422 const char *name = WMGetNotificationName(notif);
423 void *data = WMGetNotificationClientData(notif);
425 /* Parameter not used, but tell the compiler that it is ok */
426 (void) self;
428 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
429 UpdateSwitchMenuWorkspace(scr, (uintptr_t)data);
430 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {