A few cosmetic fixes.
[wmaker-crm.git] / src / usermenu.c
blob07af4564def50d2be7506e9c2bdff2a000a56827
1 /* User defined menu is good, but beer's always better
2 * if someone wanna start hacking something, He heard...
3 * TODO
4 * - enhance commands. (eg, exit, hide, list all app's member
5 * window and etc)
6 * - cache menu... dunno.. if people really use this feature :P
7 * - Violins, senseless violins!
8 * that's all, right now :P
9 * - external! WINGs menu editor.
10 * TODONOT
11 * - allow applications to share their menu. ] think it
12 * looks wierd since there still are more than 1 appicon.
14 * Syntax...
15 * (
16 * "Program Name",
17 * ("Command 1", SHORTCUT, 1),
18 * ("Command 2", SHORTCUT, 2, ("Allowed_instant_1", "Allowed_instant_2")),
19 * ("Command 3", SHORTCUT, (3,4,5), ("Allowed_instant_1")),
20 * (
21 * "Submenu",
22 * ("Kill Command", KILL),
23 * ("Hide Command", HIDE),
24 * ("Hide Others Command", HIDE_OTHERS),
25 * ("Members", MEMBERS),
26 * ("Exit Command", EXIT)
27 * )
28 * )
30 * Tips:
31 * - If you don't want short cut keys to be listed
32 * in the right side of entries, you can just put them
33 * in array instead of using the string directly.
37 #include "wconfig.h"
39 #ifdef USER_MENU
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 #include <X11/Xproto.h>
44 #include <X11/Xatom.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <unistd.h>
50 #include "WindowMaker.h"
51 #include "wcore.h"
52 #include "menu.h"
53 #include "actions.h"
54 #include "funcs.h"
55 #include "keybind.h"
57 #include "framewin.h"
60 extern proplist_t ReadProplistFromFile(char *file);
61 /*** var ***/
62 extern WPreferences wPreferences;
64 typedef struct {
65 WScreen *screen;
66 WShortKey *key;
67 int key_no;
68 } WUserMenuData;
71 static void
72 notifyClient(WMenu *menu, WMenuEntry *entry){
73 XEvent event;
74 WUserMenuData *data = entry->clientdata;
75 WScreen *scr = data->screen;
76 Window window;
77 int i;
79 window=scr->focused_window->client_win;
81 for(i=0;i<data->key_no;i++){
82 event.xkey.type = KeyPress;
83 event.xkey.display = dpy;
84 event.xkey.window = window;
85 event.xkey.subwindow = 0x0;
86 event.xkey.x = 0x0;
87 event.xkey.y = 0x0;
88 event.xkey.x_root = 0x0;
89 event.xkey.y_root = 0x0;
90 event.xkey.keycode = data->key[i].keycode;
91 event.xkey.state = data->key[i].modifier;
92 event.xkey.same_screen = YES;
93 XSendEvent(dpy, window, False, NoEventMask, &event);
94 XFlush(dpy);
95 /* should i release key too? */
99 static void
100 removeUserMenudata(void *menudata){
101 WUserMenuData *data = menudata;
102 free(data->key);
103 free(data);
106 static WUserMenuData*
107 convertShortcut(WScreen *scr, proplist_t shortcut){
108 WUserMenuData *data;
109 KeySym ksym;
110 char *k;
111 char buf[128], *b;
113 data = malloc(sizeof(WUserMenuData));
114 data->key = malloc(sizeof(WUserMenuData));
115 data->key[0].modifier = 0;
117 strcpy(buf, PLGetString(shortcut));
118 b = (char*)buf;
120 /* get modifiers */
121 while ((k = strchr(b, '+'))!=NULL) {
122 int mod;
124 *k = 0;
125 mod = wXModifierFromKey(b);
126 if (mod<0) {
127 free(data);
128 return NULL;
130 data->key[0].modifier |= mod;
132 b = k+1;
135 /* get key */
136 ksym = XStringToKeysym(b);
138 if (ksym==NoSymbol) {
139 free(data);
140 return NULL;
143 data->key[0].keycode = XKeysymToKeycode(dpy, ksym);
144 if (data->key[0].keycode==0) {
145 free(data);
146 return NULL;
148 data->screen = scr;
149 data->key_no = 1;
151 return data;
154 static WUserMenuData*
155 convertShortcuts(WScreen *scr, proplist_t shortcut){
156 WUserMenuData *data;
157 KeySym ksym;
158 char *k;
159 char *buffer;
160 char buf[128], *b;
161 int keycount,i,j,mod;
163 if (PLIsString(shortcut)){
164 keycount = 1;
166 else if (PLIsArray(shortcut)){
167 keycount = PLGetNumberOfElements(shortcut);
169 else return NULL;
170 /*for (i=0;i<keycount;i++){*/
172 data = malloc(sizeof(WUserMenuData));
173 data->key = malloc(sizeof(WShortKey)*keycount);
175 for (i=0,j=0;i<keycount;i++) {
176 data->key[j].modifier = 0;
177 if (PLIsArray(shortcut)) {
178 strcpy(buf, PLGetString(PLGetArrayElement(shortcut, i)));
180 else {
181 strcpy(buf, PLGetString(shortcut));
183 b = (char*)buf;
185 while ((k = strchr(b, '+'))!=NULL) {
186 *k = 0;
187 mod = wXModifierFromKey(b);
188 if (mod<0) {
189 break;
191 data->key[j].modifier |= mod;
192 b = k+1;
194 if (mod<0) {
195 continue;
198 ksym = XStringToKeysym(b);
199 if (ksym==NoSymbol) {
200 continue;
203 data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
204 if (data->key[j].keycode) {
205 j++;
209 keyover:
211 /* get key */
212 if (!j) {
213 free(data->key);
214 free(data);
216 data->key_no = j;
217 data->screen = scr;
219 return data;
222 static WMenu*
223 configureUserMenu(WScreen *scr, proplist_t plum){
224 char *mtitle;
225 WMenu *menu=NULL;
226 proplist_t elem, title, command, params;
227 int count,i;
228 WUserMenuData *data;
230 if (!plum) return NULL;
231 else if (!PLIsArray(plum)){
232 PLRelease(plum);
233 return NULL;
236 count = PLGetNumberOfElements(plum);
237 if (!count) return NULL;
239 elem = PLGetArrayElement(plum, 0);
240 if (!PLIsString(elem)){
241 return NULL;
244 mtitle = PLGetString(elem);
246 menu=wMenuCreateForApp(scr, mtitle, True);
248 for(i=1; i<count; i++){
249 elem = PLGetArrayElement(plum,i);
250 if(PLIsArray(PLGetArrayElement(elem,1))){
251 WMenu *submenu;
252 WMenuEntry *mentry;
254 submenu = configureUserMenu(scr,elem);
255 if (submenu)
256 mentry = wMenuAddCallback(menu, submenu->frame->title,NULL,NULL);
257 wMenuEntrySetCascade(menu, mentry, submenu);
259 else {
260 int idx = 0;
261 proplist_t instances=0;
263 title = PLGetArrayElement(elem,idx++);
264 command = PLGetArrayElement(elem,idx++);
265 if (PLGetNumberOfElements(elem) >= 3)
266 params = PLGetArrayElement(elem,idx++);
268 if (!title || !command)
269 return menu;
271 if (!strcmp("SHORTCUT",PLGetString(command))){
272 WMenuEntry *entry;
273 data = convertShortcuts(scr, params);
274 if (data){
275 entry = wMenuAddCallback(menu, PLGetString(title),
276 notifyClient, data);
277 if (PLIsString(params)) {
278 entry->rtext = GetShortcutString(PLGetString(params));
280 if (entry) {
281 entry->free_cdata = removeUserMenudata;
283 if (PLGetNumberOfElements(elem) >= 4){
284 instances = PLGetArrayElement(elem,idx++);
285 if(PLIsArray(instances))
286 if (instances && PLGetNumberOfElements(instances)
287 && PLIsArray(instances)){
288 entry->instances = PLRetain(instances);
294 /* else if */
298 return menu;
301 void
302 wUserMenuRefreshInstances(WMenu *menu, WWindow *wwin)
304 WMenuEntry* entry;
305 int i,j,count,paintflag;
307 paintflag=0;
309 if(!menu) return;
311 for (i=0; i<menu->entry_no; i++) {
312 if (menu->entries[i]->instances){
313 proplist_t ins;
314 int oldflag;
315 count = PLGetNumberOfElements(menu->entries[i]->instances);
317 oldflag = menu->entries[i]->flags.enabled;
318 menu->entries[i]->flags.enabled = 0;
319 for (j=0; j<count;j++){
320 ins = PLGetArrayElement(menu->entries[i]->instances,j);
321 if (!strcmp(wwin->wm_instance,PLGetString(ins))){
322 menu->entries[i]->flags.enabled = 1;
323 break;
326 if (oldflag != menu->entries[i]->flags.enabled)
327 paintflag=1;
330 for (i=0; i < menu->cascade_no; i++) {
331 if (!menu->cascades[i]->flags.brother)
332 wUserMenuRefreshInstances(menu->cascades[i], wwin);
333 else
334 wUserMenuRefreshInstances(menu->cascades[i]->brother, wwin);
337 if(paintflag)
338 wMenuPaint(menu);
342 static WMenu*
343 readUserMenuFile(WScreen *scr, char *file_name)
345 WMenu *menu=NULL;
346 char *mtitle;
348 proplist_t plum, elem, title, command, params;
350 int count,i;
352 plum = ReadProplistFromFile(file_name);
353 /**/
355 if(plum){
356 menu = configureUserMenu(scr, plum);
357 PLRelease(plum);
359 return menu;
363 WMenu*
364 wUserMenuGet(WScreen *scr, WWindow *wwin){
365 WMenu *menu = NULL;
366 char buffer[100];
367 char *prefix, *menufile;
369 prefix = getenv("HOME");
370 if (!prefix)
371 prefix = ".";
372 menufile = malloc(strlen(prefix)+64);
373 if (!menufile) return NULL;
375 if (wwin) {
376 FILE *f;
377 sprintf(menufile, "%s/%s.%s.menu",
378 prefix, wwin->wm_instance, wwin->wm_class);
379 f = fopen(menufile, "r");
380 if (f) {
381 fclose(f);
382 menu = readUserMenuFile(scr, menufile);
386 free(menufile);
387 return menu;
390 #endif /* USER_MENU */