1326 lines
29 KiB
C
1326 lines
29 KiB
C
/*
|
|
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
|
|
* Copyright (C) 2004-2022 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 "config.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include "E.h"
|
|
#include "backgrounds.h"
|
|
#include "conf.h"
|
|
#include "desktops.h"
|
|
#include "eimage.h"
|
|
#include "emodule.h"
|
|
#include "iclass.h"
|
|
#include "list.h"
|
|
#include "tclass.h"
|
|
#include "xwin.h"
|
|
|
|
#define ENABLE_DESTROY 0 /* Broken */
|
|
|
|
struct _imagestate {
|
|
char *im_file;
|
|
char *real_file;
|
|
char got_colors;
|
|
char unloadable;
|
|
char transparent;
|
|
char pixmapfillstyle;
|
|
char bevelstyle;
|
|
char rotate;
|
|
EImage *im;
|
|
EImageBorder *border;
|
|
unsigned int bg, hi, lo, hihi, lolo;
|
|
unsigned int bg_pixel, hi_pixel, lo_pixel, hihi_pixel, lolo_pixel;
|
|
};
|
|
|
|
typedef struct {
|
|
ImageState *normal;
|
|
ImageState *hilited;
|
|
ImageState *clicked;
|
|
ImageState *disabled;
|
|
} ImageStateArray;
|
|
|
|
struct _imageclass {
|
|
dlist_t list;
|
|
char *name;
|
|
ImageStateArray norm, active, sticky, sticky_active;
|
|
EImageBorder padding;
|
|
unsigned int ref_count;
|
|
};
|
|
|
|
static LIST_HEAD(iclass_list);
|
|
|
|
static ImageClass *ImageclassGetFallback(void);
|
|
|
|
EImage *
|
|
ThemeImageLoad(const char *file)
|
|
{
|
|
EImage *im;
|
|
char *f;
|
|
|
|
if (!file)
|
|
return NULL;
|
|
|
|
if (file[0] == '/')
|
|
{
|
|
im = EImageLoad(file);
|
|
return im;
|
|
}
|
|
|
|
f = ThemeFileFind(file, FILE_TYPE_IMAGE);
|
|
if (f)
|
|
{
|
|
im = EImageLoad(f);
|
|
Efree(f);
|
|
return im;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
ImagestateColorsSetGray(ImageState * is,
|
|
unsigned int hihi, unsigned int hi,
|
|
unsigned int bg, unsigned int lo, unsigned int lolo)
|
|
{
|
|
if (!is)
|
|
return;
|
|
COLOR32_FROM_RGB(is->hihi, hihi, hihi, hihi);
|
|
COLOR32_FROM_RGB(is->hi, hi, hi, hi);
|
|
COLOR32_FROM_RGB(is->bg, bg, bg, bg);
|
|
COLOR32_FROM_RGB(is->lo, lo, lo, lo);
|
|
COLOR32_FROM_RGB(is->lolo, lolo, lolo, lolo);
|
|
}
|
|
|
|
static ImageState *
|
|
ImagestateCreate(const char *file)
|
|
{
|
|
ImageState *is;
|
|
|
|
is = ECALLOC(ImageState, 1);
|
|
if (!is)
|
|
return NULL;
|
|
|
|
is->pixmapfillstyle = FILL_STRETCH;
|
|
ImagestateColorsSetGray(is, 255, 200, 160, 120, 64);
|
|
is->bevelstyle = BEVEL_NONE;
|
|
is->im_file = Estrdup(file);
|
|
|
|
return is;
|
|
}
|
|
|
|
static ImageState *
|
|
ImagestateCreateX(unsigned int hihi, unsigned int hi,
|
|
unsigned int lo, unsigned int lolo,
|
|
unsigned int bg_r, unsigned int bg_g, unsigned int bg_b)
|
|
{
|
|
ImageState *is;
|
|
|
|
is = ImagestateCreate(NULL);
|
|
if (!is)
|
|
return NULL;
|
|
|
|
ImagestateColorsSetGray(is, hihi, hi, 0, lo, lolo);
|
|
COLOR32_FROM_RGB(is->bg, bg_r, bg_g, bg_b);
|
|
is->bevelstyle = BEVEL_AMIGA;
|
|
|
|
return is;
|
|
}
|
|
|
|
static void
|
|
ImagestateDestroy(ImageState * is)
|
|
{
|
|
if (!is)
|
|
return;
|
|
|
|
Efree(is->im_file);
|
|
Efree(is->real_file);
|
|
|
|
if (is->im)
|
|
EImageFree(is->im);
|
|
|
|
Efree(is->border);
|
|
|
|
Efree(is);
|
|
}
|
|
|
|
static ImageState *
|
|
ImagestateSet(ImageState ** isp, const char *name)
|
|
{
|
|
ImageState *is;
|
|
|
|
is = ImagestateCreate(name);
|
|
|
|
if (*isp)
|
|
ImagestateDestroy(*isp);
|
|
*isp = is;
|
|
|
|
return is;
|
|
}
|
|
|
|
static void
|
|
ImagestateColorsAlloc(ImageState * is)
|
|
{
|
|
if (!is || is->got_colors)
|
|
return;
|
|
|
|
is->bg_pixel = EAllocColor(WinGetCmap(VROOT), is->bg);
|
|
is->hi_pixel = EAllocColor(WinGetCmap(VROOT), is->hi);
|
|
is->lo_pixel = EAllocColor(WinGetCmap(VROOT), is->lo);
|
|
is->hihi_pixel = EAllocColor(WinGetCmap(VROOT), is->hihi);
|
|
is->lolo_pixel = EAllocColor(WinGetCmap(VROOT), is->lolo);
|
|
|
|
is->got_colors = 1;
|
|
}
|
|
|
|
static void
|
|
ImagestateRealize(ImageState * is)
|
|
{
|
|
if (!is)
|
|
return;
|
|
if (is->im) /* Image is already loaded */
|
|
return;
|
|
|
|
if (!is->real_file)
|
|
{
|
|
if (!is->im_file)
|
|
return; /* No file - quit */
|
|
/* not loaded, load and setup */
|
|
is->real_file = ThemeFileFind(is->im_file, FILE_TYPE_IMAGE);
|
|
}
|
|
if (is->real_file)
|
|
{
|
|
if (is->rotate && !Conf.memory_paranoia)
|
|
{
|
|
is->im = EImageLoadOrientate(is->real_file, is->rotate);
|
|
}
|
|
else
|
|
{
|
|
is->im = EImageLoad(is->real_file);
|
|
if (is->im && is->rotate)
|
|
EImageOrientate(is->im, is->rotate);
|
|
}
|
|
}
|
|
if (!is->im)
|
|
{
|
|
#define S(s) ((s) ? (s) : "(null)")
|
|
Eprintf
|
|
("%s: Hmmm... is->im is NULL (im_file=%s real_file=%s)\n", __func__,
|
|
S(is->im_file), S(is->real_file));
|
|
EFREE_NULL(is->real_file);
|
|
return;
|
|
}
|
|
|
|
EFREE_NULL(is->im_file);
|
|
|
|
EImageCheckAlpha(is->im);
|
|
|
|
if (is->border)
|
|
EImageSetBorder(is->im, is->border);
|
|
|
|
#if 0 /* To be implemented? */
|
|
if (is->colmod)
|
|
{
|
|
Imlib_set_image_red_curve(pImlib_Context, is->im, is->colmod->red.map);
|
|
Imlib_set_image_green_curve(pImlib_Context, is->im,
|
|
is->colmod->green.map);
|
|
Imlib_set_image_blue_curve(pImlib_Context, is->im,
|
|
is->colmod->blue.map);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static ImageClass *
|
|
ImageclassCreate(const char *name)
|
|
{
|
|
ImageClass *ic;
|
|
|
|
ic = ECALLOC(ImageClass, 1);
|
|
if (!ic)
|
|
return NULL;
|
|
|
|
LIST_PREPEND(ImageClass, &iclass_list, ic);
|
|
|
|
ic->name = Estrdup(name);
|
|
|
|
return ic;
|
|
}
|
|
|
|
#if ENABLE_DESTROY
|
|
static void
|
|
FreeImageStateArray(ImageStateArray * isa)
|
|
{
|
|
ImagestateDestroy(isa->normal);
|
|
ImagestateDestroy(isa->hilited);
|
|
ImagestateDestroy(isa->clicked);
|
|
ImagestateDestroy(isa->disabled);
|
|
}
|
|
|
|
static void
|
|
ImageclassDestroy(ImageClass * ic)
|
|
{
|
|
if (!ic)
|
|
return;
|
|
|
|
if (ic->ref_count > 0)
|
|
{
|
|
DialogOK("ImageClass Error!", _("%u references remain"), ic->ref_count);
|
|
return;
|
|
}
|
|
|
|
LIST_REMOVE(ImageClass, &iclass_list, ic);
|
|
|
|
Efree(ic->name);
|
|
|
|
FreeImageStateArray(&(ic->norm));
|
|
FreeImageStateArray(&(ic->active));
|
|
FreeImageStateArray(&(ic->sticky));
|
|
FreeImageStateArray(&(ic->sticky_active));
|
|
|
|
Efree(ic);
|
|
}
|
|
#endif /* ENABLE_DESTROY */
|
|
|
|
ImageClass *
|
|
ImageclassAlloc(const char *name, int fallback)
|
|
{
|
|
ImageClass *ic;
|
|
|
|
if (!name || !name[0])
|
|
return NULL;
|
|
|
|
ic = ImageclassFind(name, fallback);
|
|
if (ic)
|
|
ic->ref_count++;
|
|
|
|
return ic;
|
|
}
|
|
|
|
void
|
|
ImageclassFree(ImageClass * ic)
|
|
{
|
|
if (ic)
|
|
ic->ref_count--;
|
|
}
|
|
|
|
const char *
|
|
ImageclassGetName(ImageClass * ic)
|
|
{
|
|
return (ic) ? ic->name : NULL;
|
|
}
|
|
|
|
EImageBorder *
|
|
ImageclassGetPadding(ImageClass * ic)
|
|
{
|
|
return (ic) ? &(ic->padding) : NULL;
|
|
}
|
|
|
|
static int
|
|
_ImageclassMatchName(const void *data, const void *match)
|
|
{
|
|
return strcmp(((const ImageClass *)data)->name, (const char *)match);
|
|
}
|
|
|
|
ImageClass *
|
|
ImageclassFind(const char *name, int fallback)
|
|
{
|
|
ImageClass *ic = NULL;
|
|
|
|
if (name)
|
|
ic = LIST_FIND(ImageClass, &iclass_list, _ImageclassMatchName, name);
|
|
if (ic || !fallback)
|
|
return ic;
|
|
|
|
#if 0
|
|
Eprintf("%s: Get fallback (%s)\n", __func__, name);
|
|
#endif
|
|
return ImageclassGetFallback();
|
|
}
|
|
|
|
#define ISTATE_SET_STATE(which, fallback) \
|
|
if (!ic->which) ic->which = ic->fallback;
|
|
|
|
static void
|
|
ImageclassPopulate(ImageClass * ic)
|
|
{
|
|
if (!ic || !ic->norm.normal)
|
|
return;
|
|
|
|
ISTATE_SET_STATE(norm.hilited, norm.normal);
|
|
ISTATE_SET_STATE(norm.clicked, norm.normal);
|
|
ISTATE_SET_STATE(norm.disabled, norm.normal);
|
|
|
|
ISTATE_SET_STATE(active.normal, norm.normal);
|
|
ISTATE_SET_STATE(active.hilited, active.normal);
|
|
ISTATE_SET_STATE(active.clicked, active.normal);
|
|
ISTATE_SET_STATE(active.disabled, active.normal);
|
|
|
|
ISTATE_SET_STATE(sticky.normal, norm.normal);
|
|
ISTATE_SET_STATE(sticky.hilited, sticky.normal);
|
|
ISTATE_SET_STATE(sticky.clicked, sticky.normal);
|
|
ISTATE_SET_STATE(sticky.disabled, sticky.normal);
|
|
|
|
ISTATE_SET_STATE(sticky_active.normal, norm.normal);
|
|
ISTATE_SET_STATE(sticky_active.hilited, sticky_active.normal);
|
|
ISTATE_SET_STATE(sticky_active.clicked, sticky_active.normal);
|
|
ISTATE_SET_STATE(sticky_active.disabled, sticky_active.normal);
|
|
}
|
|
|
|
int
|
|
ImageclassConfigLoad(FILE * fs)
|
|
{
|
|
int err = 0;
|
|
char s[FILEPATH_LEN_MAX];
|
|
char s2[FILEPATH_LEN_MAX];
|
|
char *p2;
|
|
int i1;
|
|
ImageClass *ic = NULL;
|
|
ImageState *is = NULL;
|
|
int l, r, t, b;
|
|
|
|
while (GetLine(s, sizeof(s), fs))
|
|
{
|
|
i1 = ConfigParseline1(s, s2, &p2, NULL);
|
|
|
|
/* ic not needed */
|
|
switch (i1)
|
|
{
|
|
case CONFIG_CLOSE:
|
|
ImageclassPopulate(ic);
|
|
goto done;
|
|
case CONFIG_COLORMOD:
|
|
case ICLASS_COLORMOD:
|
|
continue;
|
|
case CONFIG_CLASSNAME:
|
|
if (ImageclassFind(s2, 0))
|
|
{
|
|
SkipTillEnd(fs);
|
|
goto done;
|
|
}
|
|
ic = ImageclassCreate(s2);
|
|
continue;
|
|
}
|
|
|
|
/* ic needed */
|
|
if (!ic)
|
|
break;
|
|
|
|
switch (i1)
|
|
{
|
|
case CONFIG_INHERIT:
|
|
{
|
|
ImageClass *ic2;
|
|
|
|
ic2 = ImageclassFind(s2, 0);
|
|
if (!ic2)
|
|
goto not_ok;
|
|
ic->norm = ic2->norm;
|
|
ic->active = ic2->active;
|
|
ic->sticky = ic2->sticky;
|
|
ic->sticky_active = ic2->sticky_active;
|
|
ic->padding = ic2->padding;
|
|
}
|
|
continue;
|
|
case ICLASS_PADDING:
|
|
l = r = t = b = 0;
|
|
sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
|
|
ic->padding.left = l;
|
|
ic->padding.right = r;
|
|
ic->padding.top = t;
|
|
ic->padding.bottom = b;
|
|
continue;
|
|
case CONFIG_DESKTOP:
|
|
/* don't ask... --mandrake */
|
|
case ICLASS_NORMAL:
|
|
is = ImagestateSet(&ic->norm.normal, s2);
|
|
continue;
|
|
case ICLASS_CLICKED:
|
|
is = ImagestateSet(&ic->norm.clicked, s2);
|
|
continue;
|
|
case ICLASS_HILITED:
|
|
is = ImagestateSet(&ic->norm.hilited, s2);
|
|
continue;
|
|
case ICLASS_DISABLED:
|
|
is = ImagestateSet(&ic->norm.disabled, s2);
|
|
continue;
|
|
case ICLASS_STICKY_NORMAL:
|
|
is = ImagestateSet(&ic->sticky.normal, s2);
|
|
continue;
|
|
case ICLASS_STICKY_CLICKED:
|
|
is = ImagestateSet(&ic->sticky.clicked, s2);
|
|
continue;
|
|
case ICLASS_STICKY_HILITED:
|
|
is = ImagestateSet(&ic->sticky.hilited, s2);
|
|
continue;
|
|
case ICLASS_STICKY_DISABLED:
|
|
is = ImagestateSet(&ic->sticky.disabled, s2);
|
|
continue;
|
|
case ICLASS_ACTIVE_NORMAL:
|
|
is = ImagestateSet(&ic->active.normal, s2);
|
|
continue;
|
|
case ICLASS_ACTIVE_CLICKED:
|
|
is = ImagestateSet(&ic->active.clicked, s2);
|
|
continue;
|
|
case ICLASS_ACTIVE_HILITED:
|
|
is = ImagestateSet(&ic->active.hilited, s2);
|
|
continue;
|
|
case ICLASS_ACTIVE_DISABLED:
|
|
is = ImagestateSet(&ic->active.disabled, s2);
|
|
continue;
|
|
case ICLASS_STICKY_ACTIVE_NORMAL:
|
|
is = ImagestateSet(&ic->sticky_active.normal, s2);
|
|
continue;
|
|
case ICLASS_STICKY_ACTIVE_CLICKED:
|
|
is = ImagestateSet(&ic->sticky_active.clicked, s2);
|
|
continue;
|
|
case ICLASS_STICKY_ACTIVE_HILITED:
|
|
is = ImagestateSet(&ic->sticky_active.hilited, s2);
|
|
continue;
|
|
case ICLASS_STICKY_ACTIVE_DISABLED:
|
|
is = ImagestateSet(&ic->sticky_active.disabled, s2);
|
|
continue;
|
|
}
|
|
|
|
/* is needed */
|
|
if (!is)
|
|
break;
|
|
|
|
switch (i1)
|
|
{
|
|
case ICLASS_LRTB:
|
|
if (!is->border)
|
|
is->border = EMALLOC(EImageBorder, 1);
|
|
l = r = t = b = 0;
|
|
sscanf(p2, "%i %i %i %i", &l, &r, &t, &b);
|
|
is->border->left = l;
|
|
is->border->right = r;
|
|
is->border->top = t;
|
|
is->border->bottom = b;
|
|
/* Hmmm... imlib2 works better with this */
|
|
is->border->right++;
|
|
is->border->bottom++;
|
|
continue;
|
|
case ICLASS_FILLRULE:
|
|
is->pixmapfillstyle = atoi(s2);
|
|
continue;
|
|
case ICLASS_TRANSPARENT:
|
|
is->transparent = strtoul(s2, NULL, 0);
|
|
continue;
|
|
case ICLASS_ROTATE: /* flip goes here too */
|
|
is->rotate = strtoul(s2, NULL, 0);
|
|
continue;
|
|
case ICLASS_BEVEL:
|
|
{
|
|
int n, bevel;
|
|
|
|
n = sscanf(p2, "%i %i %i %i %i %i",
|
|
&bevel, &is->hihi, &is->hi, &is->bg, &is->lo,
|
|
&is->lolo);
|
|
if (n < 6)
|
|
goto not_ok;
|
|
is->bevelstyle = bevel;
|
|
}
|
|
continue;
|
|
default:
|
|
goto not_ok;
|
|
}
|
|
}
|
|
not_ok:
|
|
err = -1;
|
|
|
|
done:
|
|
return err;
|
|
}
|
|
|
|
ImageClass *
|
|
ImageclassCreateSimple(const char *name, const char *image)
|
|
{
|
|
ImageClass *ic;
|
|
|
|
ic = ImageclassCreate(name);
|
|
if (!ic)
|
|
return NULL;
|
|
|
|
ic->norm.normal = ImagestateCreate(image);
|
|
ic->norm.normal->unloadable = 1;
|
|
ImageclassPopulate(ic);
|
|
|
|
ImagestateRealize(ic->norm.normal);
|
|
|
|
return ic;
|
|
}
|
|
|
|
static ImageState *
|
|
ImageclassGetImageState1(ImageStateArray * pisa, int state)
|
|
{
|
|
ImageState *is;
|
|
|
|
switch (state)
|
|
{
|
|
case STATE_NORMAL:
|
|
is = pisa->normal;
|
|
break;
|
|
case STATE_HILITED:
|
|
is = pisa->hilited;
|
|
break;
|
|
case STATE_CLICKED:
|
|
is = pisa->clicked;
|
|
break;
|
|
case STATE_DISABLED:
|
|
is = pisa->disabled;
|
|
break;
|
|
default:
|
|
is = NULL;
|
|
break;
|
|
}
|
|
|
|
return is;
|
|
}
|
|
|
|
ImageState *
|
|
ImageclassGetImageState(ImageClass * ic, int state, int active, int sticky)
|
|
{
|
|
ImageState *is;
|
|
|
|
if (active)
|
|
{
|
|
if (sticky)
|
|
is = ImageclassGetImageState1(&ic->sticky_active, state);
|
|
else
|
|
is = ImageclassGetImageState1(&ic->active, state);
|
|
}
|
|
else
|
|
{
|
|
if (sticky)
|
|
is = ImageclassGetImageState1(&ic->sticky, state);
|
|
else
|
|
is = ImageclassGetImageState1(&ic->norm, state);
|
|
}
|
|
|
|
return is;
|
|
}
|
|
|
|
EImage *
|
|
ImageclassGetImage(ImageClass * ic, int active, int sticky, int state)
|
|
{
|
|
EImage *im;
|
|
ImageState *is;
|
|
|
|
if (!ic)
|
|
return NULL;
|
|
|
|
is = ImageclassGetImageState(ic, state, active, sticky);
|
|
if (!is)
|
|
return NULL;
|
|
|
|
if (!is->im)
|
|
ImagestateRealize(is);
|
|
|
|
im = is->im;
|
|
if (!im)
|
|
return NULL;
|
|
is->im = NULL;
|
|
|
|
return im;
|
|
}
|
|
|
|
char *
|
|
ImageclassGetFile(ImageClass * ic)
|
|
{
|
|
ImageState *is;
|
|
|
|
if (!ic)
|
|
return NULL;
|
|
|
|
is = ImageclassGetImageState(ic, STATE_NORMAL, 0, 0);
|
|
if (!is || !is->im_file)
|
|
return NULL;
|
|
|
|
return ThemeFileFind(is->im_file, FILE_TYPE_IMAGE);
|
|
}
|
|
|
|
EImage *
|
|
ImageclassGetImageBlended(ImageClass * ic, Win win __UNUSED__, int w, int h,
|
|
int active, int sticky, int state)
|
|
{
|
|
ImageState *is;
|
|
EImage *im, *bg;
|
|
|
|
if (!ic)
|
|
return NULL;
|
|
|
|
is = ImageclassGetImageState(ic, state, active, sticky);
|
|
if (!is)
|
|
return NULL;
|
|
|
|
if (!is->im)
|
|
ImagestateRealize(is);
|
|
im = is->im;
|
|
if (!im)
|
|
return NULL;
|
|
|
|
if (is->pixmapfillstyle == FILL_STRETCH)
|
|
{
|
|
bg = EImageCreateScaled(im, 0, 0, 0, 0, w, h);
|
|
}
|
|
else
|
|
{
|
|
int iw, ih, tw, th;
|
|
|
|
EImageGetSize(im, &iw, &ih);
|
|
|
|
tw = w;
|
|
th = h;
|
|
if (is->pixmapfillstyle & FILL_TILE_H)
|
|
tw = iw;
|
|
if (is->pixmapfillstyle & FILL_TILE_V)
|
|
th = ih;
|
|
|
|
bg = EImageCreate(w, h);
|
|
EImageTile(bg, im, 0, tw, th, 0, 0, w, h, 0, 0);
|
|
}
|
|
|
|
if ((is->unloadable) || (Conf.memory_paranoia))
|
|
{
|
|
EImageFree(is->im);
|
|
is->im = NULL;
|
|
}
|
|
|
|
return bg;
|
|
}
|
|
|
|
static void
|
|
ImagestateMakePmapMask(ImageState * is, Win win, PmapMask * pmm,
|
|
int pmapflags __UNUSED__, int w, int h)
|
|
{
|
|
if (is->pixmapfillstyle == FILL_STRETCH)
|
|
{
|
|
pmm->type = 1;
|
|
pmm->pmap = pmm->mask = NoXID;
|
|
pmm->w = w;
|
|
pmm->h = h;
|
|
EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
|
|
&pmm->mask, w, h);
|
|
}
|
|
else
|
|
{
|
|
int ww, hh, cw, ch, pw, ph;
|
|
|
|
EImageGetSize(is->im, &ww, &hh);
|
|
|
|
pw = w;
|
|
ph = h;
|
|
if (is->pixmapfillstyle & FILL_TILE_H)
|
|
pw = ww;
|
|
if (is->pixmapfillstyle & FILL_TILE_V)
|
|
ph = hh;
|
|
if (is->pixmapfillstyle & FILL_INT_TILE_H)
|
|
{
|
|
cw = w / ww;
|
|
if (cw * ww < w)
|
|
cw++;
|
|
if (cw < 1)
|
|
cw = 1;
|
|
pw = w / cw;
|
|
}
|
|
if (is->pixmapfillstyle & FILL_INT_TILE_V)
|
|
{
|
|
ch = h / hh;
|
|
if (ch * hh < h)
|
|
ch++;
|
|
if (ch < 1)
|
|
ch = 1;
|
|
ph = h / ch;
|
|
}
|
|
pmm->type = 1;
|
|
pmm->pmap = pmm->mask = NoXID;
|
|
pmm->w = pw;
|
|
pmm->h = ph;
|
|
EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap,
|
|
&pmm->mask, pw, ph);
|
|
}
|
|
}
|
|
|
|
#define LINE(x1, y1, x2, y2) \
|
|
XDrawLine(disp, win, gc, x + (x1), y + (y1), x + (x2), y + (y2))
|
|
#define RECT(x, y, w, h) \
|
|
XDrawRectangle(disp, win, gc, x, y, w, h);
|
|
|
|
static void
|
|
ImagestateDrawBevel(ImageState * is, EX_Drawable win,
|
|
int x, int y, int w, int h)
|
|
{
|
|
GC gc;
|
|
|
|
gc = EXCreateGC(win, 0, NULL);
|
|
|
|
ImagestateColorsAlloc(is);
|
|
|
|
switch (is->bevelstyle)
|
|
{
|
|
case BEVEL_AMIGA:
|
|
XSetForeground(disp, gc, is->hihi_pixel);
|
|
LINE(0, 0, w - 2, 0);
|
|
LINE(0, 0, 0, h - 2);
|
|
XSetForeground(disp, gc, is->lolo_pixel);
|
|
LINE(1, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
break;
|
|
case BEVEL_MOTIF:
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(0, 0, w - 1, 0);
|
|
LINE(0, 0, 0, h - 1);
|
|
LINE(1, 1, w - 2, 1);
|
|
LINE(1, 1, 1, h - 2);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(0, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
LINE(1, h - 2, w - 2, h - 2);
|
|
LINE(w - 2, 2, w - 2, h - 2);
|
|
break;
|
|
case BEVEL_NEXT:
|
|
XSetForeground(disp, gc, is->hihi_pixel);
|
|
LINE(0, 0, w - 1, 0);
|
|
LINE(0, 0, 0, h - 1);
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(1, 1, w - 2, 1);
|
|
LINE(1, 1, 1, h - 2);
|
|
XSetForeground(disp, gc, is->lolo_pixel);
|
|
LINE(1, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(2, h - 2, w - 2, h - 2);
|
|
LINE(w - 2, 2, w - 2, h - 2);
|
|
break;
|
|
case BEVEL_DOUBLE:
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(0, 0, w - 2, 0);
|
|
LINE(0, 0, 0, h - 2);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(1, 1, w - 3, 1);
|
|
LINE(1, 1, 1, h - 3);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(1, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(2, h - 2, w - 2, h - 2);
|
|
LINE(w - 2, 2, w - 2, h - 2);
|
|
break;
|
|
case BEVEL_WIDEDOUBLE:
|
|
XSetForeground(disp, gc, is->hihi_pixel);
|
|
LINE(0, 0, w - 1, 0);
|
|
LINE(0, 0, 0, h - 1);
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(1, 1, w - 2, 1);
|
|
LINE(1, 1, 1, h - 2);
|
|
LINE(3, h - 4, w - 4, h - 4);
|
|
LINE(w - 4, 3, w - 4, h - 4);
|
|
XSetForeground(disp, gc, is->lolo_pixel);
|
|
LINE(1, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(2, h - 2, w - 2, h - 2);
|
|
LINE(w - 2, 2, w - 2, h - 2);
|
|
LINE(3, 3, w - 4, 3);
|
|
LINE(3, 3, 3, h - 4);
|
|
break;
|
|
case BEVEL_THINPOINT:
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
LINE(0, 0, w - 2, 0);
|
|
LINE(0, 0, 0, h - 2);
|
|
XSetForeground(disp, gc, is->lo_pixel);
|
|
LINE(1, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, 1, w - 1, h - 1);
|
|
XSetForeground(disp, gc, is->hihi_pixel);
|
|
LINE(0, 0, 1, 0);
|
|
LINE(0, 0, 0, 1);
|
|
XSetForeground(disp, gc, is->lolo_pixel);
|
|
LINE(w - 2, h - 1, w - 1, h - 1);
|
|
LINE(w - 1, h - 2, w - 1, h - 1);
|
|
break;
|
|
case BEVEL_THICKPOINT:
|
|
XSetForeground(disp, gc, is->hi_pixel);
|
|
RECT(x, y, w - 1, h - 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
EXFreeGC(gc);
|
|
}
|
|
|
|
static void
|
|
ImagestateDrawNoImg(ImageState * is, EX_Drawable draw, int x, int y, int w,
|
|
int h)
|
|
{
|
|
ImagestateColorsAlloc(is);
|
|
|
|
EXFillAreaSolid(draw, x, y, w, h, is->bg_pixel);
|
|
if (is->bevelstyle != BEVEL_NONE)
|
|
ImagestateDrawBevel(is, draw, x, y, w, h);
|
|
}
|
|
|
|
void
|
|
ITApply(Win win, ImageClass * ic, ImageState * is,
|
|
int state, int active, int sticky,
|
|
TextClass * tc, TextState * ts, const char *text, int flags)
|
|
{
|
|
int w, h;
|
|
|
|
if (!win || !ic)
|
|
return;
|
|
|
|
w = WinGetW(win);
|
|
h = WinGetH(win);
|
|
if (w <= 0 || h <= 0)
|
|
return;
|
|
|
|
if (!is)
|
|
is = ImageclassGetImageState(ic, state, active, sticky);
|
|
if (!is)
|
|
return;
|
|
|
|
if (tc && text)
|
|
{
|
|
if (!ts)
|
|
ts = TextclassGetTextState(tc, state, active, sticky);
|
|
}
|
|
|
|
if (!is->im)
|
|
ImagestateRealize(is);
|
|
|
|
/* Imlib2 will not render pixmaps with dimensions > 8192 */
|
|
if (is->im && w <= 8192 && h <= 8192)
|
|
{
|
|
PmapMask pmm;
|
|
|
|
ImagestateMakePmapMask(is, win, &pmm, IC_FLAG_MAKE_MASK, w, h);
|
|
|
|
if (pmm.pmap)
|
|
{
|
|
EX_Pixmap pmap = pmm.pmap;
|
|
|
|
if ((ts && text) || (is->bevelstyle != BEVEL_NONE) ||
|
|
(flags & ITA_BGPMAP))
|
|
{
|
|
if (pmm.type != 0)
|
|
{
|
|
pmap = EGetWindowBackgroundPixmap(win);
|
|
EXCopyAreaTiled(pmm.pmap, NoXID, pmap, 0, 0, w, h, 0, 0);
|
|
}
|
|
|
|
if (is->bevelstyle != BEVEL_NONE)
|
|
ImagestateDrawBevel(is, pmap, 0, 0, w, h);
|
|
|
|
if (ts && text)
|
|
TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
|
|
&(ic->padding), 0,
|
|
TextclassGetJustification(tc),
|
|
flags & ITA_JUSTV);
|
|
}
|
|
|
|
/* Set window pixmap */
|
|
if (pmap == pmm.pmap)
|
|
ESetWindowBackgroundPixmap(win, pmap, 0);
|
|
|
|
if (pmm.w == w && pmm.h == h)
|
|
EShapeSetMask(win, 0, 0, pmm.mask);
|
|
else if (pmm.mask)
|
|
EShapeSetMaskTiled(win, 0, 0, pmm.mask, w, h);
|
|
}
|
|
|
|
PmapMaskFree(&pmm);
|
|
|
|
if ((is->unloadable) || (Conf.memory_paranoia))
|
|
{
|
|
EImageFree(is->im);
|
|
is->im = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ImagestateColorsAlloc(is);
|
|
|
|
if (is->bevelstyle == BEVEL_NONE && !text)
|
|
{
|
|
ESetWindowBackground(win, is->bg_pixel);
|
|
}
|
|
else
|
|
{
|
|
EX_Pixmap pmap;
|
|
|
|
pmap = EGetWindowBackgroundPixmap(win);
|
|
ImagestateDrawNoImg(is, pmap, 0, 0, w, h);
|
|
if (ts && text)
|
|
TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h,
|
|
&(ic->padding), 0,
|
|
TextclassGetJustification(tc),
|
|
flags & ITA_JUSTV);
|
|
}
|
|
}
|
|
EClearWindow(win);
|
|
}
|
|
|
|
void
|
|
ImageclassApply(ImageClass * ic, Win win, int active, int sticky, int state)
|
|
{
|
|
ITApply(win, ic, NULL, state, active, sticky, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
static void
|
|
PmapMaskTile(PmapMask * pmm, Win win, unsigned int w, unsigned int h)
|
|
{
|
|
EX_Pixmap pmap, mask;
|
|
|
|
pmap = ECreatePixmap(win, w, h, 0);
|
|
if (pmap == NoXID)
|
|
return;
|
|
EXCopyAreaTiled(pmm->pmap, NoXID, pmap, 0, 0, w, h, 0, 0);
|
|
|
|
mask = NoXID;
|
|
if (pmm->mask != NoXID)
|
|
mask = ECreatePixmap(win, w, h, 1);
|
|
if (mask != NoXID)
|
|
EXCopyAreaTiled(pmm->mask, NoXID, mask, 0, 0, w, h, 0, 0);
|
|
|
|
PmapMaskFree(pmm);
|
|
pmm->type = 0;
|
|
pmm->w = w;
|
|
pmm->h = h;
|
|
pmm->pmap = pmap;
|
|
pmm->mask = mask;
|
|
}
|
|
|
|
void
|
|
ImageclassApplyCopy(ImageClass * ic, Win win, int w, int h,
|
|
int active, int sticky, int state,
|
|
PmapMask * pmm, int pmapflags)
|
|
{
|
|
ImageState *is;
|
|
|
|
if (!pmm)
|
|
return;
|
|
|
|
pmm->type = 0;
|
|
pmm->pmap = pmm->mask = 0;
|
|
|
|
if ((!ic) || (!win) || (w <= 0) || (h <= 0))
|
|
return;
|
|
|
|
is = ImageclassGetImageState(ic, state, active, sticky);
|
|
if (!is)
|
|
return;
|
|
|
|
if (!is->im)
|
|
ImagestateRealize(is);
|
|
|
|
/* Imlib2 will not render pixmaps with dimensions > 8192 */
|
|
if (is->im && w <= 8192 && h <= 8192)
|
|
{
|
|
ImagestateMakePmapMask(is, win, pmm, pmapflags, w, h);
|
|
|
|
if ((pmapflags & IC_FLAG_FULL_SIZE) && pmm->pmap &&
|
|
(pmm->w != w || pmm->h != h))
|
|
{
|
|
/* Create new full sized pixmaps and fill them with the */
|
|
/* pmap and mask tiles */
|
|
PmapMaskTile(pmm, win, w, h);
|
|
}
|
|
|
|
if ((is->unloadable) || (Conf.memory_paranoia))
|
|
{
|
|
EImageFree(is->im);
|
|
is->im = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pmm->pmap)
|
|
Eprintf("%s: Hmm... pmm->pmap already set\n", __func__);
|
|
|
|
pmm->type = 0;
|
|
pmm->pmap = ECreatePixmap(win, w, h, 0);
|
|
pmm->mask = 0;
|
|
|
|
ImagestateDrawNoImg(is, pmm->pmap, 0, 0, w, h);
|
|
/* FIXME - No text */
|
|
}
|
|
}
|
|
|
|
void
|
|
ImageclassApplySimple(ImageClass * ic, Win win, EX_Drawable draw, int state,
|
|
int x, int y, int w, int h)
|
|
{
|
|
EImage *im;
|
|
|
|
if (!ic)
|
|
return;
|
|
|
|
im = ImageclassGetImage(ic, 0, 0, state);
|
|
if (im)
|
|
{
|
|
EImageRenderOnDrawable(im, win, draw, 0, x, y, w, h);
|
|
EImageFree(im);
|
|
}
|
|
else
|
|
{
|
|
ImageState *is;
|
|
|
|
is = ImageclassGetImageState(ic, state, 0, 0);
|
|
if (!is)
|
|
return;
|
|
|
|
ImagestateDrawNoImg(is, draw, x, y, w, h);
|
|
}
|
|
}
|
|
|
|
static ImageClass *
|
|
ImageclassGetFallback(void)
|
|
{
|
|
ImageClass *ic;
|
|
|
|
ic = ImageclassFind("__fb_ic", 0);
|
|
if (ic)
|
|
return ic;
|
|
|
|
/* Create fallback imageclass */
|
|
ic = ImageclassCreate("__fb_ic");
|
|
if (!ic)
|
|
return ic;
|
|
|
|
ic->norm.normal = ImagestateCreateX(255, 255, 0, 0, 160, 160, 160);
|
|
ic->norm.hilited = ImagestateCreateX(255, 255, 0, 0, 192, 192, 192);
|
|
ic->norm.clicked = ImagestateCreateX(0, 0, 255, 255, 192, 192, 192);
|
|
ic->active.normal = ImagestateCreateX(255, 255, 0, 0, 180, 140, 160);
|
|
ic->active.hilited = ImagestateCreateX(255, 255, 0, 0, 230, 190, 210);
|
|
ic->active.clicked = ImagestateCreateX(0, 0, 255, 255, 230, 190, 210);
|
|
|
|
ic->padding.left = 4;
|
|
ic->padding.right = 4;
|
|
ic->padding.top = 4;
|
|
ic->padding.bottom = 4;
|
|
|
|
ImageclassPopulate(ic);
|
|
|
|
return ic;
|
|
}
|
|
|
|
ImageClass *
|
|
ImageclassGetBlack(void)
|
|
{
|
|
ImageClass *ic;
|
|
|
|
ic = ImageclassFind("__BLACK", 0);
|
|
if (ic)
|
|
return ic;
|
|
|
|
/* Create all black image class for filler borders */
|
|
ic = ImageclassCreate("__BLACK");
|
|
if (!ic)
|
|
return ic;
|
|
|
|
ic->norm.normal = ImagestateCreate(NULL);
|
|
ImagestateColorsSetGray(ic->norm.normal, 0, 0, 0, 0, 0);
|
|
|
|
ImageclassPopulate(ic);
|
|
|
|
return ic;
|
|
}
|
|
|
|
/*
|
|
* Imageclass Module
|
|
*/
|
|
|
|
static void
|
|
ImageclassIpc(const char *params)
|
|
{
|
|
char param1[1024];
|
|
char param2[1024];
|
|
int l;
|
|
const char *p;
|
|
ImageClass *ic;
|
|
|
|
if (!params)
|
|
{
|
|
IpcPrintf("Please specify...\n");
|
|
return;
|
|
}
|
|
|
|
p = params;
|
|
l = 0;
|
|
param1[0] = param2[0] = '\0';
|
|
sscanf(p, "%1000s %1000s %n", param1, param2, &l);
|
|
p += l;
|
|
|
|
if (!strncmp(param1, "list", 2))
|
|
{
|
|
LIST_FOR_EACH(ImageClass, &iclass_list, ic) IpcPrintf("%s\n", ic->name);
|
|
return;
|
|
}
|
|
|
|
if (!param1[0])
|
|
{
|
|
IpcPrintf("ImageClass not specified\n");
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(param2, "free_pixmap"))
|
|
{
|
|
EX_Pixmap pmap;
|
|
|
|
pmap = (EX_Pixmap) strtol(p, NULL, 0);
|
|
EImagePixmapsFree(pmap, NoXID);
|
|
return;
|
|
}
|
|
|
|
ic = ImageclassFind(param1, 0);
|
|
if (!ic)
|
|
{
|
|
IpcPrintf("ImageClass not found: %s\n", param1);
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(param2, "get_padding"))
|
|
{
|
|
IpcPrintf("%i %i %i %i\n",
|
|
ic->padding.left, ic->padding.right,
|
|
ic->padding.top, ic->padding.bottom);
|
|
}
|
|
else if (!strcmp(param2, "get_image_size"))
|
|
{
|
|
ImagestateRealize(ic->norm.normal);
|
|
if (ic->norm.normal->im)
|
|
{
|
|
int w, h;
|
|
|
|
EImageGetSize(ic->norm.normal->im, &w, &h);
|
|
EImageFree(ic->norm.normal->im);
|
|
IpcPrintf("%i %i\n", w, h);
|
|
}
|
|
}
|
|
else if (!strcmp(param2, "apply"))
|
|
{
|
|
EX_Window xwin;
|
|
Win win;
|
|
char state[20];
|
|
int st, w, h;
|
|
|
|
/* 3:xwin 4:state 5:w 6:h */
|
|
xwin = NoXID;
|
|
state[0] = '\0';
|
|
w = h = -1;
|
|
sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h);
|
|
|
|
win = ECreateWinFromXwin(xwin);
|
|
if (!win)
|
|
return;
|
|
|
|
if (!strcmp(state, "normal"))
|
|
st = STATE_NORMAL;
|
|
else if (!strcmp(state, "hilited"))
|
|
st = STATE_HILITED;
|
|
else if (!strcmp(state, "clicked"))
|
|
st = STATE_CLICKED;
|
|
else if (!strcmp(state, "disabled"))
|
|
st = STATE_DISABLED;
|
|
else
|
|
st = STATE_NORMAL;
|
|
|
|
ImageclassApply(ic, win, 0, 0, st);
|
|
EDestroyWin(win);
|
|
}
|
|
else if (!strcmp(param2, "apply_copy"))
|
|
{
|
|
EX_Window xwin;
|
|
Win win;
|
|
char state[20];
|
|
int st, w, h;
|
|
PmapMask pmm;
|
|
|
|
/* 3:xwin 4:state 5:w 6:h */
|
|
xwin = NoXID;
|
|
state[0] = '\0';
|
|
w = h = -1;
|
|
sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h);
|
|
|
|
win = ECreateWinFromXwin(xwin);
|
|
if (!win)
|
|
return;
|
|
|
|
if (!strcmp(state, "normal"))
|
|
st = STATE_NORMAL;
|
|
else if (!strcmp(state, "hilited"))
|
|
st = STATE_HILITED;
|
|
else if (!strcmp(state, "clicked"))
|
|
st = STATE_CLICKED;
|
|
else if (!strcmp(state, "disabled"))
|
|
st = STATE_DISABLED;
|
|
else
|
|
st = STATE_NORMAL;
|
|
|
|
if (w < 0 || h < 0)
|
|
{
|
|
IpcPrintf("Error: missing width and/or height\n");
|
|
return;
|
|
}
|
|
|
|
ImageclassApplyCopy(ic, win, w, h, 0, 0, st, &pmm,
|
|
IC_FLAG_MAKE_MASK | IC_FLAG_FULL_SIZE);
|
|
IpcPrintf("0x%08x 0x%08x\n", pmm.pmap, pmm.mask);
|
|
EDestroyWin(win);
|
|
}
|
|
else if (!strcmp(param2, "query"))
|
|
{
|
|
IpcPrintf("ImageClass %s found\n", ic->name);
|
|
}
|
|
else if (!strcmp(param2, "ref_count"))
|
|
{
|
|
IpcPrintf("%u references remain\n", ic->ref_count);
|
|
}
|
|
else
|
|
{
|
|
IpcPrintf("Error: unknown operation specified\n");
|
|
}
|
|
}
|
|
|
|
static const IpcItem ImageclassIpcArray[] = {
|
|
{
|
|
ImageclassIpc,
|
|
"imageclass", "ic",
|
|
"List imageclasses, apply an imageclass",
|
|
NULL}
|
|
,
|
|
};
|
|
|
|
/*
|
|
* Module descriptor
|
|
*/
|
|
extern const EModule ModImageclass;
|
|
|
|
const EModule ModImageclass = {
|
|
"imageclass", "ic",
|
|
NULL,
|
|
MOD_ITEMS(ImageclassIpcArray),
|
|
{0, NULL}
|
|
};
|