ops
[wmaker-crm.git] / src / switchmenu.c
blob0a9b0ebf147edeff0d1e0dd7268fdacbc99aaa66
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997 Shige Abe
5 * Copyright (c) 1997-2003 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 int initialized = 0;
52 static void observer(void *self, WMNotification *notif);
53 static void wsobserver(void *self, WMNotification *notif);
57 * FocusWindow
59 * - Needs to check if already in the right workspace before
60 * calling wChangeWorkspace?
62 * Order:
63 * Switch to correct workspace
64 * Unshade if shaded
65 * If iconified then deiconify else focus/raise.
67 static void
68 focusWindow(WMenu *menu, WMenuEntry *entry)
70 WWindow *wwin;
71 WScreen *scr;
72 int x, y, move=0;
74 wwin = (WWindow*)entry->clientdata;
75 scr = wwin->screen_ptr;
77 wMakeWindowVisible(wwin);
79 x = wwin->frame_x;
80 y = wwin->frame_y;
82 /* bring window back to visible area */
83 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width,
84 wwin->frame->core->height);
86 if (move) {
87 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
92 void
93 InitializeSwitchMenu()
95 if (!initialized) {
96 initialized = 1;
98 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
99 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
100 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
101 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
102 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
103 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
104 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
106 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
107 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
114 * Open switch menu
117 void
118 OpenSwitchMenu(WScreen *scr, int x, int y, int keyboard)
120 WMenu *switchmenu = scr->switch_menu;
121 WWindow *wwin;
123 if (switchmenu) {
124 if (switchmenu->flags.mapped) {
125 if (!switchmenu->flags.buttoned) {
126 wMenuUnmap(switchmenu);
127 } else {
128 wRaiseFrame(switchmenu->frame->core);
130 if (keyboard)
131 wMenuMapAt(switchmenu, 0, 0, True);
132 else
133 wMenuMapCopyAt(switchmenu,
134 x-switchmenu->frame->core->width/2, y);
136 } else {
137 if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
138 y = y - switchmenu->frame->core->height/2;
140 wMenuMapAt(switchmenu, x-switchmenu->frame->core->width/2, y,
141 keyboard);
143 return;
145 switchmenu = wMenuCreate(scr,_("Windows"),True);
146 scr->switch_menu = switchmenu;
149 wwin = scr->focused_window;
150 while (wwin) {
151 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
153 wwin = wwin->prev;
156 if (switchmenu) {
157 int newx, newy;
159 if (!switchmenu->flags.realized)
160 wMenuRealize(switchmenu);
162 if (keyboard && x==0 && y==0) {
163 newx = newy = 0;
164 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
165 newx = x - switchmenu->frame->core->width/2;
166 newy = y - switchmenu->frame->core->height/2;
167 } else {
168 newx = x - switchmenu->frame->core->width/2;
169 newy = y;
171 wMenuMapAt(switchmenu, newx, newy, keyboard);
176 static int
177 menuIndexForWindow(WMenu *menu, WWindow *wwin, int old_pos)
179 int idx;
181 if (menu->entry_no == 0)
182 return -1;
184 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
185 if (old_pos >= 0) {
186 if (WS(old_pos) >= wwin->frame->workspace
187 && (old_pos == 0 || WS(old_pos-1) <= wwin->frame->workspace)) {
188 return old_pos;
191 #undef WS
193 for (idx = 0; idx < menu->entry_no; idx++) {
194 WWindow *tw = (WWindow*)menu->entries[idx]->clientdata;
196 if (!IS_OMNIPRESENT(tw)
197 && tw->frame->workspace > wwin->frame->workspace) {
198 break;
202 return idx;
207 * Update switch menu
209 void
210 UpdateSwitchMenu(WScreen *scr, WWindow *wwin, int action)
212 WMenu *switchmenu = scr->switch_menu;
213 WMenuEntry *entry;
214 char title[MAX_MENU_TEXT_LENGTH+6];
215 int len = sizeof(title);
216 int i;
217 int checkVisibility = 0;
219 if (!wwin->screen_ptr->switch_menu)
220 return;
222 * This menu is updated under the following conditions:
224 * 1. When a window is created.
225 * 2. When a window is destroyed.
227 * 3. When a window changes it's title.
228 * 4. When a window changes its workspace.
230 if (action == ACTION_ADD) {
231 char *t;
232 int idx;
234 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list))
235 return;
237 if (wwin->frame->title)
238 snprintf(title, len, "%s", wwin->frame->title);
239 else
240 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
241 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
243 if (IS_OMNIPRESENT(wwin))
244 idx = -1;
245 else {
246 idx = menuIndexForWindow(switchmenu, wwin, -1);
249 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
250 wfree(t);
252 entry->flags.indicator = 1;
253 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH+8);
254 if (IS_OMNIPRESENT(wwin))
255 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
256 else
257 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
258 scr->workspaces[wwin->frame->workspace]->name);
260 if (wwin->flags.hidden) {
261 entry->flags.indicator_type = MI_HIDDEN;
262 entry->flags.indicator_on = 1;
263 } else if (wwin->flags.miniaturized) {
264 entry->flags.indicator_type = MI_MINIWINDOW;
265 entry->flags.indicator_on = 1;
266 } else if (wwin->flags.focused) {
267 entry->flags.indicator_type = MI_DIAMOND;
268 entry->flags.indicator_on = 1;
269 } else if (wwin->flags.shaded) {
270 entry->flags.indicator_type = MI_SHADED;
271 entry->flags.indicator_on = 1;
274 wMenuRealize(switchmenu);
275 checkVisibility = 1;
276 } else {
277 char *t;
278 for (i=0; i<switchmenu->entry_no; i++) {
279 entry = switchmenu->entries[i];
280 /* this is the entry that was changed */
281 if (entry->clientdata == wwin) {
282 switch (action) {
283 case ACTION_REMOVE:
284 wMenuRemoveItem(switchmenu, i);
285 wMenuRealize(switchmenu);
286 checkVisibility = 1;
287 break;
289 case ACTION_CHANGE:
290 if (entry->text)
291 wfree(entry->text);
293 if (wwin->frame->title)
294 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
295 wwin->frame->title);
296 else
297 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s",
298 DEF_WINDOW_TITLE);
300 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
301 entry->text = t;
303 wMenuRealize(switchmenu);
304 checkVisibility = 1;
305 break;
307 case ACTION_CHANGE_WORKSPACE:
308 if (entry->rtext) {
309 int idx = -1;
310 char *t, *rt;
311 int it, ion;
313 if (IS_OMNIPRESENT(wwin)) {
314 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
315 "[*]");
316 } else {
317 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
318 "[%s]", scr->workspaces[wwin->frame->workspace]->name);
321 rt = entry->rtext;
322 entry->rtext = NULL;
323 t = entry->text;
324 entry->text = NULL;
326 it = entry->flags.indicator_type;
327 ion = entry->flags.indicator_on;
329 wMenuRemoveItem(switchmenu, i);
331 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
332 idx = menuIndexForWindow(switchmenu, wwin, i);
335 entry = wMenuInsertCallback(switchmenu, idx, t,
336 focusWindow, wwin);
337 wfree(t);
338 entry->rtext = rt;
339 entry->flags.indicator = 1;
340 entry->flags.indicator_type = it;
341 entry->flags.indicator_on = ion;
343 wMenuRealize(switchmenu);
344 checkVisibility = 1;
345 break;
348 case ACTION_CHANGE_STATE:
349 if (wwin->flags.hidden) {
350 entry->flags.indicator_type = MI_HIDDEN;
351 entry->flags.indicator_on = 1;
352 } else if (wwin->flags.miniaturized) {
353 entry->flags.indicator_type = MI_MINIWINDOW;
354 entry->flags.indicator_on = 1;
355 } else if (wwin->flags.shaded && !wwin->flags.focused) {
356 entry->flags.indicator_type = MI_SHADED;
357 entry->flags.indicator_on = 1;
358 } else {
359 entry->flags.indicator_on = wwin->flags.focused;
360 entry->flags.indicator_type = MI_DIAMOND;
362 break;
364 break;
368 if (checkVisibility) {
369 int tmp;
371 tmp = switchmenu->frame->top_width + 5;
372 /* if menu got unreachable, bring it to a visible place */
373 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
374 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
375 switchmenu->frame_y, False);
378 wMenuPaint(switchmenu);
383 void
384 UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
386 WMenu *menu = scr->switch_menu;
387 int i;
388 WWindow *wwin;
390 if (!menu)
391 return;
393 for (i=0; i<menu->entry_no; i++) {
394 wwin = (WWindow*)menu->entries[i]->clientdata;
396 if (wwin->frame->workspace==workspace
397 && !IS_OMNIPRESENT(wwin)) {
398 if (IS_OMNIPRESENT(wwin))
399 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[*]");
400 else
401 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH,"[%s]",
402 scr->workspaces[wwin->frame->workspace]->name);
403 menu->flags.realized = 0;
406 if (!menu->flags.realized)
407 wMenuRealize(menu);
411 static void
412 observer(void *self, WMNotification *notif)
414 WWindow *wwin = (WWindow*)WMGetNotificationObject(notif);
415 const char *name = WMGetNotificationName(notif);
416 void *data = WMGetNotificationClientData(notif);
418 if (!wwin)
419 return;
421 if (strcmp(name, WMNManaged) == 0)
422 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
423 else if (strcmp(name, WMNUnmanaged) == 0)
424 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
425 else if (strcmp(name, WMNChangedWorkspace) == 0)
426 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
427 else if (strcmp(name, WMNChangedFocus) == 0)
428 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
429 else if (strcmp(name, WMNChangedName) == 0)
430 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
431 else if (strcmp(name, WMNChangedState) == 0) {
432 if (strcmp((char*)data, "omnipresent") == 0) {
433 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
434 } else {
435 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
441 static void
442 wsobserver(void *self, WMNotification *notif)
444 WScreen *scr = (WScreen*)WMGetNotificationObject(notif);
445 const char *name = WMGetNotificationName(notif);
446 void *data = WMGetNotificationClientData(notif);
448 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
449 UpdateSwitchMenuWorkspace(scr, (int)data);
450 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
456 #endif /* !LITE */