*** empty log message ***
[wmaker-crm.git] / src / usermenu.c
blobd8deeff0e43b060d8cc16df11074b1589624b148
1 #ifdef USER_MENU
2 /* User defined menu is good, but beer's always better
3 * if someone wanna start hacking something, He heard...
4 * TODO
5 * - enhance commands. (eg, exit, hide, list all app's member
6 * window and etc)
7 * - cache menu... dunno.. if people really use this feature :P
8 * - Violins, senseless violins!
9 * that's all, right now :P
10 * - external! WINGs menu editor.
11 * TODONOT
12 * - allow applications to share their menu. ] think it
13 * looks wierd since there still are more than 1 appicon.
15 * Syntax...
16 * (
17 * "Program Name",
18 * ("Command 1", SHORTCUT, 1),
19 * ("Command 2", SHORTCUT, 2, ("Allowed_instant_1", "Allowed_instant_2")),
20 * ("Command 3", SHORTCUT, (3,4,5), ("Allowed_instant_1")),
21 * (
22 * "Submenu",
23 * ("Kill Command", KILL),
24 * ("Hide Command", HIDE),
25 * ("Hide Others Command", HIDE_OTHERS),
26 * ("Members", MEMBERS),
27 * ("Exit Command", EXIT)
28 * )
29 * )
31 * Tips:
32 * - If you don't want short cut keys to be listed
33 * in the right side of entries, you can just put them
34 * in array instead of using the string directly.
38 #include "wconfig.h"
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42 #include <X11/Xproto.h>
43 #include <X11/Xatom.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <stdio.h>
47 #include <unistd.h>
49 #include "WindowMaker.h"
50 #include "wcore.h"
51 #include "menu.h"
52 #include "actions.h"
53 #include "funcs.h"
54 #include "keybind.h"
56 #include "framewin.h"
59 extern proplist_t ReadProplistFromFile(char *file);
60 /*** var ***/
61 extern WPreferences wPreferences;
63 typedef struct {
64 WScreen *screen;
65 WShortKey *key;
66 int key_no;
67 } WUserMenuData;
70 static void
71 notifyClient(WMenu *menu, WMenuEntry *entry){
72 XEvent event;
73 WUserMenuData *data = entry->clientdata;
74 WScreen *scr = data->screen;
75 Window window;
76 int i;
78 window=scr->focused_window->client_win;
80 for(i=0;i<data->key_no;i++){
81 event.xkey.type = KeyPress;
82 event.xkey.display = dpy;
83 event.xkey.window = window;
84 event.xkey.subwindow = 0x0;
85 event.xkey.x = 0x0;
86 event.xkey.y = 0x0;
87 event.xkey.x_root = 0x0;
88 event.xkey.y_root = 0x0;
89 event.xkey.keycode = data->key[i].keycode;
90 event.xkey.state = data->key[i].modifier;
91 event.xkey.same_screen = YES;
92 XSendEvent(dpy, window, False, NoEventMask, &event);
93 XFlush(dpy);
94 /* should i release key too? */
98 static void
99 removeUserMenudata(void *menudata){
100 WUserMenuData *data = menudata;
101 free(data->key);
102 free(data);
105 static WUserMenuData*
106 convertShortcut(WScreen *scr, proplist_t shortcut){
107 WUserMenuData *data;
108 KeySym ksym;
109 char *k;
110 char buf[128], *b;
112 data = malloc(sizeof(WUserMenuData));
113 data->key = malloc(sizeof(WUserMenuData));
114 data->key[0].modifier = 0;
116 strcpy(buf, PLGetString(shortcut));
117 b = (char*)buf;
119 /* get modifiers */
120 while ((k = strchr(b, '+'))!=NULL) {
121 int mod;
123 *k = 0;
124 mod = wXModifierFromKey(b);
125 if (mod<0) {
126 free(data);
127 return NULL;
129 data->key[0].modifier |= mod;
131 b = k+1;
134 /* get key */
135 ksym = XStringToKeysym(b);
137 if (ksym==NoSymbol) {
138 free(data);
139 return NULL;
142 data->key[0].keycode = XKeysymToKeycode(dpy, ksym);
143 if (data->key[0].keycode==0) {
144 free(data);
145 return NULL;
147 data->screen = scr;
148 data->key_no = 1;
150 return data;
153 static WUserMenuData*
154 convertShortcuts(WScreen *scr, proplist_t shortcut){
155 WUserMenuData *data;
156 KeySym ksym;
157 char *k;
158 char *buffer;
159 char buf[128], *b;
160 int keycount,i,j,mod;
162 if (PLIsString(shortcut)){
163 keycount = 1;
165 else if (PLIsArray(shortcut)){
166 keycount = PLGetNumberOfElements(shortcut);
168 else return NULL;
169 /*for (i=0;i<keycount;i++){*/
171 data = malloc(sizeof(WUserMenuData));
172 data->key = malloc(sizeof(WShortKey)*keycount);
174 for (i=0,j=0;i<keycount;i++) {
175 data->key[j].modifier = 0;
176 if (PLIsArray(shortcut)) {
177 strcpy(buf, PLGetString(PLGetArrayElement(shortcut, i)));
179 else {
180 strcpy(buf, PLGetString(shortcut));
182 b = (char*)buf;
184 while ((k = strchr(b, '+'))!=NULL) {
185 *k = 0;
186 mod = wXModifierFromKey(b);
187 if (mod<0) {
188 break;
190 data->key[j].modifier |= mod;
191 b = k+1;
193 if (mod<0) {
194 continue;
197 ksym = XStringToKeysym(b);
198 if (ksym==NoSymbol) {
199 continue;
202 data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
203 if (data->key[j].keycode) {
204 j++;
208 keyover:
210 /* get key */
211 if (!j) {
212 free(data->key);
213 free(data);
215 data->key_no = j;
216 data->screen = scr;
218 return data;
221 static WMenu*
222 configureUserMenu(WScreen *scr, proplist_t plum){
223 char *mtitle;
224 WMenu *menu=NULL;
225 proplist_t elem, title, command, params;
226 int count,i;
227 WUserMenuData *data;
229 if (!plum) return NULL;
230 else if (!PLIsArray(plum)){
231 PLRelease(plum);
232 return NULL;
235 count = PLGetNumberOfElements(plum);
236 if (!count) return NULL;
238 elem = PLGetArrayElement(plum, 0);
239 if (!PLIsString(elem)){
240 return NULL;
243 mtitle = PLGetString(elem);
245 menu=wMenuCreateForApp(scr, mtitle, True);
247 for(i=1; i<count; i++){
248 elem = PLGetArrayElement(plum,i);
249 if(PLIsArray(PLGetArrayElement(elem,1))){
250 WMenu *submenu;
251 WMenuEntry *mentry;
253 submenu = configureUserMenu(scr,elem);
254 if (submenu)
255 mentry = wMenuAddCallback(menu, submenu->frame->title,NULL,NULL);
256 wMenuEntrySetCascade(menu, mentry, submenu);
258 else {
259 int idx = 0;
260 proplist_t instances=0;
262 title = PLGetArrayElement(elem,idx++);
263 command = PLGetArrayElement(elem,idx++);
264 if (PLGetNumberOfElements(elem) >= 3)
265 params = PLGetArrayElement(elem,idx++);
267 if (!title || !command)
268 return menu;
270 if (!strcmp("SHORTCUT",PLGetString(command))){
271 WMenuEntry *entry;
272 data = convertShortcuts(scr, params);
273 if (data){
274 entry = wMenuAddCallback(menu, PLGetString(title),
275 notifyClient, data);
276 if (PLIsString(params)) {
277 entry->rtext = GetShortcutString(PLGetString(params));
279 if (entry) {
280 entry->free_cdata = removeUserMenudata;
282 if (PLGetNumberOfElements(elem) >= 4){
283 instances = PLGetArrayElement(elem,idx++);
284 if(PLIsArray(instances))
285 if (instances && PLGetNumberOfElements(instances)
286 && PLIsArray(instances)){
287 entry->instances = PLRetain(instances);
293 /* else if */
297 return menu;
300 void
301 wUserMenuRefreshInstances(WMenu *menu, WWindow *wwin)
303 WMenuEntry* entry;
304 int i,j,count,paintflag;
306 paintflag=0;
308 if(!menu) return;
310 for (i=0; i<menu->entry_no; i++) {
311 if (menu->entries[i]->instances){
312 proplist_t ins;
313 int oldflag;
314 count = PLGetNumberOfElements(menu->entries[i]->instances);
316 oldflag = menu->entries[i]->flags.enabled;
317 menu->entries[i]->flags.enabled = 0;
318 for (j=0; j<count;j++){
319 ins = PLGetArrayElement(menu->entries[i]->instances,j);
320 if (!strcmp(wwin->wm_instance,PLGetString(ins))){
321 menu->entries[i]->flags.enabled = 1;
322 break;
325 if (oldflag != menu->entries[i]->flags.enabled)
326 paintflag=1;
329 for (i=0; i < menu->cascade_no; i++) {
330 if (!menu->cascades[i]->flags.brother)
331 wUserMenuRefreshInstances(menu->cascades[i], wwin);
332 else
333 wUserMenuRefreshInstances(menu->cascades[i]->brother, wwin);
336 if(paintflag)
337 wMenuPaint(menu);
341 static WMenu*
342 readUserMenuFile(WScreen *scr, char *file_name)
344 WMenu *menu=NULL;
345 char *mtitle;
347 proplist_t plum, elem, title, command, params;
349 int count,i;
351 plum = ReadProplistFromFile(file_name);
352 /**/
354 if(plum){
355 menu = configureUserMenu(scr, plum);
356 PLRelease(plum);
358 return menu;
362 WMenu*
363 wUserMenuGet(WScreen *scr, WWindow *wwin){
364 WMenu *menu = NULL;
365 char buffer[100];
366 char *prefix, *menufile;
368 prefix = getenv("HOME");
369 if (!prefix)
370 prefix = ".";
371 menufile = malloc(strlen(prefix)+64);
372 if (!menufile) return NULL;
374 if (wwin) {
375 FILE *f;
376 sprintf(menufile, "%s/%s.%s.menu",
377 prefix, wwin->wm_instance, wwin->wm_class);
378 f = fopen(menufile, "r");
379 if (f) {
380 fclose(f);
381 menu = readUserMenuFile(scr, menufile);
385 free(menufile);
386 return menu;
389 #endif /* USER_MENU */