WINGs: Add back wprogressindicator.c
[wmaker-crm.git] / src / usermenu.c
blob49473c875098b063a577eb7dd8738313436bfcc3
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.
22 * * * * * * * * *
23 * User defined menu is good, but beer's always better
24 * if someone wanna start hacking something, He heard...
25 * TODO
26 * - enhance commands. (eg, exit, hide, list all app's member
27 * window and etc)
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.
32 * TODONOT
33 * - allow applications to share their menu. ] think it
34 * looks wierd since there still are more than 1 appicon.
36 * Syntax...
37 * (
38 * "Program Name",
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")),
42 * (
43 * "Submenu",
44 * ("Kill Command", KILL),
45 * ("Hide Command", HIDE),
46 * ("Hide Others Command", HIDE_OTHERS),
47 * ("Members", MEMBERS),
48 * ("Exit Command", EXIT)
49 * )
50 * )
52 * Tips:
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.
59 #include "wconfig.h"
61 #ifdef USER_MENU
63 #include <X11/Xlib.h>
64 #include <X11/Xutil.h>
65 #include <X11/Xproto.h>
66 #include <X11/Xatom.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <stdio.h>
70 #include <unistd.h>
72 #include "WindowMaker.h"
73 #include "menu.h"
74 #include "actions.h"
75 #include "funcs.h"
76 #include "keybind.h"
78 #include "framewin.h"
80 #define MAX_SHORTCUT_LENGTH 32
82 /*** var ***/
83 extern WPreferences wPreferences;
85 typedef struct {
86 WScreen *screen;
87 WShortKey *key;
88 int key_no;
89 } WUserMenuData;
91 static void notifyClient(WMenu * menu, WMenuEntry * entry)
93 XEvent event;
94 WUserMenuData *data = entry->clientdata;
95 WScreen *scr = data->screen;
96 Window window;
97 int i;
99 window = scr->focused_window->client_win;
101 for (i = 0; i < data->key_no; i++) {
102 event.xkey.type = KeyPress;
103 event.xkey.display = dpy;
104 event.xkey.window = window;
105 event.xkey.root = DefaultRootWindow(dpy);
106 event.xkey.subwindow = (Window) None;
107 event.xkey.x = 0x0;
108 event.xkey.y = 0x0;
109 event.xkey.x_root = 0x0;
110 event.xkey.y_root = 0x0;
111 event.xkey.keycode = data->key[i].keycode;
112 event.xkey.state = data->key[i].modifier;
113 event.xkey.same_screen = True;
114 event.xkey.time = CurrentTime;
115 if (XSendEvent(dpy, window, False, KeyPressMask, &event)) {
116 event.xkey.type = KeyRelease;
117 event.xkey.time = CurrentTime;
118 XSendEvent(dpy, window, True, KeyReleaseMask, &event);
123 static void removeUserMenudata(void *menudata)
125 WUserMenuData *data = menudata;
126 if (data->key)
127 wfree(data->key);
128 wfree(data);
131 static WUserMenuData *convertShortcuts(WScreen * scr, WMPropList * shortcut)
133 WUserMenuData *data;
134 KeySym ksym;
135 char *k;
136 char *buffer;
137 char buf[MAX_SHORTCUT_LENGTH], *b;
138 int keycount, i, j, mod;
140 if (WMIsPLString(shortcut)) {
141 keycount = 1;
142 } else if (WMIsPLArray(shortcut)) {
143 keycount = WMGetPropListItemCount(shortcut);
144 } else
145 return NULL;
146 /*for (i=0;i<keycount;i++){ */
148 data = wmalloc(sizeof(WUserMenuData));
149 if (!data)
150 return NULL;
151 data->key = wmalloc(sizeof(WShortKey) * keycount);
152 if (!data->key) {
153 wfree(data);
154 return NULL;
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);
161 } else {
162 wstrlcpy(buf, WMGetFromPLString(shortcut), MAX_SHORTCUT_LENGTH);
164 b = (char *)buf;
166 while ((k = strchr(b, '+')) != NULL) {
167 *k = 0;
168 mod = wXModifierFromKey(b);
169 if (mod < 0) {
170 break;
172 data->key[j].modifier |= mod;
173 b = k + 1;
176 ksym = XStringToKeysym(b);
177 if (ksym == NoSymbol) {
178 continue;
181 data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
182 if (data->key[j].keycode) {
183 j++;
187 keyover:
189 /* get key */
190 if (!j) {
191 puts("fatal j");
192 wfree(data->key);
193 wfree(data);
194 return NULL;
196 data->key_no = j;
197 data->screen = scr;
199 return data;
202 static WMenu *configureUserMenu(WScreen * scr, WMPropList * plum)
204 char *mtitle;
205 WMenu *menu = NULL;
206 WMPropList *elem, *title, *command, *params;
207 int count, i;
208 WUserMenuData *data;
210 if (!plum)
211 return NULL;
212 if (!WMIsPLArray(plum)) {
213 return NULL;
216 count = WMGetPropListItemCount(plum);
217 if (!count)
218 return NULL;
220 elem = WMGetFromPLArray(plum, 0);
221 if (!WMIsPLString(elem)) {
222 return NULL;
225 mtitle = WMGetFromPLString(elem);
227 menu = wMenuCreateForApp(scr, mtitle, True);
229 for (i = 1; i < count; i++) {
230 elem = WMGetFromPLArray(plum, i);
231 if (WMIsPLArray(WMGetFromPLArray(elem, 1))) {
232 WMenu *submenu;
233 WMenuEntry *mentry;
235 submenu = configureUserMenu(scr, elem);
236 if (submenu)
237 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
238 wMenuEntrySetCascade(menu, mentry, submenu);
239 } else {
240 int idx = 0;
241 WMPropList *instances = 0;
243 title = WMGetFromPLArray(elem, idx++);
244 command = WMGetFromPLArray(elem, idx++);
245 if (WMGetPropListItemCount(elem) >= 3)
246 params = WMGetFromPLArray(elem, idx++);
248 if (!title || !command)
249 return menu;
251 if (!strcmp("SHORTCUT", WMGetFromPLString(command))) {
252 WMenuEntry *entry;
254 data = convertShortcuts(scr, params);
255 if (data) {
256 entry = wMenuAddCallback(menu, WMGetFromPLString(title),
257 notifyClient, data);
259 if (entry) {
260 if (WMIsPLString(params)) {
261 entry->rtext =
262 GetShortcutString(WMGetFromPLString(params));
264 entry->free_cdata = removeUserMenudata;
266 if (WMGetPropListItemCount(elem) >= 4) {
267 instances = WMGetFromPLArray(elem, idx++);
268 if (WMIsPLArray(instances))
269 if (instances && WMGetPropListItemCount(instances)
270 && WMIsPLArray(instances)) {
271 entry->instances =
272 WMRetainPropList(instances);
281 return menu;
284 void wUserMenuRefreshInstances(WMenu * menu, WWindow * wwin)
286 WMenuEntry *entry;
287 int i, j, count, paintflag;
289 paintflag = 0;
291 if (!menu)
292 return;
294 for (i = 0; i < menu->entry_no; i++) {
295 if (menu->entries[i]->instances) {
296 WMPropList *ins;
297 int oldflag;
298 count = WMGetPropListItemCount(menu->entries[i]->instances);
300 oldflag = menu->entries[i]->flags.enabled;
301 menu->entries[i]->flags.enabled = 0;
302 for (j = 0; j < count; j++) {
303 ins = WMGetFromPLArray(menu->entries[i]->instances, j);
304 if (!strcmp(wwin->wm_instance, WMGetFromPLString(ins))) {
305 menu->entries[i]->flags.enabled = 1;
306 break;
309 if (oldflag != menu->entries[i]->flags.enabled)
310 paintflag = 1;
313 for (i = 0; i < menu->cascade_no; i++) {
314 if (!menu->cascades[i]->flags.brother)
315 wUserMenuRefreshInstances(menu->cascades[i], wwin);
316 else
317 wUserMenuRefreshInstances(menu->cascades[i]->brother, wwin);
320 if (paintflag)
321 wMenuPaint(menu);
324 static WMenu *readUserMenuFile(WScreen * scr, char *file_name)
326 WMenu *menu;
327 char *mtitle;
328 WMPropList *plum, *elem, *title, *command, *params;
329 int count, i;
331 menu = NULL;
332 plum = WMReadPropListFromFile(file_name);
333 /**/ if (plum) {
334 menu = configureUserMenu(scr, plum);
335 WMReleasePropList(plum);
337 return menu;
340 WMenu *wUserMenuGet(WScreen * scr, WWindow * wwin)
342 WMenu *menu = NULL;
343 char buffer[100];
344 char *path = NULL;
345 char *tmp;
346 if (wwin->wm_instance && wwin->wm_class) {
347 int len = strlen(wwin->wm_instance) + strlen(wwin->wm_class) + 7;
348 tmp = wmalloc(len);
349 snprintf(tmp, len, "%s.%s.menu", wwin->wm_instance, wwin->wm_class);
350 path = wfindfile(DEF_USER_MENU_PATHS, tmp);
351 wfree(tmp);
353 if (!path)
354 return NULL;
356 if (wwin) {
357 menu = readUserMenuFile(scr, path);
360 wfree(path);
362 return menu;
365 #endif /* USER_MENU */