e16/src/borders.c

1330 lines
32 KiB
C
Raw Normal View History

/*
* 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 "ewins.h"
#include "iclass.h"
#include "snaps.h"
#include "tclass.h"
#include "tooltips.h"
#include "xwin.h"
#include <sys/time.h>
#define EWIN_BORDER_PART_EVENT_MASK \
(KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask | PointerMotionMask)
#define EWIN_BORDER_TITLE_EVENT_MASK \
(EWIN_BORDER_PART_EVENT_MASK)
2004-12-28 15:46:49 -08:00
static void BorderWinpartHandleEvents(XEvent * ev, void *prm);
static void BorderFrameHandleEvents(XEvent * ev, void *prm);
void
EwinBorderUpdateState(EWin * ewin)
{
EwinBorderDraw(ewin, 0, 0);
}
static void
BorderWinpartRealise(EWin * ewin, int i)
{
EWinBit *ewb = &ewin->bits[i];
if ((ewb->cx != ewb->x) || (ewb->cy != ewb->y) ||
(ewb->cw != ewb->w) || (ewb->ch != ewb->h))
{
2005-06-02 12:02:13 -07:00
if ((ewb->w <= 0) || (ewb->h <= 0))
{
EUnmapWindow(ewb->win);
}
else
{
EMapWindow(ewb->win);
EMoveResizeWindow(ewb->win, ewb->x, ewb->y, ewb->w, ewb->h);
}
}
}
static void
BorderWinpartITclassApply(EWin * ewin, int i, int force)
{
EWinBit *ewb = &ewin->bits[i];
ImageState *is;
TextState *ts;
const char *txt;
if (ewb->win == None)
return;
#if 0 /* Debug */
Eprintf("BorderWpITApply: %#lx %#lx %2d %d %s\n",
_EwinGetClientXwin(ewin), EoGetWin(ewin), i, force,
EwinGetName(ewin));
#endif
is = ImageclassGetImageState(ewin->border->part[i].iclass, ewb->state,
ewin->state.active, EoIsSticky(ewin));
ts = NULL;
txt = NULL;
switch (ewin->border->part[i].flags)
{
case FLAG_TITLE:
txt = EwinGetName(ewin);
if (txt && ewin->border->part[i].tclass)
ts = TextclassGetTextState(ewin->border->part[i].tclass, ewb->state,
ewin->state.active, EoIsSticky(ewin));
break;
case FLAG_MINIICON:
break;
default:
break;
}
if (!force && ewb->is == is && ewb->ts == ts)
return;
ewb->is = is;
ewb->ts = ts;
ITApply(ewb->win, ewin->border->part[i].iclass, is, ewb->w, ewb->h,
ewb->state, ewin->state.active, EoIsSticky(ewin), ewb->expose,
ST_BORDER, ewin->border->part[i].tclass, ts, txt);
}
static int
BorderWinpartDraw(EWin * ewin, int i)
{
EWinBit *ewb = &ewin->bits[i];
int move = 0, resize = 0, ret = 0;
if ((ewb->x != ewb->cx) || (ewb->y != ewb->cy))
{
move = 1;
ewb->cx = ewb->x;
ewb->cy = ewb->y;
ret = 1;
}
if ((ewb->w != ewb->cw) || (ewb->h != ewb->ch))
{
resize = 1;
ewb->cw = ewb->w;
ewb->ch = ewb->h;
}
if ((resize) || (ewb->expose))
{
BorderWinpartITclassApply(ewin, i, 1);
ewb->expose = 0;
ret = 1;
}
return ret;
}
void
BorderWinpartChange(EWin * ewin, int i, int force)
{
BorderWinpartITclassApply(ewin, i, force);
if (ewin->update.shape || ewin->border->changes_shape)
EwinPropagateShapes(ewin);
}
2004-12-28 15:46:49 -08:00
void
EwinBorderDraw(EWin * ewin, int do_shape, int do_paint)
{
int i;
if (!ewin)
return;
#if 0 /* Debug */
Eprintf("EwinBorderDraw %#lx %s d=%d s=%d p=%d\n",
_EwinGetClientXwin(ewin), EoGetName(ewin), EoGetDeskNum(ewin),
do_shape, do_paint);
#endif
for (i = 0; i < ewin->border->num_winparts; i++)
BorderWinpartITclassApply(ewin, i, do_shape || do_paint);
if (do_shape || ewin->update.shape || ewin->border->changes_shape)
EwinPropagateShapes(ewin);
}
void
EwinBorderUpdateInfo(EWin * ewin)
{
int i;
for (i = 0; i < ewin->border->num_winparts; i++)
{
if (ewin->border->part[i].flags == FLAG_TITLE)
BorderWinpartITclassApply(ewin, i, 1);
}
}
static void
BorderWinpartCalc(EWin * ewin, int i, int ww, int hh)
{
int x, y, w, h, ox, oy, max, min;
int topleft, bottomright;
topleft = ewin->border->part[i].geom.topleft.originbox;
bottomright = ewin->border->part[i].geom.bottomright.originbox;
if (topleft >= 0)
BorderWinpartCalc(ewin, topleft, ww, hh);
if (bottomright >= 0)
BorderWinpartCalc(ewin, bottomright, ww, hh);
x = y = 0;
if (topleft == -1)
{
2004-12-28 15:46:49 -08:00
x = ((ewin->border->part[i].geom.topleft.x.percent *
ww) >> 10) + ewin->border->part[i].geom.topleft.x.absolute;
2004-12-28 15:46:49 -08:00
y = ((ewin->border->part[i].geom.topleft.y.percent *
hh) >> 10) + ewin->border->part[i].geom.topleft.y.absolute;
}
else if (topleft >= 0)
{
x = ((ewin->border->part[i].geom.topleft.x.percent *
ewin->bits[topleft].w) >> 10) +
ewin->border->part[i].geom.topleft.x.absolute +
ewin->bits[topleft].x;
y = ((ewin->border->part[i].geom.topleft.y.percent *
ewin->bits[topleft].h) >> 10) +
ewin->border->part[i].geom.topleft.y.absolute +
ewin->bits[topleft].y;
}
ox = oy = 0;
if (bottomright == -1)
{
ox = ((ewin->border->
part[i].geom.bottomright.x.percent * ww) >> 10) +
ewin->border->part[i].geom.bottomright.x.absolute;
oy = ((ewin->border->
part[i].geom.bottomright.y.percent * hh) >> 10) +
ewin->border->part[i].geom.bottomright.y.absolute;
}
else if (bottomright >= 0)
{
ox = ((ewin->border->part[i].geom.bottomright.x.percent *
ewin->bits[bottomright].w) >> 10) +
ewin->border->part[i].geom.bottomright.x.absolute +
ewin->bits[bottomright].x;
oy = ((ewin->border->part[i].geom.bottomright.y.percent *
ewin->bits[bottomright].h) >> 10) +
ewin->border->part[i].geom.bottomright.y.absolute +
ewin->bits[bottomright].y;
}
/*
* calculate height before width, because we may need it in order to
* determine the font size. But we might do it the other way around for
* side borders :-)
*/
h = (oy - y) + 1;
max = ewin->border->part[i].geom.height.max;
min = ewin->border->part[i].geom.height.min;
/*
* If the title bar max size is set to zero, then set the title bar size to
* just a little bit more than the size of the title text.
*/
if (max == 0 && ewin->border->part[i].flags == FLAG_TITLE)
{
int dummywidth, wmax, wmin;
ImageClass *iclass;
TextClass *tclass;
Imlib_Border *pad;
/*
* calculate width before height, because we need it in order to
* determine the font size.
*/
w = (ox - x) + 1;
wmax = ewin->border->part[i].geom.width.max;
wmin = ewin->border->part[i].geom.width.min;
if (w > wmax)
{
w = wmax;
x = ((x + ox) - w) >> 1;
}
else if (w < wmin)
{
w = wmin;
}
iclass = ewin->border->part[i].iclass;
tclass = ewin->border->part[i].tclass;
pad = ImageclassGetPadding(iclass);
TextSize(tclass, ewin->state.active, EoIsSticky(ewin),
ewin->bits[i].state, EwinGetName(ewin), &max, &dummywidth,
w - (pad->top + pad->bottom));
max += pad->left + pad->right;
if (h > max)
{
y = y + (((h - max) * TextclassGetJustification(tclass)) >> 10);
h = max;
}
if (h < min)
{
h = min;
}
}
else
{
if (h > max)
{
h = max;
y = ((y + oy) - h) >> 1;
}
else if (h < min)
{
h = min;
}
/*
* and now the width.
*/
w = (ox - x) + 1;
max = ewin->border->part[i].geom.width.max;
min = ewin->border->part[i].geom.width.min;
/*
* If the title bar max size is set to zero, then set the title bar
* size to just a little bit more than the size of the title text.
*/
if (max == 0 && ewin->border->part[i].flags == FLAG_TITLE)
{
int dummyheight;
ImageClass *iclass;
TextClass *tclass;
Imlib_Border *pad;
iclass = ewin->border->part[i].iclass;
tclass = ewin->border->part[i].tclass;
pad = ImageclassGetPadding(iclass);
TextSize(tclass, ewin->state.active, EoIsSticky(ewin),
ewin->bits[i].state, EwinGetName(ewin), &max,
&dummyheight, h - (pad->top + pad->bottom));
max += pad->left + pad->right;
if (w > max)
{
x = x +
(((w - max) * TextclassGetJustification(tclass)) >> 10);
w = max;
}
}
if (w > max)
{
w = max;
x = ((x + ox) - w) >> 1;
}
else if (w < min)
{
w = min;
}
}
if ((ewin->state.shaded) && (!ewin->border->part[i].keep_for_shade))
{
ewin->bits[i].x = -100;
ewin->bits[i].y = -100;
ewin->bits[i].w = -1;
ewin->bits[i].h = -1;
}
else
{
ewin->bits[i].x = x;
ewin->bits[i].y = y;
ewin->bits[i].w = w;
ewin->bits[i].h = h;
}
}
2004-12-28 15:46:49 -08:00
void
EwinBorderCalcSizes(EWin * ewin, int propagate)
{
int i, ww, hh;
char reshape;
if (!ewin)
return;
if (!ewin->border)
return;
ww = EoGetW(ewin);
hh = EoGetH(ewin);
for (i = 0; i < ewin->border->num_winparts; i++)
ewin->bits[i].w = -2;
for (i = 0; i < ewin->border->num_winparts; i++)
if (ewin->bits[i].w == -2)
BorderWinpartCalc(ewin, i, ww, hh);
for (i = 0; i < ewin->border->num_winparts; i++)
BorderWinpartRealise(ewin, i);
reshape = 0;
for (i = 0; i < ewin->border->num_winparts; i++)
{
reshape |= BorderWinpartDraw(ewin, i);
ewin->bits[i].no_expose = 1;
}
#if 0 /* Debug */
Eprintf("EwinBorderCalcSizes prop=%d reshape=%d\n", propagate, reshape);
#endif
if (reshape)
ewin->update.shape = 1;
if (propagate && ewin->update.shape)
EwinPropagateShapes(ewin);
}
void
BorderIncRefcount(const Border * b)
{
((Border *) b)->ref_count++;
}
void
BorderDecRefcount(const Border * b)
{
((Border *) b)->ref_count--;
}
const char *
BorderGetName(const Border * b)
{
return (b) ? b->name : NULL;
}
2004-12-28 15:46:49 -08:00
void
EwinBorderSelect(EWin * ewin)
{
2004-12-28 15:46:49 -08:00
const Border *b;
#if 0 /* Handled in iclass.c */
/* Imlib2 will not render pixmaps with dimensions > 8192 */
if (ewin->client.w > 8000 || ewin->client.h > 8000)
ewin->state.no_border = 1;
#endif
if (ewin->state.no_border)
{
b = FindItem("BORDERLESS", 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
}
else
{
/* Quit if we already have a border that isn't an internal one */
b = ewin->border;
if (b && strncmp(b->name, "__", 2))
goto done;
b = WindowMatchEwinBorder(ewin);
}
if (!b)
b = FindItem("DEFAULT", 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
if (!b)
b = FindItem("__FALLBACK_BORDER", 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
done:
ewin->normal_border = ewin->border = b;
}
void
EwinBorderDetach(EWin * ewin)
{
const Border *b = ewin->border;
int i;
if (!b)
return;
EventCallbackUnregister(EoGetWin(ewin), 0, BorderFrameHandleEvents, ewin);
for (i = 0; i < b->num_winparts; i++)
{
EventCallbackUnregister(ewin->bits[i].win, 0,
BorderWinpartHandleEvents, &ewin->bits[i]);
if (ewin->bits[i].win)
EDestroyWindow(ewin->bits[i].win);
}
if (ewin->bits)
Efree(ewin->bits);
ewin->bits = NULL;
BorderDecRefcount(b);
ewin->border = NULL;
if (b->throwaway)
BorderDestroy((Border *) b);
}
void
2004-12-28 15:46:49 -08:00
EwinBorderSetTo(EWin * ewin, const Border * b)
{
2004-12-28 15:46:49 -08:00
int i;
if (ewin->border == b)
return;
2004-12-28 15:46:49 -08:00
if (b == NULL)
{
2004-12-28 15:46:49 -08:00
b = ewin->border;
ewin->border = NULL;
}
2004-12-28 15:46:49 -08:00
if (ewin->border)
EwinBorderDetach(ewin);
ewin->border = b;
2004-12-28 15:46:49 -08:00
BorderIncRefcount(b);
HintsSetWindowBorder(ewin);
2004-12-28 15:46:49 -08:00
EventCallbackRegister(EoGetWin(ewin), 0, BorderFrameHandleEvents, ewin);
if (b->num_winparts > 0)
ewin->bits = Emalloc(sizeof(EWinBit) * b->num_winparts);
2004-12-28 15:46:49 -08:00
for (i = 0; i < b->num_winparts; i++)
{
2004-12-28 15:46:49 -08:00
ewin->bits[i].ewin = ewin; /* Reference to associated Ewin */
ewin->bits[i].win = ECreateWindow(EoGetWin(ewin), -10, -10, 1, 1, 0);
ECursorApply(b->part[i].ec, ewin->bits[i].win);
EMapWindow(ewin->bits[i].win);
EventCallbackRegister(ewin->bits[i].win, 0,
BorderWinpartHandleEvents, &ewin->bits[i]);
/*
* KeyPressMask KeyReleaseMask ButtonPressMask
* ButtonReleaseMask
* EnterWindowMask LeaveWindowMask PointerMotionMask
* PointerMotionHintMask Button1MotionMask
* Button2MotionMask
* Button3MotionMask Button4MotionMask Button5MotionMask
* ButtonMotionMask KeymapStateMask ExposureMask
* VisibilityChangeMask StructureNotifyMask
* ResizeRedirectMask
* SubstructureNotifyMask SubstructureRedirectMask
* FocusChangeMask PropertyChangeMas ColormapChangeMask
* OwnerGrabButtonMask
*/
if (b->part[i].flags & FLAG_TITLE)
ESelectInput(ewin->bits[i].win, EWIN_BORDER_TITLE_EVENT_MASK);
else
ESelectInput(ewin->bits[i].win, EWIN_BORDER_PART_EVENT_MASK);
ewin->bits[i].x = -10;
ewin->bits[i].y = -10;
ewin->bits[i].w = -10;
ewin->bits[i].h = -10;
ewin->bits[i].cx = -99;
ewin->bits[i].cy = -99;
ewin->bits[i].cw = -99;
ewin->bits[i].ch = -99;
ewin->bits[i].state = 0;
ewin->bits[i].expose = 0;
ewin->bits[i].no_expose = 0;
ewin->bits[i].left = 0;
ewin->bits[i].is = NULL;
}
{
Window *wl;
int j = 0;
wl = Emalloc((b->num_winparts + 1) * sizeof(Window));
for (i = b->num_winparts - 1; i >= 0; i--)
{
if (b->part[i].ontop)
wl[j++] = ewin->bits[i].win;
}
wl[j++] = ewin->win_container;
for (i = b->num_winparts - 1; i >= 0; i--)
{
if (!b->part[i].ontop)
wl[j++] = ewin->bits[i].win;
}
XRestackWindows(disp, wl, j);
Efree(wl);
}
if (!ewin->state.shaded)
EMoveWindow(ewin->win_container, b->border.left, b->border.top);
ewin->update.shape = 1;
EwinBorderCalcSizes(ewin, 0);
SnapshotEwinUpdate(ewin, SNAP_USE_BORDER);
}
void
2004-12-28 15:46:49 -08:00
EwinSetBorder(EWin * ewin, const Border * b, int apply)
{
if (!b || ewin->border == b || ewin->state.no_border)
return;
if (apply)
{
EwinBorderSetTo(ewin, b);
EwinMoveResize(ewin, EoGetX(ewin), EoGetY(ewin),
ewin->client.w, ewin->client.h);
}
else
{
2004-12-28 15:46:49 -08:00
if (ewin->border)
BorderDecRefcount(ewin->border);
ewin->border = b;
2004-12-28 15:46:49 -08:00
if (b)
BorderIncRefcount(b);
}
if (!ewin->state.fullscreen)
ewin->normal_border = b;
}
void
EwinSetBorderByName(EWin * ewin, const char *name)
{
Border *b;
b = FindItem(name, 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER);
EwinSetBorder(ewin, b, 0);
}
2004-12-28 15:46:49 -08:00
Border *
BorderCreate(const char *name)
{
2004-12-28 15:46:49 -08:00
Border *b;
2004-12-28 15:46:49 -08:00
b = Ecalloc(1, sizeof(Border));
if (!b)
return NULL;
2004-12-28 15:46:49 -08:00
b->name = Estrdup(name);
b->group_border_name = NULL;
b->shadedir = 2;
return b;
}
void
2004-12-28 15:46:49 -08:00
BorderDestroy(Border * b)
{
2004-12-28 15:46:49 -08:00
int i;
2004-12-28 15:46:49 -08:00
if (!b)
return;
2004-12-28 15:46:49 -08:00
if (b->ref_count > 0)
{
2004-12-28 15:46:49 -08:00
DialogOK(_("Border Error!"), _("%u references remain\n"), b->ref_count);
return;
}
2004-12-28 15:46:49 -08:00
while (RemoveItemByPtr(b, LIST_TYPE_BORDER));
2004-12-28 15:46:49 -08:00
for (i = 0; i < b->num_winparts; i++)
{
2004-12-28 15:46:49 -08:00
if (b->part[i].iclass)
ImageclassDecRefcount(b->part[i].iclass);
2004-12-28 15:46:49 -08:00
if (b->part[i].tclass)
TextclassDecRefcount(b->part[i].tclass);
2004-12-28 15:46:49 -08:00
if (b->part[i].aclass)
ActionclassDecRefcount(b->part[i].aclass);
if (b->part[i].ec)
ECursorDecRefcount(b->part[i].ec);
}
2004-12-28 15:46:49 -08:00
if (b->num_winparts > 0)
Efree(b->part);
2004-12-28 15:46:49 -08:00
if (b->name)
Efree(b->name);
if (b->group_border_name)
Efree(b->group_border_name);
if (b->aclass)
ActionclassDecRefcount(b->aclass);
}
void
2004-12-28 15:46:49 -08:00
BorderWinpartAdd(Border * b, ImageClass * iclass, ActionClass * aclass,
TextClass * tclass, ECursor * ec, char ontop, int flags,
char isregion, int wmin, int wmax, int hmin, int hmax,
int torigin, int txp, int txa, int typ, int tya, int borigin,
int bxp, int bxa, int byp, int bya, char keep_for_shade)
{
2004-12-28 15:46:49 -08:00
int n;
2004-12-28 15:46:49 -08:00
b->num_winparts++;
n = b->num_winparts;
2004-12-28 15:46:49 -08:00
isregion = 0;
2004-12-28 15:46:49 -08:00
b->part = Erealloc(b->part, n * sizeof(WinPart));
2004-12-28 15:46:49 -08:00
if (!iclass)
iclass = ImageclassFind(NULL, 0);
2004-12-28 15:46:49 -08:00
b->part[n - 1].iclass = iclass;
if (iclass)
ImageclassIncRefcount(iclass);
2004-12-28 15:46:49 -08:00
b->part[n - 1].aclass = aclass;
if (aclass)
ActionclassIncRefcount(aclass);
b->part[n - 1].tclass = tclass;
if (tclass)
TextclassIncRefcount(tclass);
b->part[n - 1].ec = ec;
if (ec)
ECursorIncRefcount(ec);
b->part[n - 1].ontop = ontop;
b->part[n - 1].flags = flags;
b->part[n - 1].keep_for_shade = keep_for_shade;
b->part[n - 1].geom.width.min = wmin;
b->part[n - 1].geom.width.max = wmax;
b->part[n - 1].geom.height.min = hmin;
b->part[n - 1].geom.height.max = hmax;
b->part[n - 1].geom.topleft.originbox = torigin;
b->part[n - 1].geom.topleft.x.percent = txp;
b->part[n - 1].geom.topleft.x.absolute = txa;
b->part[n - 1].geom.topleft.y.percent = typ;
b->part[n - 1].geom.topleft.y.absolute = tya;
b->part[n - 1].geom.bottomright.originbox = borigin;
b->part[n - 1].geom.bottomright.x.percent = bxp;
b->part[n - 1].geom.bottomright.x.absolute = bxa;
b->part[n - 1].geom.bottomright.y.percent = byp;
b->part[n - 1].geom.bottomright.y.absolute = bya;
}
2004-12-28 15:46:49 -08:00
void
EwinBorderMinShadeSize(EWin * ewin, int *mw, int *mh)
{
int i, pw, ph, w, h, min_w, min_h;
int leftborderwidth, rightborderwidth;
int topborderwidth, bottomborderwidth;
min_w = 32;
min_h = 32;
if (!ewin)
goto done;
2004-12-28 15:46:49 -08:00
pw = EoGetW(ewin);
ph = EoGetH(ewin);
for (i = 0; i < ewin->border->num_winparts; i++)
ewin->bits[i].w = -2;
for (i = 0; i < ewin->border->num_winparts; i++)
if (ewin->bits[i].w == -2)
BorderWinpartCalc(ewin, i, pw, ph);
switch (ewin->border->shadedir)
{
case 0:
case 1:
/* get the correct width, based on the borderparts that */
/*are remaining visible */
leftborderwidth = rightborderwidth = 0;
for (i = 0; i < ewin->border->num_winparts; i++)
{
if (!ewin->border->part[i].keep_for_shade)
continue;
w = ewin->border->border.left - ewin->bits[i].x;
if (leftborderwidth < w)
leftborderwidth = w;
w = ewin->bits[i].x + ewin->bits[i].w -
2004-12-28 15:46:49 -08:00
(EoGetW(ewin) - ewin->border->border.right);
if (rightborderwidth < w)
rightborderwidth = w;
}
pw = rightborderwidth + leftborderwidth;
break;
case 2:
case 3:
topborderwidth = bottomborderwidth = 0;
for (i = 0; i < ewin->border->num_winparts; i++)
{
if (!ewin->border->part[i].keep_for_shade)
continue;
h = ewin->border->border.top - ewin->bits[i].y;
if (topborderwidth < h)
topborderwidth = h;
h = ewin->bits[i].y + ewin->bits[i].h -
2004-12-28 15:46:49 -08:00
(EoGetH(ewin) - ewin->border->border.bottom);
if (bottomborderwidth < h)
bottomborderwidth = h;
}
ph = bottomborderwidth + topborderwidth;
break;
default:
break;
}
for (i = 0; i < ewin->border->num_winparts; i++)
ewin->bits[i].w = -2;
for (i = 0; i < ewin->border->num_winparts; i++)
if (ewin->bits[i].w == -2)
BorderWinpartCalc(ewin, i, pw, ph);
min_w = 0;
min_h = 0;
for (i = 0; i < ewin->border->num_winparts; i++)
{
if (!ewin->border->part[i].keep_for_shade)
continue;
w = ewin->bits[i].x + ewin->bits[i].w;
if (min_w < w)
min_w = w;
h = ewin->bits[i].y + ewin->bits[i].h;
if (min_h < h)
min_h = h;
}
done:
*mw = min_w;
*mh = min_h;
}
2004-12-28 15:46:49 -08:00
int
BorderWinpartIndex(EWin * ewin, Window win)
{
2004-12-28 15:46:49 -08:00
int i;
2004-12-28 15:46:49 -08:00
for (i = 0; i < ewin->border->num_winparts; i++)
{
2004-12-28 15:46:49 -08:00
if (win == ewin->bits[i].win)
return i;
}
2004-12-28 15:46:49 -08:00
return -1; /* Not found */
}
void
2004-12-28 15:46:49 -08:00
EwinBorderEventsConfigure(EWin * ewin, int mode)
{
2004-12-28 15:46:49 -08:00
int i;
long emask;
2004-12-28 15:46:49 -08:00
emask = (mode) ? ~((long)0) : ~(EnterWindowMask | LeaveWindowMask);
for (i = 0; i < ewin->border->num_winparts; i++)
{
2004-12-28 15:46:49 -08:00
if (ewin->border->part[i].flags & FLAG_TITLE)
ESelectInput(ewin->bits[i].win,
2004-12-28 15:46:49 -08:00
EWIN_BORDER_TITLE_EVENT_MASK & emask);
else
ESelectInput(ewin->bits[i].win, EWIN_BORDER_PART_EVENT_MASK & emask);
}
}
2004-12-28 15:46:49 -08:00
/*
* Border event handlers
*/
#define DEBUG_BORDER_EVENTS 0
static void
BorderWinpartEventMouseDown(EWinBit * wbit, XEvent * ev)
{
EWin *ewin = wbit->ewin;
int part = wbit - ewin->bits;
2004-12-28 15:46:49 -08:00
GrabPointerSet(wbit->win, 0, 0);
2004-12-28 15:46:49 -08:00
wbit->state = STATE_CLICKED;
#if DEBUG_BORDER_EVENTS
Eprintf("BorderWinpartEventMouseDown %#lx %d\n", wbit->win, wbit->state);
#endif
BorderWinpartChange(ewin, part, 0);
FocusHandleClick(ewin, wbit->win);
2004-12-28 15:46:49 -08:00
if (ewin->border->part[part].aclass)
ActionclassEvent(ewin->border->part[part].aclass, ev, ewin);
}
2004-12-28 15:46:49 -08:00
static void
BorderWinpartEventMouseUp(EWinBit * wbit, XEvent * ev)
{
2004-12-28 15:46:49 -08:00
EWin *ewin = wbit->ewin;
int part = wbit - ewin->bits;
int left = wbit->left;
2004-12-28 15:46:49 -08:00
GrabPointerRelease();
2004-12-28 15:46:49 -08:00
if ((wbit->state == STATE_CLICKED) && (!wbit->left))
wbit->state = STATE_HILITED;
else
wbit->state = STATE_NORMAL;
#if DEBUG_BORDER_EVENTS
Eprintf("BorderWinpartEventMouseUp %#lx %d\n", wbit->win, wbit->state);
#endif
BorderWinpartChange(ewin, part, 0);
/* Beware! Actions may destroy the current border */
wbit->left = 0;
if (wbit->win == Mode.events.last_bpress && !left &&
2004-12-28 15:46:49 -08:00
ewin->border->part[part].aclass)
ActionclassEvent(ewin->border->part[part].aclass, ev, ewin);
}
2004-12-28 15:46:49 -08:00
static void
BorderWinpartEventEnter(EWinBit * wbit, XEvent * ev)
{
2004-12-28 15:46:49 -08:00
EWin *ewin = wbit->ewin;
int part = wbit - ewin->bits;
2004-12-28 15:46:49 -08:00
#if DEBUG_BORDER_EVENTS
Eprintf("BorderWinpartEventEnter %#lx %d\n", wbit->win, wbit->state);
#endif
if (wbit->state == STATE_CLICKED)
wbit->left = 0;
#if 0 /* Hmmm.. */
else
#endif
{
2004-12-28 15:46:49 -08:00
wbit->state = STATE_HILITED;
BorderWinpartChange(ewin, part, 0);
if (ewin->border->part[part].aclass)
ActionclassEvent(ewin->border->part[part].aclass, ev, ewin);
}
}
2004-12-28 15:46:49 -08:00
static void
BorderWinpartEventLeave(EWinBit * wbit, XEvent * ev)
{
2004-12-28 15:46:49 -08:00
EWin *ewin = wbit->ewin;
int part = wbit - ewin->bits;
2004-12-28 15:46:49 -08:00
#if DEBUG_BORDER_EVENTS
Eprintf("BorderWinpartEventLeave %#lx %d\n", wbit->win, wbit->state);
#endif
2004-12-28 15:46:49 -08:00
if (wbit->state == STATE_CLICKED)
wbit->left = 1;
else
{
2004-12-28 15:46:49 -08:00
wbit->state = STATE_NORMAL;
BorderWinpartChange(ewin, part, 0);
if (ewin->border->part[part].aclass)
ActionclassEvent(ewin->border->part[part].aclass, ev, ewin);
}
}
2004-12-28 15:46:49 -08:00
static void
BorderFrameHandleEvents(XEvent * ev, void *prm)
{
2004-12-28 15:46:49 -08:00
EWin *ewin = (EWin *) prm;
2004-12-28 15:46:49 -08:00
switch (ev->type)
{
2004-12-28 15:46:49 -08:00
case EnterNotify:
case LeaveNotify:
if (ewin->border->aclass)
ActionclassEvent(ewin->border->aclass, ev, ewin);
2004-12-28 15:46:49 -08:00
break;
}
}
static ActionClass *
BorderWinpartGetAclass(void *data)
{
EWinBit *wbit = (EWinBit *) data;
EWin *ewin;
int part;
/* Validate border part */
ewin = Mode.mouse_over_ewin;
if (!ewin)
return NULL;
part = wbit - ewin->bits;
if (part < 0 || part >= ewin->border->num_winparts)
return NULL;
return ewin->border->part[part].aclass;
}
static void
BorderWinpartHandleTooltip(EWinBit * wbit, int event)
{
EWin *ewin = wbit->ewin;
int part = wbit - ewin->bits;
switch (event)
{
case ButtonPress:
case LeaveNotify:
TooltipsSetPending(0, NULL, NULL);
break;
case ButtonRelease:
case EnterNotify:
case MotionNotify:
if (!ewin->border->part[part].aclass)
return;
TooltipsSetPending(0, BorderWinpartGetAclass, wbit);
break;
}
}
static void
2004-12-28 15:46:49 -08:00
BorderWinpartHandleEvents(XEvent * ev, void *prm)
{
2004-12-28 15:46:49 -08:00
EWinBit *wbit = (EWinBit *) prm;
/* Beware! Actions may destroy the current border */
BorderWinpartHandleTooltip(wbit, ev->type);
2004-12-28 15:46:49 -08:00
switch (ev->type)
{
2004-12-28 15:46:49 -08:00
case ButtonPress:
BorderWinpartEventMouseDown(wbit, ev);
break;
case ButtonRelease:
BorderWinpartEventMouseUp(wbit, ev);
break;
case EnterNotify:
BorderWinpartEventEnter(wbit, ev);
break;
case LeaveNotify:
BorderWinpartEventLeave(wbit, ev);
break;
}
}
2004-12-28 15:46:49 -08:00
/*
* Configuration load/save
*/
#include "conf.h"
2004-12-28 15:46:49 -08:00
static int
BorderPartLoad(FILE * fs, char type, Border * b)
{
int err = 0;
char s[FILEPATH_LEN_MAX];
char s2[FILEPATH_LEN_MAX];
int i1;
ImageClass *iclass = 0;
ActionClass *aclass = 0;
TextClass *tclass = 0;
ECursor *ec = NULL;
char ontop = 1;
int flags = FLAG_BUTTON;
char isregion = 0, keepshade = 1;
int wmin = 0, wmax = 0, hmin = 0, hmax = 0, torigin =
0, txp = 0, txa = 0, typ = 0, tya = 0, borigin = 0;
int bxp = 0, bxa = 0, byp = 0, bya = 0;
int fields;
type = 0;
while (GetLine(s, sizeof(s), fs))
{
s2[0] = 0;
i1 = CONFIG_INVALID;
fields = sscanf(s, "%i %4000s", &i1, s2);
if (fields < 1)
{
2004-12-28 15:46:49 -08:00
i1 = CONFIG_INVALID;
}
2004-12-28 15:46:49 -08:00
else if (i1 == CONFIG_CLOSE)
{
2004-12-28 15:46:49 -08:00
if (fields != 1)
Alert(_("CONFIG: ignoring extra data in \"%s\"\n"), s);
}
2004-12-28 15:46:49 -08:00
else if (i1 != CONFIG_INVALID)
{
2004-12-28 15:46:49 -08:00
if (fields != 2)
{
Alert(_("CONFIG: missing required data in \"%s\"\n"), s);
i1 = CONFIG_INVALID;
}
}
2004-12-28 15:46:49 -08:00
switch (i1)
{
2004-12-28 15:46:49 -08:00
case CONFIG_CLOSE:
BorderWinpartAdd(b, iclass, aclass, tclass, ec, ontop, flags,
isregion, wmin, wmax, hmin, hmax, torigin, txp,
txa, typ, tya, borigin, bxp, bxa, byp, bya,
keepshade);
goto done;
case CONFIG_IMAGECLASS:
case BORDERPART_ICLASS:
iclass = ImageclassFind(s2, 1);
break;
case CONFIG_ACTIONCLASS:
case BORDERPART_ACLASS:
aclass = FindItem(s2, 0, LIST_FINDBY_NAME, LIST_TYPE_ACLASS);
break;
case CONFIG_TEXT:
case BORDERPART_TEXTCLASS:
tclass = TextclassFind(s2, 1);
break;
case CONFIG_CURSOR:
ec = FindItem(s2, 0, LIST_FINDBY_NAME, LIST_TYPE_ECURSOR);
break;
case BORDERPART_ONTOP:
ontop = atoi(s2);
break;
case BORDERPART_FLAGS:
flags = atoi(s2);
break;
case BORDERPART_ISREGION:
isregion = atoi(s2);
break;
case BORDERPART_WMIN:
wmin = atoi(s2);
if (!wmax)
wmax = wmin;
break;
case BORDERPART_WMAX:
wmax = atoi(s2);
break;
case BORDERPART_HMIN:
hmin = atoi(s2);
if (!hmax)
hmax = hmin;
break;
case BORDERPART_HMAX:
hmax = atoi(s2);
break;
case BORDERPART_TORIGIN:
torigin = atoi(s2);
break;
case BORDERPART_TXP:
txp = atoi(s2);
break;
case BORDERPART_TXA:
txa = atoi(s2);
break;
case BORDERPART_TYP:
typ = atoi(s2);
break;
case BORDERPART_TYA:
tya = atoi(s2);
break;
case BORDERPART_BORIGIN:
borigin = atoi(s2);
break;
case BORDERPART_BXP:
bxp = atoi(s2);
break;
case BORDERPART_BXA:
bxa = atoi(s2);
break;
case BORDERPART_BYP:
byp = atoi(s2);
break;
case BORDERPART_BYA:
bya = atoi(s2);
break;
case BORDERPART_KEEPSHADE:
keepshade = atoi(s2);
break;
default:
break;
}
}
2004-12-28 15:46:49 -08:00
err = -1;
done:
return err;
}
2004-12-28 15:46:49 -08:00
int
BorderConfigLoad(FILE * fs)
{
2004-12-28 15:46:49 -08:00
int err = 0;
Border *b = 0;
char s[FILEPATH_LEN_MAX];
char s2[FILEPATH_LEN_MAX];
int i1;
char added = 0;
int fields;
2004-12-28 15:46:49 -08:00
while (GetLine(s, sizeof(s), fs))
{
2004-12-28 15:46:49 -08:00
s2[0] = 0;
i1 = CONFIG_INVALID;
fields = sscanf(s, "%i %4000s", &i1, s2);
2004-12-28 15:46:49 -08:00
if (fields < 1)
{
2004-12-28 15:46:49 -08:00
i1 = CONFIG_INVALID;
}
2004-12-28 15:46:49 -08:00
else if (i1 == CONFIG_CLOSE)
{
2004-12-28 15:46:49 -08:00
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);
i1 = CONFIG_INVALID;
}
}
if (atoi(s2) == CONFIG_OPEN)
{
err = BorderPartLoad(fs, i1, b);
if (err)
break;
}
else
{
switch (i1)
{
2004-12-28 15:46:49 -08:00
case CONFIG_CLOSE:
if (!added)
AddItem(b, b->name, 0, LIST_TYPE_BORDER);
goto done;
2004-12-28 15:46:49 -08:00
case BORDER_INIT:
AddItem(b, b->name, 0, LIST_TYPE_BORDER);
added = 1;
break;
case CONFIG_CLASSNAME:
case BORDER_NAME:
if (ConfigSkipIfExists(fs, s2, LIST_TYPE_BORDER))
goto done;
b = BorderCreate(s2);
break;
case BORDER_GROUP_NAME:
b->group_border_name = Estrdup(s2);
break;
case BORDER_LEFT:
b->border.left = atoi(s2);
break;
case BORDER_RIGHT:
b->border.right = atoi(s2);
break;
case BORDER_TOP:
b->border.top = atoi(s2);
break;
case BORDER_BOTTOM:
b->border.bottom = atoi(s2);
break;
case SHADEDIR:
b->shadedir = atoi(s2);
break;
case BORDER_CHANGES_SHAPE:
b->changes_shape = atoi(s2);
break;
case CONFIG_ACTIONCLASS:
b->aclass =
FindItem(s2, 0, LIST_FINDBY_NAME, LIST_TYPE_ACLASS);
break;
default:
break;
}
}
}
2004-12-28 15:46:49 -08:00
err = -1;
done:
2004-12-28 15:46:49 -08:00
return err;
}
Border *
BorderCreateFiller(int left, int right, int top, int bottom)
{
Border *b;
ImageClass *ic;
ic = FindItem("__BLACK", 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
b = BorderCreate("__FILLER");
b->throwaway = 1;
b->border.left = left;
b->border.right = right;
b->border.top = top;
b->border.bottom = bottom;
if (top)
BorderWinpartAdd(b, ic, NULL, NULL, NULL, 1, FLAG_BUTTON, 0,
1, 99999, 1, 99999,
-1, 0, 0, 0, 0, -1, 1024, -1, 0, top - 1, 1);
if (bottom)
BorderWinpartAdd(b, ic, NULL, NULL, NULL, 1, FLAG_BUTTON, 0,
1, 99999, 1, 99999,
-1, 0, 0, 1024, -bottom, -1, 1024, -1, 1024, -1, 1);
if (left)
BorderWinpartAdd(b, ic, NULL, NULL, NULL, 1, FLAG_BUTTON, 0,
1, 99999, 1, 99999,
-1, 0, 0, 0, top,
-1, 0, left - 1, 1024, -(bottom + 1), 1);
if (right)
BorderWinpartAdd(b, ic, NULL, NULL, NULL, 1, FLAG_BUTTON, 0,
1, 99999, 1, 99999,
-1, 1024, -right, 0, top,
-1, 1024, -1, 1024, -(bottom + 1), 1);
return b;
}
2004-12-28 15:46:49 -08:00
void
BordersSetupFallback(void)
{
2004-12-28 15:46:49 -08:00
/*
* This function creates simple internal data members to be used in
* emergencies - ie when all else fails - ie a button is told to use an
* imageclass that doesn't exist, or no DEFAULT border is defined... at
* least E won't barf on us then.
*/
Border *b;
ImageClass *ic;
ActionClass *ac;
ac = FindItem("__FALLBACK_ACTION", 0, LIST_FINDBY_NAME, LIST_TYPE_ACLASS);
ic = FindItem("__FALLBACK_ICLASS", 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
/* create a fallback border in case no border is found */
b = BorderCreate("__FALLBACK_BORDER");
AddItem(b, b->name, 0, LIST_TYPE_BORDER);
b->border.left = 8;
b->border.right = 8;
b->border.top = 8;
b->border.bottom = 8;
BorderWinpartAdd(b, ic, ac, NULL, NULL, 1, FLAG_BUTTON, 0, 8, 99999, 8,
99999, -1, 0, 0, 0, 0, -1, 1024, -1, 0, 7, 1);
BorderWinpartAdd(b, ic, ac, NULL, NULL, 1, FLAG_BUTTON, 0, 8, 99999, 8,
99999, -1, 0, 0, 1024, -8, -1, 1024, -1, 1024, -1, 1);
BorderWinpartAdd(b, ic, ac, NULL, NULL, 1, FLAG_BUTTON, 0, 8, 99999, 8,
99999, -1, 0, 0, 0, 8, -1, 0, 7, 1024, -9, 1);
BorderWinpartAdd(b, ic, ac, NULL, NULL, 1, FLAG_BUTTON, 0, 8, 99999, 8,
99999, -1, 1024, -8, 0, 8, -1, 1024, -1, 1024, -9, 1);
}