Update Serbian translation from master branch
[wmaker-crm.git] / src / winmenu.c
blob706378f5b8893b32b46e1db6d12fed2568cb33bd
1 /* winmenu.c - command menu for windows
3 * Window Maker window manager
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 <unistd.h>
27 #include <string.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/XKBlib.h>
33 #include "WindowMaker.h"
34 #include "actions.h"
35 #include "menu.h"
36 #include "main.h"
37 #include "window.h"
38 #include "client.h"
39 #include "application.h"
40 #include "keybind.h"
41 #include "misc.h"
42 #include "framewin.h"
43 #include "workspace.h"
44 #include "winspector.h"
45 #include "dialog.h"
46 #include "stacking.h"
47 #include "icon.h"
48 #include "xinerama.h"
49 #include "winmenu.h"
52 static WMenu *makeWorkspaceMenu(WScreen *scr);
53 static WMenu *makeOptionsMenu(WScreen *scr);
54 static WMenu *makeMaximizeMenu(WScreen *scr);
57 * Define the Menu entry that will be present in the Window menu
59 * The order of this list defines the order in which they will appear;
60 * make sure to keep the structure below aligned with the list because
61 * the constant index is used in many places.
63 enum
65 MC_MAXIMIZE,
66 MC_OTHERMAX,
67 MC_MINIATURIZE,
68 MC_SHADE,
69 MC_HIDE,
70 MC_MOVERESIZE,
71 MC_SELECT,
72 MC_CHANGEWKSPC,
73 MC_PROPERTIES,
74 MC_OPTIONS,
75 MC_RELAUNCH,
76 MC_CLOSE,
77 MC_KILL
80 static const struct {
81 const char *label;
82 WMenu *(*generate_submenu)(WScreen *scr);
83 } window_menu_entries[] = {
84 [MC_MAXIMIZE] = { N_("Maximize"), NULL },
85 [MC_OTHERMAX] = { N_("Other maximization"), makeMaximizeMenu },
86 [MC_MINIATURIZE] = { N_("Miniaturize"), NULL },
87 [MC_SHADE] = { N_("Shade"), NULL },
88 [MC_HIDE] = { N_("Hide"), NULL },
89 [MC_MOVERESIZE] = { N_("Resize/Move"), NULL },
90 [MC_SELECT] = { N_("Select"), NULL },
91 [MC_CHANGEWKSPC] = { N_("Move To"), makeWorkspaceMenu },
92 [MC_PROPERTIES] = { N_("Attributes..."), NULL },
93 [MC_OPTIONS] = { N_("Options"), makeOptionsMenu },
94 [MC_RELAUNCH] = { N_("Launch"), NULL },
95 [MC_CLOSE] = { N_("Close"), NULL },
96 [MC_KILL] = { N_("Kill"), NULL }
100 * Defines the menu entries for the Options sub-menu
102 * These options will be placed at the beginning of the menu, the rest will
103 * be populated with the Window Shortcut possibilities
105 enum
107 WO_KEEP_ON_TOP,
108 WO_KEEP_AT_BOTTOM,
109 WO_OMNIPRESENT
112 static const char *const menu_options_entries[] = {
113 [WO_KEEP_ON_TOP] = N_("Keep on top"),
114 [WO_KEEP_AT_BOTTOM] = N_("Keep at bottom"),
115 [WO_OMNIPRESENT] = N_("Omnipresent")
119 * Defines the menu entries for the Other maximization sub-menu
121 static const struct {
122 unsigned int indicator;
123 const char *label;
124 unsigned int shortcut_idx;
125 int maxim_direction;
126 } menu_maximize_entries[] = {
127 { MI_SNAP_V, N_("Vertical"), WKBD_VMAXIMIZE, MAX_VERTICAL },
128 { MI_SNAP_H, N_("Horizontal"), WKBD_HMAXIMIZE, MAX_HORIZONTAL },
129 { MI_CENTRAL, N_("Central"), WKBD_CENTRAL, MAX_CENTRAL },
130 { MI_SNAP_LH, N_("Left half"), WKBD_LHMAXIMIZE, MAX_VERTICAL | MAX_LEFTHALF },
131 { MI_SNAP_RH, N_("Right half"), WKBD_RHMAXIMIZE, MAX_VERTICAL | MAX_RIGHTHALF },
132 { MI_SNAP_TH, N_("Top half"), WKBD_THMAXIMIZE, MAX_HORIZONTAL | MAX_TOPHALF },
133 { MI_SNAP_BH, N_("Bottom half"), WKBD_BHMAXIMIZE, MAX_HORIZONTAL | MAX_BOTTOMHALF },
134 { MI_SNAP_TL, N_("Top left"), WKBD_LTCMAXIMIZE, MAX_LEFTHALF | MAX_TOPHALF },
135 { MI_SNAP_TR, N_("Top right"), WKBD_RTCMAXIMIZE, MAX_RIGHTHALF | MAX_TOPHALF },
136 { MI_SNAP_BL, N_("Bottom left"), WKBD_LBCMAXIMIZE, MAX_LEFTHALF | MAX_BOTTOMHALF },
137 { MI_SNAP_BR, N_("Bottom right"), WKBD_RBCMAXIMIZE, MAX_RIGHTHALF | MAX_BOTTOMHALF },
138 { MI_SNAP_TILED, N_("Tiled"), WKBD_MAXIMUS, MAX_MAXIMUS }
141 static void updateOptionsMenu(WMenu * menu, WWindow * wwin);
143 static void execWindowOptionCommand(WMenu * menu, WMenuEntry * entry)
145 WWindow *wwin = (WWindow *) entry->clientdata;
147 /* Parameter not used, but tell the compiler that it is ok */
148 (void) menu;
150 switch (entry->order) {
151 case WO_KEEP_ON_TOP:
152 if (wwin->frame->core->stacking->window_level != WMFloatingLevel)
153 ChangeStackingLevel(wwin->frame->core, WMFloatingLevel);
154 else
155 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
156 break;
158 case WO_KEEP_AT_BOTTOM:
159 if (wwin->frame->core->stacking->window_level != WMSunkenLevel)
160 ChangeStackingLevel(wwin->frame->core, WMSunkenLevel);
161 else
162 ChangeStackingLevel(wwin->frame->core, WMNormalLevel);
163 break;
165 case WO_OMNIPRESENT:
166 wWindowSetOmnipresent(wwin, !wwin->flags.omnipresent);
167 break;
171 static void execMaximizeCommand(WMenu * menu, WMenuEntry * entry)
173 WWindow *wwin = (WWindow *) entry->clientdata;
175 /* Parameter not used, but tell the compiler that it is ok */
176 (void) menu;
178 handleMaximize(wwin, menu_maximize_entries[entry->order].maxim_direction);
181 static void updateUnmaximizeShortcut(WMenuEntry * entry, int flags)
183 int key;
185 switch (flags & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL)) {
186 case MAX_HORIZONTAL:
187 key = WKBD_HMAXIMIZE;
188 break;
190 case MAX_VERTICAL:
191 key = WKBD_VMAXIMIZE;
192 break;
194 case MAX_CENTRAL:
195 key = WKBD_CENTRAL;
196 break;
198 case MAX_LEFTHALF | MAX_VERTICAL:
199 key = WKBD_LHMAXIMIZE;
200 break;
202 case MAX_RIGHTHALF | MAX_VERTICAL:
203 key = WKBD_RHMAXIMIZE;
204 break;
206 case MAX_TOPHALF | MAX_HORIZONTAL:
207 key = WKBD_THMAXIMIZE;
208 break;
210 case MAX_BOTTOMHALF | MAX_HORIZONTAL:
211 key = WKBD_BHMAXIMIZE;
212 break;
214 case MAX_LEFTHALF | MAX_TOPHALF:
215 key = WKBD_LTCMAXIMIZE;
216 break;
218 case MAX_RIGHTHALF | MAX_TOPHALF:
219 key = WKBD_RTCMAXIMIZE;
220 break;
222 case MAX_LEFTHALF | MAX_BOTTOMHALF:
223 key = WKBD_LBCMAXIMIZE;
224 break;
226 case MAX_RIGHTHALF | MAX_BOTTOMHALF:
227 key = WKBD_RBCMAXIMIZE;
228 break;
230 case MAX_MAXIMUS:
231 key = WKBD_MAXIMUS;
232 break;
234 default:
235 key = WKBD_MAXIMIZE;
236 break;
239 entry->rtext = GetShortcutKey(wKeyBindings[key]);
242 static void execMenuCommand(WMenu * menu, WMenuEntry * entry)
244 WWindow *wwin = (WWindow *) entry->clientdata;
245 WApplication *wapp;
247 CloseWindowMenu(menu->frame->screen_ptr);
249 switch (entry->order) {
250 case MC_CLOSE:
251 /* send delete message */
252 wClientSendProtocol(wwin, w_global.atom.wm.delete_window,
253 w_global.timestamp.last_event);
254 break;
256 case MC_KILL:
257 wretain(wwin);
258 if (wPreferences.dont_confirm_kill
259 || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
261 ("This will kill the application.\nAny unsaved changes will be lost.\nPlease confirm."),
262 _("Yes"), _("No"), NULL) == WAPRDefault) {
263 if (!wwin->flags.destroyed)
264 wClientKill(wwin);
266 wrelease(wwin);
267 break;
269 case MC_MINIATURIZE:
270 if (wwin->flags.miniaturized) {
271 wDeiconifyWindow(wwin);
272 } else {
273 if (wwin->protocols.MINIATURIZE_WINDOW) {
274 wClientSendProtocol(wwin, w_global.atom.gnustep.wm_miniaturize_window,
275 w_global.timestamp.last_event);
276 } else {
277 wIconifyWindow(wwin);
280 break;
282 case MC_MAXIMIZE:
283 if (wwin->flags.maximized)
284 wUnmaximizeWindow(wwin);
285 else
286 wMaximizeWindow(wwin, MAX_VERTICAL | MAX_HORIZONTAL,
287 wGetHeadForWindow(wwin));
288 break;
290 case MC_SHADE:
291 if (wwin->flags.shaded)
292 wUnshadeWindow(wwin);
293 else
294 wShadeWindow(wwin);
295 break;
297 case MC_SELECT:
298 if (!wwin->flags.miniaturized)
299 wSelectWindow(wwin, !wwin->flags.selected);
300 else
301 wIconSelect(wwin->icon);
302 break;
304 case MC_MOVERESIZE:
305 wKeyboardMoveResizeWindow(wwin);
306 break;
308 case MC_PROPERTIES:
309 wShowInspectorForWindow(wwin);
310 break;
312 case MC_RELAUNCH:
313 (void) RelaunchWindow(wwin);
314 break;
316 case MC_HIDE:
317 wapp = wApplicationOf(wwin->main_window);
318 wHideApplication(wapp);
319 break;
323 static void switchWSCommand(WMenu * menu, WMenuEntry * entry)
325 WWindow *wwin = (WWindow *) entry->clientdata;
327 /* Parameter not used, but tell the compiler that it is ok */
328 (void) menu;
330 wSelectWindow(wwin, False);
331 wWindowChangeWorkspace(wwin, entry->order);
334 static void makeShortcutCommand(WMenu * menu, WMenuEntry * entry)
336 WWindow *wwin = (WWindow *) entry->clientdata;
337 WScreen *scr = wwin->screen_ptr;
338 int index = entry->order - wlengthof(menu_options_entries);
340 /* Parameter not used, but tell the compiler that it is ok */
341 (void) menu;
343 if (scr->shortcutWindows[index]) {
344 WMFreeArray(scr->shortcutWindows[index]);
345 scr->shortcutWindows[index] = NULL;
348 if (wwin->flags.selected && scr->selected_windows) {
349 scr->shortcutWindows[index] = WMDuplicateArray(scr->selected_windows);
350 /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
351 WMInsertInArray(scr->shortcutWindows[index], 0, wwin); */
352 } else {
353 scr->shortcutWindows[index] = WMCreateArray(4);
354 WMAddToArray(scr->shortcutWindows[index], wwin);
357 wSelectWindow(wwin, !wwin->flags.selected);
358 XFlush(dpy);
359 wusleep(3000);
360 wSelectWindow(wwin, !wwin->flags.selected);
361 XFlush(dpy);
364 static void updateWorkspaceMenu(WMenu * menu)
366 WScreen *scr = menu->frame->screen_ptr;
367 char title[MAX_WORKSPACENAME_WIDTH + 1];
368 WMenuEntry *entry;
369 int i;
371 for (i = 0; i < scr->workspace_count; i++) {
372 if (i < menu->entry_no) {
374 entry = menu->entries[i];
375 if (strcmp(entry->text, scr->workspaces[i]->name) != 0) {
376 wfree(entry->text);
377 strncpy(title, scr->workspaces[i]->name, MAX_WORKSPACENAME_WIDTH);
378 title[MAX_WORKSPACENAME_WIDTH] = 0;
379 menu->entries[i]->text = wstrdup(title);
380 menu->entries[i]->rtext = GetShortcutKey(wKeyBindings[WKBD_MOVE_WORKSPACE1 + i]);
381 menu->flags.realized = 0;
383 } else {
384 strncpy(title, scr->workspaces[i]->name, MAX_WORKSPACENAME_WIDTH);
385 title[MAX_WORKSPACENAME_WIDTH] = 0;
387 entry = wMenuAddCallback(menu, title, switchWSCommand, NULL);
388 entry->rtext = GetShortcutKey(wKeyBindings[WKBD_MOVE_WORKSPACE1 + i]);
390 menu->flags.realized = 0;
393 /* workspace shortcut labels */
394 if (i / 10 == scr->current_workspace / 10)
395 entry->rtext = GetShortcutKey(wKeyBindings[WKBD_MOVE_WORKSPACE1 + (i % 10)]);
396 else
397 entry->rtext = NULL;
400 if (!menu->flags.realized)
401 wMenuRealize(menu);
404 static void updateMakeShortcutMenu(WMenu * menu, WWindow * wwin)
406 WMenu *smenu = menu->cascades[menu->entries[MC_OPTIONS]->cascade];
407 int i;
408 char buffer[64];
409 KeyCode kcode;
411 if (!smenu)
412 return;
414 for (i = wlengthof(menu_options_entries); i < smenu->entry_no; i++) {
415 int shortcutNo = i - wlengthof(menu_options_entries);
416 WMenuEntry *entry = smenu->entries[i];
417 WMArray *shortSelWindows = wwin->screen_ptr->shortcutWindows[shortcutNo];
419 snprintf(buffer, sizeof(buffer), _("Set Shortcut %i"), shortcutNo + 1);
421 if (!shortSelWindows) {
422 entry->flags.indicator_on = 0;
423 } else {
424 entry->flags.indicator_on = 1;
425 if (WMCountInArray(shortSelWindows, wwin))
426 entry->flags.indicator_type = MI_DIAMOND;
427 else
428 entry->flags.indicator_type = MI_CHECK;
431 if (strcmp(buffer, entry->text) != 0) {
432 wfree(entry->text);
433 entry->text = wstrdup(buffer);
434 smenu->flags.realized = 0;
437 kcode = wKeyBindings[WKBD_WINDOW1 + shortcutNo].keycode;
439 if (kcode) {
440 char *tmp;
442 tmp = GetShortcutKey(wKeyBindings[WKBD_WINDOW1 + shortcutNo]);
443 if (tmp == NULL) {
444 if (entry->rtext != NULL) {
445 /* There was a shortcut, but there is no more */
446 wfree(entry->rtext);
447 entry->rtext = NULL;
448 smenu->flags.realized = 0;
450 } else if (entry->rtext == NULL) {
451 /* There was no shortcut, but there is one now */
452 entry->rtext = tmp;
453 smenu->flags.realized = 0;
454 } else if (strcmp(tmp, entry->rtext) != 0) {
455 /* There was a shortcut, but it has changed */
456 wfree(entry->rtext);
457 entry->rtext = tmp;
458 smenu->flags.realized = 0;
459 } else {
460 /* There was a shortcut but it did not change */
461 wfree(tmp);
463 wMenuSetEnabled(smenu, i, True);
464 } else {
465 wMenuSetEnabled(smenu, i, False);
466 if (entry->rtext) {
467 wfree(entry->rtext);
468 entry->rtext = NULL;
469 smenu->flags.realized = 0;
472 entry->clientdata = wwin;
474 if (!smenu->flags.realized)
475 wMenuRealize(smenu);
478 static void updateOptionsMenu(WMenu * menu, WWindow * wwin)
480 WMenu *smenu = menu->cascades[menu->entries[MC_OPTIONS]->cascade];
482 /* keep on top check */
483 smenu->entries[WO_KEEP_ON_TOP]->clientdata = wwin;
484 smenu->entries[WO_KEEP_ON_TOP]->flags.indicator_on =
485 (wwin->frame->core->stacking->window_level == WMFloatingLevel) ? 1 : 0;
486 wMenuSetEnabled(smenu, WO_KEEP_ON_TOP, !wwin->flags.miniaturized);
487 smenu->entries[WO_KEEP_ON_TOP]->rtext = GetShortcutKey(wKeyBindings[WKBD_KEEP_ON_TOP]);
489 /* keep at bottom check */
490 smenu->entries[WO_KEEP_AT_BOTTOM]->clientdata = wwin;
491 smenu->entries[WO_KEEP_AT_BOTTOM]->flags.indicator_on =
492 (wwin->frame->core->stacking->window_level == WMSunkenLevel) ? 1 : 0;
493 wMenuSetEnabled(smenu, WO_KEEP_AT_BOTTOM, !wwin->flags.miniaturized);
494 smenu->entries[WO_KEEP_AT_BOTTOM]->rtext = GetShortcutKey(wKeyBindings[WKBD_KEEP_AT_BOTTOM]);
496 /* omnipresent check */
497 smenu->entries[WO_OMNIPRESENT]->clientdata = wwin;
498 smenu->entries[WO_OMNIPRESENT]->flags.indicator_on = IS_OMNIPRESENT(wwin);
499 smenu->entries[WO_OMNIPRESENT]->rtext = GetShortcutKey(wKeyBindings[WKBD_OMNIPRESENT]);
501 smenu->flags.realized = 0;
502 wMenuRealize(smenu);
505 static void updateMaximizeMenu(WMenu * menu, WWindow * wwin)
507 WMenu *smenu = menu->cascades[menu->entries[MC_OTHERMAX]->cascade];
508 int i;
510 for (i = 0; i < smenu->entry_no; i++) {
511 smenu->entries[i]->clientdata = wwin;
512 smenu->entries[i]->rtext = GetShortcutKey(wKeyBindings[menu_maximize_entries[i].shortcut_idx]);
515 smenu->flags.realized = 0;
516 wMenuRealize(smenu);
519 static WMenu *makeWorkspaceMenu(WScreen * scr)
521 WMenu *menu;
523 menu = wMenuCreate(scr, NULL, False);
524 if (!menu) {
525 wwarning(_("could not create submenu for window menu"));
526 return NULL;
529 updateWorkspaceMenu(menu);
532 * The Workspace Menu is made visible in the screen structure because
533 * it is updated when there is a change on workspaces. This was done
534 * to be efficient, avoiding re-generating completely the window menu
535 * and its sub-menus every time it is needed.
537 scr->workspace_submenu = menu;
539 return menu;
542 static WMenu *makeOptionsMenu(WScreen * scr)
544 WMenu *menu;
545 WMenuEntry *entry;
546 int i;
548 menu = wMenuCreate(scr, NULL, False);
549 if (!menu) {
550 wwarning(_("could not create submenu for window menu"));
551 return NULL;
554 for (i = 0; i < wlengthof(menu_options_entries); i++) {
555 entry = wMenuAddCallback(menu, _(menu_options_entries[i]), execWindowOptionCommand, NULL);
556 entry->flags.indicator = 1;
557 entry->flags.indicator_type = MI_CHECK;
560 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
561 entry = wMenuAddCallback(menu, "", makeShortcutCommand, NULL);
562 entry->flags.indicator = 1;
565 return menu;
568 static WMenu *makeMaximizeMenu(WScreen * scr)
570 WMenu *menu;
571 WMenuEntry *entry;
572 int i;
574 menu = wMenuCreate(scr, NULL, False);
575 if (!menu) {
576 wwarning(_("could not create submenu for window menu"));
577 return NULL;
580 for (i = 0; i < wlengthof(menu_maximize_entries); i++) {
581 entry = wMenuAddCallback(menu, _(menu_maximize_entries[i].label), execMaximizeCommand, NULL);
582 entry->flags.indicator = entry->flags.indicator_on = 1;
583 entry->flags.indicator_type = menu_maximize_entries[i].indicator;
586 return menu;
589 static WMenu *createWindowMenu(WScreen * scr)
591 WMenu *menu;
592 int i;
594 menu = wMenuCreate(scr, NULL, False);
596 for (i = 0; i < wlengthof(window_menu_entries); i++) {
597 WMenuEntry *entry;
599 entry = wMenuAddCallback(menu, _(window_menu_entries[i].label),
600 (window_menu_entries[i].generate_submenu == NULL)?execMenuCommand:NULL,
601 NULL);
602 if (window_menu_entries[i].generate_submenu != NULL) {
603 WMenu *submenu;
605 submenu = window_menu_entries[i].generate_submenu(scr);
606 wMenuEntrySetCascade(menu, entry, submenu);
610 return menu;
613 void CloseWindowMenu(WScreen * scr)
615 if (scr->window_menu) {
616 if (scr->window_menu->flags.mapped)
617 wMenuUnmap(scr->window_menu);
619 if (scr->window_menu->entries[0]->clientdata) {
620 WWindow *wwin = (WWindow *) scr->window_menu->entries[0]->clientdata;
622 wwin->flags.menu_open_for_me = 0;
624 scr->window_menu->entries[0]->clientdata = NULL;
628 static void updateMenuForWindow(WMenu * menu, WWindow * wwin)
630 WApplication *wapp = wApplicationOf(wwin->main_window);
631 WScreen *scr = wwin->screen_ptr;
632 int i;
634 updateOptionsMenu(menu, wwin);
635 updateMaximizeMenu(menu, wwin);
637 updateMakeShortcutMenu(menu, wwin);
639 wMenuSetEnabled(menu, MC_HIDE, wapp != NULL && !WFLAGP(wapp->main_window_desc, no_appicon));
641 wMenuSetEnabled(menu, MC_CLOSE, (wwin->protocols.DELETE_WINDOW && !WFLAGP(wwin, no_closable)));
643 if (wwin->flags.miniaturized) {
644 static char *text = NULL;
645 if (!text)
646 text = _("Deminiaturize");
648 menu->entries[MC_MINIATURIZE]->text = text;
649 } else {
650 static char *text = NULL;
651 if (!text)
652 text = _("Miniaturize");
654 menu->entries[MC_MINIATURIZE]->text = text;
657 wMenuSetEnabled(menu, MC_MINIATURIZE, !WFLAGP(wwin, no_miniaturizable));
659 if (wwin->flags.maximized) {
660 static char *text = NULL;
661 if (!text)
662 text = _("Unmaximize");
664 menu->entries[MC_MAXIMIZE]->text = text;
665 updateUnmaximizeShortcut(menu->entries[MC_MAXIMIZE], wwin->flags.maximized);
666 } else {
667 static char *text = NULL;
668 if (!text)
669 text = _("Maximize");
671 menu->entries[MC_MAXIMIZE]->text = text;
672 menu->entries[MC_MAXIMIZE]->rtext = GetShortcutKey(wKeyBindings[WKBD_MAXIMIZE]);
674 wMenuSetEnabled(menu, MC_MAXIMIZE, IS_RESIZABLE(wwin));
676 wMenuSetEnabled(menu, MC_MOVERESIZE, IS_RESIZABLE(wwin)
677 && !wwin->flags.miniaturized);
679 if (wwin->flags.shaded) {
680 static char *text = NULL;
681 if (!text)
682 text = _("Unshade");
684 menu->entries[MC_SHADE]->text = text;
685 } else {
686 static char *text = NULL;
687 if (!text)
688 text = _("Shade");
690 menu->entries[MC_SHADE]->text = text;
693 wMenuSetEnabled(menu, MC_SHADE, !WFLAGP(wwin, no_shadeable)
694 && !wwin->flags.miniaturized);
696 if (wwin->flags.selected) {
697 static char *text = NULL;
698 if (!text)
699 text = _("Deselect");
701 menu->entries[MC_SELECT]->text = text;
702 } else {
703 static char *text = NULL;
704 if (!text)
705 text = _("Select");
707 menu->entries[MC_SELECT]->text = text;
710 wMenuSetEnabled(menu, MC_CHANGEWKSPC, !IS_OMNIPRESENT(wwin));
712 if (!wwin->flags.inspector_open) {
713 wMenuSetEnabled(menu, MC_PROPERTIES, True);
714 } else {
715 wMenuSetEnabled(menu, MC_PROPERTIES, False);
718 /* Update shortcut labels except for (Un)Maximize which is
719 * handled separately.
721 menu->entries[MC_MINIATURIZE]->rtext = GetShortcutKey(wKeyBindings[WKBD_MINIATURIZE]);
722 menu->entries[MC_SHADE]->rtext = GetShortcutKey(wKeyBindings[WKBD_SHADE]);
723 menu->entries[MC_HIDE]->rtext = GetShortcutKey(wKeyBindings[WKBD_HIDE]);
724 menu->entries[MC_MOVERESIZE]->rtext = GetShortcutKey(wKeyBindings[WKBD_MOVERESIZE]);
725 menu->entries[MC_SELECT]->rtext = GetShortcutKey(wKeyBindings[WKBD_SELECT]);
726 menu->entries[MC_RELAUNCH]->rtext = GetShortcutKey(wKeyBindings[WKBD_RELAUNCH]);
727 menu->entries[MC_CLOSE]->rtext = GetShortcutKey(wKeyBindings[WKBD_CLOSE]);
729 /* set the client data of the entries to the window */
730 for (i = 0; i < menu->entry_no; i++) {
731 menu->entries[i]->clientdata = wwin;
734 for (i = 0; i < scr->workspace_submenu->entry_no; i++) {
735 scr->workspace_submenu->entries[i]->clientdata = wwin;
736 if (i == scr->current_workspace)
737 wMenuSetEnabled(scr->workspace_submenu, i, False);
738 else
739 wMenuSetEnabled(scr->workspace_submenu, i, True);
742 menu->flags.realized = 0;
743 wMenuRealize(menu);
746 static WMenu *open_window_menu_core(WWindow *wwin)
748 WScreen *scr = wwin->screen_ptr;
749 WMenu *menu;
751 wwin->flags.menu_open_for_me = 1;
753 if (!scr->window_menu) {
754 scr->window_menu = createWindowMenu(scr);
756 /* hack to save some memory allocation/deallocation */
757 wfree(scr->window_menu->entries[MC_MINIATURIZE]->text);
758 wfree(scr->window_menu->entries[MC_MAXIMIZE]->text);
759 wfree(scr->window_menu->entries[MC_SHADE]->text);
760 wfree(scr->window_menu->entries[MC_SELECT]->text);
761 } else {
762 updateWorkspaceMenu(scr->workspace_submenu);
765 menu = scr->window_menu;
766 if (menu->flags.mapped) {
767 wMenuUnmap(menu);
768 if (menu->entries[0]->clientdata == wwin)
769 return NULL;
772 updateMenuForWindow(menu, wwin);
774 return menu;
777 static void prepare_menu_position(WMenu *menu, int *x, int *y)
779 WMRect rect;
781 rect = wGetRectForHead(menu->frame->screen_ptr,
782 wGetHeadForPointerLocation(menu->frame->screen_ptr));
783 if (*x < rect.pos.x - menu->frame->core->width / 2)
784 *x = rect.pos.x - menu->frame->core->width / 2;
785 if (*y < rect.pos.y)
786 *y = rect.pos.y;
789 void OpenWindowMenu(WWindow *wwin, int x, int y, int keyboard)
791 WMenu *menu;
793 menu = open_window_menu_core(wwin);
794 if (!menu)
795 return;
797 /* Specific menu position */
798 x -= menu->frame->core->width / 2;
799 if (x + menu->frame->core->width > wwin->frame_x + wwin->frame->core->width)
800 x = wwin->frame_x + wwin->frame->core->width - menu->frame->core->width;
801 if (x < wwin->frame_x)
802 x = wwin->frame_x;
804 /* Common menu position */
805 prepare_menu_position(menu, &x, &y);
807 if (!wwin->flags.internal_window)
808 wMenuMapAt(menu, x, y, keyboard);
811 void OpenWindowMenu2(WWindow *wwin, int x, int y, int keyboard)
813 int i;
814 WMenu *menu;
815 WScreen *scr = wwin->screen_ptr;
817 menu = open_window_menu_core(wwin);
818 if (!menu)
819 return;
821 /* Specific menu position */
822 for (i = 0; i < scr->workspace_submenu->entry_no; i++) {
823 scr->workspace_submenu->entries[i]->clientdata = wwin;
824 wMenuSetEnabled(scr->workspace_submenu, i, True);
827 x -= menu->frame->core->width / 2;
829 /* Common menu position */
830 prepare_menu_position(menu, &x, &y);
832 if (!wwin->flags.internal_window)
833 wMenuMapAt(menu, x, y, keyboard);
836 void OpenMiniwindowMenu(WWindow * wwin, int x, int y)
838 WMenu *menu;
840 menu = open_window_menu_core(wwin);
841 if (!menu)
842 return;
844 x -= menu->frame->core->width / 2;
846 wMenuMapAt(menu, x, y, False);
849 void DestroyWindowMenu(WScreen *scr)
851 if (scr->window_menu) {
852 scr->window_menu->entries[MC_MINIATURIZE]->text = NULL;
853 scr->window_menu->entries[MC_MAXIMIZE]->text = NULL;
854 scr->window_menu->entries[MC_SHADE]->text = NULL;
855 scr->window_menu->entries[MC_SELECT]->text = NULL;
856 wMenuDestroy(scr->window_menu, True);
857 scr->window_menu = NULL;