e16/src/tclass.c

653 lines
16 KiB
C

/*
* Copyright (C) 2000-2005 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2005 Kim Woelders
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "E.h"
#include "conf.h"
static char *
TextstateFontLookup(const char *name)
{
const char *font;
if (*name == '*')
{
font = FontLookup(name + 1);
if (font)
name = font;
}
return Estrdup(name);
}
static TextState *
TextstateCreate(void)
{
TextState *ts;
ts = Ecalloc(1, sizeof(TextState));
if (!ts)
return NULL;
ts->fontname = NULL;
ts->style.mode = MODE_WRAP_CHAR;
ts->style.orientation = FONT_TO_RIGHT;
ts->efont = NULL;
ts->xfont = NULL;
ts->xfontset = 0;
return ts;
}
static void
TextStateDestroy(TextState * ts)
{
if (ts->fontname)
Efree(ts->fontname);
if (ts->xfont)
XFreeFont(disp, ts->xfont);
if (ts->efont)
Efont_free(ts->efont);
Efree(ts);
}
static TextClass *
TextclassCreate(const char *name)
{
TextClass *tc;
tc = Ecalloc(1, sizeof(TextClass));
if (!tc)
return NULL;
tc->name = Estrdup(name);
tc->justification = 512;
return tc;
}
static void
TextclassDestroy(TextClass * tc)
{
if (tc->ref_count > 0)
{
DialogOK(_("Textclass Error!"), _("%u references remain\n"),
tc->ref_count);
return;
}
if (tc->name)
Efree(tc->name);
if (tc->norm.normal)
TextStateDestroy(tc->norm.normal);
if (tc->norm.hilited)
TextStateDestroy(tc->norm.hilited);
if (tc->norm.clicked)
TextStateDestroy(tc->norm.clicked);
if (tc->norm.disabled)
TextStateDestroy(tc->norm.disabled);
if (tc->active.normal)
TextStateDestroy(tc->active.normal);
if (tc->active.hilited)
TextStateDestroy(tc->active.hilited);
if (tc->active.clicked)
TextStateDestroy(tc->active.clicked);
if (tc->active.disabled)
TextStateDestroy(tc->active.disabled);
if (tc->sticky.normal)
TextStateDestroy(tc->sticky.normal);
if (tc->sticky.hilited)
TextStateDestroy(tc->sticky.hilited);
if (tc->sticky.clicked)
TextStateDestroy(tc->sticky.clicked);
if (tc->sticky.disabled)
TextStateDestroy(tc->sticky.disabled);
if (tc->sticky_active.normal)
TextStateDestroy(tc->sticky_active.normal);
if (tc->sticky_active.hilited)
TextStateDestroy(tc->sticky_active.hilited);
if (tc->sticky_active.clicked)
TextStateDestroy(tc->sticky_active.clicked);
if (tc->sticky_active.disabled)
TextStateDestroy(tc->sticky_active.disabled);
Efree(tc);
}
static void
TextclassPopulate(TextClass * tclass)
{
if (!tclass)
return;
if (!tclass->norm.normal)
return;
if (!tclass->norm.hilited)
tclass->norm.hilited = tclass->norm.normal;
if (!tclass->norm.clicked)
tclass->norm.clicked = tclass->norm.normal;
if (!tclass->norm.disabled)
tclass->norm.disabled = tclass->norm.normal;
if (!tclass->active.normal)
tclass->active.normal = tclass->norm.normal;
if (!tclass->active.hilited)
tclass->active.hilited = tclass->active.normal;
if (!tclass->active.clicked)
tclass->active.clicked = tclass->active.normal;
if (!tclass->active.disabled)
tclass->active.disabled = tclass->active.normal;
if (!tclass->sticky.normal)
tclass->sticky.normal = tclass->norm.normal;
if (!tclass->sticky.hilited)
tclass->sticky.hilited = tclass->sticky.normal;
if (!tclass->sticky.clicked)
tclass->sticky.clicked = tclass->sticky.normal;
if (!tclass->sticky.disabled)
tclass->sticky.disabled = tclass->sticky.normal;
if (!tclass->sticky_active.normal)
tclass->sticky_active.normal = tclass->norm.normal;
if (!tclass->sticky_active.hilited)
tclass->sticky_active.hilited = tclass->sticky_active.normal;
if (!tclass->sticky_active.clicked)
tclass->sticky_active.clicked = tclass->sticky_active.normal;
if (!tclass->sticky_active.disabled)
tclass->sticky_active.disabled = tclass->sticky_active.normal;
}
TextClass *
TextclassFind(const char *name, int fallback)
{
TextClass *tc;
if (name)
{
tc = FindItem(name, 0, LIST_FINDBY_NAME, LIST_TYPE_TCLASS);
if (tc || !fallback)
return tc;
}
tc = FindItem("__FALLBACK_TCLASS", 0, LIST_FINDBY_NAME, LIST_TYPE_TCLASS);
return tc;
}
int
TextclassConfigLoad(FILE * fs)
{
int err = 0;
char s[FILEPATH_LEN_MAX];
char s2[FILEPATH_LEN_MAX];
int i1, r, g, b;
TextClass *tc = NULL;
TextState *ts = NULL;
int fields;
while (GetLine(s, sizeof(s), fs))
{
s2[0] = 0;
i1 = CONFIG_INVALID;
fields = sscanf(s, "%i %4000[^=]", &i1, s2);
if (fields < 1)
{
i1 = CONFIG_INVALID;
}
else if (i1 == CONFIG_CLOSE)
{
if (fields != 1)
Alert(_("CONFIG: ignoring extra data in \"%s\"\n"), s);
}
else if (i1 != CONFIG_INVALID)
{
if (fields != 2)
{
Alert(_("CONFIG: missing required data in \"%s\"\n"), s);
i1 = CONFIG_INVALID;
}
}
switch (i1)
{
case CONFIG_CLOSE:
if (tc)
{
TextclassPopulate(tc);
AddItem(tc, tc->name, 0, LIST_TYPE_TCLASS);
}
goto done;
case CONFIG_CLASSNAME:
if (ConfigSkipIfExists(fs, s2, LIST_TYPE_TCLASS))
goto done;
tc = TextclassCreate(s2);
break;
case TEXT_ORIENTATION:
if (ts)
ts->style.orientation = atoi(s2);
break;
case TEXT_JUSTIFICATION:
if (tc)
tc->justification = atoi(s2);
break;
case CONFIG_DESKTOP:
case ICLASS_NORMAL:
if (tc)
tc->norm.normal = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_CLICKED:
if (tc)
tc->norm.clicked = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_HILITED:
if (tc)
tc->norm.hilited = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_DISABLED:
if (tc)
tc->norm.disabled = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_NORMAL:
if (tc)
tc->sticky.normal = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_CLICKED:
if (tc)
tc->sticky.clicked = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_HILITED:
if (tc)
tc->sticky.hilited = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_DISABLED:
if (tc)
tc->sticky.disabled = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_ACTIVE_NORMAL:
if (tc)
tc->active.normal = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_ACTIVE_CLICKED:
if (tc)
tc->active.clicked = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_ACTIVE_HILITED:
if (tc)
tc->active.hilited = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_ACTIVE_DISABLED:
if (tc)
tc->active.disabled = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_ACTIVE_NORMAL:
if (tc)
tc->sticky_active.normal = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_ACTIVE_CLICKED:
if (tc)
tc->sticky_active.clicked = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_ACTIVE_HILITED:
if (tc)
tc->sticky_active.hilited = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case ICLASS_STICKY_ACTIVE_DISABLED:
if (tc)
tc->sticky_active.disabled = ts = TextstateCreate();
if (ts)
{
ts->fontname = TextstateFontLookup(s2);
ts->style.mode = MODE_VERBATIM;
}
break;
case TEXT_MODE:
if (ts)
ts->style.mode = atoi(s2);
break;
case TEXT_EFFECT:
if (ts)
ts->effect = atoi(s2);
break;
case TEXT_FG_COL:
if (ts)
{
r = g = b = 0;
sscanf(s, "%*s %i %i %i", &r, &g, &b);
ESetColor(&ts->fg_col, r, g, b);
}
break;
case TEXT_BG_COL:
if (ts)
{
r = g = b = 0;
sscanf(s, "%*s %i %i %i", &r, &g, &b);
ESetColor(&ts->bg_col, r, g, b);
}
break;
default:
Alert(_("Warning: unable to determine what to do with\n"
"the following text in the middle of current Text"
" definition:\n" "%s\nWill ignore and continue...\n"), s);
}
}
err = -1;
done:
return err;
}
void
TextclassApply(ImageClass * iclass, Window win, int w, int h, int active,
int sticky, int state, char expose __UNUSED__,
TextClass * tclass, const char *text)
{
if ((!iclass) || (!tclass) || (!text) || (!win) || (w < 1) || (h < 1))
return;
#if USE_DQ_TCLASS /* Try not using the draw queue here. */
if (Mode.queue_up)
{
DrawQueue *dq;
dq = Emalloc(sizeof(DrawQueue));
dq->win = win;
dq->iclass = iclass;
if (dq->iclass)
dq->iclass->ref_count++;
dq->w = w;
dq->h = h;
dq->active = active;
dq->sticky = sticky;
dq->state = state;
dq->expose = expose;
dq->tclass = tclass;
if (dq->tclass)
dq->tclass->ref_count++;
if (text)
dq->text = Estrdup(text);
else
dq->text = NULL;
dq->w = w;
dq->shape_propagate = 0;
dq->pager = NULL;
dq->redraw_pager = NULL;
dq->d = NULL;
dq->di = NULL;
dq->x = 0;
dq->y = 0;
AddItem(dq, "DRAW", dq->win, LIST_TYPE_DRAW);
return;
}
#endif
XClearWindow(disp, win);
TextDraw(tclass, win, active, sticky, state, text, iclass->padding.left,
iclass->padding.top,
w - (iclass->padding.left + iclass->padding.right),
h - (iclass->padding.top + iclass->padding.bottom),
h - (iclass->padding.top + iclass->padding.bottom),
tclass->justification);
}
/*
* Textclass Module
*/
static void
TextclassSighan(int sig, void *prm __UNUSED__)
{
TextClass *tc;
switch (sig)
{
case ESIGNAL_INIT:
/* create a fallback textclass in case no textclass is found */
tc = TextclassCreate("__FALLBACK_TCLASS");
tc->norm.normal = TextstateCreate();
tc->norm.normal->fontname =
Estrdup("-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*");
ESetColor(&(tc->norm.normal->fg_col), 0, 0, 0);
AddItem(tc, tc->name, 0, LIST_TYPE_TCLASS);
break;
}
}
static void
TextclassIpc(const char *params, Client * c __UNUSED__)
{
char param1[FILEPATH_LEN_MAX];
char param2[FILEPATH_LEN_MAX];
char param3[FILEPATH_LEN_MAX];
char pq;
TextClass *tc;
if (!params)
{
IpcPrintf("Please specify...\n");
return;
}
param1[0] = 0;
param2[0] = 0;
param3[0] = 0;
word(params, 1, param1);
word(params, 2, param2);
if (!strncmp(param1, "list", 2))
{
TextClass **lst;
int num, i;
lst = (TextClass **) ListItemType(&num, LIST_TYPE_TCLASS);
for (i = 0; i < num; i++)
IpcPrintf("%s\n", lst[i]->name);
if (lst)
Efree(lst);
return;
}
if (!param1[0])
{
IpcPrintf("TextClass not specified\n");
return;
}
tc = TextclassFind(param1, 0);
if (!tc)
{
IpcPrintf("TextClass not found: %s\n", param1);
return;
}
if (!strcmp(param2, "create"))
{
}
else if (!strcmp(param2, "delete"))
{
if (tc)
TextclassDestroy(tc);
}
else if (!strcmp(param2, "modify"))
{
}
else if (!strcmp(param2, "apply"))
{
if (tc)
{
int state;
int x, y;
const char *txt;
Window win;
word(params, 3, param3);
win = (Window) strtol(param3, (char **)NULL, 0);
word(params, 4, param3);
x = atoi(param3);
word(params, 5, param3);
y = atoi(param3);
word(params, 6, param3);
state = STATE_NORMAL;
if (!strcmp(param3, "normal"))
state = STATE_NORMAL;
else if (!strcmp(param3, "hilited"))
state = STATE_HILITED;
else if (!strcmp(param3, "clicked"))
state = STATE_CLICKED;
else if (!strcmp(param3, "disabled"))
state = STATE_DISABLED;
txt = atword(params, 7);
pq = Mode.queue_up;
Mode.queue_up = 0;
if (txt)
TextDraw(tc, win, 0, 0, state, txt, x, y, 99999, 99999, 17, 0);
Mode.queue_up = pq;
}
}
else if (!strcmp(param2, "query_size"))
{
if (tc)
{
int w, h;
const char *txt;
w = h = 0;
txt = atword(params, 3);
if (txt)
TextSize(tc, 0, 0, STATE_NORMAL, txt, &w, &h, 17);
IpcPrintf("%i %i\n", w, h);
}
}
else if (!strcmp(param2, "query"))
{
if (tc)
IpcPrintf("TextClass %s found\n", tc->name);
}
else if (!strcmp(param2, "ref_count"))
{
if (tc)
IpcPrintf("%u references remain.\n", tc->ref_count);
}
else
{
IpcPrintf("Error: Unknown operation specified\n");
}
}
IpcItem TextclassIpcArray[] = {
{
TextclassIpc,
"textclass", NULL,
"List textclasses, create/delete/modify/apply a textclass",
NULL}
,
};
#define N_IPC_FUNCS (sizeof(TextclassIpcArray)/sizeof(IpcItem))
/*
* Module descriptor
*/
EModule ModTextclass = {
"textclass", "tc",
TextclassSighan,
{N_IPC_FUNCS, TextclassIpcArray}
,
{0, NULL}
};