fixed bug in positioning of window list menu when opened by kbd
[wmaker-crm.git] / src / switchmenu.c
blobc0a8590591f747c9fbf5429cd2e4d1b0984df66a
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997 Shige Abe and
5 * Alfredo K. Kojima
6 *
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.
24 #include "wconfig.h"
26 #ifndef LITE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
35 #include "WindowMaker.h"
36 #include "window.h"
37 #include "actions.h"
38 #include "client.h"
39 #include "funcs.h"
40 #include "stacking.h"
41 #include "workspace.h"
42 #include "framewin.h"
44 /********* Global Variables *******/
45 extern WPreferences wPreferences;
46 extern Time LastTimestamp;
49 static void observer(void *self, WMNotification *notif);
50 static void wsobserver(void *self, WMNotification *notif);
54 * FocusWindow
56 * - Needs to check if already in the right workspace before
57 * calling wChangeWorkspace?
59 * Order:
60 * Switch to correct workspace
61 * Unshade if shaded
62 * If iconified then deiconify else focus/raise.
64 static void
65 focusWindow(WMenu *menu, WMenuEntry *entry)
67 WWindow *wwin;
68 WScreen *scr;
69 int x, y, move=0;
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,
81 wwin->frame->core->height);
83 if (move) {
84 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
90 * Open switch menu
93 void
94 OpenSwitchMenu(WScreen *scr, int x, int y, int keyboard)
96 WMenu *switchmenu = scr->switch_menu;
97 WWindow *wwin;
98 static int initialized = 0;
100 if (!initialized) {
101 initialized = 1;
103 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
104 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
105 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
106 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
107 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
108 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
109 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
111 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
112 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
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,
126 x-switchmenu->frame->core->width/2, y);
128 } else {
129 if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
130 y = y - switchmenu->frame->core->height/2;
132 wMenuMapAt(switchmenu, x-switchmenu->frame->core->width/2, y,
133 keyboard);
135 return;
137 switchmenu = wMenuCreate(scr,_("Windows"),True);
138 scr->switch_menu = switchmenu;
141 wwin = scr->focused_window;
142 while (wwin) {
143 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
145 wwin = wwin->prev;
148 if (switchmenu) {
149 int newx, newy;
151 if (!switchmenu->flags.realized)
152 wMenuRealize(switchmenu);
154 if (keyboard && x==0 && y==0) {
155 newx = newy = 0;
156 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
157 newx = x - switchmenu->frame->core->width/2;
158 newy = y - switchmenu->frame->core->height/2;
159 } else {
160 newx = x - switchmenu->frame->core->width/2;
161 newy = y;
163 wMenuMapAt(switchmenu, newx, newy, keyboard);
168 static int
169 menuIndexForWindow(WMenu *menu, WWindow *wwin, int old_pos)
171 int idx;
173 if (menu->entry_no == 0)
174 return -1;
176 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
177 if (old_pos >= 0) {
178 if (WS(old_pos) >= wwin->frame->workspace
179 && (old_pos == 0 || WS(old_pos-1) <= wwin->frame->workspace)) {
180 return old_pos;
183 #undef WS
185 for (idx = 0; idx < menu->entry_no; idx++) {
186 WWindow *tw = (WWindow*)menu->entries[idx]->clientdata;
188 if (!IS_OMNIPRESENT(tw)
189 && tw->frame->workspace > wwin->frame->workspace) {
190 break;
194 return idx;
199 * Update switch menu
201 void
202 UpdateSwitchMenu(WScreen *scr, WWindow *wwin, int action)
204 WMenu *switchmenu = scr->switch_menu;
205 WMenuEntry *entry;
206 char title[MAX_MENU_TEXT_LENGTH+6];
207 int len = sizeof(title);
208 int i;
209 int checkVisibility = 0;
211 if (!wwin->screen_ptr->switch_menu)
212 return;
214 * This menu is updated under the following conditions:
216 * 1. When a window is created.
217 * 2. When a window is destroyed.
219 * 3. When a window changes it's title.
220 * 4. When a window changes its workspace.
222 if (action == ACTION_ADD) {
223 char *t;
224 int idx;
226 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list))
227 return;
229 if (wwin->frame->title)
230 snprintf(title, len, "%s", wwin->frame->title);
231 else
232 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
233 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
235 if (IS_OMNIPRESENT(wwin))
236 idx = -1;
237 else {
238 idx = menuIndexForWindow(switchmenu, wwin, -1);
241 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
242 wfree(t);
244 entry->flags.indicator = 1;
245 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH+8);
246 if (IS_OMNIPRESENT(wwin))
247 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
248 else
249 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
250 scr->workspaces[wwin->frame->workspace]->name);
252 if (wwin->flags.hidden) {
253 entry->flags.indicator_type = MI_HIDDEN;
254 entry->flags.indicator_on = 1;
255 } else if (wwin->flags.miniaturized) {
256 entry->flags.indicator_type = MI_MINIWINDOW;
257 entry->flags.indicator_on = 1;
258 } else if (wwin->flags.focused) {
259 entry->flags.indicator_type = MI_DIAMOND;
260 entry->flags.indicator_on = 1;
261 } else if (wwin->flags.shaded) {
262 entry->flags.indicator_type = MI_SHADED;
263 entry->flags.indicator_on = 1;
266 wMenuRealize(switchmenu);
267 checkVisibility = 1;
268 } else {
269 char *t;
270 for (i=0; i<switchmenu->entry_no; i++) {
271 entry = switchmenu->entries[i];
272 /* this is the entry that was changed */
273 if (entry->clientdata == wwin) {
274 switch (action) {
275 case ACTION_REMOVE:
276 wMenuRemoveItem(switchmenu, i);
277 wMenuRealize(switchmenu);
278 checkVisibility = 1;
279 break;
281 case ACTION_CHANGE:
282 if (entry->text)
283 wfree(entry->text);
285 if (wwin->frame->title)
286 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
287 wwin->frame->title);
288 else
289 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
290 DEF_WINDOW_TITLE);
292 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
293 entry->text = t;
295 wMenuRealize(switchmenu);
296 checkVisibility = 1;
297 break;
299 case ACTION_CHANGE_WORKSPACE:
300 if (entry->rtext) {
301 int idx = -1;
302 char *t, *rt;
303 int it, ion;
305 if (IS_OMNIPRESENT(wwin)) {
306 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
307 "[*]");
308 } else {
309 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
310 "[%s]", scr->workspaces[wwin->frame->workspace]->name);
313 rt = entry->rtext;
314 entry->rtext = NULL;
315 t = entry->text;
316 entry->text = NULL;
318 it = entry->flags.indicator_type;
319 ion = entry->flags.indicator_on;
321 wMenuRemoveItem(switchmenu, i);
323 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
324 idx = menuIndexForWindow(switchmenu, wwin, i);
327 entry = wMenuInsertCallback(switchmenu, idx, t,
328 focusWindow, wwin);
329 wfree(t);
330 entry->rtext = rt;
331 entry->flags.indicator = 1;
332 entry->flags.indicator_type = it;
333 entry->flags.indicator_on = ion;
335 wMenuRealize(switchmenu);
336 checkVisibility = 1;
337 break;
340 case ACTION_CHANGE_STATE:
341 if (wwin->flags.hidden) {
342 entry->flags.indicator_type = MI_HIDDEN;
343 entry->flags.indicator_on = 1;
344 } else if (wwin->flags.miniaturized) {
345 entry->flags.indicator_type = MI_MINIWINDOW;
346 entry->flags.indicator_on = 1;
347 } else if (wwin->flags.shaded && !wwin->flags.focused) {
348 entry->flags.indicator_type = MI_SHADED;
349 entry->flags.indicator_on = 1;
350 } else {
351 entry->flags.indicator_on = wwin->flags.focused;
352 entry->flags.indicator_type = MI_DIAMOND;
354 break;
356 break;
360 if (checkVisibility) {
361 int tmp;
363 tmp = switchmenu->frame->top_width + 5;
364 /* if menu got unreachable, bring it to a visible place */
365 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
366 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
367 switchmenu->frame_y, False);
370 wMenuPaint(switchmenu);
375 void
376 UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
378 WMenu *menu = scr->switch_menu;
379 int i;
380 WWindow *wwin;
382 if (!menu)
383 return;
385 for (i=0; i<menu->entry_no; i++) {
386 wwin = (WWindow*)menu->entries[i]->clientdata;
388 if (wwin->frame->workspace==workspace
389 && !IS_OMNIPRESENT(wwin)) {
390 if (IS_OMNIPRESENT(wwin))
391 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[*]");
392 else
393 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[%s]",
394 scr->workspaces[wwin->frame->workspace]->name);
395 menu->flags.realized = 0;
398 if (!menu->flags.realized)
399 wMenuRealize(menu);
403 static void observer(void *self, WMNotification *notif)
405 WWindow *wwin = (WWindow*)WMGetNotificationObject(notif);
406 const char *name = WMGetNotificationName(notif);
407 void *data = WMGetNotificationClientData(notif);
409 if (strcmp(name, WMNManaged) == 0 && wwin)
410 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
411 else if (strcmp(name, WMNUnmanaged) == 0 && wwin)
412 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
413 else if (strcmp(name, WMNChangedWorkspace) == 0 && wwin)
414 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
415 else if (strcmp(name, WMNChangedFocus) == 0 && wwin)
416 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
417 else if (strcmp(name, WMNChangedName) == 0 && wwin)
418 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
419 else if (strcmp(name, WMNChangedState) == 0 && wwin) {
421 if (strcmp((char*)data, "omnipresent") == 0) {
422 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
423 } else {
424 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
430 static void wsobserver(void *self, WMNotification *notif)
432 WScreen *scr = (WScreen*)WMGetNotificationObject(notif);
433 const char *name = WMGetNotificationName(notif);
434 void *data = WMGetNotificationClientData(notif);
436 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
437 UpdateSwitchMenuWorkspace(scr, (int)data);
438 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
444 #endif /* !LITE */