2285 lines
50 KiB
C
2285 lines
50 KiB
C
/*
|
|
* Copyright (C) 2000-2005 Carsten Haitzler, Geoff Harrison and various contributors
|
|
* Copyright (C) 2004-2005 Kim Woelders
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
* and software packages that this Software was used.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include "E.h"
|
|
#include <X11/keysym.h>
|
|
|
|
#define DEBUG_MENU_EVENTS 0
|
|
|
|
struct
|
|
{
|
|
EWin *context_ewin;
|
|
int current_depth;
|
|
Menu *list[256];
|
|
char clicked;
|
|
char just_shown;
|
|
Window cover_win;
|
|
Window win_covered;
|
|
} Mode_menus;
|
|
|
|
struct _menustyle
|
|
{
|
|
char *name;
|
|
TextClass *tclass;
|
|
ImageClass *bg_iclass;
|
|
ImageClass *item_iclass;
|
|
ImageClass *sub_iclass;
|
|
char use_item_bg;
|
|
char iconpos;
|
|
int maxx;
|
|
int maxy;
|
|
char *border_name;
|
|
unsigned int ref_count;
|
|
};
|
|
|
|
struct _menuitem
|
|
{
|
|
Menu *menu;
|
|
ImageClass *icon_iclass;
|
|
char *text;
|
|
void *params;
|
|
Menu *child;
|
|
char state;
|
|
PmapMask pmm[3];
|
|
Window win;
|
|
Window icon_win;
|
|
short icon_w;
|
|
short icon_h;
|
|
short text_w;
|
|
short text_h;
|
|
short text_x;
|
|
short text_y;
|
|
};
|
|
|
|
struct _menu
|
|
{
|
|
char *name;
|
|
char *title;
|
|
MenuStyle *style;
|
|
EWin *ewin;
|
|
int w, h;
|
|
int num;
|
|
MenuItem **items;
|
|
Window win;
|
|
PmapMask pmm;
|
|
char shown;
|
|
char stuck;
|
|
char internal; /* Don't destroy when reloading */
|
|
char redraw;
|
|
Menu *parent;
|
|
MenuItem *sel_item;
|
|
time_t last_change;
|
|
void *data;
|
|
unsigned int ref_count;
|
|
};
|
|
|
|
#define MENU_ITEM_EVENT_MASK \
|
|
KeyPressMask | KeyReleaseMask | \
|
|
ButtonPressMask | ButtonReleaseMask | \
|
|
EnterWindowMask | LeaveWindowMask /* | PointerMotionMask */
|
|
|
|
static void MenuRedraw(Menu * m);
|
|
static void MenuRealize(Menu * m);
|
|
static void MenuActivateItem(Menu * m, MenuItem * mi);
|
|
static void MenuDrawItem(Menu * m, MenuItem * mi, char shape);
|
|
|
|
static void MenuHandleEvents(XEvent * ev, void *m);
|
|
static void MenuItemHandleEvents(XEvent * ev, void *mi);
|
|
static void MenuMaskerHandleEvents(XEvent * ev, void *prm);
|
|
|
|
static void MenusHide(void);
|
|
|
|
static Menu *active_menu = NULL;
|
|
static MenuItem *active_item = NULL;
|
|
|
|
static void
|
|
GrabKeyboard(Window win)
|
|
{
|
|
int rc;
|
|
|
|
rc = XGrabKeyboard(disp, win, False, GrabModeAsync, GrabModeAsync,
|
|
CurrentTime);
|
|
#if DEBUG_MENU_EVENTS
|
|
Eprintf("GrabKeyboard %#lx %d\n", win, rc);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
UngrabKeyboard(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = XUngrabKeyboard(disp, CurrentTime);
|
|
#if DEBUG_MENU_EVENTS
|
|
Eprintf("UngrabKeyboard %d\n", rc);
|
|
#endif
|
|
}
|
|
|
|
static Menu *
|
|
FindMenu(Window win)
|
|
{
|
|
Menu *menu = NULL;
|
|
Menu **menus;
|
|
int i, num;
|
|
|
|
menus = (Menu **) ListItemType(&num, LIST_TYPE_MENU);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
if (menus[i]->win != win)
|
|
continue;
|
|
menu = menus[i];
|
|
break;
|
|
}
|
|
if (menus)
|
|
Efree(menus);
|
|
|
|
return menu;
|
|
}
|
|
|
|
#if 0
|
|
static EWin *
|
|
FindEwinByMenu(Menu * m)
|
|
{
|
|
EWin *const *ewins;
|
|
int i, num;
|
|
|
|
ewins = EwinListGetAll(&num);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
if (ewins[i]->data == (void *)m)
|
|
return ewins[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#else
|
|
#define FindEwinByMenu(m) (m->ewin)
|
|
#endif
|
|
|
|
void
|
|
MenuHide(Menu * m)
|
|
{
|
|
EWin *ewin;
|
|
|
|
MenuActivateItem(m, NULL);
|
|
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
HideEwin(ewin);
|
|
EReparentWindow(m->win, VRoot.win, ewin->client.x, ewin->client.y);
|
|
}
|
|
m->ewin = NULL;
|
|
|
|
m->stuck = 0;
|
|
m->shown = 0;
|
|
}
|
|
|
|
static void
|
|
MenuEwinMoveResize(EWin * ewin, int resize __UNUSED__)
|
|
{
|
|
Menu *m = ewin->data;
|
|
|
|
if (!m)
|
|
return;
|
|
|
|
if (TransparencyEnabled())
|
|
m->redraw = 1;
|
|
|
|
if ((!m->style->use_item_bg && m->pmm.pmap == 0) || m->redraw)
|
|
MenuRedraw(m);
|
|
}
|
|
|
|
static void
|
|
MenuEwinRefresh(EWin * ewin)
|
|
{
|
|
MenuEwinMoveResize(ewin, 0);
|
|
}
|
|
|
|
static void
|
|
MenuEwinClose(EWin * ewin)
|
|
{
|
|
if ((Menu *) (ewin->data) == active_menu)
|
|
{
|
|
UngrabKeyboard();
|
|
active_menu = NULL;
|
|
active_item = NULL;
|
|
}
|
|
|
|
ewin->data = NULL;
|
|
}
|
|
|
|
static void
|
|
MenuEwinInit(EWin * ewin, void *ptr)
|
|
{
|
|
Menu *m = ptr;
|
|
|
|
ewin->data = ptr;
|
|
|
|
ewin->MoveResize = MenuEwinMoveResize;
|
|
ewin->Refresh = MenuEwinRefresh;
|
|
ewin->Close = MenuEwinClose;
|
|
|
|
ewin->skiptask = 1;
|
|
ewin->skip_ext_pager = 1;
|
|
ewin->no_actions = 1;
|
|
ewin->skipfocus = 1;
|
|
ewin->skipwinlist = 1;
|
|
ewin->neverfocus = 1;
|
|
ewin->client.grav = StaticGravity;
|
|
|
|
ewin->client.width.min = ewin->client.width.max = ewin->client.w = m->w;
|
|
ewin->client.height.min = ewin->client.height.max = ewin->client.h = m->h;
|
|
ewin->client.no_resize_h = ewin->client.no_resize_v = 1;
|
|
|
|
EoSetSticky(ewin, 1);
|
|
EoSetLayer(ewin, 3);
|
|
EoSetFloating(ewin, 1);
|
|
EoSetOpacity(ewin, OpacityExt(Conf.menus.opacity));
|
|
}
|
|
|
|
static void MenuShowMasker(Menu * m);
|
|
|
|
static void
|
|
MenuShow(Menu * m, char noshow)
|
|
{
|
|
EWin *ewin;
|
|
int x, y;
|
|
int wx = 0, wy = 0; /* wx, wy added to stop menus */
|
|
unsigned int w, h, mw, mh; /* from appearing offscreen */
|
|
int head_num = 0;
|
|
|
|
if ((m->num <= 0) || (!m->style))
|
|
return;
|
|
|
|
if (m->shown)
|
|
return;
|
|
|
|
if (m->stuck)
|
|
return;
|
|
|
|
if (!m->win)
|
|
MenuRealize(m);
|
|
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
#if 0 /* FIXME - Why? */
|
|
if ((Mode.button) &&
|
|
FindItem((char *)Mode.button, 0, LIST_FINDBY_POINTER,
|
|
LIST_TYPE_BUTTON))
|
|
{
|
|
ButtonDrawWithState(Mode.button, STATE_NORMAL);
|
|
}
|
|
#endif
|
|
#if 0 /* ??? */
|
|
RaiseEwin(ewin);
|
|
ShowEwin(ewin);
|
|
return;
|
|
#else
|
|
MenuHide(m);
|
|
#endif
|
|
}
|
|
|
|
EGetGeometry(m->items[0]->win, NULL, &x, &y, &w, &h, NULL, NULL);
|
|
mw = m->w;
|
|
mh = m->h;
|
|
|
|
wx = 0;
|
|
wy = 0;
|
|
if (Conf.menus.onscreen)
|
|
{
|
|
Border *b;
|
|
|
|
b = (Border *) FindItem(m->style->border_name, 0, LIST_FINDBY_NAME,
|
|
LIST_TYPE_BORDER);
|
|
if (b)
|
|
{
|
|
int width;
|
|
int height;
|
|
int x_origin;
|
|
int y_origin;
|
|
|
|
head_num =
|
|
GetPointerScreenGeometry(&x_origin, &y_origin, &width, &height);
|
|
|
|
if (Mode.x - x - ((int)mw / 2) > (x_origin + width))
|
|
wx = x_origin + (int)b->border.left;
|
|
else if (Mode.x + ((int)mw / 2) > (int)(x_origin + width))
|
|
wx = (x_origin + width) - (int)mw - (int)b->border.right;
|
|
else
|
|
wx = Mode.x - x - ((int)w / 2);
|
|
|
|
if ((wx - ((int)w / 2)) < x_origin)
|
|
wx = x_origin + (int)b->border.left;
|
|
|
|
if (Mode.y + (int)mh > (int)VRoot.h)
|
|
wy = (y_origin + height) - (int)mh - (int)b->border.bottom;
|
|
else
|
|
wy = Mode.y - y - ((int)h / 2);
|
|
|
|
if ((wy - ((int)h / 2) - (int)b->border.top) < y_origin)
|
|
wy = y_origin + (int)b->border.top;
|
|
}
|
|
}
|
|
|
|
if (Conf.menus.onscreen)
|
|
EMoveWindow(m->win, wx, wy);
|
|
else
|
|
EMoveWindow(m->win, Mode.x - x - (w / 2), Mode.y - y - (h / 2));
|
|
|
|
ewin = AddInternalToFamily(m->win, m->style->border_name, EWIN_TYPE_MENU, m,
|
|
MenuEwinInit);
|
|
m->ewin = ewin;
|
|
if (ewin)
|
|
{
|
|
ewin->client.event_mask |= KeyPressMask;
|
|
ESelectInput(m->win, ewin->client.event_mask);
|
|
|
|
ewin->head = head_num;
|
|
if (Conf.menus.slide)
|
|
EwinInstantShade(ewin, 0);
|
|
ICCCM_Cmap(NULL);
|
|
MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin));
|
|
FloatEwinAt(ewin, EoGetX(ewin), EoGetY(ewin));
|
|
if (!noshow)
|
|
{
|
|
ShowEwin(ewin);
|
|
if (Conf.menus.slide)
|
|
EwinUnShade(ewin);
|
|
}
|
|
}
|
|
|
|
m->stuck = 0;
|
|
|
|
if (!FindMenu(m->win))
|
|
AddItem(m, m->name, m->win, LIST_TYPE_MENU);
|
|
|
|
Mode_menus.just_shown = 1;
|
|
|
|
m->shown = 1;
|
|
if (Mode_menus.current_depth == 0)
|
|
{
|
|
Mode_menus.context_ewin = GetContextEwin();
|
|
#if 0
|
|
Eprintf("Mode_menus.context_ewin set %s\n",
|
|
EwinGetName(Mode_menus.context_ewin));
|
|
#endif
|
|
ecore_x_sync();
|
|
#if 1 /* ??? */
|
|
Mode_menus.list[0] = m;
|
|
Mode_menus.current_depth = 1;
|
|
MenuShowMasker(m);
|
|
#endif
|
|
TooltipsEnable(0);
|
|
GrabKeyboard(m->win);
|
|
}
|
|
m->ref_count++;
|
|
}
|
|
|
|
static void
|
|
MenuStyleSetName(MenuStyle * ms, const char *name)
|
|
{
|
|
if (ms->name)
|
|
Efree(ms->name);
|
|
ms->name = Estrdup(name);
|
|
}
|
|
|
|
static MenuStyle *
|
|
MenuStyleCreate(const char *name)
|
|
{
|
|
MenuStyle *ms;
|
|
|
|
ms = Ecalloc(1, sizeof(MenuStyle));
|
|
ms->iconpos = ICON_LEFT;
|
|
MenuStyleSetName(ms, name);
|
|
|
|
return ms;
|
|
}
|
|
|
|
MenuItem *
|
|
MenuItemCreate(const char *text, ImageClass * iclass,
|
|
const char *action_params, Menu * child)
|
|
{
|
|
MenuItem *mi;
|
|
|
|
mi = Ecalloc(1, sizeof(MenuItem));
|
|
|
|
mi->icon_iclass = iclass;
|
|
if (iclass)
|
|
iclass->ref_count++;
|
|
|
|
mi->text = (text) ? Estrdup((text[0]) ? _(text) : "?!?") : NULL;
|
|
mi->params = Estrdup(action_params);
|
|
mi->child = child;
|
|
mi->state = STATE_NORMAL;
|
|
|
|
return mi;
|
|
}
|
|
|
|
void
|
|
MenuSetName(Menu * m, const char *name)
|
|
{
|
|
if (m->name)
|
|
Efree(m->name);
|
|
m->name = Estrdup(name);
|
|
AddItem(m, m->name, m->win, LIST_TYPE_MENU);
|
|
}
|
|
|
|
void
|
|
MenuSetTitle(Menu * m, const char *title)
|
|
{
|
|
if (m->title)
|
|
Efree(m->title);
|
|
m->title = (title) ? Estrdup(_(title)) : NULL;
|
|
}
|
|
|
|
void
|
|
MenuSetData(Menu * m, char *data)
|
|
{
|
|
if (m->data)
|
|
Efree(m->data);
|
|
m->data = data;
|
|
}
|
|
|
|
void
|
|
MenuSetTimestamp(Menu * m, time_t t)
|
|
{
|
|
m->last_change = t;
|
|
}
|
|
|
|
const char *
|
|
MenuGetName(const Menu * m)
|
|
{
|
|
return m->name;
|
|
}
|
|
|
|
Window
|
|
MenuGetWindow(const Menu * m)
|
|
{
|
|
return m->win;
|
|
}
|
|
|
|
const char *
|
|
MenuGetData(const Menu * m)
|
|
{
|
|
return m->data;
|
|
}
|
|
|
|
time_t
|
|
MenuGetTimestamp(const Menu * m)
|
|
{
|
|
return m->last_change;
|
|
}
|
|
|
|
void
|
|
MenuSetStyle(Menu * m, MenuStyle * ms)
|
|
{
|
|
if (m->style)
|
|
m->style->ref_count--;
|
|
if (!ms && m->parent)
|
|
ms = m->parent->style;
|
|
if (!ms)
|
|
ms = FindItem("DEFAULT", 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
m->style = ms;
|
|
if (ms)
|
|
ms->ref_count++;
|
|
}
|
|
|
|
int
|
|
MenuIsNotEmpty(const Menu * m)
|
|
{
|
|
return m && (m->num > 0) && m->style;
|
|
}
|
|
|
|
Menu *
|
|
MenuCreate(const char *name, const char *title, Menu * parent, MenuStyle * ms)
|
|
{
|
|
Menu *m;
|
|
|
|
m = Ecalloc(1, sizeof(Menu));
|
|
if (!m)
|
|
return m;
|
|
|
|
m->parent = parent;
|
|
MenuSetName(m, name);
|
|
MenuSetTitle(m, title);
|
|
MenuSetStyle(m, ms);
|
|
|
|
return m;
|
|
}
|
|
|
|
void
|
|
MenuDestroy(Menu * m)
|
|
{
|
|
int i, j;
|
|
char s[4096];
|
|
|
|
if (!m)
|
|
return;
|
|
|
|
MenuHide(m);
|
|
|
|
if (m->win)
|
|
EDestroyWindow(m->win);
|
|
|
|
Esnprintf(s, sizeof(s), "__.%s", m->name);
|
|
RemoveTimerEvent(s);
|
|
RemoveItem((char *)m, m->win, LIST_FINDBY_POINTER, LIST_TYPE_MENU);
|
|
if (m->name)
|
|
Efree(m->name);
|
|
if (m->title)
|
|
Efree(m->title);
|
|
|
|
for (i = 0; i < m->num; i++)
|
|
{
|
|
if (m->items[i])
|
|
{
|
|
if (m->items[i]->child)
|
|
{
|
|
if (FindItem
|
|
((char *)m->items[i]->child, 0, LIST_FINDBY_POINTER,
|
|
LIST_TYPE_MENU))
|
|
MenuDestroy(m->items[i]->child);
|
|
}
|
|
if (m->items[i]->text)
|
|
Efree(m->items[i]->text);
|
|
if (m->items[i]->params)
|
|
Efree(m->items[i]->params);
|
|
for (j = 0; j < 3; j++)
|
|
FreePmapMask(&(m->items[i]->pmm[j]));
|
|
if (m->items[i]->icon_iclass)
|
|
m->items[i]->icon_iclass->ref_count--;
|
|
if (m->items[i])
|
|
Efree(m->items[i]);
|
|
}
|
|
}
|
|
|
|
if (m->items)
|
|
Efree(m->items);
|
|
if (m->data)
|
|
Efree(m->data);
|
|
FreePmapMask(&m->pmm);
|
|
|
|
Efree(m);
|
|
}
|
|
|
|
/* NB - this doesnt free imageclasses if we created them for the menu
|
|
* FIXME: so it will leak if we create new imageclasses and stop using
|
|
* old ones for menu icons. we need to add some ref counting in menu icon
|
|
* imageclasses to knw to free them when not used
|
|
*/
|
|
void
|
|
MenuEmpty(Menu * m)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < m->num; i++)
|
|
{
|
|
if (m->items[i])
|
|
{
|
|
if (m->items[i]->child)
|
|
MenuDestroy(m->items[i]->child);
|
|
if (m->items[i]->text)
|
|
Efree(m->items[i]->text);
|
|
if (m->items[i]->params)
|
|
Efree(m->items[i]->params);
|
|
for (j = 0; j < 3; j++)
|
|
FreePmapMask(&(m->items[i]->pmm[j]));
|
|
if (m->items[i]->win)
|
|
EDestroyWindow(m->items[i]->win);
|
|
if (m->items[i])
|
|
Efree(m->items[i]);
|
|
}
|
|
}
|
|
if (m->items)
|
|
Efree(m->items);
|
|
m->items = NULL;
|
|
m->num = 0;
|
|
}
|
|
|
|
void
|
|
MenuRepack(Menu * m)
|
|
{
|
|
EWin *ewin;
|
|
unsigned int w, h;
|
|
|
|
m->redraw = 1;
|
|
if (m->win)
|
|
MenuRealize(m);
|
|
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
w = m->w;
|
|
h = m->h;
|
|
ewin->client.height.min = h;
|
|
ewin->client.height.max = h;
|
|
ewin->client.width.min = w;
|
|
ewin->client.width.max = w;
|
|
ResizeEwin(ewin, w, h);
|
|
RaiseEwin(ewin);
|
|
}
|
|
}
|
|
|
|
void
|
|
MenuAddItem(Menu * m, MenuItem * item)
|
|
{
|
|
m->num++;
|
|
m->items = Erealloc(m->items, sizeof(MenuItem *) * m->num);
|
|
m->items[m->num - 1] = item;
|
|
}
|
|
|
|
static void
|
|
MenuRealize(Menu * m)
|
|
{
|
|
int i, maxh = 0, maxw = 0;
|
|
int maxx1, maxx2, w, h, x, y, r, mmw, mmh;
|
|
unsigned int iw, ih;
|
|
Imlib_Image *im;
|
|
char pq, has_i, has_s;
|
|
|
|
if (!m->style)
|
|
return;
|
|
|
|
if (!m->win)
|
|
{
|
|
m->win = ECreateWindow(VRoot.win, 0, 0, 1, 1, 0);
|
|
EventCallbackRegister(m->win, 0, MenuHandleEvents, m);
|
|
}
|
|
|
|
if (m->title)
|
|
{
|
|
HintsSetWindowName(m->win, m->title);
|
|
}
|
|
|
|
maxh = 0;
|
|
maxx1 = 0;
|
|
maxx2 = 0;
|
|
has_i = 0;
|
|
has_s = 0;
|
|
|
|
for (i = 0; i < m->num; i++)
|
|
{
|
|
m->items[i]->menu = m;
|
|
|
|
if (m->items[i]->child)
|
|
has_s = 1;
|
|
else
|
|
has_i = 1;
|
|
|
|
m->items[i]->win = ECreateWindow(m->win, 0, 0, 1, 1, 0);
|
|
EventCallbackRegister(m->items[i]->win, 0, MenuItemHandleEvents,
|
|
m->items[i]);
|
|
ESelectInput(m->items[i]->win, MENU_ITEM_EVENT_MASK);
|
|
EMapWindow(m->items[i]->win);
|
|
|
|
if ((m->style) && (m->style->tclass) && (m->items[i]->text))
|
|
{
|
|
TextSize(m->style->tclass, 0, 0, 0, m->items[i]->text, &w, &h, 17);
|
|
if (h > maxh)
|
|
maxh = h;
|
|
if (w > maxx1)
|
|
maxx1 = w;
|
|
m->items[i]->text_w = w;
|
|
m->items[i]->text_h = h;
|
|
}
|
|
if (m->items[i]->icon_iclass)
|
|
{
|
|
im = ELoadImage(m->items[i]->icon_iclass->norm.normal->im_file);
|
|
if (im)
|
|
{
|
|
imlib_context_set_image(im);
|
|
m->items[i]->icon_win =
|
|
ECreateWindow(m->items[i]->win, 0, 0,
|
|
imlib_image_get_width(),
|
|
imlib_image_get_height(), 0);
|
|
EMapWindow(m->items[i]->icon_win);
|
|
m->items[i]->icon_w = imlib_image_get_width();
|
|
m->items[i]->icon_h = imlib_image_get_height();
|
|
if (imlib_image_get_height() > maxh)
|
|
maxh = imlib_image_get_height();
|
|
if (imlib_image_get_width() > maxx2)
|
|
maxx2 = imlib_image_get_width();
|
|
imlib_free_image();
|
|
}
|
|
else
|
|
m->items[i]->icon_iclass = NULL;
|
|
}
|
|
}
|
|
if (((has_i) && (has_s)) || ((!has_i) && (!has_s)))
|
|
{
|
|
if (m->style->item_iclass->padding.top >
|
|
m->style->sub_iclass->padding.top)
|
|
maxh += m->style->item_iclass->padding.top;
|
|
else
|
|
maxh += m->style->sub_iclass->padding.top;
|
|
if (m->style->item_iclass->padding.bottom >
|
|
m->style->sub_iclass->padding.bottom)
|
|
maxh += m->style->item_iclass->padding.bottom;
|
|
else
|
|
maxh += m->style->sub_iclass->padding.bottom;
|
|
maxw = maxx1 + maxx2;
|
|
if (m->style->item_iclass->padding.left >
|
|
m->style->sub_iclass->padding.left)
|
|
maxw += m->style->item_iclass->padding.left;
|
|
else
|
|
maxw += m->style->sub_iclass->padding.left;
|
|
if (m->style->item_iclass->padding.right >
|
|
m->style->sub_iclass->padding.right)
|
|
maxw += m->style->item_iclass->padding.right;
|
|
else
|
|
maxw += m->style->sub_iclass->padding.right;
|
|
}
|
|
else if (has_i)
|
|
{
|
|
maxh += m->style->item_iclass->padding.top;
|
|
maxh += m->style->item_iclass->padding.bottom;
|
|
maxw = maxx1 + maxx2;
|
|
maxw += m->style->item_iclass->padding.left;
|
|
maxw += m->style->item_iclass->padding.right;
|
|
}
|
|
else if (has_s)
|
|
{
|
|
maxh += m->style->sub_iclass->padding.top;
|
|
maxh += m->style->sub_iclass->padding.bottom;
|
|
maxw = maxx1 + maxx2;
|
|
maxw += m->style->sub_iclass->padding.left;
|
|
maxw += m->style->sub_iclass->padding.right;
|
|
}
|
|
x = 0;
|
|
y = 0;
|
|
if ((m->style->bg_iclass) && (!m->style->use_item_bg))
|
|
{
|
|
x = m->style->bg_iclass->padding.left;
|
|
y = m->style->bg_iclass->padding.top;
|
|
}
|
|
|
|
r = 0;
|
|
mmw = 0;
|
|
mmh = 0;
|
|
pq = Mode.queue_up;
|
|
Mode.queue_up = 0;
|
|
|
|
for (i = 0; i < m->num; i++)
|
|
{
|
|
EMoveResizeWindow(m->items[i]->win, x, y, maxw, maxh);
|
|
if (m->style->iconpos == ICON_LEFT)
|
|
{
|
|
m->items[i]->text_x = m->style->item_iclass->padding.left + maxx2;
|
|
m->items[i]->text_w = maxx1;
|
|
m->items[i]->text_y = (maxh - m->items[i]->text_h) / 2;
|
|
if (m->items[i]->icon_win)
|
|
EMoveWindow(m->items[i]->icon_win,
|
|
m->style->item_iclass->padding.left +
|
|
((maxx2 - m->items[i]->icon_w) / 2),
|
|
((maxh - m->items[i]->icon_h) / 2));
|
|
}
|
|
else
|
|
{
|
|
m->items[i]->text_x = m->style->item_iclass->padding.left;
|
|
m->items[i]->text_w = maxx1;
|
|
m->items[i]->text_y = (maxh - m->items[i]->text_h) / 2;
|
|
if (m->items[i]->icon_win)
|
|
EMoveWindow(m->items[i]->icon_win,
|
|
maxw - m->style->item_iclass->padding.right -
|
|
maxx2 + ((maxx2 - w) / 2), ((maxh - h) / 2));
|
|
}
|
|
if (m->items[i]->icon_iclass)
|
|
{
|
|
iw = 0;
|
|
ih = 0;
|
|
EGetGeometry(m->items[i]->icon_win, NULL, NULL, NULL, &iw, &ih,
|
|
NULL, NULL);
|
|
ImageclassApply(m->items[i]->icon_iclass, m->items[i]->icon_win,
|
|
iw, ih, 0, 0, STATE_NORMAL, 0, ST_MENU_ITEM);
|
|
}
|
|
if (x + maxw > mmw)
|
|
mmw = x + maxw;
|
|
if (y + maxh > mmh)
|
|
mmh = y + maxh;
|
|
if ((m->style->maxx) || (m->style->maxy))
|
|
{
|
|
if (m->style->maxy)
|
|
{
|
|
y += maxh;
|
|
r++;
|
|
if (r >= m->style->maxy)
|
|
{
|
|
r = 0;
|
|
x += maxw;
|
|
y = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x += maxw;
|
|
r++;
|
|
if (r >= m->style->maxx)
|
|
{
|
|
r = 0;
|
|
y += maxh;
|
|
x = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
y += maxh;
|
|
}
|
|
|
|
if ((m->style->bg_iclass) && (!m->style->use_item_bg))
|
|
{
|
|
mmw += m->style->bg_iclass->padding.right;
|
|
mmh += m->style->bg_iclass->padding.bottom;
|
|
}
|
|
|
|
m->redraw = 1;
|
|
m->w = mmw;
|
|
m->h = mmh;
|
|
EResizeWindow(m->win, mmw, mmh);
|
|
|
|
Mode.queue_up = pq;
|
|
}
|
|
|
|
static void
|
|
MenuRedraw(Menu * m)
|
|
{
|
|
int i, j, w, h;
|
|
|
|
if (m->redraw)
|
|
{
|
|
for (i = 0; i < m->num; i++)
|
|
{
|
|
for (j = 0; j < 3; j++)
|
|
FreePmapMask(&(m->items[i]->pmm[j]));
|
|
|
|
}
|
|
m->redraw = 0;
|
|
}
|
|
|
|
if (!m->style->use_item_bg)
|
|
{
|
|
w = m->w;
|
|
h = m->h;
|
|
FreePmapMask(&m->pmm);
|
|
ImageclassApplyCopy(m->style->bg_iclass, m->win, w, h, 0, 0,
|
|
STATE_NORMAL, &m->pmm, 1, ST_MENU);
|
|
ESetWindowBackgroundPixmap(m->win, m->pmm.pmap);
|
|
EShapeCombineMask(m->win, ShapeBounding, 0, 0, m->pmm.mask, ShapeSet);
|
|
for (i = 0; i < m->num; i++)
|
|
MenuDrawItem(m, m->items[i], 0);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < m->num; i++)
|
|
MenuDrawItem(m, m->items[i], 0);
|
|
PropagateShapes(m->win);
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuDrawItem(Menu * m, MenuItem * mi, char shape)
|
|
{
|
|
PmapMask *mi_pmm;
|
|
char pq;
|
|
|
|
pq = Mode.queue_up;
|
|
Mode.queue_up = 0;
|
|
|
|
mi_pmm = &(mi->pmm[(int)(mi->state)]);
|
|
|
|
if (!mi_pmm->pmap)
|
|
{
|
|
GC gc;
|
|
unsigned int w, h;
|
|
int x, y;
|
|
int item_type;
|
|
ImageClass *ic;
|
|
|
|
EGetGeometry(mi->win, NULL, &x, &y, &w, &h, NULL, NULL);
|
|
|
|
mi_pmm->type = 0;
|
|
mi_pmm->pmap = ECreatePixmap(mi->win, w, h, VRoot.depth);
|
|
mi_pmm->mask = None;
|
|
|
|
ic = (mi->child) ? m->style->sub_iclass : m->style->item_iclass;
|
|
item_type = (mi->state != STATE_NORMAL) ? ST_MENU_ITEM : ST_MENU;
|
|
|
|
if (!m->style->use_item_bg)
|
|
{
|
|
gc = ECreateGC(m->pmm.pmap, 0, NULL);
|
|
XCopyArea(disp, m->pmm.pmap, mi_pmm->pmap, gc, x, y, w, h, 0, 0);
|
|
if ((mi->state != STATE_NORMAL) || (mi->child))
|
|
{
|
|
PmapMask pmm;
|
|
|
|
ImageclassApplyCopy(ic, mi->win, w, h, 0, 0, mi->state, &pmm,
|
|
1, item_type);
|
|
if (pmm.mask)
|
|
{
|
|
XSetClipMask(disp, gc, pmm.mask);
|
|
XSetClipOrigin(disp, gc, 0, 0);
|
|
}
|
|
XCopyArea(disp, pmm.pmap, mi_pmm->pmap, gc, 0, 0, w, h, 0, 0);
|
|
FreePmapMask(&pmm);
|
|
}
|
|
EFreeGC(gc);
|
|
}
|
|
else
|
|
{
|
|
ImageclassApplyCopy(ic, mi_pmm->pmap, w, h, 0, 0, mi->state,
|
|
mi_pmm, 1, item_type);
|
|
}
|
|
|
|
if (mi->text)
|
|
{
|
|
TextDraw(m->style->tclass, mi_pmm->pmap, 0, 0, mi->state,
|
|
mi->text, mi->text_x, mi->text_y, mi->text_w, mi->text_h,
|
|
17, m->style->tclass->justification);
|
|
}
|
|
}
|
|
|
|
ESetWindowBackgroundPixmap(mi->win, mi_pmm->pmap);
|
|
EShapeCombineMask(mi->win, ShapeBounding, 0, 0, mi_pmm->mask, ShapeSet);
|
|
EClearWindow(mi->win);
|
|
|
|
if ((shape) && (m->style->use_item_bg))
|
|
PropagateShapes(m->win);
|
|
|
|
if (mi->state == STATE_HILITED)
|
|
{
|
|
active_item = mi;
|
|
if (active_menu != m)
|
|
{
|
|
active_menu = m;
|
|
UngrabKeyboard();
|
|
GrabKeyboard(m->win);
|
|
}
|
|
}
|
|
|
|
Mode.queue_up = pq;
|
|
}
|
|
|
|
static void
|
|
MenuShowMasker(Menu * m)
|
|
{
|
|
EWin *ewin;
|
|
|
|
ewin = FindEwinByMenu(m);
|
|
if ((ewin) && (!Mode_menus.cover_win))
|
|
{
|
|
EObj *eo;
|
|
|
|
Mode_menus.cover_win =
|
|
ECreateEventWindow(ewin->parent, 0, 0, VRoot.w, VRoot.h);
|
|
Mode_menus.win_covered = EoGetWin(ewin);
|
|
eo = EobjRegister(Mode_menus.cover_win, EOBJ_TYPE_OVERR);
|
|
EobjSetDesk(eo, EoGetDesk(ewin));
|
|
EobjSetLayer(eo, 2);
|
|
EobjSetFloating(eo, 1);
|
|
EobjListStackLower(eo);
|
|
ESelectInput(Mode_menus.cover_win,
|
|
ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
|
|
LeaveWindowMask);
|
|
EMapWindow(Mode_menus.cover_win);
|
|
EventCallbackRegister(Mode_menus.cover_win, 0, MenuMaskerHandleEvents,
|
|
NULL);
|
|
#if 1 /* FIXME - Too expensive */
|
|
StackDesktop(EoGetDesk(ewin));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuHideMasker(void)
|
|
{
|
|
if (Mode_menus.cover_win)
|
|
{
|
|
EobjUnregister(Mode_menus.cover_win);
|
|
EDestroyWindow(Mode_menus.cover_win);
|
|
Mode_menus.cover_win = 0;
|
|
Mode_menus.win_covered = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenusDestroyLoaded(void)
|
|
{
|
|
Menu *menu;
|
|
Menu **menus;
|
|
int i, num, found_one;
|
|
|
|
/* Free all menustyles first (gulp) */
|
|
do
|
|
{
|
|
found_one = 0;
|
|
menus = (Menu **) ListItemType(&num, LIST_TYPE_MENU);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
menu = menus[i];
|
|
if (menu->internal)
|
|
continue;
|
|
|
|
MenuDestroy(menu);
|
|
/* Destroying a menu may result in sub-menus being
|
|
* destroyed too, so we have to re-find all menus
|
|
* afterwards. Inefficient yes, but it works...
|
|
*/
|
|
found_one = 1;
|
|
break;
|
|
}
|
|
if (menus)
|
|
Efree(menus);
|
|
}
|
|
while (found_one);
|
|
}
|
|
|
|
/*
|
|
* Internal menus
|
|
*/
|
|
|
|
static Menu *
|
|
RefreshInternalMenu(Menu * m, MenuStyle * ms,
|
|
Menu * (mcf) (const char *xxx, MenuStyle * ms))
|
|
{
|
|
char was = 0;
|
|
int lx = 0, ly = 0;
|
|
EWin *ewin;
|
|
|
|
if (m)
|
|
{
|
|
ewin = FindEwinByMenu(m);
|
|
if ((m->win) && (ewin))
|
|
{
|
|
lx = EoGetX(ewin);
|
|
ly = EoGetY(ewin);
|
|
was = 1;
|
|
}
|
|
MenuDestroy(m);
|
|
m = NULL;
|
|
}
|
|
|
|
if (!ms)
|
|
return NULL;
|
|
|
|
m = mcf("MENU", ms);
|
|
if ((was) && (m))
|
|
{
|
|
m->internal = 1;
|
|
MenuShow(m, 1);
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
MoveEwin(ewin, lx, ly);
|
|
ShowEwin(ewin);
|
|
}
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
static void
|
|
MenusShowNamed(const char *name)
|
|
{
|
|
Menu *m;
|
|
|
|
/* Hide any menus currently up */
|
|
if (MenusActive())
|
|
MenusHide();
|
|
|
|
m = FindItem(name, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU);
|
|
if (m)
|
|
{
|
|
if (!FindEwinByMenu(m)) /* Don't show if already shown */
|
|
MenuShow(m, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
ShowInternalMenu(Menu ** pm, MenuStyle ** pms, const char *style,
|
|
Menu * (mcf) (const char *name, MenuStyle * ms))
|
|
{
|
|
Menu *m = *pm;
|
|
MenuStyle *ms = *pms;
|
|
|
|
/* Hide any menus currently up */
|
|
if (MenusActive())
|
|
MenusHide();
|
|
|
|
if (!ms)
|
|
{
|
|
ms = FindItem(style, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (!ms)
|
|
ms = FindItem("DEFAULT", 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (!ms)
|
|
return;
|
|
*pms = ms;
|
|
}
|
|
|
|
*pm = m = RefreshInternalMenu(m, ms, mcf);
|
|
if (m)
|
|
{
|
|
if (!FindEwinByMenu(m))
|
|
MenuShow(m, 0);
|
|
}
|
|
}
|
|
|
|
int
|
|
MenusActive(void)
|
|
{
|
|
return Mode_menus.current_depth;
|
|
}
|
|
|
|
static void
|
|
MenusHide(void)
|
|
{
|
|
int i;
|
|
|
|
while (RemoveTimerEvent("SUBMENU_SHOW"))
|
|
;
|
|
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
if (!Mode_menus.list[i]->stuck)
|
|
MenuHide(Mode_menus.list[i]);
|
|
}
|
|
MenuHideMasker();
|
|
Mode_menus.current_depth = 0;
|
|
Mode_menus.clicked = 0;
|
|
TooltipsEnable(1);
|
|
|
|
#if 0
|
|
/* If all done properly this shouldn't be necessary... */
|
|
UngrabKeyboard();
|
|
active_menu = NULL;
|
|
active_item = NULL;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Menu event handlers
|
|
*/
|
|
|
|
static MenuItem *
|
|
MenuFindNextItem(Menu * m, MenuItem * mi, int inc)
|
|
{
|
|
int i;
|
|
|
|
if (mi == NULL)
|
|
{
|
|
if (m->num > 0)
|
|
return m->items[0];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < m->num; i++)
|
|
if (m->items[i] == mi)
|
|
{
|
|
i = (i + inc + m->num) % m->num;
|
|
return m->items[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static MenuItem *
|
|
MenuFindParentItem(Menu * m)
|
|
{
|
|
int i;
|
|
Menu *mp;
|
|
|
|
mp = m->parent;
|
|
if (mp == NULL)
|
|
return NULL;
|
|
|
|
for (i = 0; i < mp->num; i++)
|
|
if (mp->items[i]->child == m)
|
|
return mp->items[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if 0
|
|
static EWin *
|
|
MenuFindContextEwin(Menu * m __UNUSED__)
|
|
{
|
|
#if 0
|
|
while (m && m->parent)
|
|
m = m->parent;
|
|
|
|
if (!m)
|
|
return NULL;
|
|
|
|
return FindEwinSpawningMenu(m);
|
|
#endif
|
|
return Mode_menus.context_ewin;
|
|
}
|
|
#endif
|
|
|
|
static KeySym
|
|
MenuKeyPressConversion(KeySym key)
|
|
{
|
|
if (key == Conf.menus.key.left)
|
|
return XK_Left;
|
|
if (key == Conf.menus.key.right)
|
|
return XK_Right;
|
|
if (key == Conf.menus.key.up)
|
|
return XK_Up;
|
|
if (key == Conf.menus.key.down)
|
|
return XK_Down;
|
|
if (key == Conf.menus.key.escape)
|
|
return XK_Escape;
|
|
if (key == Conf.menus.key.ret)
|
|
return XK_Return;
|
|
|
|
/* The key does not correspond to any set, use the default behavior
|
|
* associated to the key */
|
|
return key;
|
|
}
|
|
|
|
static void
|
|
MenuEventKeyPress(Menu * m, XEvent * ev)
|
|
{
|
|
KeySym key;
|
|
MenuItem *mi;
|
|
EWin *ewin;
|
|
|
|
mi = NULL;
|
|
if (active_menu)
|
|
{
|
|
m = active_menu;
|
|
mi = active_item;
|
|
}
|
|
|
|
/* NB! m != NULL */
|
|
|
|
key = XLookupKeysym(&ev->xkey, 0);
|
|
switch (MenuKeyPressConversion(key))
|
|
{
|
|
case XK_Escape:
|
|
MenusHide();
|
|
break;
|
|
case XK_Down:
|
|
check_next:
|
|
mi = MenuFindNextItem(m, mi, 1);
|
|
goto check_activate;
|
|
case XK_Up:
|
|
mi = MenuFindNextItem(m, mi, -1);
|
|
goto check_activate;
|
|
case XK_Left:
|
|
mi = MenuFindParentItem(m);
|
|
m = m->parent;
|
|
goto check_menu;
|
|
case XK_Right:
|
|
if (mi == NULL)
|
|
goto check_next;
|
|
m = mi->child;
|
|
if (!m || m->num <= 0)
|
|
break;
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin == NULL || !EwinIsMapped(ewin))
|
|
break;
|
|
mi = m->items[0];
|
|
goto check_menu;
|
|
check_menu:
|
|
if (!m)
|
|
break;
|
|
goto check_activate;
|
|
check_activate:
|
|
if (!mi)
|
|
break;
|
|
if (active_menu && active_item && active_menu != m)
|
|
MenuActivateItem(active_menu, NULL);
|
|
MenuActivateItem(m, mi);
|
|
break;
|
|
case XK_Return:
|
|
if (!mi)
|
|
break;
|
|
if (!mi->params)
|
|
break;
|
|
MenusHide();
|
|
SetContextEwin(Mode_menus.context_ewin);
|
|
EFunc(mi->params);
|
|
SetContextEwin(NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuItemEventMouseDown(MenuItem * mi, XEvent * ev __UNUSED__)
|
|
{
|
|
Menu *m;
|
|
EWin *ewin;
|
|
|
|
Mode_menus.just_shown = 0;
|
|
|
|
m = mi->menu;
|
|
mi->state = STATE_CLICKED;
|
|
MenuDrawItem(m, mi, 1);
|
|
|
|
if (mi->child && mi->child->shown == 0)
|
|
{
|
|
int mx, my;
|
|
unsigned int mw, mh;
|
|
EWin *ewin2;
|
|
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
EGetGeometry(mi->win, NULL, &mx, &my, &mw, &mh, NULL, NULL);
|
|
#if 1 /* Whatgoesonhere ??? */
|
|
MenuShow(mi->child, 1);
|
|
ewin2 = FindEwinByMenu(mi->child);
|
|
if (ewin2)
|
|
{
|
|
MoveEwin(ewin2,
|
|
EoGetX(ewin) + ewin->border->border.left + mx + mw,
|
|
EoGetY(ewin) + ewin->border->border.top + my -
|
|
ewin2->border->border.top);
|
|
RaiseEwin(ewin2);
|
|
ShowEwin(ewin2);
|
|
if (Conf.menus.slide)
|
|
EwinUnShade(ewin2);
|
|
Mode_menus.list[Mode_menus.current_depth++] = mi->child;
|
|
}
|
|
#else
|
|
ewin2 = FindEwinByMenu(mi->child);
|
|
if (!ewin2)
|
|
MenuShow(mi->child, 1);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
MenuItemEventMouseUp(MenuItem * mi, XEvent * ev __UNUSED__)
|
|
{
|
|
Menu *m;
|
|
|
|
if (Mode_menus.just_shown)
|
|
{
|
|
Mode_menus.just_shown = 0;
|
|
return;
|
|
}
|
|
|
|
m = mi->menu;
|
|
|
|
if ((m) && (mi->state))
|
|
{
|
|
mi->state = STATE_HILITED;
|
|
MenuDrawItem(m, mi, 1);
|
|
if ((mi->params) /* && (!Mode_menus.just_shown) */ )
|
|
{
|
|
MenusHide();
|
|
SetContextEwin(Mode_menus.context_ewin);
|
|
EFunc(mi->params);
|
|
SetContextEwin(NULL);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0 /* Was in HandleMotion() */
|
|
void
|
|
MenusHandleMotion(void)
|
|
{
|
|
#define SCROLL_RATIO 2/3
|
|
if ((MenusActive() || (Mode_menus.clicked)))
|
|
{
|
|
int i, offx = 0, offy = 0, xdist = 0, ydist = 0;
|
|
EWin *ewin;
|
|
EWin *menus[256];
|
|
int fx[256];
|
|
int fy[256];
|
|
int tx[256];
|
|
int ty[256];
|
|
static int menu_scroll_dist = 4;
|
|
int my_width, my_height, x_org, y_org, head_num = 0;
|
|
|
|
head_num = ScreenGetGeometry(Mode.x, Mode.y, &x_org, &y_org,
|
|
&my_width, &my_height);
|
|
|
|
if (Mode.x > ((x_org + my_width) - (menu_scroll_dist + 1)))
|
|
{
|
|
xdist = -(menu_scroll_dist + (Mode.x - (x_org + my_width)));
|
|
}
|
|
else if (Mode.x < (menu_scroll_dist + x_org))
|
|
{
|
|
xdist = x_org + menu_scroll_dist - (Mode.x);
|
|
}
|
|
|
|
if (Mode.y > (VRoot.h - (menu_scroll_dist + 1)))
|
|
{
|
|
ydist = -(menu_scroll_dist + (Mode.y - (y_org + my_height)));
|
|
}
|
|
else if (Mode.y < (menu_scroll_dist + y_org))
|
|
{
|
|
ydist = y_org + menu_scroll_dist - (Mode.y);
|
|
}
|
|
|
|
/* That's a hack to avoid unwanted events:
|
|
* If the user entered the border area, he has to
|
|
* leave it first, before he can scroll menus again ...
|
|
*/
|
|
if ((xdist != 0) || (ydist != 0) || Mode.doingslide)
|
|
{
|
|
/* -10 has no meaning, only makes sure that the if's */
|
|
/* above can't be fulfilled ... */
|
|
menu_scroll_dist = -10;
|
|
}
|
|
else
|
|
{
|
|
menu_scroll_dist = 13;
|
|
}
|
|
|
|
if (Mode_menus.current_depth > 0)
|
|
{
|
|
int x1, y1, x2, y2;
|
|
|
|
x1 = x_org + my_width;
|
|
x2 = x_org - 1;
|
|
y1 = y_org + my_height;
|
|
y2 = y_org - 1;
|
|
/* work out the minimum and maximum extents of our */
|
|
/* currently active menus */
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
if (Mode_menus.list[i])
|
|
{
|
|
ewin = FindEwinByMenu(Mode_menus.list[i]);
|
|
if (ewin)
|
|
{
|
|
if (EoGetX(ewin) < x1)
|
|
x1 = EoGetX(ewin);
|
|
if (EoGetY(ewin) < y1)
|
|
y1 = EoGetY(ewin);
|
|
if ((EoGetX(ewin) + EoGetW(ewin) - 1) > x2)
|
|
x2 = EoGetX(ewin) + EoGetW(ewin) - 1;
|
|
if ((EoGetY(ewin) + EoGetH(ewin) - 1) > y2)
|
|
y2 = EoGetY(ewin) + EoGetH(ewin) - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (xdist < 0)
|
|
{
|
|
offx = (x_org + my_width) - x2;
|
|
}
|
|
else if (xdist > 0)
|
|
{
|
|
offx = x_org - x1;
|
|
}
|
|
if (ydist < 0)
|
|
{
|
|
offy = (y_org + my_height) - y2;
|
|
}
|
|
else if (ydist > 0)
|
|
{
|
|
offy = y_org - y1;
|
|
}
|
|
|
|
if ((xdist < 0) && (offx <= 0))
|
|
xdist = offx;
|
|
if ((xdist > 0) && (offx >= 0))
|
|
xdist = offx;
|
|
if ((ydist < 0) && (offy <= 0))
|
|
ydist = offy;
|
|
if ((ydist > 0) && (offy >= 0))
|
|
ydist = offy;
|
|
|
|
/* only if any active menus are partially off screen then scroll */
|
|
if ((((xdist > 0) && (x1 < x_org))
|
|
|| ((xdist < 0) && (x2 >= (x_org + my_width))))
|
|
|| (((ydist > 0) && (y1 < y_org))
|
|
|| ((ydist < 0) && (y2 >= (y_org + my_height)))))
|
|
{
|
|
/* If we would scroll too far, limit scrolling to 2/3s of screen */
|
|
if (ydist < -my_width)
|
|
ydist = -my_width * SCROLL_RATIO;
|
|
if (ydist > my_width)
|
|
ydist = my_width * SCROLL_RATIO;
|
|
|
|
if (xdist < -my_height)
|
|
xdist = -my_height * SCROLL_RATIO;
|
|
if (xdist > my_height)
|
|
xdist = my_height * SCROLL_RATIO;
|
|
|
|
if (Mode_menus.current_depth)
|
|
{
|
|
#ifdef HAS_XINERAMA
|
|
ewin = FindEwinByMenu(Mode_menus.list[0]);
|
|
if (ewin->head == head_num)
|
|
{
|
|
#endif
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
menus[i] = NULL;
|
|
if (Mode_menus.list[i])
|
|
{
|
|
ewin = FindEwinByMenu(Mode_menus.list[i]);
|
|
if (ewin)
|
|
{
|
|
menus[i] = ewin;
|
|
fx[i] = EoGetX(ewin);
|
|
fy[i] = EoGetY(ewin);
|
|
tx[i] = EoGetX(ewin) + xdist;
|
|
ty[i] = EoGetY(ewin) + ydist;
|
|
}
|
|
}
|
|
}
|
|
SlideEwinsTo(menus, fx, fy, tx, ty,
|
|
Mode_menus.current_depth,
|
|
Conf.shadespeed);
|
|
if (((xdist != 0) || (ydist != 0))
|
|
&& (Conf.menus.warp))
|
|
XWarpPointer(disp, None, None, 0, 0, 0, 0, xdist,
|
|
ydist);
|
|
#ifdef HAS_XINERAMA
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
struct _mdata
|
|
{
|
|
Menu *m;
|
|
MenuItem *mi;
|
|
};
|
|
|
|
static void
|
|
MenusSetEvents(int on)
|
|
{
|
|
int i, j;
|
|
Menu *m;
|
|
long event_mask;
|
|
|
|
event_mask = (on) ? MENU_ITEM_EVENT_MASK : 0;
|
|
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
m = Mode_menus.list[i];
|
|
if (!m)
|
|
continue;
|
|
|
|
for (j = 0; j < m->num; j++)
|
|
ESelectInput(m->items[j]->win, event_mask);
|
|
}
|
|
}
|
|
|
|
static void
|
|
SubmenuShowTimeout(int val __UNUSED__, void *dat)
|
|
{
|
|
int mx, my;
|
|
unsigned int mw, mh;
|
|
Menu *m;
|
|
MenuItem *mi;
|
|
EWin *ewin2, *ewin;
|
|
struct _mdata *data;
|
|
|
|
data = (struct _mdata *)dat;
|
|
if (!data)
|
|
return;
|
|
if (!data->m)
|
|
return;
|
|
|
|
m = data->m;
|
|
ewin = FindItem(NULL, m->win, LIST_FINDBY_ID, LIST_TYPE_EWIN);
|
|
if (!ewin)
|
|
return;
|
|
if (!ewin->shown)
|
|
return;
|
|
|
|
mi = data->mi;
|
|
MenuShow(mi->child, 1);
|
|
ewin2 = FindItem(NULL, mi->child->win, LIST_FINDBY_ID, LIST_TYPE_EWIN);
|
|
if (!ewin2)
|
|
return;
|
|
|
|
EGetGeometry(mi->win, NULL, &mx, &my, &mw, &mh, NULL, NULL);
|
|
MoveEwin(ewin2,
|
|
EoGetX(ewin) + ewin->border->border.left + mx + mw,
|
|
EoGetY(ewin) + ewin->border->border.top + my -
|
|
ewin2->border->border.top);
|
|
RaiseEwin(ewin2);
|
|
ShowEwin(ewin2);
|
|
|
|
if (Conf.menus.slide)
|
|
EwinUnShade(ewin2);
|
|
|
|
if (Mode_menus.list[Mode_menus.current_depth - 1] != mi->child)
|
|
Mode_menus.list[Mode_menus.current_depth++] = mi->child;
|
|
|
|
if (Conf.menus.onscreen)
|
|
{
|
|
EWin *menus[256];
|
|
int fx[256];
|
|
int fy[256];
|
|
int tx[256];
|
|
int ty[256];
|
|
int i;
|
|
int xdist = 0, ydist = 0;
|
|
|
|
if (EoGetX(ewin2) + EoGetW(ewin2) > VRoot.w)
|
|
xdist = VRoot.w - (EoGetX(ewin2) + EoGetW(ewin2));
|
|
if (EoGetY(ewin2) + EoGetH(ewin2) > VRoot.h)
|
|
ydist = VRoot.h - (EoGetY(ewin2) + EoGetH(ewin2));
|
|
if ((xdist != 0) || (ydist != 0))
|
|
{
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
menus[i] = NULL;
|
|
if (Mode_menus.list[i])
|
|
{
|
|
ewin = FindEwinByMenu(Mode_menus.list[i]);
|
|
if (ewin)
|
|
{
|
|
menus[i] = ewin;
|
|
fx[i] = EoGetX(ewin);
|
|
fy[i] = EoGetY(ewin);
|
|
tx[i] = EoGetX(ewin) + xdist;
|
|
ty[i] = EoGetY(ewin) + ydist;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Disable menu item events while sliding */
|
|
MenusSetEvents(0);
|
|
SlideEwinsTo(menus, fx, fy, tx, ty, Mode_menus.current_depth,
|
|
Conf.shadespeed);
|
|
MenusSetEvents(1);
|
|
|
|
if (Conf.menus.warp)
|
|
XWarpPointer(disp, None, mi->win, 0, 0, 0, 0,
|
|
mi->text_w / 2, mi->text_h / 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuActivateItem(Menu * m, MenuItem * mi)
|
|
{
|
|
static struct _mdata mdata;
|
|
int i, j;
|
|
|
|
if (m->sel_item)
|
|
{
|
|
m->sel_item->state = STATE_NORMAL;
|
|
MenuDrawItem(m, m->sel_item, 1);
|
|
}
|
|
|
|
m->sel_item = mi;
|
|
|
|
if (mi == NULL)
|
|
return;
|
|
|
|
mi->state = STATE_HILITED;
|
|
MenuDrawItem(m, mi, 1);
|
|
|
|
RemoveTimerEvent("SUBMENU_SHOW");
|
|
|
|
for (i = 0; i < Mode_menus.current_depth; i++)
|
|
{
|
|
if (Mode_menus.list[i] == m)
|
|
{
|
|
if ((!mi->child) ||
|
|
((mi->child) && (Mode_menus.list[i + 1] != mi->child)))
|
|
{
|
|
for (j = i + 1; j < Mode_menus.current_depth; j++)
|
|
MenuHide(Mode_menus.list[j]);
|
|
Mode_menus.current_depth = i + 1;
|
|
i = Mode_menus.current_depth;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((mi->child) && (!mi->child->shown) && MenusActive())
|
|
{
|
|
EWin *ewin;
|
|
|
|
mi->child->parent = m;
|
|
ewin = FindEwinByMenu(m);
|
|
if (ewin)
|
|
{
|
|
mdata.m = m;
|
|
mdata.mi = mi;
|
|
DoIn("SUBMENU_SHOW", 0.2, SubmenuShowTimeout, 0, &mdata);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuItemEventMouseIn(MenuItem * mi, XEvent * ev)
|
|
{
|
|
Window win = ev->xcrossing.window;
|
|
Menu *m;
|
|
|
|
m = mi->menu;
|
|
|
|
#if 0 /* FIXME - TBD */
|
|
PagerHideAllHi();
|
|
#endif
|
|
|
|
if ((win == mi->icon_win) && (ev->xcrossing.detail == NotifyAncestor))
|
|
goto done;
|
|
if ((win == mi->win) && (ev->xcrossing.detail == NotifyInferior))
|
|
goto done;
|
|
|
|
MenuActivateItem(m, mi);
|
|
|
|
done:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
MenuItemEventMouseOut(MenuItem * mi, XEvent * ev)
|
|
{
|
|
Window win = ev->xcrossing.window;
|
|
Menu *m;
|
|
|
|
m = mi->menu;
|
|
|
|
if ((win == mi->icon_win) && (ev->xcrossing.detail == NotifyAncestor))
|
|
goto done;
|
|
if ((win == mi->win) && (ev->xcrossing.detail == NotifyInferior))
|
|
goto done;
|
|
|
|
MenuActivateItem(m, NULL);
|
|
|
|
done:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
MenuHandleEvents(XEvent * ev, void *prm)
|
|
{
|
|
Menu *m = (Menu *) prm;
|
|
|
|
#if DEBUG_MENU_EVENTS
|
|
Eprintf("MenuHandleEvents %d\n", ev->type);
|
|
#endif
|
|
switch (ev->type)
|
|
{
|
|
case KeyPress:
|
|
MenuEventKeyPress(m, ev);
|
|
break;
|
|
case ButtonRelease:
|
|
break;
|
|
case EnterNotify:
|
|
GrabKeyboard(m->win);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuItemHandleEvents(XEvent * ev, void *prm)
|
|
{
|
|
MenuItem *mi = (MenuItem *) prm;
|
|
|
|
#if DEBUG_MENU_EVENTS
|
|
Eprintf("MenuItemHandleEvents %d\n", ev->type);
|
|
#endif
|
|
switch (ev->type)
|
|
{
|
|
case ButtonPress:
|
|
MenuItemEventMouseDown(mi, ev);
|
|
break;
|
|
case ButtonRelease:
|
|
MenuItemEventMouseUp(mi, ev);
|
|
break;
|
|
case EnterNotify:
|
|
MenuItemEventMouseIn(mi, ev);
|
|
break;
|
|
case LeaveNotify:
|
|
MenuItemEventMouseOut(mi, ev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenuMaskerHandleEvents(XEvent * ev, void *prm __UNUSED__)
|
|
{
|
|
#if DEBUG_MENU_EVENTS
|
|
Eprintf("MenuMaskerHandleEvents %d\n", ev->type);
|
|
#endif
|
|
switch (ev->type)
|
|
{
|
|
case ButtonRelease:
|
|
MenusHide();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Configuration load/save
|
|
*/
|
|
#include "conf.h"
|
|
|
|
int
|
|
MenuStyleConfigLoad(FILE * ConfigFile)
|
|
{
|
|
int err = 0;
|
|
char s[FILEPATH_LEN_MAX];
|
|
char s2[FILEPATH_LEN_MAX];
|
|
int i1;
|
|
MenuStyle *ms = NULL;
|
|
int fields;
|
|
|
|
while (GetLine(s, sizeof(s), ConfigFile))
|
|
{
|
|
s2[0] = 0;
|
|
i1 = CONFIG_INVALID;
|
|
fields = sscanf(s, "%i %4000s", &i1, s2);
|
|
|
|
if (fields < 1)
|
|
{
|
|
i1 = CONFIG_INVALID;
|
|
}
|
|
else if (i1 == CONFIG_CLOSE)
|
|
{
|
|
if (fields != 1)
|
|
Alert(_("CONFIG: ignoring extra data in \"%s\"\n"), s);
|
|
}
|
|
else if (i1 != CONFIG_INVALID)
|
|
{
|
|
if (fields != 2)
|
|
Alert(_("CONFIG: missing required data in \"%s\"\n"), s);
|
|
}
|
|
|
|
switch (i1)
|
|
{
|
|
case CONFIG_CLOSE:
|
|
AddItem(ms, ms->name, 0, LIST_TYPE_MENU_STYLE);
|
|
goto done;
|
|
case CONFIG_CLASSNAME:
|
|
ms = MenuStyleCreate(s2);
|
|
break;
|
|
case CONFIG_TEXT:
|
|
ms->tclass = TextclassFind(s2, 1);
|
|
if (ms->tclass)
|
|
ms->tclass->ref_count++;
|
|
break;
|
|
case MENU_BG_ICLASS:
|
|
ms->bg_iclass = ImageclassFind(s2, 0);
|
|
if (ms->bg_iclass)
|
|
ms->bg_iclass->ref_count++;
|
|
break;
|
|
case MENU_ITEM_ICLASS:
|
|
ms->item_iclass = ImageclassFind(s2, 0);
|
|
if (ms->item_iclass)
|
|
ms->item_iclass->ref_count++;
|
|
break;
|
|
case MENU_SUBMENU_ICLASS:
|
|
ms->sub_iclass = ImageclassFind(s2, 0);
|
|
if (ms->sub_iclass)
|
|
ms->sub_iclass->ref_count++;
|
|
break;
|
|
case MENU_USE_ITEM_BACKGROUND:
|
|
ms->use_item_bg = atoi(s2);
|
|
if (ms->use_item_bg)
|
|
{
|
|
if (ms->bg_iclass)
|
|
{
|
|
ms->bg_iclass->ref_count--;
|
|
ms->bg_iclass = NULL;
|
|
}
|
|
}
|
|
break;
|
|
case MENU_MAX_COLUMNS:
|
|
ms->maxx = atoi(s2);
|
|
break;
|
|
case MENU_MAX_ROWS:
|
|
ms->maxy = atoi(s2);
|
|
break;
|
|
case CONFIG_BORDER:
|
|
{
|
|
/* FIXME!!! I don't think this file is loaded in the
|
|
* right order!
|
|
*/
|
|
Border *b;
|
|
|
|
if (ms->border_name)
|
|
Efree(ms->border_name);
|
|
|
|
ms->border_name = Estrdup(s2);
|
|
|
|
b = (Border *) FindItem(ms->border_name, 0, LIST_FINDBY_NAME,
|
|
LIST_TYPE_BORDER);
|
|
if (b)
|
|
b->ref_count++;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
err = -1;
|
|
|
|
done:
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
MenuConfigLoad(FILE * fs)
|
|
{
|
|
int err = 0;
|
|
char s[FILEPATH_LEN_MAX];
|
|
char s2[FILEPATH_LEN_MAX];
|
|
char s3[FILEPATH_LEN_MAX];
|
|
char s4[FILEPATH_LEN_MAX];
|
|
char s5[FILEPATH_LEN_MAX];
|
|
char *txt = NULL;
|
|
const char *params = NULL;
|
|
int i1, i2;
|
|
Menu *m = NULL, *mm;
|
|
MenuItem *mi;
|
|
MenuStyle *ms;
|
|
ImageClass *ic = NULL;
|
|
int fields;
|
|
int act = 0;
|
|
|
|
while (GetLine(s, sizeof(s), fs))
|
|
{
|
|
s2[0] = 0;
|
|
i1 = CONFIG_INVALID;
|
|
fields = sscanf(s, "%i %4000s", &i1, s2);
|
|
|
|
if (fields < 1)
|
|
{
|
|
i1 = CONFIG_INVALID;
|
|
}
|
|
else if (i1 == CONFIG_CLOSE)
|
|
{
|
|
if (fields != 1)
|
|
Alert(_("CONFIG: ignoring extra data in \"%s\"\n"), s);
|
|
}
|
|
else if (i1 != CONFIG_INVALID)
|
|
{
|
|
if (fields != 2)
|
|
{
|
|
Alert(_("CONFIG: missing required data in \"%s\"\n"), s);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (i1)
|
|
{
|
|
case CONFIG_MENU:
|
|
err = -1;
|
|
i2 = atoi(s2);
|
|
if (i2 != CONFIG_OPEN)
|
|
goto done;
|
|
m = NULL;
|
|
ic = NULL;
|
|
_EFREE(txt);
|
|
act = 0;
|
|
break;
|
|
case CONFIG_CLOSE:
|
|
if (m)
|
|
MenuRealize(m);
|
|
err = 0;
|
|
break;
|
|
|
|
case MENU_PREBUILT:
|
|
sscanf(s, "%i %4000s %4000s %4000s %4000s", &i1, s2, s3, s4, s5);
|
|
if (!strcmp(s4, "dirscan"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (!ms)
|
|
ms = FindItem("DEFAULT", 0, LIST_FINDBY_NAME,
|
|
LIST_TYPE_MENU_STYLE);
|
|
|
|
if (ms)
|
|
{
|
|
SoundPlay("SOUND_SCANNING");
|
|
m = MenuCreateFromDirectory(s2, NULL, ms, s5);
|
|
}
|
|
}
|
|
else if (!strcmp(s4, "gnome"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromGnome(s2, NULL, ms, s5);
|
|
}
|
|
else if (!strcmp(s4, "borders"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromBorders(s2, ms);
|
|
}
|
|
else if (!strcmp(s4, "themes"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromThemes(s2, ms);
|
|
}
|
|
else if (!strcmp(s4, "file"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromFlatFile(s2, NULL, ms, s5);
|
|
}
|
|
else if (!strcmp(s4, "windowlist"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromAllEWins(s2, ms);
|
|
}
|
|
else if (!strcmp(s4, "desktopwindowlist"))
|
|
{
|
|
ms = FindItem(s3, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
m = MenuCreateFromDesktops(s2, ms);
|
|
}
|
|
break;
|
|
case CONFIG_CLASSNAME:
|
|
if (!m)
|
|
m = MenuCreate(s2, NULL, NULL, NULL);
|
|
else
|
|
MenuSetName(m, s2);
|
|
break;
|
|
case MENU_USE_STYLE:
|
|
{
|
|
ms = FindItem(s2, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
|
|
if (ms)
|
|
MenuSetStyle(m, ms);
|
|
}
|
|
break;
|
|
case MENU_TITLE:
|
|
if (m)
|
|
MenuSetTitle(m, atword(s, 2));
|
|
break;
|
|
case MENU_ITEM:
|
|
#if 0 /* FIXME - Why ? */
|
|
if ((txt) || (ic))
|
|
{
|
|
mi = MenuItemCreate(txt, ic, NULL, NULL);
|
|
MenuAddItem(m, mi);
|
|
}
|
|
#endif
|
|
ic = NULL;
|
|
if (strcmp("NULL", s2))
|
|
ic = ImageclassFind(s2, 0);
|
|
_EFDUP(txt, atword(s, 3));
|
|
break;
|
|
case MENU_ACTION:
|
|
if ((txt) || (ic))
|
|
{
|
|
char ok = 1;
|
|
|
|
/* if its an execute line then check to see if the exec is
|
|
* on your system before adding the menu entry */
|
|
if (!strcmp(s2, "exec"))
|
|
{
|
|
char buf[1024];
|
|
char *path;
|
|
|
|
params = atword(s, 3);
|
|
if (params)
|
|
{
|
|
sscanf(atword(s, 3), "%1000s", buf);
|
|
path = pathtoexec(buf);
|
|
if (path)
|
|
Efree(path);
|
|
else
|
|
ok = 0;
|
|
}
|
|
}
|
|
if (ok)
|
|
{
|
|
params = atword(s, 2);
|
|
mi = MenuItemCreate(txt, ic, params, NULL);
|
|
MenuAddItem(m, mi);
|
|
}
|
|
ic = NULL;
|
|
_EFREE(txt);
|
|
}
|
|
break;
|
|
case MENU_SUBMENU:
|
|
sscanf(s, "%i %4000s %4000s", &i1, s2, s3);
|
|
ic = NULL;
|
|
if (strcmp("NULL", s3))
|
|
ic = ImageclassFind(s3, 0);
|
|
mm = FindItem(s2, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU);
|
|
/* if submenu empty - dont put it in - only if menu found */
|
|
if (MenuIsNotEmpty(mm))
|
|
{
|
|
mi = MenuItemCreate(atword(s, 4), ic, NULL, mm);
|
|
MenuAddItem(m, mi);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (err)
|
|
ConfigAlertLoad(_("Menu"));
|
|
_EFREE(txt);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Menus Module
|
|
*/
|
|
|
|
static void
|
|
MenusSighan(int sig, void *prm __UNUSED__)
|
|
{
|
|
switch (sig)
|
|
{
|
|
case ESIGNAL_CONFIGURE:
|
|
ConfigFileLoad("menus.cfg", NULL, MenuConfigLoad, 1);
|
|
break;
|
|
|
|
case ESIGNAL_AREA_SWITCH_START:
|
|
case ESIGNAL_DESK_SWITCH_START:
|
|
MenusHide();
|
|
break;
|
|
|
|
case ESIGNAL_EWIN_UNMAP:
|
|
if ((EWin *) prm == Mode_menus.context_ewin)
|
|
MenusHide();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
MenusIpc(const char *params, Client * c __UNUSED__)
|
|
{
|
|
const char *p;
|
|
char cmd[128], prm[4096];
|
|
int i, len, num;
|
|
|
|
cmd[0] = prm[0] = '\0';
|
|
p = params;
|
|
if (p)
|
|
{
|
|
len = 0;
|
|
sscanf(p, "%100s %4000s %n", cmd, prm, &len);
|
|
p += len;
|
|
}
|
|
|
|
if (!p || cmd[0] == '?')
|
|
{
|
|
IpcPrintf("Menus - depth=%d, clicked=%d\n",
|
|
Mode_menus.current_depth, Mode_menus.clicked);
|
|
}
|
|
else if (!strncmp(cmd, "list", 2))
|
|
{
|
|
Menu **lst;
|
|
|
|
lst = (Menu **) ListItemType(&num, LIST_TYPE_MENU);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
IpcPrintf("%s\n", MenuGetName(lst[i]));
|
|
}
|
|
if (lst)
|
|
Efree(lst);
|
|
|
|
}
|
|
else if (!strncmp(cmd, "reload", 2))
|
|
{
|
|
MenusDestroyLoaded();
|
|
ConfigFileLoad("menus.cfg", NULL, MenuConfigLoad, 1);
|
|
}
|
|
else if (!strncmp(cmd, "show", 2))
|
|
{
|
|
/* FIXME - Menus should have update function? */
|
|
void ShowAllTaskMenu(void);
|
|
void ShowDeskMenu(void);
|
|
void ShowGroupMenu(void);
|
|
|
|
if (!strcmp(prm, "deskmenu"))
|
|
{
|
|
SoundPlay("SOUND_MENU_SHOW");
|
|
ShowDeskMenu();
|
|
}
|
|
else if (!strcmp(prm, "taskmenu"))
|
|
{
|
|
SoundPlay("SOUND_MENU_SHOW");
|
|
ShowAllTaskMenu();
|
|
}
|
|
else if (!strcmp(prm, "groupmenu"))
|
|
{
|
|
SoundPlay("SOUND_MENU_SHOW");
|
|
ShowGroupMenu();
|
|
}
|
|
else if (!strcmp(prm, "named"))
|
|
{
|
|
SoundPlay("SOUND_MENU_SHOW");
|
|
MenusShowNamed(p);
|
|
}
|
|
else
|
|
{
|
|
SoundPlay("SOUND_MENU_SHOW");
|
|
MenusShowNamed(prm);
|
|
}
|
|
}
|
|
}
|
|
|
|
IpcItem MenusIpcArray[] = {
|
|
{
|
|
MenusIpc,
|
|
"menus", "mnu",
|
|
"Menu functions",
|
|
" menus list Show existing menus\n"
|
|
" menus reload Reload menus.cfg without restarting\n"
|
|
" menus show <name> Show named menu\n"}
|
|
,
|
|
};
|
|
#define N_IPC_FUNCS (sizeof(MenusIpcArray)/sizeof(IpcItem))
|
|
|
|
static const CfgItem MenusCfgItems[] = {
|
|
CFG_ITEM_BOOL(Conf.menus, slide, 0),
|
|
CFG_ITEM_BOOL(Conf.menus, onscreen, 1),
|
|
CFG_ITEM_BOOL(Conf.menus, warp, 1),
|
|
CFG_ITEM_INT(Conf.menus, opacity, 220),
|
|
CFG_ITEM_INT(Conf.menus, key.left, XK_Left),
|
|
CFG_ITEM_INT(Conf.menus, key.right, XK_Right),
|
|
CFG_ITEM_INT(Conf.menus, key.up, XK_Up),
|
|
CFG_ITEM_INT(Conf.menus, key.down, XK_Down),
|
|
CFG_ITEM_INT(Conf.menus, key.escape, XK_Escape),
|
|
CFG_ITEM_INT(Conf.menus, key.ret, XK_Return),
|
|
};
|
|
#define N_CFG_ITEMS (sizeof(MenusCfgItems)/sizeof(CfgItem))
|
|
|
|
/*
|
|
* Module descriptor
|
|
*/
|
|
EModule ModMenus = {
|
|
"menus", "menu",
|
|
MenusSighan,
|
|
{N_IPC_FUNCS, MenusIpcArray},
|
|
{N_CFG_ITEMS, MenusCfgItems}
|
|
};
|