Files
wmaker/src/usermenu.c
T

377 lines
9.6 KiB
C
Raw Normal View History

/* usermenu.c- user defined menu
*
* Window Maker window manager
*
* Copyright (c) hmmm... Should I put everybody's name here?
* Where's my lawyer?? -- ]d :D
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
* * * * * * * * *
* User defined menu is good, but beer's always better
1999-04-10 19:32:34 +00:00
* if someone wanna start hacking something, He heard...
* TODO
* - enhance commands. (eg, exit, hide, list all app's member
* window and etc)
* - cache menu... dunno.. if people really use this feature :P
* - Violins, senseless violins!
* that's all, right now :P
* - external! WINGs menu editor.
* TODONOT
* - allow applications to share their menu. ] think it
* looks wierd since there still are more than 1 appicon.
*
* Syntax...
* (
* "Program Name",
* ("Command 1", SHORTCUT, 1),
* ("Command 2", SHORTCUT, 2, ("Allowed_instant_1", "Allowed_instant_2")),
* ("Command 3", SHORTCUT, (3,4,5), ("Allowed_instant_1")),
* (
* "Submenu",
* ("Kill Command", KILL),
* ("Hide Command", HIDE),
* ("Hide Others Command", HIDE_OTHERS),
* ("Members", MEMBERS),
* ("Exit Command", EXIT)
* )
* )
*
* Tips:
* - If you don't want short cut keys to be listed
* in the right side of entries, you can just put them
* in array instead of using the string directly.
*
*/
#include "wconfig.h"
1999-04-11 03:01:22 +00:00
#ifdef USER_MENU
1999-04-10 19:32:34 +00:00
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "WindowMaker.h"
#include "wcore.h"
#include "menu.h"
#include "actions.h"
#include "funcs.h"
#include "keybind.h"
#include "framewin.h"
extern proplist_t ReadProplistFromFile(char *file);
/*** var ***/
extern WPreferences wPreferences;
typedef struct {
1999-04-16 19:56:08 +00:00
WScreen *screen;
WShortKey *key;
int key_no;
1999-04-10 19:32:34 +00:00
} WUserMenuData;
static void
1999-04-17 18:24:23 +00:00
notifyClient(WMenu *menu, WMenuEntry *entry)
{
1999-04-10 19:32:34 +00:00
XEvent event;
WUserMenuData *data = entry->clientdata;
WScreen *scr = data->screen;
Window window;
1999-04-16 19:56:08 +00:00
int i;
1999-04-10 19:32:34 +00:00
window=scr->focused_window->client_win;
1999-04-17 18:24:23 +00:00
for(i=0;i<data->key_no;i++) {
1999-04-16 19:56:08 +00:00
event.xkey.type = KeyPress;
event.xkey.display = dpy;
event.xkey.window = window;
1999-05-15 21:47:28 +00:00
event.xkey.root = DefaultRootWindow(dpy);
event.xkey.subwindow = (Window)None;
1999-04-16 19:56:08 +00:00
event.xkey.x = 0x0;
event.xkey.y = 0x0;
event.xkey.x_root = 0x0;
event.xkey.y_root = 0x0;
event.xkey.keycode = data->key[i].keycode;
event.xkey.state = data->key[i].modifier;
1999-05-15 21:47:28 +00:00
event.xkey.same_screen = True;
event.xkey.time = CurrentTime;
if (XSendEvent(dpy, window, False, KeyPressMask, &event)) {
event.xkey.type = KeyRelease;
event.xkey.time = CurrentTime;
XSendEvent(dpy, window, True, KeyReleaseMask, &event);
}
1999-04-16 19:56:08 +00:00
}
1999-04-10 19:32:34 +00:00
}
static void
1999-04-17 18:24:23 +00:00
removeUserMenudata(void *menudata)
{
1999-04-16 19:56:08 +00:00
WUserMenuData *data = menudata;
if(data->key) wfree(data->key);
wfree(data);
1999-04-10 19:32:34 +00:00
}
1999-04-16 19:56:08 +00:00
1999-04-10 19:32:34 +00:00
static WUserMenuData*
1999-04-17 18:24:23 +00:00
convertShortcuts(WScreen *scr, proplist_t shortcut)
{
1999-04-10 19:32:34 +00:00
WUserMenuData *data;
KeySym ksym;
char *k;
1999-04-16 19:56:08 +00:00
char *buffer;
1999-04-10 19:32:34 +00:00
char buf[128], *b;
1999-04-16 19:56:08 +00:00
int keycount,i,j,mod;
1999-04-17 18:24:23 +00:00
if (PLIsString(shortcut)) {
1999-04-16 19:56:08 +00:00
keycount = 1;
1999-04-10 19:32:34 +00:00
}
1999-04-17 18:24:23 +00:00
else if (PLIsArray(shortcut)) {
1999-04-16 19:56:08 +00:00
keycount = PLGetNumberOfElements(shortcut);
}
else return NULL;
/*for (i=0;i<keycount;i++){*/
data = wmalloc(sizeof(WUserMenuData));
if (!data) return NULL;
data->key = wmalloc(sizeof(WShortKey)*keycount);
if (!data->key) {
wfree(data);
1999-04-10 19:32:34 +00:00
return NULL;
}
1999-04-16 19:56:08 +00:00
for (i=0,j=0;i<keycount;i++) {
data->key[j].modifier = 0;
if (PLIsArray(shortcut)) {
strcpy(buf, PLGetString(PLGetArrayElement(shortcut, i)));
1999-04-17 18:24:23 +00:00
} else {
1999-04-16 19:56:08 +00:00
strcpy(buf, PLGetString(shortcut));
}
b = (char*)buf;
while ((k = strchr(b, '+'))!=NULL) {
*k = 0;
mod = wXModifierFromKey(b);
if (mod<0) {
break;
}
data->key[j].modifier |= mod;
b = k+1;
}
ksym = XStringToKeysym(b);
if (ksym==NoSymbol) {
continue;
}
data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
if (data->key[j].keycode) {
j++;
}
}
keyover:
1999-04-10 19:32:34 +00:00
1999-04-16 19:56:08 +00:00
/* get key */
if (!j) {
puts("fatal j");
wfree(data->key);
wfree(data);
1999-04-10 19:32:34 +00:00
return NULL;
}
1999-04-16 19:56:08 +00:00
data->key_no = j;
1999-04-10 19:32:34 +00:00
data->screen = scr;
return data;
}
static WMenu*
1999-04-17 18:24:23 +00:00
configureUserMenu(WScreen *scr, proplist_t plum)
{
1999-04-16 19:56:08 +00:00
char *mtitle;
WMenu *menu=NULL;
proplist_t elem, title, command, params;
int count,i;
1999-04-10 19:32:34 +00:00
WUserMenuData *data;
1999-04-16 19:56:08 +00:00
if (!plum) return NULL;
1999-04-17 18:24:23 +00:00
if (!PLIsArray(plum)) {
1999-04-16 19:56:08 +00:00
return NULL;
}
count = PLGetNumberOfElements(plum);
if (!count) return NULL;
elem = PLGetArrayElement(plum, 0);
1999-04-17 18:24:23 +00:00
if (!PLIsString(elem)) {
1999-04-16 19:56:08 +00:00
return NULL;
}
mtitle = PLGetString(elem);
menu=wMenuCreateForApp(scr, mtitle, True);
1999-04-17 18:24:23 +00:00
for(i=1; i<count; i++) {
1999-04-16 19:56:08 +00:00
elem = PLGetArrayElement(plum,i);
1999-04-17 18:24:23 +00:00
if(PLIsArray(PLGetArrayElement(elem,1))) {
1999-04-16 19:56:08 +00:00
WMenu *submenu;
WMenuEntry *mentry;
submenu = configureUserMenu(scr,elem);
if (submenu)
mentry = wMenuAddCallback(menu, submenu->frame->title,
NULL, NULL);
wMenuEntrySetCascade(menu, mentry, submenu);
}
else {
int idx = 0;
proplist_t instances=0;
title = PLGetArrayElement(elem,idx++);
command = PLGetArrayElement(elem,idx++);
if (PLGetNumberOfElements(elem) >= 3)
params = PLGetArrayElement(elem,idx++);
if (!title || !command)
return menu;
1999-04-17 18:24:23 +00:00
if (!strcmp("SHORTCUT",PLGetString(command))) {
1999-04-16 19:56:08 +00:00
WMenuEntry *entry;
data = convertShortcuts(scr, params);
if (data){
entry = wMenuAddCallback(menu, PLGetString(title),
notifyClient, data);
if (entry) {
if (PLIsString(params)) {
entry->rtext = GetShortcutString(PLGetString(params));
}
entry->free_cdata = removeUserMenudata;
1999-04-17 18:24:23 +00:00
if (PLGetNumberOfElements(elem) >= 4) {
1999-04-16 19:56:08 +00:00
instances = PLGetArrayElement(elem,idx++);
if(PLIsArray(instances))
1999-04-17 18:24:23 +00:00
if (instances && PLGetNumberOfElements(instances)
&& PLIsArray(instances)){
entry->instances = PLRetain(instances);
1999-04-16 19:56:08 +00:00
}
}
}
}
}
}
}
return menu;
1999-04-10 19:32:34 +00:00
}
void
wUserMenuRefreshInstances(WMenu *menu, WWindow *wwin)
{
1999-04-16 19:56:08 +00:00
WMenuEntry* entry;
int i,j,count,paintflag;
paintflag=0;
if(!menu) return;
for (i=0; i<menu->entry_no; i++) {
if (menu->entries[i]->instances){
proplist_t ins;
int oldflag;
count = PLGetNumberOfElements(menu->entries[i]->instances);
oldflag = menu->entries[i]->flags.enabled;
menu->entries[i]->flags.enabled = 0;
1999-04-17 18:24:23 +00:00
for (j=0; j<count;j++) {
1999-04-16 19:56:08 +00:00
ins = PLGetArrayElement(menu->entries[i]->instances,j);
1999-04-17 18:24:23 +00:00
if (!strcmp(wwin->wm_instance,PLGetString(ins))) {
1999-04-16 19:56:08 +00:00
menu->entries[i]->flags.enabled = 1;
break;
}
}
if (oldflag != menu->entries[i]->flags.enabled)
paintflag=1;
}
}
for (i=0; i < menu->cascade_no; i++) {
if (!menu->cascades[i]->flags.brother)
1999-04-17 18:24:23 +00:00
wUserMenuRefreshInstances(menu->cascades[i], wwin);
1999-04-16 19:56:08 +00:00
else
1999-04-17 18:24:23 +00:00
wUserMenuRefreshInstances(menu->cascades[i]->brother, wwin);
1999-04-16 19:56:08 +00:00
}
1999-04-17 18:24:23 +00:00
if (paintflag)
1999-04-16 19:56:08 +00:00
wMenuPaint(menu);
1999-04-10 19:32:34 +00:00
}
static WMenu*
readUserMenuFile(WScreen *scr, char *file_name)
{
1999-04-16 19:56:08 +00:00
WMenu *menu;
char *mtitle;
proplist_t plum, elem, title, command, params;
int count,i;
menu=NULL;
plum = ReadProplistFromFile(file_name);
/**/
if(plum){
menu = configureUserMenu(scr, plum);
PLRelease(plum);
}
1999-04-10 19:32:34 +00:00
return menu;
}
WMenu*
1999-04-17 18:24:23 +00:00
wUserMenuGet(WScreen *scr, WWindow *wwin)
{
1999-04-16 19:56:08 +00:00
WMenu *menu = NULL;
char buffer[100];
char *path = NULL;
char *tmp;
if ( wwin->wm_instance && wwin->wm_class ) {
tmp=wmalloc(strlen(wwin->wm_instance)+strlen(wwin->wm_class)+7);
sprintf(tmp,"%s.%s.menu",wwin->wm_instance,wwin->wm_class);
path = wfindfile(DEF_USER_MENU_PATHS,tmp);
wfree(tmp);
if (!path) return NULL;
if (wwin) {
menu = readUserMenuFile(scr, path);
}
wfree(path);
1999-04-16 19:56:08 +00:00
}
return menu;
1999-04-10 19:32:34 +00:00
}
#endif /* USER_MENU */