Address some sparse warnings
[wmaker-crm.git] / src / switchmenu.c
blobdc97c33acd9b573a713679ba642e6bc12309de87
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
23 #include "wconfig.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
33 #include "WindowMaker.h"
34 #include "window.h"
35 #include "actions.h"
36 #include "client.h"
37 #include "funcs.h"
38 #include "stacking.h"
39 #include "workspace.h"
40 #include "framewin.h"
42 /********* Global Variables *******/
43 extern WPreferences wPreferences;
44 extern Time LastTimestamp;
46 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 wwin = (WWindow *) entry->clientdata;
69 scr = wwin->screen_ptr;
71 wMakeWindowVisible(wwin);
73 x = wwin->frame_x;
74 y = wwin->frame_y;
76 /* bring window back to visible area */
77 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width, wwin->frame->core->height);
79 if (move) {
80 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
84 void InitializeSwitchMenu(void)
86 if (!initialized) {
87 initialized = 1;
89 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
90 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
91 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
92 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
93 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
94 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
95 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
97 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
98 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
104 * Open switch menu
107 void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
109 WMenu *switchmenu = scr->switch_menu;
110 WWindow *wwin;
112 if (switchmenu) {
113 if (switchmenu->flags.mapped) {
114 if (!switchmenu->flags.buttoned) {
115 wMenuUnmap(switchmenu);
116 } else {
117 wRaiseFrame(switchmenu->frame->core);
119 if (keyboard)
120 wMenuMapAt(switchmenu, 0, 0, True);
121 else
122 wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
124 } else {
125 if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
126 y = y - switchmenu->frame->core->height / 2;
128 wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
130 return;
132 switchmenu = wMenuCreate(scr, _("Windows"), True);
133 scr->switch_menu = switchmenu;
135 wwin = scr->focused_window;
136 while (wwin) {
137 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
139 wwin = wwin->prev;
142 if (switchmenu) {
143 int newx, newy;
145 if (!switchmenu->flags.realized)
146 wMenuRealize(switchmenu);
148 if (keyboard && x == 0 && y == 0) {
149 newx = newy = 0;
150 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
151 newx = x - switchmenu->frame->core->width / 2;
152 newy = y - switchmenu->frame->core->height / 2;
153 } else {
154 newx = x - switchmenu->frame->core->width / 2;
155 newy = y;
157 wMenuMapAt(switchmenu, newx, newy, keyboard);
161 static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
163 int idx;
165 if (menu->entry_no <= old_pos)
166 return -1;
168 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
169 if (old_pos >= 0) {
170 if (WS(old_pos) >= wwin->frame->workspace
171 && (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
172 return old_pos;
175 #undef WS
177 for (idx = 0; idx < menu->entry_no; idx++) {
178 WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
180 if (!IS_OMNIPRESENT(tw)
181 && tw->frame->workspace > wwin->frame->workspace) {
182 break;
186 return idx;
190 * Update switch menu
192 void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
194 WMenu *switchmenu = scr->switch_menu;
195 WMenuEntry *entry;
196 char title[MAX_MENU_TEXT_LENGTH + 6];
197 int len = sizeof(title);
198 int i;
199 int checkVisibility = 0;
201 if (!wwin->screen_ptr->switch_menu)
202 return;
204 * This menu is updated under the following conditions:
206 * 1. When a window is created.
207 * 2. When a window is destroyed.
209 * 3. When a window changes it's title.
210 * 4. When a window changes its workspace.
212 if (action == ACTION_ADD) {
213 char *t;
214 int idx;
216 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
217 return;
220 if (wwin->frame->title)
221 snprintf(title, len, "%s", wwin->frame->title);
222 else
223 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
224 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
226 if (IS_OMNIPRESENT(wwin))
227 idx = -1;
228 else {
229 idx = menuIndexForWindow(switchmenu, wwin, -1);
232 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
233 wfree(t);
235 entry->flags.indicator = 1;
236 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
237 if (IS_OMNIPRESENT(wwin))
238 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
239 else
240 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
241 scr->workspaces[wwin->frame->workspace]->name);
243 if (wwin->flags.hidden) {
244 entry->flags.indicator_type = MI_HIDDEN;
245 entry->flags.indicator_on = 1;
246 } else if (wwin->flags.miniaturized) {
247 entry->flags.indicator_type = MI_MINIWINDOW;
248 entry->flags.indicator_on = 1;
249 } else if (wwin->flags.focused) {
250 entry->flags.indicator_type = MI_DIAMOND;
251 entry->flags.indicator_on = 1;
252 } else if (wwin->flags.shaded) {
253 entry->flags.indicator_type = MI_SHADED;
254 entry->flags.indicator_on = 1;
257 wMenuRealize(switchmenu);
258 checkVisibility = 1;
259 } else {
260 char *t;
261 for (i = 0; i < switchmenu->entry_no; i++) {
262 entry = switchmenu->entries[i];
263 /* this is the entry that was changed */
264 if (entry->clientdata == wwin) {
265 switch (action) {
266 case ACTION_REMOVE:
267 wMenuRemoveItem(switchmenu, i);
268 wMenuRealize(switchmenu);
269 checkVisibility = 1;
270 break;
272 case ACTION_CHANGE:
273 if (entry->text)
274 wfree(entry->text);
276 if (wwin->frame->title)
277 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
278 else
279 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
281 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
282 entry->text = t;
284 wMenuRealize(switchmenu);
285 checkVisibility = 1;
286 break;
288 case ACTION_CHANGE_WORKSPACE:
289 if (entry->rtext) {
290 int idx = -1;
291 char *t, *rt;
292 int it, ion;
294 if (IS_OMNIPRESENT(wwin)) {
295 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
296 } else {
297 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
298 "[%s]",
299 scr->workspaces[wwin->frame->workspace]->name);
302 rt = entry->rtext;
303 entry->rtext = NULL;
304 t = entry->text;
305 entry->text = NULL;
307 it = entry->flags.indicator_type;
308 ion = entry->flags.indicator_on;
310 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
311 idx = menuIndexForWindow(switchmenu, wwin, i);
314 wMenuRemoveItem(switchmenu, i);
316 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
317 wfree(t);
318 entry->rtext = rt;
319 entry->flags.indicator = 1;
320 entry->flags.indicator_type = it;
321 entry->flags.indicator_on = ion;
323 wMenuRealize(switchmenu);
324 checkVisibility = 1;
325 break;
327 case ACTION_CHANGE_STATE:
328 if (wwin->flags.hidden) {
329 entry->flags.indicator_type = MI_HIDDEN;
330 entry->flags.indicator_on = 1;
331 } else if (wwin->flags.miniaturized) {
332 entry->flags.indicator_type = MI_MINIWINDOW;
333 entry->flags.indicator_on = 1;
334 } else if (wwin->flags.shaded && !wwin->flags.focused) {
335 entry->flags.indicator_type = MI_SHADED;
336 entry->flags.indicator_on = 1;
337 } else {
338 entry->flags.indicator_on = wwin->flags.focused;
339 entry->flags.indicator_type = MI_DIAMOND;
341 break;
343 break;
347 if (checkVisibility) {
348 int tmp;
350 tmp = switchmenu->frame->top_width + 5;
351 /* if menu got unreachable, bring it to a visible place */
352 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
353 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
354 switchmenu->frame_y, False);
357 wMenuPaint(switchmenu);
360 static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
362 WMenu *menu = scr->switch_menu;
363 int i;
364 WWindow *wwin;
366 if (!menu)
367 return;
369 for (i = 0; i < menu->entry_no; i++) {
370 wwin = (WWindow *) menu->entries[i]->clientdata;
372 if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
373 if (IS_OMNIPRESENT(wwin))
374 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
375 else
376 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
377 scr->workspaces[wwin->frame->workspace]->name);
378 menu->flags.realized = 0;
381 if (!menu->flags.realized)
382 wMenuRealize(menu);
385 static void observer(void *self, WMNotification * notif)
387 WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
388 const char *name = WMGetNotificationName(notif);
389 void *data = WMGetNotificationClientData(notif);
391 if (!wwin)
392 return;
394 if (strcmp(name, WMNManaged) == 0)
395 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
396 else if (strcmp(name, WMNUnmanaged) == 0)
397 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
398 else if (strcmp(name, WMNChangedWorkspace) == 0)
399 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
400 else if (strcmp(name, WMNChangedFocus) == 0)
401 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
402 else if (strcmp(name, WMNChangedName) == 0)
403 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
404 else if (strcmp(name, WMNChangedState) == 0) {
405 if (strcmp((char *)data, "omnipresent") == 0) {
406 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
407 } else {
408 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
413 static void wsobserver(void *self, WMNotification * notif)
415 WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
416 const char *name = WMGetNotificationName(notif);
417 void *data = WMGetNotificationClientData(notif);
419 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
420 UpdateSwitchMenuWorkspace(scr, (uintptr_t)data);
421 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {