wmaker: Fix compiler warnings about pointer <--> integer conversion
[wmaker-crm.git] / src / switchmenu.c
blob0db6e71a780d47cd123d5f873a660c244e02d779
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.
24 #include "wconfig.h"
26 #ifndef LITE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
36 #include "WindowMaker.h"
37 #include "window.h"
38 #include "actions.h"
39 #include "client.h"
40 #include "funcs.h"
41 #include "stacking.h"
42 #include "workspace.h"
43 #include "framewin.h"
45 /********* Global Variables *******/
46 extern WPreferences wPreferences;
47 extern Time LastTimestamp;
50 static int initialized = 0;
53 static void observer(void *self, WMNotification *notif);
54 static void wsobserver(void *self, WMNotification *notif);
58 * FocusWindow
60 * - Needs to check if already in the right workspace before
61 * calling wChangeWorkspace?
63 * Order:
64 * Switch to correct workspace
65 * Unshade if shaded
66 * If iconified then deiconify else focus/raise.
68 static void
69 focusWindow(WMenu *menu, WMenuEntry *entry)
71 WWindow *wwin;
72 WScreen *scr;
73 int x, y, move=0;
75 wwin = (WWindow*)entry->clientdata;
76 scr = wwin->screen_ptr;
78 wMakeWindowVisible(wwin);
80 x = wwin->frame_x;
81 y = wwin->frame_y;
83 /* bring window back to visible area */
84 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width,
85 wwin->frame->core->height);
87 if (move) {
88 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
93 void
94 InitializeSwitchMenu()
96 if (!initialized) {
97 initialized = 1;
99 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
100 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
101 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
102 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
103 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
104 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
105 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
107 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
108 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
115 * Open switch menu
118 void
119 OpenSwitchMenu(WScreen *scr, int x, int y, int keyboard)
121 WMenu *switchmenu = scr->switch_menu;
122 WWindow *wwin;
124 if (switchmenu) {
125 if (switchmenu->flags.mapped) {
126 if (!switchmenu->flags.buttoned) {
127 wMenuUnmap(switchmenu);
128 } else {
129 wRaiseFrame(switchmenu->frame->core);
131 if (keyboard)
132 wMenuMapAt(switchmenu, 0, 0, True);
133 else
134 wMenuMapCopyAt(switchmenu,
135 x-switchmenu->frame->core->width/2, y);
137 } else {
138 if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
139 y = y - switchmenu->frame->core->height/2;
141 wMenuMapAt(switchmenu, x-switchmenu->frame->core->width/2, y,
142 keyboard);
144 return;
146 switchmenu = wMenuCreate(scr,_("Windows"),True);
147 scr->switch_menu = switchmenu;
150 wwin = scr->focused_window;
151 while (wwin) {
152 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
154 wwin = wwin->prev;
157 if (switchmenu) {
158 int newx, newy;
160 if (!switchmenu->flags.realized)
161 wMenuRealize(switchmenu);
163 if (keyboard && x==0 && y==0) {
164 newx = newy = 0;
165 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
166 newx = x - switchmenu->frame->core->width/2;
167 newy = y - switchmenu->frame->core->height/2;
168 } else {
169 newx = x - switchmenu->frame->core->width/2;
170 newy = y;
172 wMenuMapAt(switchmenu, newx, newy, keyboard);
177 static int
178 menuIndexForWindow(WMenu *menu, WWindow *wwin, int old_pos)
180 int idx;
182 if (menu->entry_no <= old_pos)
183 return -1;
185 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
186 if (old_pos >= 0) {
187 if (WS(old_pos) >= wwin->frame->workspace
188 && (old_pos == 0 || WS(old_pos-1) <= wwin->frame->workspace)) {
189 return old_pos;
192 #undef WS
194 for (idx = 0; idx < menu->entry_no; idx++) {
195 WWindow *tw = (WWindow*)menu->entries[idx]->clientdata;
197 if (!IS_OMNIPRESENT(tw)
198 && tw->frame->workspace > wwin->frame->workspace) {
199 break;
203 return idx;
208 * Update switch menu
210 void
211 UpdateSwitchMenu(WScreen *scr, WWindow *wwin, int action)
213 WMenu *switchmenu = scr->switch_menu;
214 WMenuEntry *entry;
215 char title[MAX_MENU_TEXT_LENGTH+6];
216 int len = sizeof(title);
217 int i;
218 int checkVisibility = 0;
220 if (!wwin->screen_ptr->switch_menu)
221 return;
223 * This menu is updated under the following conditions:
225 * 1. When a window is created.
226 * 2. When a window is destroyed.
228 * 3. When a window changes it's title.
229 * 4. When a window changes its workspace.
231 if (action == ACTION_ADD) {
232 char *t;
233 int idx;
235 if (wwin->flags.internal_window ||
236 WFLAGP(wwin, skip_window_list) ||
237 IS_GNUSTEP_MENU(wwin)) {
238 return;
241 if (wwin->frame->title)
242 snprintf(title, len, "%s", wwin->frame->title);
243 else
244 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
245 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
247 if (IS_OMNIPRESENT(wwin))
248 idx = -1;
249 else {
250 idx = menuIndexForWindow(switchmenu, wwin, -1);
253 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
254 wfree(t);
256 entry->flags.indicator = 1;
257 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH+8);
258 if (IS_OMNIPRESENT(wwin))
259 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
260 else
261 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
262 scr->workspaces[wwin->frame->workspace]->name);
264 if (wwin->flags.hidden) {
265 entry->flags.indicator_type = MI_HIDDEN;
266 entry->flags.indicator_on = 1;
267 } else if (wwin->flags.miniaturized) {
268 entry->flags.indicator_type = MI_MINIWINDOW;
269 entry->flags.indicator_on = 1;
270 } else if (wwin->flags.focused) {
271 entry->flags.indicator_type = MI_DIAMOND;
272 entry->flags.indicator_on = 1;
273 } else if (wwin->flags.shaded) {
274 entry->flags.indicator_type = MI_SHADED;
275 entry->flags.indicator_on = 1;
278 wMenuRealize(switchmenu);
279 checkVisibility = 1;
280 } else {
281 char *t;
282 for (i=0; i<switchmenu->entry_no; i++) {
283 entry = switchmenu->entries[i];
284 /* this is the entry that was changed */
285 if (entry->clientdata == wwin) {
286 switch (action) {
287 case ACTION_REMOVE:
288 wMenuRemoveItem(switchmenu, i);
289 wMenuRealize(switchmenu);
290 checkVisibility = 1;
291 break;
293 case ACTION_CHANGE:
294 if (entry->text)
295 wfree(entry->text);
297 if (wwin->frame->title)
298 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
299 wwin->frame->title);
300 else
301 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
302 DEF_WINDOW_TITLE);
304 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
305 entry->text = t;
307 wMenuRealize(switchmenu);
308 checkVisibility = 1;
309 break;
311 case ACTION_CHANGE_WORKSPACE:
312 if (entry->rtext) {
313 int idx = -1;
314 char *t, *rt;
315 int it, ion;
317 if (IS_OMNIPRESENT(wwin)) {
318 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
319 "[*]");
320 } else {
321 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
322 "[%s]", scr->workspaces[wwin->frame->workspace]->name);
325 rt = entry->rtext;
326 entry->rtext = NULL;
327 t = entry->text;
328 entry->text = NULL;
330 it = entry->flags.indicator_type;
331 ion = entry->flags.indicator_on;
333 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
334 idx = menuIndexForWindow(switchmenu, wwin, i);
337 wMenuRemoveItem(switchmenu, i);
339 entry = wMenuInsertCallback(switchmenu, idx, t,
340 focusWindow, wwin);
341 wfree(t);
342 entry->rtext = rt;
343 entry->flags.indicator = 1;
344 entry->flags.indicator_type = it;
345 entry->flags.indicator_on = ion;
347 wMenuRealize(switchmenu);
348 checkVisibility = 1;
349 break;
352 case ACTION_CHANGE_STATE:
353 if (wwin->flags.hidden) {
354 entry->flags.indicator_type = MI_HIDDEN;
355 entry->flags.indicator_on = 1;
356 } else if (wwin->flags.miniaturized) {
357 entry->flags.indicator_type = MI_MINIWINDOW;
358 entry->flags.indicator_on = 1;
359 } else if (wwin->flags.shaded && !wwin->flags.focused) {
360 entry->flags.indicator_type = MI_SHADED;
361 entry->flags.indicator_on = 1;
362 } else {
363 entry->flags.indicator_on = wwin->flags.focused;
364 entry->flags.indicator_type = MI_DIAMOND;
366 break;
368 break;
372 if (checkVisibility) {
373 int tmp;
375 tmp = switchmenu->frame->top_width + 5;
376 /* if menu got unreachable, bring it to a visible place */
377 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
378 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
379 switchmenu->frame_y, False);
382 wMenuPaint(switchmenu);
387 void
388 UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
390 WMenu *menu = scr->switch_menu;
391 int i;
392 WWindow *wwin;
394 if (!menu)
395 return;
397 for (i=0; i<menu->entry_no; i++) {
398 wwin = (WWindow*)menu->entries[i]->clientdata;
400 if (wwin->frame->workspace==workspace
401 && !IS_OMNIPRESENT(wwin)) {
402 if (IS_OMNIPRESENT(wwin))
403 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[*]");
404 else
405 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[%s]",
406 scr->workspaces[wwin->frame->workspace]->name);
407 menu->flags.realized = 0;
410 if (!menu->flags.realized)
411 wMenuRealize(menu);
415 static void
416 observer(void *self, WMNotification *notif)
418 WWindow *wwin = (WWindow*)WMGetNotificationObject(notif);
419 const char *name = WMGetNotificationName(notif);
420 void *data = WMGetNotificationClientData(notif);
422 if (!wwin)
423 return;
425 if (strcmp(name, WMNManaged) == 0)
426 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
427 else if (strcmp(name, WMNUnmanaged) == 0)
428 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
429 else if (strcmp(name, WMNChangedWorkspace) == 0)
430 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
431 else if (strcmp(name, WMNChangedFocus) == 0)
432 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
433 else if (strcmp(name, WMNChangedName) == 0)
434 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
435 else if (strcmp(name, WMNChangedState) == 0) {
436 if (strcmp((char*)data, "omnipresent") == 0) {
437 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
438 } else {
439 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
445 static void
446 wsobserver(void *self, WMNotification *notif)
448 WScreen *scr = (WScreen*)WMGetNotificationObject(notif);
449 const char *name = WMGetNotificationName(notif);
450 void *data = WMGetNotificationClientData(notif);
452 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
453 UpdateSwitchMenuWorkspace(scr, (int)(uintptr_t)data);
454 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
460 #endif /* !LITE */