wmaker: removed unused macro DBLCLICK_TIME
[wmaker-crm.git] / src / switchmenu.c
bloba614e4fe0f09155a787b53d8be99253410aa4869
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 "misc.h"
37 #include "stacking.h"
38 #include "workspace.h"
39 #include "framewin.h"
40 #include "switchmenu.h"
42 #define IS_GNUSTEP_MENU(w) ((w)->wm_gnustep_attr && \
43 ((w)->wm_gnustep_attr->flags & GSWindowLevelAttr) && \
44 ((w)->wm_gnustep_attr->window_level == WMMainMenuWindowLevel || \
45 (w)->wm_gnustep_attr->window_level == WMSubmenuWindowLevel))
47 static int initialized = 0;
48 static void observer(void *self, WMNotification * notif);
49 static void wsobserver(void *self, WMNotification * notif);
52 * FocusWindow
54 * - Needs to check if already in the right workspace before
55 * calling wChangeWorkspace?
57 * Order:
58 * Switch to correct workspace
59 * Unshade if shaded
60 * If iconified then deiconify else focus/raise.
62 static void focusWindow(WMenu * menu, WMenuEntry * entry)
64 WWindow *wwin;
66 /* Parameter not used, but tell the compiler that it is ok */
67 (void) menu;
69 wwin = (WWindow *) entry->clientdata;
70 wWindowSingleFocus(wwin);
73 void InitializeSwitchMenu(void)
75 if (!initialized) {
76 initialized = 1;
78 WMAddNotificationObserver(observer, NULL, WMNManaged, NULL);
79 WMAddNotificationObserver(observer, NULL, WMNUnmanaged, NULL);
80 WMAddNotificationObserver(observer, NULL, WMNChangedWorkspace, NULL);
81 WMAddNotificationObserver(observer, NULL, WMNChangedState, NULL);
82 WMAddNotificationObserver(observer, NULL, WMNChangedFocus, NULL);
83 WMAddNotificationObserver(observer, NULL, WMNChangedStacking, NULL);
84 WMAddNotificationObserver(observer, NULL, WMNChangedName, NULL);
86 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceChanged, NULL);
87 WMAddNotificationObserver(wsobserver, NULL, WMNWorkspaceNameChanged, NULL);
93 * Open switch menu
96 void OpenSwitchMenu(WScreen * scr, int x, int y, int keyboard)
98 WMenu *switchmenu = scr->switch_menu;
99 WWindow *wwin;
101 if (switchmenu) {
102 if (switchmenu->flags.mapped) {
103 if (!switchmenu->flags.buttoned) {
104 wMenuUnmap(switchmenu);
105 } else {
106 wRaiseFrame(switchmenu->frame->core);
108 if (keyboard)
109 wMenuMapAt(switchmenu, 0, 0, True);
110 else
111 wMenuMapCopyAt(switchmenu, x - switchmenu->frame->core->width / 2, y);
113 } else {
114 if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
115 y = y - switchmenu->frame->core->height / 2;
117 wMenuMapAt(switchmenu, x - switchmenu->frame->core->width / 2, y, keyboard);
119 return;
121 switchmenu = wMenuCreate(scr, _("Windows"), True);
122 scr->switch_menu = switchmenu;
124 wwin = scr->focused_window;
125 while (wwin) {
126 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
128 wwin = wwin->prev;
131 if (switchmenu) {
132 int newx, newy;
134 if (!switchmenu->flags.realized)
135 wMenuRealize(switchmenu);
137 if (keyboard && x == 0 && y == 0) {
138 newx = newy = 0;
139 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
140 newx = x - switchmenu->frame->core->width / 2;
141 newy = y - switchmenu->frame->core->height / 2;
142 } else {
143 newx = x - switchmenu->frame->core->width / 2;
144 newy = y;
146 wMenuMapAt(switchmenu, newx, newy, keyboard);
150 static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
152 int idx;
154 if (menu->entry_no <= old_pos)
155 return -1;
157 #define WS(i) ((WWindow*)menu->entries[i]->clientdata)->frame->workspace
158 if (old_pos >= 0) {
159 if (WS(old_pos) >= wwin->frame->workspace
160 && (old_pos == 0 || WS(old_pos - 1) <= wwin->frame->workspace)) {
161 return old_pos;
164 #undef WS
166 for (idx = 0; idx < menu->entry_no; idx++) {
167 WWindow *tw = (WWindow *) menu->entries[idx]->clientdata;
169 if (!IS_OMNIPRESENT(tw)
170 && tw->frame->workspace > wwin->frame->workspace) {
171 break;
175 return idx;
179 * Update switch menu
181 void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
183 WMenu *switchmenu = scr->switch_menu;
184 WMenuEntry *entry;
185 char title[MAX_MENU_TEXT_LENGTH + 6];
186 int len = sizeof(title);
187 int i;
188 int checkVisibility = 0;
190 if (!wwin->screen_ptr->switch_menu)
191 return;
193 * This menu is updated under the following conditions:
195 * 1. When a window is created.
196 * 2. When a window is destroyed.
198 * 3. When a window changes it's title.
199 * 4. When a window changes its workspace.
201 if (action == ACTION_ADD) {
202 char *t;
203 int idx;
205 if (wwin->flags.internal_window || WFLAGP(wwin, skip_window_list) || IS_GNUSTEP_MENU(wwin)) {
206 return;
209 if (wwin->frame->title)
210 snprintf(title, len, "%s", wwin->frame->title);
211 else
212 snprintf(title, len, "%s", DEF_WINDOW_TITLE);
213 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
215 if (IS_OMNIPRESENT(wwin))
216 idx = -1;
217 else {
218 idx = menuIndexForWindow(switchmenu, wwin, -1);
221 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
222 wfree(t);
224 entry->flags.indicator = 1;
225 entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
226 if (IS_OMNIPRESENT(wwin))
227 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
228 else
229 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
230 scr->workspaces[wwin->frame->workspace]->name);
232 if (wwin->flags.hidden) {
233 entry->flags.indicator_type = MI_HIDDEN;
234 entry->flags.indicator_on = 1;
235 } else if (wwin->flags.miniaturized) {
236 entry->flags.indicator_type = MI_MINIWINDOW;
237 entry->flags.indicator_on = 1;
238 } else if (wwin->flags.focused) {
239 entry->flags.indicator_type = MI_DIAMOND;
240 entry->flags.indicator_on = 1;
241 } else if (wwin->flags.shaded) {
242 entry->flags.indicator_type = MI_SHADED;
243 entry->flags.indicator_on = 1;
246 wMenuRealize(switchmenu);
247 checkVisibility = 1;
248 } else {
249 char *t;
250 for (i = 0; i < switchmenu->entry_no; i++) {
251 entry = switchmenu->entries[i];
252 /* this is the entry that was changed */
253 if (entry->clientdata == wwin) {
254 switch (action) {
255 case ACTION_REMOVE:
256 wMenuRemoveItem(switchmenu, i);
257 wMenuRealize(switchmenu);
258 checkVisibility = 1;
259 break;
261 case ACTION_CHANGE:
262 if (entry->text)
263 wfree(entry->text);
265 if (wwin->frame->title)
266 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", wwin->frame->title);
267 else
268 snprintf(title, MAX_MENU_TEXT_LENGTH, "%s", DEF_WINDOW_TITLE);
270 t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
271 entry->text = t;
273 wMenuRealize(switchmenu);
274 checkVisibility = 1;
275 break;
277 case ACTION_CHANGE_WORKSPACE:
278 if (entry->rtext) {
279 int idx = -1;
280 char *t, *rt;
281 int it, ion;
283 if (IS_OMNIPRESENT(wwin)) {
284 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
285 } else {
286 snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
287 "[%s]",
288 scr->workspaces[wwin->frame->workspace]->name);
291 rt = entry->rtext;
292 entry->rtext = NULL;
293 t = entry->text;
294 entry->text = NULL;
296 it = entry->flags.indicator_type;
297 ion = entry->flags.indicator_on;
299 if (!IS_OMNIPRESENT(wwin) && idx < 0) {
300 idx = menuIndexForWindow(switchmenu, wwin, i);
303 wMenuRemoveItem(switchmenu, i);
305 entry = wMenuInsertCallback(switchmenu, idx, t, focusWindow, wwin);
306 wfree(t);
307 entry->rtext = rt;
308 entry->flags.indicator = 1;
309 entry->flags.indicator_type = it;
310 entry->flags.indicator_on = ion;
312 wMenuRealize(switchmenu);
313 checkVisibility = 1;
314 break;
316 case ACTION_CHANGE_STATE:
317 if (wwin->flags.hidden) {
318 entry->flags.indicator_type = MI_HIDDEN;
319 entry->flags.indicator_on = 1;
320 } else if (wwin->flags.miniaturized) {
321 entry->flags.indicator_type = MI_MINIWINDOW;
322 entry->flags.indicator_on = 1;
323 } else if (wwin->flags.shaded && !wwin->flags.focused) {
324 entry->flags.indicator_type = MI_SHADED;
325 entry->flags.indicator_on = 1;
326 } else {
327 entry->flags.indicator_on = wwin->flags.focused;
328 entry->flags.indicator_type = MI_DIAMOND;
330 break;
332 break;
336 if (checkVisibility) {
337 int tmp;
339 tmp = switchmenu->frame->top_width + 5;
340 /* if menu got unreachable, bring it to a visible place */
341 if (switchmenu->frame_x < tmp - (int)switchmenu->frame->core->width) {
342 wMenuMove(switchmenu, tmp - (int)switchmenu->frame->core->width,
343 switchmenu->frame_y, False);
346 wMenuPaint(switchmenu);
349 static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
351 WMenu *menu = scr->switch_menu;
352 int i;
353 WWindow *wwin;
355 if (!menu)
356 return;
358 for (i = 0; i < menu->entry_no; i++) {
359 wwin = (WWindow *) menu->entries[i]->clientdata;
361 if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
362 if (IS_OMNIPRESENT(wwin))
363 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
364 else
365 snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
366 scr->workspaces[wwin->frame->workspace]->name);
367 menu->flags.realized = 0;
370 if (!menu->flags.realized)
371 wMenuRealize(menu);
374 static void observer(void *self, WMNotification * notif)
376 WWindow *wwin = (WWindow *) WMGetNotificationObject(notif);
377 const char *name = WMGetNotificationName(notif);
378 void *data = WMGetNotificationClientData(notif);
380 /* Parameter not used, but tell the compiler that it is ok */
381 (void) self;
383 if (!wwin)
384 return;
386 if (strcmp(name, WMNManaged) == 0)
387 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
388 else if (strcmp(name, WMNUnmanaged) == 0)
389 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_REMOVE);
390 else if (strcmp(name, WMNChangedWorkspace) == 0)
391 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
392 else if (strcmp(name, WMNChangedFocus) == 0)
393 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
394 else if (strcmp(name, WMNChangedName) == 0)
395 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
396 else if (strcmp(name, WMNChangedState) == 0) {
397 if (strcmp((char *)data, "omnipresent") == 0) {
398 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
399 } else {
400 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
405 static void wsobserver(void *self, WMNotification * notif)
407 WScreen *scr = (WScreen *) WMGetNotificationObject(notif);
408 const char *name = WMGetNotificationName(notif);
409 void *data = WMGetNotificationClientData(notif);
411 /* Parameter not used, but tell the compiler that it is ok */
412 (void) self;
414 if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
415 UpdateSwitchMenuWorkspace(scr, (uintptr_t)data);
416 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {