1 /* usermenu.c- user defined menu
3 * Window Maker window manager
5 * Copyright (c) hmmm... Should I put everybody's name here?
6 * Where's my lawyer?? -- ]d :D
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * User defined menu is good, but beer's always better
24 * if someone wanna start hacking something, He heard...
26 * - enhance commands. (eg, exit, hide, list all app's member
28 * - cache menu... dunno.. if people really use this feature :P
29 * - Violins, senseless violins!
30 * that's all, right now :P
31 * - external! WINGs menu editor.
33 * - allow applications to share their menu. ] think it
34 * looks weird since there still are more than 1 appicon.
39 * ("Command 1", SHORTCUT, 1),
40 * ("Command 2", SHORTCUT, 2, ("Allowed_instant_1", "Allowed_instant_2")),
41 * ("Command 3", SHORTCUT, (3,4,5), ("Allowed_instant_1")),
44 * ("Kill Command", KILL),
45 * ("Hide Command", HIDE),
46 * ("Hide Others Command", HIDE_OTHERS),
47 * ("Members", MEMBERS),
48 * ("Exit Command", EXIT)
53 * - If you don't want short cut keys to be listed
54 * in the right side of entries, you can just put them
55 * in array instead of using the string directly.
64 #include <X11/Xutil.h>
65 #include <X11/Xproto.h>
66 #include <X11/Xatom.h>
72 #include "WindowMaker.h"
76 #include "xmodifier.h"
81 #define MAX_SHORTCUT_LENGTH 32
90 static void notifyClient(WMenu
*menu
, WMenuEntry
*entry
)
93 WUserMenuData
*data
= entry
->clientdata
;
94 WScreen
*scr
= data
->screen
;
100 window
= scr
->focused_window
->client_win
;
102 for (i
= 0; i
< data
->key_no
; i
++) {
103 event
.xkey
.type
= KeyPress
;
104 event
.xkey
.display
= dpy
;
105 event
.xkey
.window
= window
;
106 event
.xkey
.root
= DefaultRootWindow(dpy
);
107 event
.xkey
.subwindow
= (Window
) None
;
110 event
.xkey
.x_root
= 0x0;
111 event
.xkey
.y_root
= 0x0;
112 event
.xkey
.keycode
= data
->key
[i
].keycode
;
113 event
.xkey
.state
= data
->key
[i
].modifier
;
114 event
.xkey
.same_screen
= True
;
115 event
.xkey
.time
= CurrentTime
;
116 if (XSendEvent(dpy
, window
, False
, KeyPressMask
, &event
)) {
117 event
.xkey
.type
= KeyRelease
;
118 event
.xkey
.time
= CurrentTime
;
119 XSendEvent(dpy
, window
, True
, KeyReleaseMask
, &event
);
124 static void removeUserMenudata(void *menudata
)
126 WUserMenuData
*data
= menudata
;
133 static WUserMenuData
*convertShortcuts(WScreen
*scr
, WMPropList
*shortcut
)
137 char *k
, buf
[MAX_SHORTCUT_LENGTH
], *b
;
138 int keycount
, i
, j
, mod
;
140 if (WMIsPLString(shortcut
))
142 else if (WMIsPLArray(shortcut
))
143 keycount
= WMGetPropListItemCount(shortcut
);
147 data
= wmalloc(sizeof(WUserMenuData
));
151 data
->key
= wmalloc(sizeof(WShortKey
) * keycount
);
157 for (i
= 0, j
= 0; i
< keycount
; i
++) {
158 data
->key
[j
].modifier
= 0;
159 if (WMIsPLArray(shortcut
))
160 wstrlcpy(buf
, WMGetFromPLString(WMGetFromPLArray(shortcut
, i
)), MAX_SHORTCUT_LENGTH
);
162 wstrlcpy(buf
, WMGetFromPLString(shortcut
), MAX_SHORTCUT_LENGTH
);
166 while ((k
= strchr(b
, '+')) != NULL
) {
168 mod
= wXModifierFromKey(b
);
172 data
->key
[j
].modifier
|= mod
;
176 ksym
= XStringToKeysym(b
);
177 if (ksym
== NoSymbol
)
180 data
->key
[j
].keycode
= XKeysymToKeycode(dpy
, ksym
);
181 if (data
->key
[j
].keycode
)
199 static WMenu
*configureUserMenu(WScreen
*scr
, WMPropList
*plum
)
203 WMPropList
*elem
, *title
, *command
, *params
= NULL
;
210 if (!WMIsPLArray(plum
))
213 count
= WMGetPropListItemCount(plum
);
217 elem
= WMGetFromPLArray(plum
, 0);
218 if (!WMIsPLString(elem
))
221 mtitle
= WMGetFromPLString(elem
);
222 menu
= wMenuCreateForApp(scr
, mtitle
, True
);
224 for (i
= 1; i
< count
; i
++) {
225 elem
= WMGetFromPLArray(plum
, i
);
226 if (WMIsPLArray(WMGetFromPLArray(elem
, 1))) {
228 WMenuEntry
*mentry
= NULL
;
230 submenu
= configureUserMenu(scr
, elem
);
232 mentry
= wMenuAddCallback(menu
, submenu
->frame
->title
, NULL
, NULL
);
234 wMenuEntrySetCascade(menu
, mentry
, submenu
);
237 WMPropList
*instances
= 0;
239 title
= WMGetFromPLArray(elem
, idx
++);
240 command
= WMGetFromPLArray(elem
, idx
++);
241 if (WMGetPropListItemCount(elem
) >= 3)
242 params
= WMGetFromPLArray(elem
, idx
++);
244 if (!title
|| !command
)
247 if (!strcmp("SHORTCUT", WMGetFromPLString(command
))) {
250 data
= convertShortcuts(scr
, params
);
252 entry
= wMenuAddCallback(menu
, WMGetFromPLString(title
),
256 if (WMIsPLString(params
))
258 GetShortcutString(WMGetFromPLString(params
));
260 entry
->free_cdata
= removeUserMenudata
;
262 if (WMGetPropListItemCount(elem
) >= 4) {
263 instances
= WMGetFromPLArray(elem
, idx
++);
264 if (WMIsPLArray(instances
))
265 if (instances
&& WMGetPropListItemCount(instances
)
266 && WMIsPLArray(instances
)) {
268 WMRetainPropList(instances
);
280 void wUserMenuRefreshInstances(WMenu
*menu
, WWindow
*wwin
)
282 int i
, j
, count
, paintflag
;
289 for (i
= 0; i
< menu
->entry_no
; i
++) {
290 if (menu
->entries
[i
]->instances
) {
293 count
= WMGetPropListItemCount(menu
->entries
[i
]->instances
);
295 oldflag
= menu
->entries
[i
]->flags
.enabled
;
296 menu
->entries
[i
]->flags
.enabled
= 0;
297 for (j
= 0; j
< count
; j
++) {
298 ins
= WMGetFromPLArray(menu
->entries
[i
]->instances
, j
);
299 if (!strcmp(wwin
->wm_instance
, WMGetFromPLString(ins
))) {
300 menu
->entries
[i
]->flags
.enabled
= 1;
305 if (oldflag
!= menu
->entries
[i
]->flags
.enabled
)
310 for (i
= 0; i
< menu
->cascade_no
; i
++) {
311 if (!menu
->cascades
[i
]->flags
.brother
)
312 wUserMenuRefreshInstances(menu
->cascades
[i
], wwin
);
314 wUserMenuRefreshInstances(menu
->cascades
[i
]->brother
, wwin
);
321 static WMenu
*readUserMenuFile(WScreen
*scr
, const char *file_name
)
326 plum
= WMReadPropListFromFile(file_name
);
328 menu
= configureUserMenu(scr
, plum
);
329 WMReleasePropList(plum
);
335 WMenu
*wUserMenuGet(WScreen
*scr
, WWindow
*wwin
)
338 char *tmp
, *path
= NULL
;
340 if (wwin
&& wwin
->wm_instance
&& wwin
->wm_class
) {
341 int len
= strlen(wwin
->wm_instance
) + strlen(wwin
->wm_class
) + 7;
343 snprintf(tmp
, len
, "%s.%s.menu", wwin
->wm_instance
, wwin
->wm_class
);
344 path
= wfindfile(DEF_USER_MENU_PATHS
, tmp
);
350 menu
= readUserMenuFile(scr
, path
);
357 #endif /* USER_MENU */