e16/src/menus.c

2569 lines
59 KiB
C

/*
* Copyright (C) 2000-2004 Carsten Haitzler, Geoff Harrison and various contributors
*
* 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.
*/
#define DECLARE_STRUCT_MENU 1
#include "E.h"
#include <sys/stat.h>
#include <errno.h>
static void MenuRedraw(Menu * m);
static void MenuDrawItem(Menu * m, MenuItem * mi, char shape);
static void FileMenuUpdate(int val, void *data);
static void FillFlatFileMenu(Menu * m, MenuStyle * ms, char *name,
char *file, Menu * parent);
Menu *
FindMenuItem(Window win, MenuItem ** mi)
{
Menu *menu = NULL;
Menu **menus;
int i, j, num;
EDBUG(6, "FindMenuItem");
menus = (Menu **) ListItemType(&num, LIST_TYPE_MENU);
for (i = 0; i < num; i++)
{
for (j = 0; j < menus[i]->num; j++)
{
if ((win == menus[i]->items[j]->win) ||
(win == menus[i]->items[j]->icon_win))
{
*mi = menus[i]->items[j];
menu = menus[i];
break;
}
}
}
if (menus)
Efree(menus);
EDBUG_RETURN(menu);
}
Menu *
FindMenu(Window win)
{
Menu *menu = NULL;
Menu **menus;
int i, num;
EDBUG(6, "FindMenu");
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);
EDBUG_RETURN(menu);
}
EWin *
FindEwinSpawningMenu(Menu * m)
{
EWin *ewin = NULL;
EWin **ewins;
int i, num;
EDBUG(6, "FindEwinSpawningMenu");
ewins = (EWin **) ListItemType(&num, LIST_TYPE_EWIN);
for (i = 0; i < num; i++)
{
if (ewins[i]->shownmenu != m->win)
continue;
ewin = ewins[i];
break;
}
if (ewins)
Efree(ewins);
EDBUG_RETURN(ewin);
}
void
MenuHide(Menu * m)
{
EWin *ewin;
EDBUG(5, "MenuHide");
if (m->win)
EUnmapWindow(disp, m->win);
ewin = FindEwinSpawningMenu(m);
if (ewin)
ewin->shownmenu = 0;
ewin = FindEwinByMenu(m);
if (ewin)
{
HideEwin(ewin);
}
if (m->sel_item)
{
m->sel_item->state = STATE_NORMAL;
MenuDrawItem(m, m->sel_item, 1);
m->sel_item = NULL;
}
m->stuck = 0;
m->shown = 0;
EDBUG_RETURN_;
}
static void
MenuMoveResize(EWin * ewin, int resize)
{
Menu *m = ewin->menu;
if (!m)
return;
if ((!m->style->use_item_bg && m->pmm.pmap == 0) ||
Conf.theme.transparency || IclassIsTransparent(m->style->bg_iclass))
MenuRedraw(m);
return;
resize = 0;
}
static void
MenuRefresh(EWin * ewin)
{
MenuMoveResize(ewin, 0);
}
static void
MenuEwinInit(EWin * ewin, void *ptr)
{
ewin->menu = (Menu *) ptr;
ewin->MoveResize = MenuMoveResize;
ewin->Refresh = MenuRefresh;
}
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;
EDBUG(5, "MenuShow");
if ((m->num <= 0) || (!m->style))
EDBUG_RETURN_;
if (m->shown)
return;
if (m->stuck)
{
Button *button;
EWin *ewin99;
if ((button = FindButton(Mode.context_win)))
{
ButtonDrawWithState(button, STATE_NORMAL);
}
else if ((ewin99 = FindEwinByDecoration(Mode.context_win)))
{
int i99;
for (i99 = 0; i99 < ewin99->border->num_winparts; i99++)
{
if (Mode.context_win == ewin99->bits[i99].win)
{
ewin99->bits[i99].state = STATE_NORMAL;
ChangeEwinWinpart(ewin99, i99);
i99 = ewin99->border->num_winparts;
}
}
}
EDBUG_RETURN_;
}
if (!m->win)
MenuRealize(m);
ewin = FindEwinByMenu(m);
if (ewin)
{
if ((Mode.button) &&
FindItem((char *)Mode.button, 0, LIST_FINDBY_POINTER,
LIST_TYPE_BUTTON))
{
ButtonDrawWithState(Mode.button, STATE_NORMAL);
}
#if 0 /* ??? */
RaiseEwin(ewin);
ShowEwin(ewin);
EDBUG_RETURN_;
#else
MenuHide(m);
#endif
}
GetWinXY(m->items[0]->win, &x, &y);
GetWinWH(m->items[0]->win, &w, &h);
GetWinWH(m->win, &mw, &mh);
if (!Mode.button)
{
int dum;
Window rt, ch;
XQueryPointer(disp, m->win, &rt, &ch, &(Mode.x), &(Mode.y), &dum, &dum,
(unsigned int *)&dum);
}
wx = 0;
wy = 0;
if (Conf.menusonscreen)
{
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)root.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 ((Mode.x >= 0) && (Mode.y >= 0))
{
if (Conf.menusonscreen)
EMoveWindow(disp, m->win, wx, wy);
else
EMoveWindow(disp, m->win, Mode.x - x - (w / 2),
Mode.y - y - (h / 2));
}
else if ((Mode.x >= 0) && (Mode.y < 0))
{
if (((-Mode.y) + (int)mh) > (int)root.h)
Mode.y = -((-Mode.y) - Mode.context_h - mh);
if (Conf.menusonscreen)
EMoveWindow(disp, m->win, wx, -Mode.y);
else
EMoveWindow(disp, m->win, Mode.x - x - (w / 2), -Mode.y);
}
else if ((Mode.x < 0) && (Mode.y >= 0))
{
if (((-Mode.x) + (int)mw) > (int)root.w)
Mode.x = -((-Mode.x) - Mode.context_w - mw);
if (Conf.menusonscreen)
EMoveWindow(disp, m->win, -Mode.x, wy);
else
EMoveWindow(disp, m->win, -Mode.x, Mode.y - y - (h / 2));
}
else
{
if (((-Mode.x) + (int)mw) > (int)root.w)
Mode.x = -((-Mode.x) - Mode.context_w - mw);
if (((-Mode.y) + (int)mh) > (int)root.h)
Mode.y = -((-Mode.y) - Mode.context_h - mh);
EMoveWindow(disp, m->win, -Mode.x, -Mode.y);
}
ewin = AddInternalToFamily(m->win, m->style->border_name, EWIN_TYPE_MENU, m,
MenuEwinInit);
if (ewin)
{
ewin->head = head_num;
if (Conf.menuslide)
InstantShadeEwin(ewin, 0);
ICCCM_Cmap(NULL);
MoveEwin(ewin, ewin->x, ewin->y);
if (!noshow)
{
ShowEwin(ewin);
if (Conf.menuslide)
UnShadeEwin(ewin);
}
}
m->stuck = 0;
if (!FindMenu(m->win))
AddItem(m, m->name, m->win, LIST_TYPE_MENU);
{
Button *button;
EWin *ewin99;
if ((button = FindButton(Mode.context_win)))
{
ButtonDrawWithState(button, STATE_NORMAL);
}
else if ((ewin99 = FindEwinByDecoration(Mode.context_win)))
{
int i99;
for (i99 = 0; i99 < ewin99->border->num_winparts; i99++)
{
if (Mode.context_win == ewin99->bits[i99].win)
{
ewin99->bits[i99].state = STATE_NORMAL;
ChangeEwinWinpart(ewin99, i99);
i99 = ewin99->border->num_winparts;
}
}
}
}
m->shown = 1;
EDBUG_RETURN_;
}
MenuStyle *
MenuStyleCreate(void)
{
MenuStyle *ms;
EDBUG(5, "MenuStyleCreate");
ms = Emalloc(sizeof(MenuStyle));
ms->name = NULL;
ms->tclass = NULL;
ms->bg_iclass = NULL;
ms->item_iclass = NULL;
ms->sub_iclass = NULL;
ms->use_item_bg = 0;
ms->iconpos = ICON_LEFT;
ms->maxx = 0;
ms->maxy = 0;
ms->border_name = NULL;
ms->ref_count = 0;
EDBUG_RETURN(ms);
}
MenuItem *
MenuItemCreate(const char *text, ImageClass * iclass, int action_id,
const char *action_params, Menu * child)
{
MenuItem *mi;
EDBUG(5, "MenuItemCreate");
mi = Emalloc(sizeof(MenuItem));
mi->icon_iclass = iclass;
if (iclass)
iclass->ref_count++;
mi->text = Estrdup(text);
mi->act_id = action_id;
if (action_params)
{
mi->params = Estrdup(action_params);
}
else
{
mi->params = NULL;
}
mi->child = child;
mi->state = STATE_NORMAL;
mi->win = 0;
mi->pmm[0].pmap = 0;
mi->pmm[1].pmap = 0;
mi->pmm[2].pmap = 0;
mi->pmm[0].mask = 0;
mi->pmm[1].mask = 0;
mi->pmm[2].mask = 0;
mi->icon_win = 0;
mi->icon_w = 0;
mi->icon_h = 0;
mi->text_w = 0;
mi->text_h = 0;
mi->text_x = 0;
mi->text_y = 0;
EDBUG_RETURN(mi);
}
Menu *
MenuCreate(const char *name)
{
Menu *m;
EDBUG(5, "MenuCreate");
m = Emalloc(sizeof(Menu));
m->ref_count = 0;
m->name = NULL;
m->title = NULL;
m->style = NULL;
m->num = 0;
m->items = NULL;
m->win = 0;
m->pmm.pmap = 0;
m->pmm.mask = 0;
m->shown = 0;
m->stuck = 0;
m->internal = 0;
m->parent = NULL;
m->sel_item = NULL;
m->data = NULL;
m->ref_menu = NULL;
m->last_change = 0;
MenuAddName(m, name);
EDBUG_RETURN(m);
}
void
MenuDestroy(Menu * m)
{
int i, j;
char s[4096];
EDBUG(5, "MenuDestroy");
if (!m)
EDBUG_RETURN_;
MenuHide(m);
if (m->win)
EDestroyWindow(disp, 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);
EDBUG_RETURN_;
}
/* 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;
EDBUG(5, "MenuEmpty");
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(disp, m->items[i]->win);
if (m->items[i])
Efree(m->items[i]);
}
}
if (m->items)
Efree(m->items);
m->items = NULL;
m->num = 0;
EDBUG_RETURN_;
}
void
MenuRepack(Menu * m)
{
EWin *ewin;
unsigned int w, h;
EDBUG(5, "MenuRepack");
ewin = FindEwinByMenu(m);
if (m->win)
MenuRealize(m);
if (ewin)
{
GetWinWH(m->win, &w, &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);
}
EDBUG_RETURN_;
}
void
MenuAddItem(Menu * menu, MenuItem * item)
{
EDBUG(5, "MenuAddItem");
menu->num++;
menu->items = Erealloc(menu->items, sizeof(MenuItem *) * menu->num);
menu->items[menu->num - 1] = item;
EDBUG_RETURN_;
}
void
MenuAddName(Menu * menu, const char *name)
{
EDBUG(5, "MenuAddName");
if (menu->name)
Efree(menu->name);
menu->name = Estrdup(name);
AddItem(menu, menu->name, menu->win, LIST_TYPE_MENU);
EDBUG_RETURN_;
}
void
MenuAddTitle(Menu * menu, const char *title)
{
EDBUG(5, "MenuAddTitle");
if (menu->title)
Efree(menu->title);
menu->title = Estrdup(title);
EDBUG_RETURN_;
}
void
MenuAddStyle(Menu * menu, const char *style)
{
EDBUG(5, "MenuAddStyle");
menu->style = FindItem(style, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU_STYLE);
EDBUG_RETURN_;
}
void
MenuRealize(Menu * m)
{
int i, maxh = 0, maxw =
0, maxx1, maxx2, w, h, x, y, r, mmw, mmh;
unsigned int iw, ih;
Imlib_Image *im;
XSetWindowAttributes att;
XTextProperty xtp;
char pq, has_i, has_s;
EDBUG(5, "MenuRealize");
if (!m->style)
EDBUG_RETURN_;
if (!m->win)
m->win = ECreateWindow(root.win, 0, 0, 1, 1, 0);
if (m->title)
{
xtp.encoding = XA_STRING;
xtp.format = 8;
xtp.value = (unsigned char *)(m->title);
xtp.nitems = strlen((char *)(xtp.value));
XSetWMName(disp, m->win, &xtp);
}
maxh = 0;
maxx1 = 0;
maxx2 = 0;
has_i = 0;
has_s = 0;
att.event_mask = PointerMotionMask;
XChangeWindowAttributes(disp, m->win, CWEventMask, &att);
att.event_mask =
ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask
| PointerMotionMask;
for (i = 0; i < m->num; i++)
{
if (m->items[i]->child)
has_s = 1;
else
has_i = 1;
m->items[i]->win = ECreateWindow(m->win, 0, 0, 1, 1, 0);
XChangeWindowAttributes(disp, m->items[i]->win, CWEventMask, &att);
EMapWindow(disp, 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(disp, m->items[i]->icon_win);
XChangeWindowAttributes(disp, m->items[i]->icon_win,
CWEventMask, &att);
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 = queue_up;
queue_up = 0;
for (i = 0; i < m->num; i++)
{
EMoveResizeWindow(disp, 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(disp, 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(disp, 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;
GetWinWH(m->items[i]->icon_win, &iw, &ih);
IclassApply(m->items[i]->icon_iclass, m->items[i]->icon_win, iw,
ih, 0, 0, STATE_NORMAL, 0);
}
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;
}
EResizeWindow(disp, m->win, mmw, mmh);
queue_up = pq;
EDBUG_RETURN_;
}
static void
MenuRedraw(Menu * m)
{
int i, w, h;
if (!m->style->use_item_bg)
{
GetWinWH(m->win, &w, &h);
FreePmapMask(&m->pmm);
IclassApplyCopy(m->style->bg_iclass, m->win, w, h, 0, 0,
STATE_NORMAL, &m->pmm, 1);
ESetWindowBackgroundPixmap(disp, m->win, m->pmm.pmap);
EShapeCombineMask(disp, 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);
}
}
void
MenuDrawItem(Menu * m, MenuItem * mi, char shape)
{
GC gc;
XGCValues gcv;
unsigned int w, h;
int x, y;
char pq;
PmapMask *mi_pmm;
EDBUG(5, "MenuDrawItem");
pq = queue_up;
queue_up = 0;
mi_pmm = &(mi->pmm[(int)(mi->state)]);
if (Conf.theme.transparency || IclassIsTransparent(m->style->bg_iclass))
FreePmapMask(mi_pmm);
if (!mi_pmm->pmap)
{
if (mi->text)
{
GetWinWH(mi->win, &w, &h);
GetWinXY(mi->win, &x, &y);
if (!m->style->use_item_bg)
{
mi_pmm->type = 0;
mi_pmm->pmap = ECreatePixmap(disp, mi->win, w, h, root.depth);
gc = XCreateGC(disp, m->pmm.pmap, 0, &gcv);
XCopyArea(disp, m->pmm.pmap, mi_pmm->pmap, gc, x, y, w, h, 0,
0);
mi_pmm->mask = None;
if ((mi->state != STATE_NORMAL) || (mi->child))
{
PmapMask pmm;
if (mi->child)
IclassApplyCopy(m->style->sub_iclass, mi->win, w, h,
0, 0, mi->state, &pmm, 1);
else
IclassApplyCopy(m->style->item_iclass, mi->win, w, h,
0, 0, mi->state, &pmm, 1);
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);
}
XFreeGC(disp, gc);
}
else
{
if (mi->child)
IclassApplyCopy(m->style->sub_iclass, mi->win, w, h, 0, 0,
mi->state, mi_pmm, 1);
else
IclassApplyCopy(m->style->item_iclass, mi->win, w, h, 0, 0,
mi->state, mi_pmm, 1);
}
}
}
if ((m->style->tclass) && (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);
}
if (mi->text)
{
ESetWindowBackgroundPixmap(disp, mi->win, mi_pmm->pmap);
EShapeCombineMask(disp, mi->win, ShapeBounding, 0, 0, mi_pmm->mask,
ShapeSet);
XClearWindow(disp, mi->win);
}
else
{
GetWinWH(mi->win, &w, &h);
GetWinXY(mi->win, &x, &y);
if (!m->style->use_item_bg)
{
if ((mi->state != STATE_NORMAL) || (mi->child))
IclassApply(m->style->item_iclass, mi->win, w, h, 0, 0,
mi->state, 0);
else
{
ESetWindowBackgroundPixmap(disp, mi->win, ParentRelative);
EShapeCombineMask(disp, mi->win, ShapeBounding, 0, 0, None,
ShapeSet);
XClearWindow(disp, mi->win);
}
}
else
{
if (mi->child)
IclassApply(m->style->sub_iclass, mi->win, w, h, 0, 0,
mi->state, 0);
else
IclassApply(m->style->item_iclass, mi->win, w, h, 0, 0,
mi->state, 0);
}
}
if ((shape) && (m->style->use_item_bg))
PropagateShapes(m->win);
queue_up = pq;
EDBUG_RETURN_;
}
Menu *
MenuCreateFromDirectory(const char *name, MenuStyle * ms, const char *dir)
{
Progressbar *p = NULL;
Menu *m, *mm;
int i, num;
char **list, s[4096], ss[4096], cs[4096];
const char *ext;
MenuItem *mi;
struct stat st;
const char *chmap =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
FILE *f;
EDBUG(5, "MenuCreateFromDirectory");
m = MenuCreate(name);
m->style = ms;
if (stat(dir, &st) >= 0)
{
int aa, bb, cc;
aa = (int)st.st_ino;
bb = (int)st.st_dev;
cc = 0;
if (st.st_mtime > st.st_ctime)
cc = st.st_mtime;
else
cc = st.st_ctime;
Esnprintf(cs, sizeof(cs),
"%s/cached/img/.%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
EDirUserCache(), chmap[(aa >> 0) & 0x3f],
chmap[(aa >> 6) & 0x3f], chmap[(aa >> 12) & 0x3f],
chmap[(aa >> 18) & 0x3f], chmap[(aa >> 24) & 0x3f],
chmap[(aa >> 28) & 0x3f], chmap[(bb >> 0) & 0x3f],
chmap[(bb >> 6) & 0x3f], chmap[(bb >> 12) & 0x3f],
chmap[(bb >> 18) & 0x3f], chmap[(bb >> 24) & 0x3f],
chmap[(bb >> 28) & 0x3f], chmap[(cc >> 0) & 0x3f],
chmap[(cc >> 6) & 0x3f], chmap[(cc >> 12) & 0x3f],
chmap[(cc >> 18) & 0x3f], chmap[(cc >> 24) & 0x3f],
chmap[(cc >> 28) & 0x3f]);
/* cached dir listing - use it */
if (exists(cs))
{
f = fopen(cs, "r");
while (fgets(s, sizeof(s), f))
{
s[strlen(s) - 1] = 0;
word(s, 1, ss);
if (!strcmp(ss, "BG"))
{
Background *bg;
char ok = 1;
char s2[4096], s3[512];
word(s, 3, s3);
bg = (Background *) FindItem(s3, 0, LIST_FINDBY_NAME,
LIST_TYPE_BACKGROUND);
if (!bg)
{
Imlib_Image *im;
word(s, 2, s2);
Esnprintf(ss, sizeof(ss), "%s/%s", dir, s2);
im = imlib_load_image(ss);
if (im)
{
Imlib_Image *im2;
XColor xclr;
char tile = 1, keep_asp = 0;
int width, height;
int scalex = 0, scaley = 0;
int scr_asp, im_asp;
int w2, h2;
int maxw = 48, maxh = 48;
int justx = 512, justy = 512;
Esnprintf(s2, sizeof(s2), "%s/cached/img/%s",
EDirUserCache(), s3);
imlib_context_set_image(im);
width = imlib_image_get_width();
height = imlib_image_get_height();
h2 = maxh;
w2 =
(imlib_image_get_width() * h2) /
imlib_image_get_height();
if (w2 > maxw)
{
w2 = maxw;
h2 =
(imlib_image_get_height() * w2) /
imlib_image_get_width();
}
im2 = imlib_create_cropped_scaled_image(0, 0,
imlib_image_get_width
(),
imlib_image_get_height
(), w2,
h2);
imlib_free_image_and_decache();
imlib_context_set_image(im2);
imlib_image_set_format("ppm");
imlib_save_image(s2);
imlib_free_image_and_decache();
scr_asp = (root.w << 16) / root.h;
im_asp = (width << 16) / height;
if (width == height)
{
justx = 0;
justy = 0;
scalex = 0;
scaley = 0;
tile = 1;
keep_asp = 0;
}
else if ((!(IN_RANGE(scr_asp, im_asp, 16000)))
&& ((width < 480) && (height < 360)))
{
justx = 0;
justy = 0;
scalex = 0;
scaley = 0;
tile = 1;
keep_asp = 0;
}
else if (IN_RANGE(scr_asp, im_asp, 16000))
{
justx = 0;
justy = 0;
scalex = 1024;
scaley = 1024;
tile = 0;
keep_asp = 0;
}
else if (im_asp > scr_asp)
{
justx = 512;
justy = 512;
scalex = 1024;
scaley = 0;
tile = 0;
keep_asp = 1;
}
else
{
justx = 512;
justy = 512;
scalex = 0;
scaley = 1024;
tile = 0;
keep_asp = 1;
}
ESetColor(&xclr, 0, 0, 0);
bg = CreateDesktopBG(s3, &xclr, ss, tile,
keep_asp, justx, justy,
scalex, scaley, NULL, 0,
0, 0, 0, 0);
AddItem(bg, bg->name, 0, LIST_TYPE_BACKGROUND);
}
else
ok = 0;
}
if (ok)
{
ImageClass *ic = NULL;
char stmp[4096];
ic = CreateIclass();
ic->name = Estrdup("`");
ic->norm.normal = CreateImageState();
Esnprintf(stmp, sizeof(stmp), "%s/cached/img/%s",
EDirUserCache(), s3);
ic->norm.normal->im_file = Estrdup(stmp);
ic->norm.normal->unloadable = 1;
IclassPopulate(ic);
AddItem(ic, ic->name, 0, LIST_TYPE_ICLASS);
mi = MenuItemCreate(NULL, ic, ACTION_BACKGROUND_SET,
s3, NULL);
MenuAddItem(m, mi);
}
}
else if (!strcmp(ss, "EXE"))
{
word(s, 2, ss);
Esnprintf(s, sizeof(s), "%s/%s", dir, ss);
mi = MenuItemCreate(NULL, NULL, ACTION_EXEC, s, NULL);
MenuAddItem(m, mi);
}
else if (!strcmp(ss, "DIR"))
{
char tmp[4096];
word(s, 2, tmp);
Esnprintf(s, sizeof(s), "%s/%s:%s", dir, tmp, name);
Esnprintf(ss, sizeof(ss), "%s/%s", dir, tmp);
mm = MenuCreateFromDirectory(s, ms, ss);
mm->parent = m;
mi = MenuItemCreate(tmp, NULL, 0, NULL, mm);
MenuAddItem(m, mi);
}
}
fclose(f);
EDBUG_RETURN(m);
}
}
list = E_ls(dir, &num);
Esnprintf(s, sizeof(s), "Scanning %s", dir);
if (!init_win_ext)
p = CreateProgressbar(s, 600, 16);
if (p)
ShowProgressbar(p);
f = fopen(cs, "w");
for (i = 0; i < num; i++)
{
if (p)
SetProgressbar(p, (i * 100) / num);
Esnprintf(ss, sizeof(ss), "%s/%s", dir, list[i]);
/* skip "dot" files and dirs - senisble */
if ((*(list[i]) != '.') && (stat(ss, &st) >= 0))
{
ext = FileExtension(ss);
if (S_ISDIR(st.st_mode))
{
Esnprintf(s, sizeof(s), "%s/%s:%s", dir, list[i], name);
Esnprintf(ss, sizeof(ss), "%s/%s", dir, list[i]);
mm = MenuCreateFromDirectory(s, ms, ss);
mm->parent = m;
mi = MenuItemCreate(list[i], NULL, 0, NULL, mm);
MenuAddItem(m, mi);
if (f)
fprintf(f, "DIR %s\n", list[i]);
}
/* that's it - people are stupid and have executable images and just */
/* don't get it - so I'm disablign this to save people from their own */
/* stupidity */
/* else if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
* {
* mi = MenuItemCreate(list[i], NULL, ACTION_EXEC, ss, NULL);
* MenuAddItem(m, mi);
* if (f)
* fprintf(f, "EXE %s\n", list[i]);
* }
*/
else if ((!strcmp(ext, "jpg")) || (!strcmp(ext, "JPG"))
|| (!strcmp(ext, "jpeg")) || (!strcmp(ext, "Jpeg"))
|| (!strcmp(ext, "JPEG")) || (!strcmp(ext, "Jpg"))
|| (!strcmp(ext, "gif")) || (!strcmp(ext, "Gif"))
|| (!strcmp(ext, "GIF")) || (!strcmp(ext, "png"))
|| (!strcmp(ext, "Png")) || (!strcmp(ext, "PNG"))
|| (!strcmp(ext, "tif")) || (!strcmp(ext, "Tif"))
|| (!strcmp(ext, "TIFF")) || (!strcmp(ext, "tiff"))
|| (!strcmp(ext, "Tiff")) || (!strcmp(ext, "TIFF"))
|| (!strcmp(ext, "xpm")) || (!strcmp(ext, "Xpm"))
|| (!strcmp(ext, "XPM")) || (!strcmp(ext, "ppm"))
|| (!strcmp(ext, "PPM")) || (!strcmp(ext, "pgm"))
|| (!strcmp(ext, "PGM")) || (!strcmp(ext, "pnm"))
|| (!strcmp(ext, "PNM")) || (!strcmp(ext, "bmp"))
|| (!strcmp(ext, "Bmp")) || (!strcmp(ext, "BMP")))
{
Background *bg;
char ok = 1;
char s2[4096], s3[512];
int aa, bb, cc;
aa = (int)st.st_ino;
bb = (int)st.st_dev;
cc = 0;
if (st.st_mtime > st.st_ctime)
cc = st.st_mtime;
else
cc = st.st_ctime;
Esnprintf(s3, sizeof(s3),
".%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
chmap[(aa >> 0) & 0x3f], chmap[(aa >> 6) & 0x3f],
chmap[(aa >> 12) & 0x3f], chmap[(aa >> 18) & 0x3f],
chmap[(aa >> 24) & 0x3f], chmap[(aa >> 28) & 0x3f],
chmap[(bb >> 0) & 0x3f], chmap[(bb >> 6) & 0x3f],
chmap[(bb >> 12) & 0x3f], chmap[(bb >> 18) & 0x3f],
chmap[(bb >> 24) & 0x3f], chmap[(bb >> 28) & 0x3f],
chmap[(cc >> 0) & 0x3f], chmap[(cc >> 6) & 0x3f],
chmap[(cc >> 12) & 0x3f], chmap[(cc >> 18) & 0x3f],
chmap[(cc >> 24) & 0x3f], chmap[(cc >> 28) & 0x3f]);
bg = (Background *) FindItem(s3, 0, LIST_FINDBY_NAME,
LIST_TYPE_BACKGROUND);
if (!bg)
{
Imlib_Image *im;
im = imlib_load_image(ss);
if (im)
{
Imlib_Image *im2;
XColor xclr;
char tile = 1, keep_asp = 0;
int width, height, scalex =
0, scaley = 0;
int scr_asp, im_asp, w2, h2;
int maxw = 48, maxh = 48;
Esnprintf(s2, sizeof(s2), "%s/cached/img/%s",
EDirUserCache(), s3);
imlib_context_set_image(im);
width = imlib_image_get_width();
height = imlib_image_get_height();
h2 = maxh;
w2 =
(imlib_image_get_width() * h2) /
imlib_image_get_height();
if (w2 > maxw)
{
w2 = maxw;
h2 =
(imlib_image_get_height() * w2) /
imlib_image_get_width();
}
im2 = imlib_create_cropped_scaled_image(0, 0,
imlib_image_get_width
(),
imlib_image_get_height
(), w2, h2);
imlib_free_image_and_decache();
imlib_context_set_image(im2);
imlib_image_set_format("ppm");
imlib_save_image(s2);
imlib_free_image_and_decache();
scr_asp = (root.w << 16) / root.h;
im_asp = (width << 16) / height;
if (width == height)
{
scalex = 0;
scaley = 0;
tile = 1;
keep_asp = 0;
}
else if ((!(IN_RANGE(scr_asp, im_asp, 16000)))
&& ((width < 480) && (height < 360)))
{
scalex = 0;
scaley = 0;
tile = 1;
keep_asp = 0;
}
else if (IN_RANGE(scr_asp, im_asp, 16000))
{
scalex = 1024;
scaley = 1024;
tile = 0;
keep_asp = 0;
}
else if (im_asp > scr_asp)
{
scalex = 1024;
scaley = 0;
tile = 0;
keep_asp = 1;
}
else
{
scalex = 0;
scaley = 1024;
tile = 0;
keep_asp = 1;
}
ESetColor(&xclr, 0, 0, 0);
bg = CreateDesktopBG(s3, &xclr, ss, tile, keep_asp,
512, 512, scalex, scaley, NULL,
0, 0, 0, 0, 0);
AddItem(bg, bg->name, 0, LIST_TYPE_BACKGROUND);
}
else
ok = 0;
}
if (ok)
{
ImageClass *ic = NULL;
char stmp[4096];
ic = CreateIclass();
ic->name = Estrdup("`");
ic->norm.normal = CreateImageState();
Esnprintf(stmp, sizeof(stmp), "%s/cached/img/%s",
EDirUserCache(), s3);
ic->norm.normal->im_file = Estrdup(stmp);
ic->norm.normal->unloadable = 1;
IclassPopulate(ic);
AddItem(ic, ic->name, 0, LIST_TYPE_ICLASS);
mi = MenuItemCreate(NULL, ic, ACTION_BACKGROUND_SET, s3,
NULL);
MenuAddItem(m, mi);
}
if (f)
fprintf(f, "BG %s %s\n", list[i], s3);
}
}
}
if (f)
fclose(f);
if (p)
FreeProgressbar(p);
if (list)
freestrlist(list, num);
EDBUG_RETURN(m);
}
Menu *
MenuCreateFromFlatFile(const char *name, MenuStyle * ms, const char *file,
Menu * parent)
{
Menu *m;
char s[4096], *ff = NULL;
static int calls = 0;
EDBUG(5, "MenuCreateFromFlatFile");
calls++;
if (calls > 255)
{
calls--;
EDBUG_RETURN(NULL);
}
ff = FindFile(file);
if (!ff)
EDBUG_RETURN(NULL);
if (canread(ff))
{
m = MenuCreate(name);
m->style = ms;
m->last_change = moddate(ff);
if (parent)
FillFlatFileMenu(m, m->style, m->name, ff, parent);
else
FillFlatFileMenu(m, m->style, m->name, ff, m);
m->data = ff;
m->ref_menu = parent;
Esnprintf(s, sizeof(s), "__.%s", m->name);
DoIn(s, 2.0, FileMenuUpdate, 0, m);
calls--;
EDBUG_RETURN(m);
}
Efree(ff);
calls--;
EDBUG_RETURN(NULL);
}
static void
FillFlatFileMenu(Menu * m, MenuStyle * ms, char *name, char *file,
Menu * parent)
{
FILE *f;
char first = 1;
char s[4096];
f = fopen(file, "r");
if (!f)
{
fprintf(stderr, "Unable to open menu file %s -- %s\n", file,
strerror(errno));
return;
}
while (fgets(s, 4096, f))
{
s[strlen(s) - 1] = 0;
if ((s[0]) && s[0] != '#')
{
if (first)
{
char *wd;
wd = field(s, 0);
if (wd)
{
MenuAddTitle(m, wd);
Efree(wd);
}
first = 0;
}
else
{
char *txt = NULL, *icon = NULL, *act = NULL;
char *params = NULL, *tmp = NULL, wd[4096];
MenuItem *mi;
ImageClass *icc = NULL;
Menu *mm;
int count = 0;
txt = field(s, 0);
icon = field(s, 1);
act = field(s, 2);
params = field(s, 3);
tmp = NULL;
if (icon)
{
Esnprintf(wd, sizeof(wd), "__FM.%s", icon);
icc =
FindItem(wd, 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
if (!icc)
{
icc = CreateIclass();
icc->name = Estrdup(wd);
icc->norm.normal = CreateImageState();
icc->norm.normal->im_file = icon;
IclassPopulate(icc);
AddItem(icc, icc->name, 0, LIST_TYPE_ICLASS);
}
else
{
Efree(icon);
}
}
if ((act) && (!strcmp(act, "exec")) && (params))
{
word(params, 1, wd);
tmp = pathtoexec(wd);
if (tmp)
{
Efree(tmp);
mi = MenuItemCreate(txt, icc, ACTION_EXEC, params,
NULL);
MenuAddItem(m, mi);
}
}
else if ((act) && (!strcmp(act, "menu")) && (params))
{
Esnprintf(wd, sizeof(wd), "__FM.%s.%i", name, count);
count++;
mm = MenuCreateFromFlatFile(wd, ms, params, parent);
if (mm)
{
mm->parent = m;
mi = MenuItemCreate(txt, icc, 0, NULL, mm);
MenuAddItem(m, mi);
}
}
else
{
mi = MenuItemCreate(txt, icc, 0, NULL, NULL);
MenuAddItem(m, mi);
}
if (txt)
Efree(txt);
if (act)
Efree(act);
if (params)
Efree(params);
}
}
}
fclose(f);
}
static void
FileMenuUpdate(int val, void *data)
{
Menu *m, *mm;
time_t lastmod = 0;
char s[4096];
m = (Menu *) data;
if (!m)
return;
if (!FindItem((char *)m, m->win, LIST_FINDBY_POINTER, LIST_TYPE_MENU))
return;
/* if the menu is up dont update */
if (((Mode.cur_menu_mode) || (clickmenu)) && (Mode.cur_menu_depth > 0))
{
Esnprintf(s, sizeof(s), "__.%s", m->name);
DoIn(s, 2.0, FileMenuUpdate, 0, m);
return;
}
mm = m;
if (m->ref_menu)
mm = m->ref_menu;
if (!exists(m->data))
{
MenuHide(m);
MenuEmpty(m);
return;
}
if (m->data)
lastmod = moddate(m->data);
if (lastmod > m->last_change)
{
m->last_change = lastmod;
if (m == mm)
{
Esnprintf(s, sizeof(s), "__.%s", m->name);
DoIn(s, 2.0, FileMenuUpdate, 0, m);
}
MenuEmpty(mm);
FillFlatFileMenu(mm, mm->style, mm->name, mm->data, mm);
MenuRepack(mm);
return;
}
Esnprintf(s, sizeof(s), "__.%s", m->name);
DoIn(s, 2.0, FileMenuUpdate, 0, m);
val = 0;
}
Menu *
MenuCreateFromGnome(const char *name, MenuStyle * ms, const char *dir)
{
Menu *m, *mm;
int i, num;
char **list, s[4096], ss[4096];
MenuItem *mi;
FILE *f;
char *lang, name_buf[20];
EDBUG(5, "MenuCreateFromGnome");
if ((lang = setlocale(LC_MESSAGES, NULL)) != NULL)
Esnprintf(name_buf, sizeof(name_buf), "Name[%s]=", lang);
else
name_buf[0] = '\0';
m = MenuCreate(name);
m->style = ms;
list = E_ls(dir, &num);
for (i = 0; i < num; i++)
{
if ((strcmp(list[i], ".")) && (strcmp(list[i], "..")))
{
Esnprintf(ss, sizeof(ss), "%s/%s", dir, list[i]);
if (isdir(ss))
{
Esnprintf(s, sizeof(s), "%s/%s:%s", dir, list[i], name);
mm = MenuCreateFromGnome(s, ms, ss);
mm->parent = m;
name = list[i];
if (name_buf[0])
{
Esnprintf(s, sizeof(s), "%s/.directory", ss);
if ((f = fopen(s, "r")) != NULL)
{
while (fgets(s, sizeof(s), f))
{
if (!strncmp(s, name_buf, strlen(name_buf)))
{
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = 0;
name = &(s[strlen(name_buf)]);
break;
}
}
fclose(f);
}
}
mi = MenuItemCreate(name, NULL, 0, NULL, mm);
MenuAddItem(m, mi);
}
else
{
f = fopen(ss, "r");
if (f)
{
char *iname = NULL, *exec = NULL, *texec =
NULL, *tmp;
char *en_name = NULL;
while (fgets(s, sizeof(s), f))
{
if (s[strlen(s) - 1] == '\n')
s[strlen(s) - 1] = 0;
if (!strncmp(s, "Name=", strlen("Name=")))
en_name = Estrdup(&(s[strlen("Name=")]));
else if (name_buf[0]
&& !strncmp(s, name_buf, strlen(name_buf)))
iname = Estrdup(&(s[strlen(name_buf)]));
else if (!strncmp
(s, "TryExec=", strlen("TryExec=")))
texec = Estrdup(&(s[strlen("TryExec=")]));
else if (!strncmp(s, "Exec=", strlen("Exec=")))
exec = Estrdup(&(s[strlen("Exec=")]));
}
if (iname)
{
if (en_name)
Efree(en_name);
}
else
{
if (en_name)
iname = en_name;
}
fclose(f);
if ((iname) && (exec))
{
tmp = NULL;
if (texec)
tmp = pathtoexec(texec);
if ((tmp) || (!texec))
{
if (tmp)
Efree(tmp);
mi = MenuItemCreate(iname, NULL, ACTION_EXEC,
exec, NULL);
MenuAddItem(m, mi);
}
}
if (iname)
Efree(iname);
if (exec)
Efree(exec);
if (texec)
Efree(texec);
}
}
}
}
if (list)
freestrlist(list, num);
EDBUG_RETURN(m);
}
Menu *
MenuCreateFromThemes(const char *name, MenuStyle * ms)
{
Menu *m;
char **lst;
int i, num;
char ss[4096], *s;
MenuItem *mi;
EDBUG(5, "MenuCreateFromThemes");
m = MenuCreate(name);
m->style = ms;
lst = ListThemes(&num);
if (lst)
{
for (i = 0; i < num; i++)
{
s = fullfileof(lst[i]);
Esnprintf(ss, sizeof(ss), "restart_theme %s", s);
Efree(s);
s = fileof(lst[i]);
mi = MenuItemCreate(s, NULL, ACTION_EXIT, ss, NULL);
MenuAddItem(m, mi);
Efree(s);
}
freestrlist(lst, i);
}
EDBUG_RETURN(m);
}
static int
BorderNameCompare(void *b1, void *b2)
{
if (b1 && b2)
return strcmp(((Border *) b1)->name, ((Border *) b2)->name);
return 0;
}
Menu *
MenuCreateFromBorders(const char *name, MenuStyle * ms)
{
Menu *m;
Border **lst;
int i, num;
MenuItem *mi;
EDBUG(5, "MenuCreateFromBorders");
m = MenuCreate(name);
m->style = ms;
lst = (Border **) ListItemType(&num, LIST_TYPE_BORDER);
if (lst)
Quicksort((void **)lst, 0, num - 1, BorderNameCompare);
for (i = 0; i < num; i++)
{
/* if its not internal (ie doesnt start with _ ) */
if (lst[i]->name[0] != '_')
{
mi = MenuItemCreate(lst[i]->name, NULL, ACTION_SET_WINDOW_BORDER,
lst[i]->name, NULL);
MenuAddItem(m, mi);
}
}
if (lst)
Efree(lst);
EDBUG_RETURN(m);
}
Menu *
MenuCreateFromAllEWins(const char *name, MenuStyle * ms)
{
Menu *m;
EWin **lst;
int i, num;
char s[256];
MenuItem *mi;
EDBUG(5, "MenuCreateFromEWins");
m = MenuCreate(name);
m->style = ms;
lst = (EWin **) ListItemType(&num, LIST_TYPE_EWIN);
if (lst)
{
for (i = 0; i < num; i++)
{
if ((!lst[i]->menu) && (!lst[i]->pager) && (!lst[i]->skipwinlist)
&& (EwinGetTitle(lst[i])) && (!lst[i]->ibox))
{
Esnprintf(s, sizeof(s), "%i", (int)(lst[i]->client.win));
mi = MenuItemCreate(EwinGetTitle(lst[i]), NULL,
ACTION_FOCUS_SET, s, NULL);
MenuAddItem(m, mi);
}
}
Efree(lst);
}
EDBUG_RETURN(m);
}
#if 0 /* Not used */
static Menu *
MenuCreateFromDesktopEWins(char *name, MenuStyle * ms, int desk)
{
Menu *m;
EWin **lst;
int i, num;
char s[256];
MenuItem *mi;
EDBUG(5, "MenuCreateFromDesktopEWins");
m = MenuCreate(name);
m->style = ms;
lst = (EWin **) ListItemType(&num, LIST_TYPE_EWIN);
if (lst)
{
for (i = 0; i < num; i++)
{
if (((lst[i]->desktop == desk) || (lst[i]->sticky))
&& (!lst[i]->menu) && (!lst[i]->pager)
&& (!lst[i]->skipwinlist) && (lst[i]->client.title)
&& (!lst[i]->ibox))
{
Esnprintf(s, sizeof(s), "%i", (int)(lst[i]->client.win));
mi = MenuItemCreate(lst[i]->client.title, NULL,
ACTION_FOCUS_SET, s, NULL);
MenuAddItem(m, mi);
}
}
Efree(lst);
}
EDBUG_RETURN(m);
desk = 0;
}
#endif
Menu *
MenuCreateFromDesktops(const char *name, MenuStyle * ms)
{
Menu *m, *mm;
EWin **lst;
int j, i, num;
char s[256];
MenuItem *mi;
EDBUG(5, "MenuCreateFromDesktops");
m = MenuCreate(name);
m->style = ms;
lst = (EWin **) ListItemType(&num, LIST_TYPE_EWIN);
for (j = 0; j < Conf.desks.num; j++)
{
mm = MenuCreate("__SUBMENUDESK_E");
mm->style = ms;
Esnprintf(s, sizeof(s), "%i", j);
mi = MenuItemCreate(_("Go to this Desktop"), NULL, ACTION_GOTO_DESK, s,
NULL);
MenuAddItem(mm, mi);
for (i = 0; i < num; i++)
{
if (((lst[i]->desktop == j) || (lst[i]->sticky)) && (!lst[i]->menu)
&& (!lst[i]->pager) && (!lst[i]->skipwinlist)
&& (EwinGetTitle(lst[i])) && (!lst[i]->ibox))
{
Esnprintf(s, sizeof(s), "%i", (int)(lst[i]->client.win));
mi = MenuItemCreate(EwinGetTitle(lst[i]), NULL,
ACTION_FOCUS_SET, s, NULL);
MenuAddItem(mm, mi);
}
}
mm->parent = m;
Esnprintf(s, sizeof(s), _("Desktop %i"), j);
mi = MenuItemCreate(s, NULL, 0, NULL, mm);
MenuAddItem(m, mi);
}
if (lst)
Efree(lst);
EDBUG_RETURN(m);
}
#if 0 /* Not finished */
Menu *
MenuCreateMoveToDesktop(char *name, MenuStyle * ms)
{
Menu *m;
int i;
char s1[256], s2[256];
MenuItem *mi;
EDBUG(5, "MenuCreateDesktops");
m = MenuCreate(name);
m->style = ms;
for (i = 0; i < Mode.numdesktops; i++)
{
Esnprintf(s1, sizeof(s1), _("Desktop %i"), i);
Esnprintf(s2, sizeof(s2), "%i", i);
mi = MenuItemCreate(s1, NULL, ACTION_MOVE_TO_DESK, s2, NULL);
MenuAddItem(m, mi);
}
EDBUG_RETURN(m);
}
#endif
static Menu *
MenuCreateFromGroups(const char *name, MenuStyle * ms)
{
Menu *m, *mm;
Group **lst;
int i, j, num;
char s[256];
MenuItem *mi;
EDBUG(5, "MenuCreateFromEWins");
m = MenuCreate(name);
m->style = ms;
lst = (Group **) ListItemType(&num, LIST_TYPE_GROUP);
if (lst)
{
for (i = 0; i < num; i++)
{
mm = MenuCreate("__SUBMENUGROUP_E");
mm->style = ms;
Esnprintf(s, sizeof(s), "%li", lst[i]->members[0]->client.win);
mi = MenuItemCreate(_("Show/Hide this group"), NULL,
ACTION_SHOW_HIDE_GROUP, s, NULL);
MenuAddItem(mm, mi);
mi = MenuItemCreate(_("Iconify this group"), NULL, ACTION_ICONIFY,
s, NULL);
MenuAddItem(mm, mi);
for (j = 0; j < lst[i]->num_members; j++)
{
Esnprintf(s, sizeof(s), "%li",
lst[i]->members[j]->client.win);
mi =
MenuItemCreate(EwinGetTitle(lst[i]->members[j]), NULL,
ACTION_FOCUS_SET, s, NULL);
MenuAddItem(mm, mi);
}
mm->parent = m;
Esnprintf(s, sizeof(s), _("Group %i"), i);
mi = MenuItemCreate(s, NULL, 0, NULL, mm);
MenuAddItem(m, mi);
}
Efree(lst);
}
EDBUG_RETURN(m);
}
void
MenuShowMasker(Menu * m)
{
EWin *ewin;
ewin = FindEwinByMenu(m);
if ((ewin) && (!Mode.menu_cover_win))
{
Window parent;
Window wl[2];
parent = desks.desk[ewin->desktop].win;
Mode.menu_cover_win = ECreateEventWindow(parent, 0, 0, root.w, root.h);
Mode.menu_win_covered = ewin->win;
wl[0] = Mode.menu_win_covered;
wl[1] = Mode.menu_cover_win;
XSelectInput(disp, Mode.menu_cover_win,
ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
LeaveWindowMask);
XRestackWindows(disp, wl, 2);
EMapWindow(disp, Mode.menu_cover_win);
}
}
void
MenuHideMasker(void)
{
if (Mode.menu_cover_win)
{
EDestroyWindow(disp, Mode.menu_cover_win);
Mode.menu_cover_win = 0;
Mode.menu_win_covered = 0;
}
}
void
ShowNamedMenu(const char *name)
{
Menu *m;
EDBUG(5, "ShowNamedMenu");
m = FindItem(name, 0, LIST_FINDBY_NAME, LIST_TYPE_MENU);
if (m)
{
Mode.cur_menu_mode = 1;
XUngrabPointer(disp, CurrentTime);
if (!FindEwinByMenu(m)) /* Don't show if already shown */
MenuShow(m, 0);
Mode.cur_menu[0] = m;
Mode.cur_menu_depth = 1;
MenuShowMasker(m);
m->ref_count++;
}
else
{
Mode.cur_menu[0] = NULL;
Mode.cur_menu_depth = 0;
MenuHideMasker();
}
EDBUG_RETURN_;
}
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);
}
void
MenusHideByWindow(Window win)
{
Menu *m;
int i, ok;
m = FindMenu(win);
if (m)
{
MenuHide(m);
ok = 0;
for (i = 0; i < Mode.cur_menu_depth; i++)
{
if (ok)
MenuHide(Mode.cur_menu[i]);
if (Mode.cur_menu[i] == m)
ok = 1;
}
MenuHideMasker();
}
}
/*
* Internal menus
*/
#if 0 /* Not used */
static Menu *task_menu[ENLIGHTENMENT_CONF_NUM_DESKTOPS];
#endif
void
MenusInit(void)
{
#if 0 /* Not used */
int i;
for (i = 0; i < ENLIGHTENMENT_CONF_NUM_DESKTOPS; task_menu[i++] = NULL);
#endif
}
static Menu *
RefreshInternalMenu(Menu * m, MenuStyle * ms,
Menu * (mcf) (const char *xxx, MenuStyle * ms))
{
char was = 0;
int lx = 0, ly = 0;
EWin *ewin;
EDBUG(5, "RefreshInternalMenu");
if (m)
{
ewin = FindEwinByMenu(m);
if ((m->win) && (ewin))
{
lx = ewin->x;
ly = ewin->y;
was = 1;
}
MenuDestroy(m);
m = NULL;
}
if (!ms)
EDBUG_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);
}
Mode.cur_menu[0] = m;
Mode.cur_menu_depth = 1;
MenuShowMasker(m);
}
EDBUG_RETURN(m);
}
static void
ShowInternalMenu(Menu ** pm, MenuStyle ** pms, const char *style,
Menu * (mcf) (const char *name, MenuStyle * ms))
{
Menu *m = *pm;
MenuStyle *ms = *pms;
EDBUG(5, "ShowInternalMenu");
XUngrabPointer(disp, CurrentTime);
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)
EDBUG_RETURN_;
*pms = ms;
}
Mode.cur_menu_mode = 1;
*pm = m = RefreshInternalMenu(m, ms, mcf);
if (m)
{
if (!FindEwinByMenu(m))
MenuShow(m, 0);
Mode.cur_menu[0] = m;
Mode.cur_menu_depth = 1;
MenuShowMasker(m);
}
else
{
Mode.cur_menu[0] = NULL;
Mode.cur_menu_depth = 0;
MenuHideMasker();
}
EDBUG_RETURN_;
}
#if 0 /* Not used */
static Menu *
RefreshTaskMenu(int desk)
{
char was = 0;
int lx = 0, ly = 0;
EWin *ewin;
EDBUG(5, "RefreshTaskMenu");
if (task_menu[desk])
{
ewin = FindEwinByMenu(task_menu[desk]);
if ((task_menu[desk]->win) && (ewin))
{
lx = ewin->x;
ly = ewin->y;
was = 1;
}
MenuDestroy(task_menu[desk]);
}
task_menu[desk] = NULL;
if (!task_menu_style)
{
EDBUG_RETURN(NULL);
}
task_menu[desk] = MenuCreateFromDesktopEWins("MENU", task_menu_style, desk);
if ((was) && (task_menu[desk]))
{
task_menu[desk]->internal = 1;
MenuShow(task_menu[desk], 1);
ewin = FindEwinByMenu(task_menu[desk]);
if (ewin)
{
MoveEwin(ewin, lx, ly);
ShowEwin(ewin);
}
Mode.cur_menu[0] = task_menu[desk];
Mode.cur_menu_depth = 1;
MenuShowMasker(task_menu[desk]);
}
EDBUG_RETURN(task_menu[desk]);
}
void
ShowTaskMenu(void)
{
EDBUG(5, "ShowTaskMenu");
EDBUG_RETURN_;
}
#endif
void
ShowAllTaskMenu(void)
{
static MenuStyle *ms = NULL;
static Menu *m = NULL;
EDBUG(5, "ShowAllTaskMenu");
ShowInternalMenu(&m, &ms, "TASK_MENU", MenuCreateFromAllEWins);
EDBUG_RETURN_;
}
void
ShowDeskMenu(void)
{
static MenuStyle *ms = NULL;
static Menu *m = NULL;
EDBUG(5, "ShowDeskMenu");
ShowInternalMenu(&m, &ms, "DESK_MENU", MenuCreateFromDesktops);
EDBUG_RETURN_;
}
void
ShowGroupMenu(void)
{
static MenuStyle *ms = NULL;
static Menu *m = NULL;
EDBUG(5, "ShowGroupMenu");
ShowInternalMenu(&m, &ms, "GROUP_MENU", MenuCreateFromGroups);
EDBUG_RETURN_;
}
void
MenusHide(void)
{
int i;
for (i = 0; i < Mode.cur_menu_depth; i++)
{
if (!Mode.cur_menu[i]->stuck)
MenuHide(Mode.cur_menu[i]);
}
MenuHideMasker();
Mode.cur_menu_depth = 0;
Mode.cur_menu_mode = 0;
clickmenu = 0;
}
Window
MenuWindow(Menu * m)
{
return m->win;
}
/*
* Menu event handlers
*/
int
MenusEventMouseDown(XEvent * ev)
{
Menu *m;
MenuItem *mi;
EWin *ewin;
m = FindMenuItem(ev->xbutton.window, &mi);
if (m == NULL)
return 0;
if (mi == NULL)
goto done;
Mode.cur_menu_mode = 1;
mi->state = STATE_CLICKED;
MenuDrawItem(m, mi, 1);
if (mi->child && mi->child->shown == 0)
{
int mx, my;
unsigned int mw, mh;
EWin *ewin2;
Mode.cur_menu[0] = m;
Mode.cur_menu_depth = 1;
MenuShowMasker(m);
XUngrabPointer(disp, CurrentTime);
ewin = FindEwinByMenu(m);
if (ewin)
{
GetWinXY(mi->win, &mx, &my);
GetWinWH(mi->win, &mw, &mh);
#if 1 /* Whatgoesonhere ??? */
MenuShow(mi->child, 1);
ewin2 = FindEwinByMenu(mi->child);
if (ewin2)
{
MoveEwin(ewin2,
ewin->x + ewin->border->border.left + mx + mw,
ewin->y + ewin->border->border.top + my -
ewin2->border->border.top);
RaiseEwin(ewin2);
ShowEwin(ewin2);
if (Conf.menuslide)
UnShadeEwin(ewin2);
Mode.cur_menu[Mode.cur_menu_depth++] = mi->child;
}
#else
ewin2 = FindEwinByMenu(mi->child);
if (!ewin2)
MenuShow(mi->child, 1);
#endif
}
}
done:
return 1;
}
int
MenusEventMouseUp(XEvent * ev)
{
Menu *m;
MenuItem *mi;
m = FindMenuItem(ev->xbutton.window, &mi);
if ((m) && (mi->state))
{
mi->state = STATE_HILITED;
MenuDrawItem(m, mi, 1);
if ((mi->act_id) && (!Mode.justclicked))
{
ActionsCall(mi->act_id, NULL, mi->params);
if (clickmenu)
{
MenusHide();
return 1;
}
}
}
if ((Mode.cur_menu_mode) && (!clickmenu))
{
if (!m)
{
EWin *ewin;
Window ww;
ww = WindowAtXY(Mode.x, Mode.y);
if ((ewin = FindEwinByChildren(ww)))
{
int i;
for (i = 0; i < ewin->border->num_winparts; i++)
{
if (ww == ewin->bits[i].win)
{
if ((ewin->border->part[i].flags & FLAG_TITLE)
&& (ewin->menu))
{
ewin->menu->stuck = 1;
i = ewin->border->num_winparts;
}
}
}
}
}
MenusHide();
return 1;
}
if ((Mode.cur_menu_mode) && (!Mode.justclicked))
{
MenusHide();
return 1;
}
return 0;
}
struct _mdata
{
Menu *m;
MenuItem *mi;
EWin *ewin;
};
static void
SubmenuShowTimeout(int val, void *dat)
{
int mx, my;
unsigned int mw, mh;
EWin *ewin2, *ewin;
struct _mdata *data;
data = (struct _mdata *)dat;
if (!data)
return;
if (!data->m)
return;
if (!FindEwinByMenu(data->m))
return;
GetWinXY(data->mi->win, &mx, &my);
GetWinWH(data->mi->win, &mw, &mh);
MenuShow(data->mi->child, 1);
ewin2 = FindEwinByMenu(data->mi->child);
if (ewin2)
{
MoveEwin(ewin2,
data->ewin->x + data->ewin->border->border.left + mx + mw,
data->ewin->y + data->ewin->border->border.top + my -
ewin2->border->border.top);
RaiseEwin(ewin2);
ShowEwin(ewin2);
if (Conf.menuslide)
UnShadeEwin(ewin2);
if (Mode.cur_menu[Mode.cur_menu_depth - 1] != data->mi->child)
Mode.cur_menu[Mode.cur_menu_depth++] = data->mi->child;
if (Conf.menusonscreen)
{
EWin *menus[256];
int fx[256];
int fy[256];
int tx[256];
int ty[256];
int i;
int xdist = 0, ydist = 0;
if (ewin2->x + ewin2->w > root.w)
xdist = root.w - (ewin2->x + ewin2->w);
if (ewin2->y + ewin2->h > root.h)
ydist = root.h - (ewin2->y + ewin2->h);
if ((xdist != 0) || (ydist != 0))
{
for (i = 0; i < Mode.cur_menu_depth; i++)
{
menus[i] = NULL;
if (Mode.cur_menu[i])
{
ewin = FindEwinByMenu(Mode.cur_menu[i]);
if (ewin)
{
menus[i] = ewin;
fx[i] = ewin->x;
fy[i] = ewin->y;
tx[i] = ewin->x + xdist;
ty[i] = ewin->y + ydist;
}
}
}
SlideEwinsTo(menus, fx, fy, tx, ty, Mode.cur_menu_depth,
Conf.shadespeed);
if (Conf.warpmenus)
XWarpPointer(disp, None, None, 0, 0, 0, 0, xdist, ydist);
}
}
}
val = 0;
}
int
MenusEventMouseIn(XEvent * ev)
{
static struct _mdata mdata;
Window win = ev->xcrossing.window;
Menu *m;
MenuItem *mi;
int i;
int j;
m = FindMenuItem(win, &mi);
if (m == NULL)
return 0;
if (mi == NULL)
goto done;
PagerHideAllHi();
if ((win == mi->icon_win) && (ev->xcrossing.detail == NotifyAncestor))
goto done;
if ((win == mi->win) && (ev->xcrossing.detail == NotifyInferior))
goto done;
mi->state = STATE_HILITED;
MenuDrawItem(m, mi, 1);
RemoveTimerEvent("SUBMENU_SHOW");
for (i = 0; i < Mode.cur_menu_depth; i++)
{
if (Mode.cur_menu[i] == m)
{
if ((!mi->child) ||
((mi->child) && (Mode.cur_menu[i + 1] != mi->child)))
{
for (j = i + 1; j < Mode.cur_menu_depth; j++)
MenuHide(Mode.cur_menu[j]);
Mode.cur_menu_depth = i + 1;
i = Mode.cur_menu_depth;
break;
}
}
}
if ((mi->child) && (!mi->child->shown) && (Mode.cur_menu_mode))
{
EWin *ewin;
ewin = FindEwinByMenu(m);
if (ewin)
{
mdata.m = m;
mdata.mi = mi;
mdata.ewin = ewin;
DoIn("SUBMENU_SHOW", 0.2, SubmenuShowTimeout, 0, &mdata);
}
}
done:
return 1;
}
int
MenusEventMouseOut(XEvent * ev)
{
Window win = ev->xcrossing.window;
Menu *m;
MenuItem *mi;
m = FindMenuItem(win, &mi);
if (m == NULL)
return 0;
if (mi == NULL)
goto done;
if ((win == mi->icon_win) && (ev->xcrossing.detail == NotifyAncestor))
goto done;
if ((win == mi->win) && (ev->xcrossing.detail == NotifyInferior))
goto done;
mi->state = STATE_NORMAL;
MenuDrawItem(m, mi, 1);
done:
return 1;
}