Icon: Replace code by call to helper function in wIconCreateWithIconFile
[wmaker-crm.git] / src / switchmenu.c
blob5a3f961aa5a1bf4de9b84b6d73f0a4ee0d7580bb
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 "funcs.h"
37 #include "stacking.h"
38 #include "workspace.h"
39 #include "framewin.h"
41 /********* Global Variables *******/
42 extern WPreferences wPreferences;
44 static int initialized = 0;
45 static void observer(void *self, WMNotification * notif);
46 static void wsobserver(void *self, WMNotification * notif);
49 * FocusWindow
51 * - Needs to check if already in the right workspace before
52 * calling wChangeWorkspace?
54 * Order:
55 * Switch to correct workspace
56 * Unshade if shaded
57 * If iconified then deiconify else focus/raise.
59 static void focusWindow(WMenu * menu, WMenuEntry * entry)
61 WWindow *wwin;
62 WScreen *scr;
63 int x, y, move = 0;
65 wwin = (WWindow *) entry->clientdata;
66 scr = wwin->screen_ptr;
68 wMakeWindowVisible(wwin);
70 x = wwin->frame_x;
71 y = wwin->frame_y;
73 /* bring window back to visible area */
74 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width, wwin->frame->core->height);
76 if (move) {
77 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
81 void InitializeSwitchMenu(void)
83 if (!initialized) {
84 initialized = 1;
86 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
87 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
88 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
89 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
90 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
91 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
92 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
94 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
95 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
101 * Open switch menu
104 void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
106 WMenu *switchmenu = scr->switch_menu;
107 WWindow *wwin;
109 if (switchmenu) {
110 if (switchmenu->flags.mapped) {
111 if (!switchmenu->flags.buttoned) {
112 wMenuUnmap(switchmenu);
113 } else {
114 wRaiseFrame(switchmenu->frame->core);
116 if (keyboard)
117 wMenuMapAt(switchmenu, 0, 0, True);
118 else
119 wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
121 } else {
122 if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
123 y = y - switchmenu->frame->core->height / 2;
125 wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
127 return;
129 switchmenu = wMenuCreate(scr, _("Windows"), True);
130 scr->switch_menu = switchmenu;
132 wwin = scr->focused_window;
133 while (wwin) {
134 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
136 wwin = wwin->prev;
139 if (switchmenu) {
140 int newx, newy;
142 if (!switchmenu->flags.realized)
143 wMenuRealize(switchmenu);
145 if (keyboard && x == 0 && y == 0) {
146 newx = newy = 0;
147 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
148 newx = x - switchmenu->frame->core->width / 2;
149 newy = y - switchmenu->frame->core->height / 2;
150 } else {
151 newx = x - switchmenu->frame->core->width / 2;
152 newy = y;
154 wMenuMapAt(switchmenu, newx, newy, keyboard);
158 static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
160 int idx;
162 if (menu->entry_no <= old_pos)
163 return -1;
165 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
166 if (old_pos >= 0) {
167 if (WS(old_pos) >= wwin->frame->workspace
168 && (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
169 return old_pos;
172 #undef WS
174 for (idx = 0; idx < menu->entry_no; idx++) {
175 WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
177 if (!IS_OMNIPRESENT(tw)
178 && tw->frame->workspace > wwin->frame->workspace) {
179 break;
183 return idx;
187 * Update switch menu
189 void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
191 WMenu *switchmenu = scr->switch_menu;
192 WMenuEntry *entry;
193 char title[MAX_MENU_TEXT_LENGTH + 6];
194 int len = sizeof(title);
195 int i;
196 int checkVisibility = 0;
198 if (!wwin->screen_ptr->switch_menu)
199 return;
201 * This menu is updated under the following conditions:
203 * 1. When a window is created.
204 * 2. When a window is destroyed.
206 * 3. When a window changes it's title.
207 * 4. When a window changes its workspace.
209 if (action == ACTION_ADD) {
210 char *t;
211 int idx;
213 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
214 return;
217 if (wwin->frame->title)
218 snprintf(title, len, "%s", wwin->frame->title);
219 else
220 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
221 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
223 if (IS_OMNIPRESENT(wwin))
224 idx = -1;
225 else {
226 idx = menuIndexForWindow(switchmenu, wwin, -1);
229 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
230 wfree(t);
232 entry->flags.indicator = 1;
233 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
234 if (IS_OMNIPRESENT(wwin))
235 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
236 else
237 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
238 scr->workspaces[wwin->frame->workspace]->name);
240 if (wwin->flags.hidden) {
241 entry->flags.indicator_type = MI_HIDDEN;
242 entry->flags.indicator_on = 1;
243 } else if (wwin->flags.miniaturized) {
244 entry->flags.indicator_type = MI_MINIWINDOW;
245 entry->flags.indicator_on = 1;
246 } else if (wwin->flags.focused) {
247 entry->flags.indicator_type = MI_DIAMOND;
248 entry->flags.indicator_on = 1;
249 } else if (wwin->flags.shaded) {
250 entry->flags.indicator_type = MI_SHADED;
251 entry->flags.indicator_on = 1;
254 wMenuRealize(switchmenu);
255 checkVisibility = 1;
256 } else {
257 char *t;
258 for (i = 0; i < switchmenu->entry_no; i++) {
259 entry = switchmenu->entries[i];
260 /* this is the entry that was changed */
261 if (entry->clientdata == wwin) {
262 switch (action) {
263 case ACTION_REMOVE:
264 wMenuRemoveItem(switchmenu, i);
265 wMenuRealize(switchmenu);
266 checkVisibility = 1;
267 break;
269 case ACTION_CHANGE:
270 if (entry->text)
271 wfree(entry->text);
273 if (wwin->frame->title)
274 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
275 else
276 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
278 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
279 entry->text = t;
281 wMenuRealize(switchmenu);
282 checkVisibility = 1;
283 break;
285 case ACTION_CHANGE_WORKSPACE:
286 if (entry->rtext) {
287 int idx = -1;
288 char *t, *rt;
289 int it, ion;
291 if (IS_OMNIPRESENT(wwin)) {
292 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
293 } else {
294 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
295 "[%s]",
296 scr->workspaces[wwin->frame->workspace]->name);
299 rt = entry->rtext;
300 entry->rtext = NULL;
301 t = entry->text;
302 entry->text = NULL;
304 it = entry->flags.indicator_type;
305 ion = entry->flags.indicator_on;
307 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
308 idx = menuIndexForWindow(switchmenu, wwin, i);
311 wMenuRemoveItem(switchmenu, i);
313 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
314 wfree(t);
315 entry->rtext = rt;
316 entry->flags.indicator = 1;
317 entry->flags.indicator_type = it;
318 entry->flags.indicator_on = ion;
320 wMenuRealize(switchmenu);
321 checkVisibility = 1;
322 break;
324 case ACTION_CHANGE_STATE:
325 if (wwin->flags.hidden) {
326 entry->flags.indicator_type = MI_HIDDEN;
327 entry->flags.indicator_on = 1;
328 } else if (wwin->flags.miniaturized) {
329 entry->flags.indicator_type = MI_MINIWINDOW;
330 entry->flags.indicator_on = 1;
331 } else if (wwin->flags.shaded && !wwin->flags.focused) {
332 entry->flags.indicator_type = MI_SHADED;
333 entry->flags.indicator_on = 1;
334 } else {
335 entry->flags.indicator_on = wwin->flags.focused;
336 entry->flags.indicator_type = MI_DIAMOND;
338 break;
340 break;
344 if (checkVisibility) {
345 int tmp;
347 tmp = switchmenu->frame->top_width + 5;
348 /* if menu got unreachable, bring it to a visible place */
349 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
350 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
351 switchmenu->frame_y, False);
354 wMenuPaint(switchmenu);
357 static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
359 WMenu *menu = scr->switch_menu;
360 int i;
361 WWindow *wwin;
363 if (!menu)
364 return;
366 for (i = 0; i < menu->entry_no; i++) {
367 wwin = (WWindow *) menu->entries[i]->clientdata;
369 if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
370 if (IS_OMNIPRESENT(wwin))
371 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
372 else
373 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
374 scr->workspaces[wwin->frame->workspace]->name);
375 menu->flags.realized = 0;
378 if (!menu->flags.realized)
379 wMenuRealize(menu);
382 static void observer(void *self, WMNotification * notif)
384 WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
385 const char *name = WMGetNotificationName(notif);
386 void *data = WMGetNotificationClientData(notif);
388 if (!wwin)
389 return;
391 if (strcmp(name, WMNManaged) == 0)
392 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
393 else if (strcmp(name, WMNUnmanaged) == 0)
394 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
395 else if (strcmp(name, WMNChangedWorkspace) == 0)
396 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
397 else if (strcmp(name, WMNChangedFocus) == 0)
398 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
399 else if (strcmp(name, WMNChangedName) == 0)
400 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
401 else if (strcmp(name, WMNChangedState) == 0) {
402 if (strcmp((char *)data, "omnipresent") == 0) {
403 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
404 } else {
405 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
410 static void wsobserver(void *self, WMNotification * notif)
412 WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
413 const char *name = WMGetNotificationName(notif);
414 void *data = WMGetNotificationClientData(notif);
416 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
417 UpdateSwitchMenuWorkspace(scr, (uintptr_t)data);
418 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {