Change to the linux kernel coding style
[wmaker-crm.git] / src / switchmenu.c
Commit [+]AuthorDateLineData
6830b057 dan2004-10-12 21:28:27 +00001/*
9af1c6c4 dan1998-10-21 14:43:47 +00002 * Window Maker window manager
6830b057 dan2004-10-12 21:28:27 +00003 *
cab71ba6 dan2002-01-04 07:32:37 +00004 * Copyright (c) 1997 Shige Abe
4153e2fd dan2003-01-16 23:30:45 +00005 * Copyright (c) 1997-2003 Alfredo K. Kojima
6830b057 dan2004-10-12 21:28:27 +00006 *
9d2e6ef9 scottc1998-09-29 22:36:29 +00007 * 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.
11 *
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.
16 *
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
6830b057 dan2004-10-12 21:28:27 +000019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
9d2e6ef9 scottc1998-09-29 22:36:29 +000020 * USA.
21 */
22
9d2e6ef9 scottc1998-09-29 22:36:29 +000023#include "wconfig.h"
24
0261c326 dan1999-01-06 15:22:33 +000025#ifndef LITE
26
9d2e6ef9 scottc1998-09-29 22:36:29 +000027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
06f59b99 Carlos R. Mafra2008-11-06 01:37:44 +010030#include <stdint.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000031
32#include <X11/Xlib.h>
33#include <X11/Xutil.h>
34
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"
43
44/********* Global Variables *******/
45extern WPreferences wPreferences;
46extern Time LastTimestamp;
47
851835c7 dan2002-09-11 15:02:43 +000048static int initialized = 0;
49
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020050static void observer(void *self, WMNotification * notif);
51static void wsobserver(void *self, WMNotification * notif);
5ef342d9 kojima2001-09-06 21:42:28 +000052
9d2e6ef9 scottc1998-09-29 22:36:29 +000053/*
54 * FocusWindow
55 *
56 * - Needs to check if already in the right workspace before
57 * calling wChangeWorkspace?
58 *
59 * Order:
60 * Switch to correct workspace
61 * Unshade if shaded
62 * If iconified then deiconify else focus/raise.
63 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020064static void focusWindow(WMenu * menu, WMenuEntry * entry)
9d2e6ef9 scottc1998-09-29 22:36:29 +000065{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020066 WWindow *wwin;
67 WScreen *scr;
68 int x, y, move = 0;
9d2e6ef9 scottc1998-09-29 22:36:29 +000069
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020070 wwin = (WWindow *) entry->clientdata;
71 scr = wwin->screen_ptr;
9d2e6ef9 scottc1998-09-29 22:36:29 +000072
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020073 wMakeWindowVisible(wwin);
9d2e6ef9 scottc1998-09-29 22:36:29 +000074
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020075 x = wwin->frame_x;
76 y = wwin->frame_y;
6830b057 dan2004-10-12 21:28:27 +000077
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020078 /* bring window back to visible area */
79 move = wScreenBringInside(scr, &x, &y, wwin->frame->core->width, wwin->frame->core->height);
9d2e6ef9 scottc1998-09-29 22:36:29 +000080
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020081 if (move) {
82 wWindowConfigure(wwin, x, y, wwin->client.width, wwin->client.height);
83 }
9d2e6ef9 scottc1998-09-29 22:36:29 +000084}
851835c7 dan2002-09-11 15:02:43 +000085
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020086void InitializeSwitchMenu()
851835c7 dan2002-09-11 15:02:43 +000087{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020088 if (!initialized) {
89 initialized = 1;
90
91 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
92 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
93 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
94 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
95 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
96 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
97 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
98
99 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
100 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
101 }
851835c7 dan2002-09-11 15:02:43 +0000102}
103
9d2e6ef9 scottc1998-09-29 22:36:29 +0000104/*
105 *
6830b057 dan2004-10-12 21:28:27 +0000106 * Open switch menu
9d2e6ef9 scottc1998-09-29 22:36:29 +0000107 *
108 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000110{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 WMenu *switchmenu = scr->switch_menu;
112 WWindow *wwin;
113
114 if (switchmenu) {
115 if (switchmenu->flags.mapped) {
116 if (!switchmenu->flags.buttoned) {
117 wMenuUnmap(switchmenu);
118 } else {
119 wRaiseFrame(switchmenu->frame->core);
120
121 if (keyboard)
122 wMenuMapAt(switchmenu, 0, 0, True);
123 else
124 wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
125 }
126 } else {
127 if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
128 y = y - switchmenu->frame->core->height / 2;
129 }
130 wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
131 }
132 return;
133 }
134 switchmenu = wMenuCreate(scr, _("Windows"), True);
135 scr->switch_menu = switchmenu;
136
137 wwin = scr->focused_window;
138 while (wwin) {
139 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
140
141 wwin = wwin->prev;
142 }
143
144 if (switchmenu) {
145 int newx, newy;
146
147 if (!switchmenu->flags.realized)
148 wMenuRealize(switchmenu);
149
150 if (keyboard && x == 0 && y == 0) {
151 newx = newy = 0;
152 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
153 newx = x - switchmenu->frame->core->width / 2;
154 newy = y - switchmenu->frame->core->height / 2;
155 } else {
156 newx = x - switchmenu->frame->core->width / 2;
157 newy = y;
158 }
159 wMenuMapAt(switchmenu, newx, newy, keyboard);
160 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000161}
162
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200163static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
0261c326 dan1999-01-06 15:22:33 +0000164{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200165 int idx;
0261c326 dan1999-01-06 15:22:33 +0000166
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200167 if (menu->entry_no <= old_pos)
168 return -1;
0261c326 dan1999-01-06 15:22:33 +0000169
170#define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200171 if (old_pos >= 0) {
172 if (WS(old_pos) >= wwin->frame->workspace
173 && (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
174 return old_pos;
175 }
176 }
0261c326 dan1999-01-06 15:22:33 +0000177#undef WS
178
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200179 for (idx = 0; idx < menu->entry_no; idx++) {
180 WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
0261c326 dan1999-01-06 15:22:33 +0000181
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200182 if (!IS_OMNIPRESENT(tw)
183 && tw->frame->workspace > wwin->frame->workspace) {
184 break;
185 }
186 }
0261c326 dan1999-01-06 15:22:33 +0000187
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200188 return idx;
0261c326 dan1999-01-06 15:22:33 +0000189}
190
9d2e6ef9 scottc1998-09-29 22:36:29 +0000191/*
9d2e6ef9 scottc1998-09-29 22:36:29 +0000192 * Update switch menu
9d2e6ef9 scottc1998-09-29 22:36:29 +0000193 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200194void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000195{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200196 WMenu *switchmenu = scr->switch_menu;
197 WMenuEntry *entry;
198 char title[MAX_MENU_TEXT_LENGTH + 6];
199 int len = sizeof(title);
200 int i;
201 int checkVisibility = 0;
202
203 if (!wwin->screen_ptr->switch_menu)
204 return;
205 /*
206 * This menu is updated under the following conditions:
207 *
208 * 1. When a window is created.
209 * 2. When a window is destroyed.
210 *
211 * 3. When a window changes it's title.
212 * 4. When a window changes its workspace.
213 */
214 if (action == ACTION_ADD) {
215 char *t;
216 int idx;
217
218 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
219 return;
220 }
221
222 if (wwin->frame->title)
223 snprintf(title, len, "%s", wwin->frame->title);
224 else
225 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
226 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
227
228 if (IS_OMNIPRESENT(wwin))
229 idx = -1;
230 else {
231 idx = menuIndexForWindow(switchmenu, wwin, -1);
232 }
233
234 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
235 wfree(t);
236
237 entry->flags.indicator = 1;
238 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
239 if (IS_OMNIPRESENT(wwin))
240 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
241 else
242 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
243 scr->workspaces[wwin->frame->workspace]->name);
244
245 if (wwin->flags.hidden) {
246 entry->flags.indicator_type = MI_HIDDEN;
247 entry->flags.indicator_on = 1;
248 } else if (wwin->flags.miniaturized) {
249 entry->flags.indicator_type = MI_MINIWINDOW;
250 entry->flags.indicator_on = 1;
251 } else if (wwin->flags.focused) {
252 entry->flags.indicator_type = MI_DIAMOND;
253 entry->flags.indicator_on = 1;
254 } else if (wwin->flags.shaded) {
255 entry->flags.indicator_type = MI_SHADED;
256 entry->flags.indicator_on = 1;
257 }
258
259 wMenuRealize(switchmenu);
260 checkVisibility = 1;
261 } else {
262 char *t;
263 for (i = 0; i < switchmenu->entry_no; i++) {
264 entry = switchmenu->entries[i];
265 /* this is the entry that was changed */
266 if (entry->clientdata == wwin) {
267 switch (action) {
268 case ACTION_REMOVE:
269 wMenuRemoveItem(switchmenu, i);
270 wMenuRealize(switchmenu);
271 checkVisibility = 1;
272 break;
273
274 case ACTION_CHANGE:
275 if (entry->text)
276 wfree(entry->text);
277
278 if (wwin->frame->title)
279 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
280 else
281 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
282
283 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
284 entry->text = t;
285
286 wMenuRealize(switchmenu);
287 checkVisibility = 1;
288 break;
289
290 case ACTION_CHANGE_WORKSPACE:
291 if (entry->rtext) {
292 int idx = -1;
293 char *t, *rt;
294 int it, ion;
295
296 if (IS_OMNIPRESENT(wwin)) {
297 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
298 } else {
299 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
300 "[%s]",
301 scr->workspaces[wwin->frame->workspace]->name);
302 }
303
304 rt = entry->rtext;
305 entry->rtext = NULL;
306 t = entry->text;
307 entry->text = NULL;
308
309 it = entry->flags.indicator_type;
310 ion = entry->flags.indicator_on;
311
312 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
313 idx = menuIndexForWindow(switchmenu, wwin, i);
314 }
315
316 wMenuRemoveItem(switchmenu, i);
317
318 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
319 wfree(t);
320 entry->rtext = rt;
321 entry->flags.indicator = 1;
322 entry->flags.indicator_type = it;
323 entry->flags.indicator_on = ion;
324 }
325 wMenuRealize(switchmenu);
326 checkVisibility = 1;
327 break;
328
329 case ACTION_CHANGE_STATE:
330 if (wwin->flags.hidden) {
331 entry->flags.indicator_type = MI_HIDDEN;
332 entry->flags.indicator_on = 1;
333 } else if (wwin->flags.miniaturized) {
334 entry->flags.indicator_type = MI_MINIWINDOW;
335 entry->flags.indicator_on = 1;
336 } else if (wwin->flags.shaded && !wwin->flags.focused) {
337 entry->flags.indicator_type = MI_SHADED;
338 entry->flags.indicator_on = 1;
339 } else {
340 entry->flags.indicator_on = wwin->flags.focused;
341 entry->flags.indicator_type = MI_DIAMOND;
342 }
343 break;
344 }
345 break;
346 }
347 }
348 }
349 if (checkVisibility) {
350 int tmp;
351
352 tmp = switchmenu->frame->top_width + 5;
353 /* if menu got unreachable, bring it to a visible place */
354 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
355 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
356 switchmenu->frame_y, False);
357 }
358 }
359 wMenuPaint(switchmenu);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000360}
361
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200362void UpdateSwitchMenuWorkspace(WScreen * scr, int workspace)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000363{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200364 WMenu *menu = scr->switch_menu;
365 int i;
366 WWindow *wwin;
367
368 if (!menu)
369 return;
370
371 for (i = 0; i < menu->entry_no; i++) {
372 wwin = (WWindow *) menu->entries[i]->clientdata;
373
374 if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
375 if (IS_OMNIPRESENT(wwin))
376 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
377 else
378 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
379 scr->workspaces[wwin->frame->workspace]->name);
380 menu->flags.realized = 0;
381 }
382 }
383 if (!menu->flags.realized)
384 wMenuRealize(menu);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000385}
0261c326 dan1999-01-06 15:22:33 +0000386
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200387static void observer(void *self, WMNotification * notif)
5ef342d9 kojima2001-09-06 21:42:28 +0000388{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200389 WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
390 const char *name = WMGetNotificationName(notif);
391 void *data = WMGetNotificationClientData(notif);
392
393 if (!wwin)
394 return;
395
396 if (strcmp(name, WMNManaged) == 0)
397 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
398 else if (strcmp(name, WMNUnmanaged) == 0)
399 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
400 else if (strcmp(name, WMNChangedWorkspace) == 0)
401 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
402 else if (strcmp(name, WMNChangedFocus) == 0)
403 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
404 else if (strcmp(name, WMNChangedName) == 0)
405 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
406 else if (strcmp(name, WMNChangedState) == 0) {
407 if (strcmp((char *)data, "omnipresent") == 0) {
408 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
409 } else {
410 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
411 }
412 }
5ef342d9 kojima2001-09-06 21:42:28 +0000413}
414
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200415static void wsobserver(void *self, WMNotification * notif)
5ef342d9 kojima2001-09-06 21:42:28 +0000416{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200417 WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
418 const char *name = WMGetNotificationName(notif);
419 void *data = WMGetNotificationClientData(notif);
5ef342d9 kojima2001-09-06 21:42:28 +0000420
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200421 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
422 UpdateSwitchMenuWorkspace(scr, (int)(uintptr_t) data);
423 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
6830b057 dan2004-10-12 21:28:27 +0000424
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200425 }
5ef342d9 kojima2001-09-06 21:42:28 +0000426}
427
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428#endif /* !LITE */