eterm/src/pixmap.c

1258 lines
38 KiB
C

/* pixmap.c -- Eterm pixmap handling routines
* This file is original work by Michael Jennings <mej@eterm.org> and
* Tuomo Venalainen <vendu@cc.hut.fi>. This file, and any other file
* bearing this same message or a similar one, is distributed under
* the GNU Public License (GPL) as outlined in the COPYING file.
*
* Copyright (C) 1997, Michael Jennings and Tuomo Venalainen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
static const char cvs_ident[] = "$Id$";
#include "config.h"
#include "feature.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <Imlib.h>
#include "../libmej/debug.h"
#include "../libmej/mem.h"
#include "../libmej/strings.h"
#include "e.h"
#include "main.h"
#include "menus.h"
#include "options.h"
#include "pixmap.h"
#include "screen.h"
#ifdef PIXMAP_SCROLLBAR
# include "scrollbar.h"
#endif
#include "term.h"
#ifdef USE_POSIX_THREADS
# include "threads.h"
#endif
#include "Eterm.xpm" /* Icon pixmap */
#ifdef PIXMAP_SUPPORT
Pixmap desktop_pixmap = None;
Pixmap viewport_pixmap = None;
Window desktop_window = None;
unsigned char desktop_pixmap_is_mine = 0;
ImlibData *imlib_id = NULL;
image_t images[image_max] =
{
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL},
# ifdef PIXMAP_SCROLLBAR
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL}
# endif
# ifdef PIXMAP_MENUBAR
,
{None, 0, NULL, NULL, NULL, NULL},
{None, 0, NULL, NULL, NULL, NULL}
# endif
};
#endif
#ifdef PIXMAP_SUPPORT
const char *
get_image_type(unsigned short type)
{
switch (type) {
case image_bg:
return "image_bg";
break;
case image_up:
return "image_up";
break;
case image_down:
return "image_down";
break;
case image_left:
return "image_left";
break;
case image_right:
return "image_right";
break;
# ifdef PIXMAP_SCROLLBAR
case image_sb:
return "image_sb";
break;
case image_sa:
return "image_sa";
break;
# endif
# ifdef PIXMAP_MENUBAR
case image_menu:
return "image_menu";
break;
case image_submenu:
return "image_submenu";
break;
# endif
case image_max:
return "image_max";
break;
default:
return "";
break;
}
return ("");
}
unsigned short
parse_pixmap_ops(char *str)
{
unsigned short op = OP_NONE;
char *token;
REQUIRE_RVAL(str && *str, OP_NONE);
D_PIXMAP(("parse_pixmap_ops(str [%s]) called.\n", str));
for (; (token = strsep(&str, ":"));) {
if (!BEG_STRCASECMP("tiled", token)) {
op |= OP_TILE;
} else if (!BEG_STRCASECMP("hscaled", token)) {
op |= OP_HSCALE;
} else if (!BEG_STRCASECMP("vscaled", token)) {
op |= OP_VSCALE;
} else if (!BEG_STRCASECMP("scaled", token)) {
op |= OP_SCALE;
} else if (!BEG_STRCASECMP("propscaled", token)) {
op |= OP_PROPSCALE;
}
}
return (op);
}
unsigned short
set_pixmap_scale(const char *geom, pixmap_t *pmap)
{
static char str[GEOM_LEN + 1] =
{'\0'};
int w = 0, h = 0, x = 0, y = 0;
unsigned short op = OP_NONE;
int flags;
unsigned short changed = 0;
char *p, *opstr;
int n;
if (geom == NULL)
return 0;
D_PIXMAP(("scale_pixmap(\"%s\")\n", geom));
if (!strcmp(geom, "?")) {
sprintf(str, "[%dx%d+%d+%d]", pmap->w, pmap->h, pmap->x, pmap->y);
xterm_seq(XTerm_title, str);
return 0;
}
if ((opstr = strchr(geom, ':')) != NULL) {
*opstr++ = '\0';
op |= parse_pixmap_ops(opstr);
}
if ((p = strchr(geom, ';')) == NULL)
p = strchr(geom, '\0');
n = (p - geom);
if (n > GEOM_LEN - 1)
return 0;
strncpy(str, geom, n);
str[n] = '\0';
flags = XParseGeometry(str, &x, &y, &w, &h);
if (!flags) {
flags |= WidthValue; /* default is tile */
w = 0;
}
if (flags & WidthValue) {
if (!(flags & XValue)) {
x = 50;
}
if (!(flags & HeightValue))
h = w;
if (w && !h) {
w = pmap->w * ((float) w / 100);
h = pmap->h;
} else if (h && !w) {
w = pmap->w;
h = pmap->h * ((float) h / 100);
}
/* If they want scaling, but didn't give a percentage, assume 100% */
if (op & OP_PROPSCALE) {
if (!w)
w = 100;
if (!h)
h = 100;
} else {
if ((op & OP_HSCALE) && !w) {
w = 100;
}
if ((op & OP_VSCALE) && !h) {
h = 100;
}
}
if (pmap->w != w) {
pmap->w = w;
changed++;
}
if (pmap->h != h) {
pmap->h = h;
changed++;
}
}
if (!(flags & YValue)) {
if (flags & XNegative)
flags |= YNegative;
y = x;
}
if (!(flags & WidthValue) && geom[0] != '=') {
x += pmap->x;
y += pmap->y;
} else {
if (flags & XNegative)
x += 100;
if (flags & YNegative)
y += 100;
}
x = (x <= 0 ? 0 : (x >= 100 ? 100 : x));
y = (y <= 0 ? 0 : (y >= 100 ? 100 : y));;
if (pmap->x != x) {
pmap->x = x;
changed++;
}
if (pmap->y != y) {
pmap->y = y;
changed++;
}
if (pmap->op != op) {
pmap->op = op;
changed++;
}
D_PIXMAP(("scale_pixmap() returning %hu, *pmap == { op [%hu], w [%hd], h [%hd], x [%hd], y [%hd] }\n",
changed, pmap->op, pmap->w, pmap->h, pmap->x, pmap->y));
return changed;
}
void
reset_simage(simage_t * simg, unsigned long mask)
{
ASSERT(simg != NULL);
if ((mask & RESET_IMLIB_IM) && simg->iml->im) {
Imlib_destroy_image(imlib_id, simg->iml->im);
simg->iml->im = NULL;
}
if ((mask & RESET_PMAP_PIXMAP) && simg->pmap->pixmap != None) {
Imlib_free_pixmap(imlib_id, simg->pmap->pixmap);
simg->pmap->pixmap = None;
}
if ((mask & RESET_PMAP_MASK) && simg->pmap->mask != None) {
Imlib_free_pixmap(imlib_id, simg->pmap->mask);
simg->pmap->mask = None;
}
if ((mask & RESET_IMLIB_BORDER) && simg->iml->border) {
FREE(simg->iml->border);
simg->iml->border = NULL;
}
if ((mask & RESET_IMLIB_MOD) && simg->iml->mod) {
FREE(simg->iml->mod);
simg->iml->mod = NULL;
}
if ((mask & RESET_IMLIB_RMOD) && simg->iml->rmod) {
FREE(simg->iml->rmod);
simg->iml->rmod = NULL;
}
if ((mask & RESET_IMLIB_GMOD) && simg->iml->gmod) {
FREE(simg->iml->gmod);
simg->iml->gmod = NULL;
}
if ((mask & RESET_IMLIB_BMOD) && simg->iml->bmod) {
FREE(simg->iml->bmod);
simg->iml->bmod = NULL;
}
if (mask & RESET_PMAP_GEOM) {
simg->pmap->w = 0;
simg->pmap->h = 0;
simg->pmap->x = 50;
simg->pmap->y = 50;
simg->pmap->op = OP_NONE;
}
}
void
paste_simage(simage_t * simg, Window win, unsigned short x, unsigned short y, unsigned short w, unsigned short h)
{
ASSERT(simg != NULL);
REQUIRE(win != None);
if (simg->iml->border) {
Imlib_set_image_border(imlib_id, simg->iml->im, simg->iml->border);
}
if (simg->iml->mod) {
Imlib_set_image_modifier(imlib_id, simg->iml->im, simg->iml->mod);
}
if (simg->iml->rmod) {
Imlib_set_image_red_modifier(imlib_id, simg->iml->im, simg->iml->rmod);
}
if (simg->iml->gmod) {
Imlib_set_image_green_modifier(imlib_id, simg->iml->im, simg->iml->gmod);
}
if (simg->iml->bmod) {
Imlib_set_image_blue_modifier(imlib_id, simg->iml->im, simg->iml->bmod);
}
Imlib_paste_image(imlib_id, simg->iml->im, win, x, y, w, h);
}
void
redraw_image(unsigned char which) {
switch (which) {
case image_bg:
render_simage(images[image_bg].current, TermWin.vt, TermWin_TotalWidth(), TermWin_TotalHeight(), image_bg, 0);
scr_touch();
break;
case image_up:
render_simage(images[image_up].current, scrollbar_get_uparrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_up, 0);
scrollbar_show(0);
break;
case image_down:
render_simage(images[image_down].current, scrollbar_get_downarrow_win(), scrollbar_arrow_width(), scrollbar_arrow_width(), image_down, 0);
scrollbar_show(0);
break;
# ifdef PIXMAP_SCROLLBAR
case image_sb:
render_simage(images[image_sb].current, scrollbar_get_win(), scrollbar_trough_width(), scrollbar_trough_height(), image_sb, 0);
scrollbar_show(0);
break;
case image_sa:
render_simage(images[image_sa].current, scrollbar_get_anchor_win(), scrollbar_anchor_width(), scrollbar_anchor_height(), image_sa, 0);
scrollbar_show(0);
break;
# endif
default:
D_PIXMAP(("redraw_image(): Bad value %u\n", which));
break;
}
}
void
render_simage(simage_t * simg, Window win, unsigned short width, unsigned short height, unsigned char which, renderop_t renderop)
{
XGCValues gcvalue;
GC gc;
short xsize, ysize;
short xpos = 0, ypos = 0;
Pixmap pixmap = None;
unsigned short rendered = 0;
unsigned short xscaled = 0, yscaled = 0;
# ifdef PIXMAP_OFFSET
static unsigned int last_x = 0, last_y = 0;
int x, y;
int px, py;
unsigned int pw, ph, pb, pd;
Window w, dummy;
Screen *scr;
# endif /* PIXMAP_OFFSET */
scr = ScreenOfDisplay(Xdisplay, Xscreen);
if (!scr)
return;
ASSERT(simg != NULL);
ASSERT(simg->iml != NULL);
ASSERT(simg->pmap != NULL);
D_PIXMAP(("render_simage(): Rendering simg->iml->im 0x%08x (%s) at %hux%hu onto window 0x%08x\n", simg->iml->im, get_image_type(which), width, height, win));
D_PIXMAP(("render_simage(): Image mode is 0x%02x\n", images[which].mode));
if ((which == image_bg) && image_mode_is(image_bg, MODE_VIEWPORT)) {
width = scr->width;
height = scr->height;
}
if (!(width) || !(height))
return;
gcvalue.foreground = gcvalue.background = PixColors[bgColor];
gc = XCreateGC(Xdisplay, win, GCForeground | GCBackground, &gcvalue);
pixmap = simg->pmap->pixmap; /* Save this for later */
if ((images[which].mode & MODE_AUTO) && (images[which].mode & ALLOW_AUTO) && (which != image_bg)) {
char buff[255], *iclass = NULL, *state = NULL;
switch (which) {
case image_up: iclass = "BUTTON_ARROW_UP"; break;
case image_down: iclass = "BUTTON_ARROW_DOWN"; break;
case image_left: iclass = "BUTTON_ARROW_LEFT"; break;
case image_right: iclass = "BUTTON_ARROW_RIGHT"; break;
# ifdef PIXMAP_SCROLLBAR
case image_sb: iclass = "BAR_VERTICAL"; state = "clicked"; break;
case image_sa: iclass = "BAR_VERTICAL"; ((images[which].current == images[which].selected) ? (state = "hilited") : (state = "clicked")); break;
# endif
case image_menu: iclass = "BAR_HORIZONTAL"; state = "normal"; break;
case image_submenu: iclass = "DEFAULT_MENU_SUB"; break;
default: break;
}
if (!state) {
if (images[which].current == images[which].selected) {
state = "hilited";
} else if (images[which].current == images[which].clicked) {
state = "clicked";
} else {
state = "normal";
}
}
if (iclass && state) {
snprintf(buff, sizeof(buff), "imageclass %s apply %ld %s", iclass, (long int) win, state);
enl_ipc_send(buff);
return;
}
}
# ifdef PIXMAP_OFFSET
if (image_mode_is(which, MODE_TRANS) && image_mode_is(which, ALLOW_TRANS)) {
if (desktop_window == None) {
get_desktop_window();
}
if (desktop_window == None) {
print_error("Unable to locate desktop window. If you are running Enlightenment, please\n"
"restart. If not, please set your background image with Esetroot, then try again.");
FOREACH_IMAGE(if (image_mode_is(idx, MODE_TRANS)) {image_set_mode(idx, MODE_IMAGE); image_allow_mode(idx, ALLOW_IMAGE);});
render_simage(simg, win, width, height, which, renderop);
return;
}
if (desktop_pixmap == None) {
desktop_pixmap = get_desktop_pixmap();
last_x = last_y = -1;
if (desktop_pixmap != None && need_colormod()) {
pixmap = desktop_pixmap;
XGetGeometry(Xdisplay, desktop_pixmap, &w, &px, &py, &pw, &ph, &pb, &pd);
D_PIXMAP(("render_simage(): XGetGeometry() returned w = 0x%08x, pw == %u, ph == %u\n", w, pw, ph));
if (pw < (unsigned int) scr->width || ph < (unsigned int) scr->height) {
desktop_pixmap = XCreatePixmap(Xdisplay, win, pw, ph, Xdepth);
XCopyArea(Xdisplay, pixmap, desktop_pixmap, gc, 0, 0, pw, ph, 0, 0);
colormod_trans(desktop_pixmap, gc, pw, ph);
} else {
desktop_pixmap = XCreatePixmap(Xdisplay, win, scr->width, scr->height, Xdepth);
XCopyArea(Xdisplay, pixmap, desktop_pixmap, gc, 0, 0, scr->width, scr->height, 0, 0);
colormod_trans(desktop_pixmap, gc, scr->width, scr->height);
}
desktop_pixmap_is_mine = 1;
pixmap = None;
} else {
desktop_pixmap_is_mine = 0;
}
}
if (desktop_pixmap != None) {
XTranslateCoordinates(Xdisplay, win, desktop_window, 0, 0, &x, &y, &w);
if (simg->pmap->pixmap != None) {
XFreePixmap(Xdisplay, simg->pmap->pixmap);
}
simg->pmap->pixmap = XCreatePixmap(Xdisplay, win, width, height, Xdepth);
D_PIXMAP(("desktop_pixmap == 0x%08x, simg->pmap->pixmap == 0x%08x\n", desktop_pixmap, simg->pmap->pixmap));
if (simg->pmap->pixmap != None) {
XGetGeometry(Xdisplay, desktop_pixmap, &w, &px, &py, &pw, &ph, &pb, &pd);
if ((pw <= 0) || (ph <= 0)) {
print_error("Value of desktop pixmap property is invalid. Please restart your "
"window manager or use Esetroot to set a new one.");
desktop_pixmap = None;
D_PIXMAP(("Setting background of window 0x%08x to the background color\n", win));
XSetWindowBackground(Xdisplay, win, PixColors[bgColor]);
} else {
if (pw < (unsigned int) scr->width || ph < (unsigned int) scr->height) {
XFreeGC(Xdisplay, gc);
gc = XCreateGC(Xdisplay, desktop_pixmap, 0, &gcvalue);
XSetTile(Xdisplay, gc, desktop_pixmap);
XSetTSOrigin(Xdisplay, gc, pw - (x % pw), ph - (y % ph));
XSetFillStyle(Xdisplay, gc, FillTiled);
XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, scr->width, scr->height);
} else {
XCopyArea(Xdisplay, desktop_pixmap, simg->pmap->pixmap, gc, x, y, width, height, 0, 0);
}
D_PIXMAP(("Setting background of window 0x%08x to 0x%08x\n", win, simg->pmap->pixmap));
XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap);
}
}
} else {
D_PIXMAP(("Setting background of window 0x%08x to the background color\n", win));
XSetWindowBackground(Xdisplay, win, PixColors[bgColor]);
}
} else if (image_mode_is(which, MODE_VIEWPORT) && image_mode_is(which, ALLOW_VIEWPORT)) {
D_PIXMAP(("Viewport mode enabled. viewport_pixmap == 0x%08x and simg->pmap->pixmap == 0x%08x\n", viewport_pixmap, simg->pmap->pixmap));
if (viewport_pixmap == None) {
imlib_t *tmp_iml = images[image_bg].current->iml;
xsize = tmp_iml->im->rgb_width;
ysize = tmp_iml->im->rgb_height;
if (tmp_iml->border) {
Imlib_set_image_border(imlib_id, tmp_iml->im, tmp_iml->border);
}
if (tmp_iml->mod) {
Imlib_set_image_modifier(imlib_id, tmp_iml->im, tmp_iml->mod);
}
if (tmp_iml->rmod) {
Imlib_set_image_red_modifier(imlib_id, tmp_iml->im, tmp_iml->rmod);
}
if (tmp_iml->gmod) {
Imlib_set_image_green_modifier(imlib_id, tmp_iml->im, tmp_iml->gmod);
}
if (tmp_iml->bmod) {
Imlib_set_image_blue_modifier(imlib_id, tmp_iml->im, tmp_iml->bmod);
}
if ((images[image_bg].current->pmap->w > 0) || (images[image_bg].current->pmap->op & OP_SCALE)) {
D_PIXMAP(("Scaling image to %dx%d\n", scr->width, scr->height));
Imlib_render(imlib_id, tmp_iml->im, scr->width, scr->height);
} else {
D_PIXMAP(("Tiling image at %dx%d\n", xsize, ysize));
Imlib_render(imlib_id, tmp_iml->im, xsize, ysize);
}
viewport_pixmap = Imlib_copy_image(imlib_id, tmp_iml->im);
D_PIXMAP(("Created viewport_pixmap == 0x%08x\n", viewport_pixmap));
} else {
XGetGeometry(Xdisplay, viewport_pixmap, &dummy, &px, &py, &pw, &ph, &pb, &pd);
xsize = (short) pw;
ysize = (short) ph;
}
if (simg->pmap->pixmap != None) {
XGetGeometry(Xdisplay, simg->pmap->pixmap, &dummy, &px, &py, &pw, &ph, &pb, &pd);
if (pw != width || ph != height) {
Imlib_free_pixmap(imlib_id, simg->pmap->pixmap);
simg->pmap->pixmap = None;
}
}
if (simg->pmap->pixmap == None) {
simg->pmap->pixmap = XCreatePixmap(Xdisplay, win, width, height, Xdepth);
D_PIXMAP(("Created simg->pmap->pixmap == 0x%08x\n", simg->pmap->pixmap));
}
XTranslateCoordinates(Xdisplay, win, Xroot, 0, 0, &x, &y, &dummy);
D_PIXMAP(("Translated coords are %d, %d\n", x, y));
if ((images[image_bg].current->pmap->w > 0) || (images[image_bg].current->pmap->op & OP_SCALE)) {
XCopyArea(Xdisplay, viewport_pixmap, simg->pmap->pixmap, gc, x, y, width, height, 0, 0);
} else {
XFreeGC(Xdisplay, gc);
gc = XCreateGC(Xdisplay, viewport_pixmap, 0, &gcvalue);
XSetTile(Xdisplay, gc, viewport_pixmap);
XSetTSOrigin(Xdisplay, gc, xsize - (x % xsize), ysize - (y % ysize));
XSetFillStyle(Xdisplay, gc, FillTiled);
XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, width, height);
}
D_PIXMAP(("Setting background of window 0x%08x to 0x%08x\n", win, simg->pmap->pixmap));
XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap);
} else
# endif
if (image_mode_is(which, MODE_IMAGE) && image_mode_is(which, ALLOW_IMAGE)) {
if (simg->iml->im) {
int w = simg->pmap->w;
int h = simg->pmap->h;
int x = simg->pmap->x;
int y = simg->pmap->y;
xsize = simg->iml->im->rgb_width;
ysize = simg->iml->im->rgb_height;
D_PIXMAP(("render_simage(): w == %d, h == %d, x == %d, y == %d, xsize == %d, ysize == %d\n", w, h, x, y, xsize, ysize));
if ((simg->pmap->op & OP_PROPSCALE)) {
double x_ratio, y_ratio;
x_ratio = ((double) width) / ((double) xsize);
y_ratio = ((double) height) / ((double) ysize);
if (x_ratio > 1) {
/* Window is larger than image. Smaller ratio determines whether which image dimension is closer in value
to the corresponding window dimension, which is the scale factor we want to use */
if (x_ratio > y_ratio) {
x_ratio = y_ratio;
}
} else {
if (x_ratio > y_ratio) {
x_ratio = y_ratio;
}
}
xscaled = (unsigned short) ((xsize * x_ratio) * ((float) w / 100.0));
yscaled = (unsigned short) ((ysize * x_ratio) * ((float) h / 100.0));
} else {
if (w > 0) {
xscaled = width * ((float) w / 100.0);
} else {
xscaled = xsize;
}
if (h > 0) {
yscaled = height * ((float) h / 100.0);
} else {
yscaled = ysize;
}
}
xpos = (short) ((width - xscaled) * ((float) x / 100.0));
ypos = (short) ((height - yscaled) * ((float) y / 100.0));
D_PIXMAP(("render_simage(): Calculated scaled size as %hux%hu with origin at (%hd, %hd)\n", xscaled, yscaled, xpos, ypos));
if (simg->iml->last_w != xscaled || simg->iml->last_h != yscaled || 1) {
simg->iml->last_w = xscaled;
simg->iml->last_h = yscaled;
if (simg->iml->border) {
D_PIXMAP(("render_simage(): Setting image border: { left [%d], right [%d], top [%d], bottom [%d] }\n",
simg->iml->border->left, simg->iml->border->right, simg->iml->border->top, simg->iml->border->bottom));
Imlib_set_image_border(imlib_id, simg->iml->im, simg->iml->border);
}
if (simg->iml->mod) {
D_PIXMAP(("render_simage(): Setting image modifier: { gamma [0x%08x], brightness [0x%08x], contrast [0x%08x] }\n",
simg->iml->mod->gamma, simg->iml->mod->brightness, simg->iml->mod->contrast));
Imlib_set_image_modifier(imlib_id, simg->iml->im, simg->iml->mod);
}
if (simg->iml->rmod) {
D_PIXMAP(("render_simage(): Setting image red modifier: { gamma [0x%08x], brightness [0x%08x], contrast [0x%08x] }\n",
simg->iml->rmod->gamma, simg->iml->rmod->brightness, simg->iml->rmod->contrast));
Imlib_set_image_red_modifier(imlib_id, simg->iml->im, simg->iml->rmod);
}
if (simg->iml->gmod) {
D_PIXMAP(("render_simage(): Setting image green modifier: { gamma [0x%08x], brightness [0x%08x], contrast [0x%08x] }\n",
simg->iml->gmod->gamma, simg->iml->gmod->brightness, simg->iml->gmod->contrast));
Imlib_set_image_green_modifier(imlib_id, simg->iml->im, simg->iml->gmod);
}
if (simg->iml->bmod) {
D_PIXMAP(("render_simage(): Setting image blue modifier: { gamma [0x%08x], brightness [0x%08x], contrast [0x%08x] }\n",
simg->iml->bmod->gamma, simg->iml->bmod->brightness, simg->iml->bmod->contrast));
Imlib_set_image_blue_modifier(imlib_id, simg->iml->im, simg->iml->bmod);
}
D_PIXMAP(("render_simage(): Rendering image simg->iml->im [0x%08x] to %hdx%hd pixmap\n", simg->iml->im, xscaled, yscaled));
Imlib_render(imlib_id, simg->iml->im, xscaled, yscaled);
rendered = 1;
}
simg->pmap->pixmap = Imlib_copy_image(imlib_id, simg->iml->im);
simg->pmap->mask = Imlib_copy_mask(imlib_id, simg->iml->im);
if (simg->pmap->mask != None) {
shaped_window_apply_mask(win, simg->pmap->mask);
}
} else {
XSetWindowBackground(Xdisplay, win, PixColors[bgColor]);
reset_simage(simg, RESET_ALL);
}
if (simg->pmap->pixmap != None) {
if (pixmap != None) {
Imlib_free_pixmap(imlib_id, pixmap);
}
if (xscaled != width || yscaled != height || xpos != 0 || ypos != 0) {
unsigned char single;
single = ((xscaled < width || yscaled < height) && !(simg->pmap->op & OP_TILE)) ? 1 : 0;
pixmap = simg->pmap->pixmap;
simg->pmap->pixmap = XCreatePixmap(Xdisplay, win, width, height, Xdepth);
if (single)
XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, width, height);
XSetTile(Xdisplay, gc, pixmap);
XSetTSOrigin(Xdisplay, gc, xpos, ypos);
XSetFillStyle(Xdisplay, gc, FillTiled);
if (single) {
XCopyArea(Xdisplay, pixmap, simg->pmap->pixmap, gc, 0, 0, xscaled, yscaled, xpos, ypos);
} else {
XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, width, height);
}
Imlib_free_pixmap(imlib_id, pixmap);
}
if (simg->iml->bevel != NULL) {
Imlib_bevel_pixmap(imlib_id, simg->pmap->pixmap, width, height, simg->iml->bevel->edges, simg->iml->bevel->up);
}
D_PIXMAP(("Setting background of window 0x%08x to 0x%08x\n", win, simg->pmap->pixmap));
XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap);
}
} else {
unsigned short cidx;
switch (which) {
case image_up:
case image_down:
case image_left:
case image_right:
# ifdef PIXMAP_SCROLLBAR
case image_sb:
case image_sa:
# endif
cidx = (TermWin.focus ? scrollColor : unfocusedScrollColor);
break;
case image_menu:
case image_submenu:
cidx = (TermWin.focus ? menuColor : unfocusedMenuColor);
break;
default:
cidx = bgColor;
break;
}
XSetWindowBackground(Xdisplay, win, PixColors[cidx]);
image_set_mode(which, MODE_SOLID);
}
XClearWindow(Xdisplay, win);
XFreeGC(Xdisplay, gc);
XSync(Xdisplay, False);
}
const char *
search_path(const char *pathlist, const char *file, const char *ext)
{
static char name[PATH_MAX];
char *p;
const char *path;
int maxpath, len;
struct stat fst;
if (!pathlist || !file) { /* If either one is NULL, there really isn't much point in going on.... */
return ((const char *) NULL);
}
if (!ext) {
ext = "";
}
getcwd(name, PATH_MAX);
D_OPTIONS(("search_path(\"%s\", \"%s\", \"%s\") called from \"%s\".\n", pathlist, file, ext, name));
D_OPTIONS(("search_path(): Checking for file \"%s\"\n", file));
if (!access(file, R_OK)) {
if (stat(file, &fst)) {
D_OPTIONS(("Unable to stat %s -- %s\n", file, strerror(errno)));
} else {
D_OPTIONS(("Stat returned mode 0x%08o, S_ISDIR() == %d\n", fst.st_mode, S_ISDIR(fst.st_mode)));
}
if (!S_ISDIR(fst.st_mode))
return file;
}
if ((p = strchr(file, '@')) == NULL)
p = strchr(file, '\0');
len = (p - file);
/* check about adding a trailing extension */
if (ext != NULL) {
char *dot;
dot = strrchr(p, '.');
path = strrchr(p, '/');
if (dot != NULL || (path != NULL && dot <= path))
ext = NULL;
}
/* leave room for an extra '/' and trailing '\0' */
maxpath = sizeof(name) - (len + (ext ? strlen(ext) : 0) + 2);
if (maxpath <= 0)
return NULL;
/* check if we can find it now */
strncpy(name, file, len);
name[len] = '\0';
D_OPTIONS(("search_path(): Checking for file \"%s\"\n", name));
if (!access(name, R_OK)) {
stat(name, &fst);
if (!S_ISDIR(fst.st_mode))
return name;
}
if (ext) {
strcat(name, ext);
D_OPTIONS(("search_path(): Checking for file \"%s\"\n", name));
if (!access(name, R_OK)) {
stat(name, &fst);
if (!S_ISDIR(fst.st_mode))
return name;
}
}
for (path = pathlist; path != NULL && *path != '\0'; path = p) {
int n;
/* colon delimited */
if ((p = strchr(path, ':')) == NULL)
p = strchr(path, '\0');
n = (p - path);
if (*p != '\0')
p++;
if (n > 0 && n <= maxpath) {
strncpy(name, path, n);
if (name[n - 1] != '/')
name[n++] = '/';
name[n] = '\0';
strncat(name, file, len);
D_OPTIONS(("search_path(): Checking for file \"%s\"\n", name));
if (!access(name, R_OK)) {
stat(name, &fst);
if (!S_ISDIR(fst.st_mode))
return name;
}
if (ext) {
strcat(name, ext);
D_OPTIONS(("search_path(): Checking for file \"%s\"\n", name));
if (!access(name, R_OK)) {
stat(name, &fst);
if (!S_ISDIR(fst.st_mode))
return name;
}
}
}
}
D_OPTIONS(("search_path(): File \"%s\" not found in path.\n", file));
return ((const char *) NULL);
}
unsigned short
load_image(const char *file, short type)
{
const char *f;
imlib_t img;
char *geom;
ASSERT_RVAL(file != NULL, 0);
ASSERT_RVAL(type >= 0 && type < image_max, 0);
D_PIXMAP(("load_image(%s, %d)\n", file, type));
if (*file != '\0') {
if ((geom = strchr(file, '@')) != NULL) {
*geom++ = 0;
} else if ((geom = strchr(file, ';')) != NULL) {
*geom++ = 0;
}
if (geom != NULL) {
set_pixmap_scale(geom, images[type].current->pmap);
}
if ((f = search_path(rs_path, file, PIXMAP_EXT)) == NULL) {
f = search_path(getenv(PATH_ENV), file, PIXMAP_EXT);
}
if (f != NULL) {
img.im = Imlib_load_image(imlib_id, (char *) f);
if (img.im == NULL) {
print_error("Unable to load image file \"%s\"", file);
return 0;
} else {
reset_simage(images[type].current, (RESET_IMLIB_IM | RESET_PMAP_PIXMAP | RESET_PMAP_MASK));
images[type].current->iml->im = img.im;
}
D_PIXMAP(("load_image() exiting. images[%s].current->iml->im == 0x%08x\n", get_image_type(type), images[type].current->iml->im));
return 1;
}
}
reset_simage(images[type].current, RESET_ALL);
return 0;
}
void
free_desktop_pixmap(void)
{
if (desktop_pixmap_is_mine) {
XFreePixmap(Xdisplay, desktop_pixmap);
desktop_pixmap_is_mine = 0;
}
desktop_pixmap = None;
}
# ifdef PIXMAP_OFFSET
# define MOD_IS_SET(mod) ((mod) && ((mod)->brightness != 0xff || (mod)->contrast != 0xff || (mod)->gamma != 0xff))
unsigned char
need_colormod(void)
{
register imlib_t *iml = images[image_bg].current->iml;
if (MOD_IS_SET(iml->mod) || MOD_IS_SET(iml->rmod) || MOD_IS_SET(iml->gmod) || MOD_IS_SET(iml->bmod)) {
return 1;
} else {
return 0;
}
}
void
colormod_trans(Pixmap p, GC gc, unsigned short w, unsigned short h)
{
XImage *ximg;
register unsigned long v, i;
unsigned long x, y;
unsigned int r, g, b;
unsigned short rm, gm, bm, shade;
ImlibColor ctab[256];
int real_depth = 0;
register int br, bg, bb;
register unsigned int mr, mg, mb;
imlib_t *iml = images[image_bg].current->iml;
D_PIXMAP(("colormod_trans(p == 0x%08x, gc, w == %hu, h == %hu) called.\n", p, w, h));
if (iml->mod) {
shade = iml->mod->brightness;
} else {
shade = 256;
}
if (iml->rmod) {
rm = (iml->rmod->brightness * shade) >> 8;
} else {
rm = shade;
}
if (iml->gmod) {
gm = (iml->gmod->brightness * shade) >> 8;
} else {
gm = shade;
}
if (iml->bmod) {
bm = (iml->bmod->brightness * shade) >> 8;
} else {
bm = shade;
}
if (rm == 256 && gm == 256 && bm == 256) {
return; /* Nothing to do */
}
if (Xdepth <= 8) {
XColor cols[256];
for (i = 0; i < (unsigned long) (1 << Xdepth); i++) {
cols[i].pixel = i;
cols[i].flags = DoRed | DoGreen | DoBlue;
}
XQueryColors(Xdisplay, cmap, cols, 1 << Xdepth);
for (i = 0; i < (unsigned long) (1 << Xdepth); i++) {
ctab[i].r = cols[i].red >> 8;
ctab[i].g = cols[i].green >> 8;
ctab[i].b = cols[i].blue >> 8;
ctab[i].pixel = cols[i].pixel;
}
} else if (Xdepth == 16) {
XWindowAttributes xattr;
XGetWindowAttributes(Xdisplay, desktop_window, &xattr);
if ((xattr.visual->red_mask == 0x7c00) && (xattr.visual->green_mask == 0x3e0) && (xattr.visual->blue_mask == 0x1f)) {
real_depth = 15;
}
}
if (!real_depth) {
real_depth = Xdepth;
}
ximg = XGetImage(Xdisplay, p, 0, 0, w, h, -1, ZPixmap);
if (ximg == NULL) {
print_warning("colormod_trans: XGetImage(Xdisplay, 0x%08x, 0, 0, %d, %d, -1, ZPixmap) returned NULL.",
p, w, h);
return;
}
D_PIXMAP(("XGetImage(Xdisplay, 0x%08x, 0, 0, %d, %d, -1, ZPixmap) returned 0x%08x.", p, w, h, ximg));
if (Xdepth <= 8) {
D_PIXMAP(("Rendering low-depth image, depth == %d\n", (int) Xdepth));
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
v = XGetPixel(ximg, x, y);
r = (ctab[v & 0xff].r * rm) >> 8;
g = (ctab[v & 0xff].g * gm) >> 8;
b = (ctab[v & 0xff].b * bm) >> 8;
v = Imlib_best_color_match(imlib_id, &r, &g, &b);
XPutPixel(ximg, x, y, v);
}
}
} else {
D_PIXMAP(("Rendering high-depth image, depth == %d\n", real_depth));
/* Determine bitshift and bitmask values */
switch (real_depth) {
case 15:
br = 7;
bg = 2;
bb = 3;
mr = mg = mb = 0xf8;
break;
case 16:
br = 8;
bg = bb = 3;
mr = mb = 0xf8;
mg = 0xfc;
break;
case 24:
case 32:
br = 16;
bg = 8;
bb = 0;
mr = mg = mb = 0xff;
break;
default:
print_warning("colormod_trans: Bit depth of %d is unsupported for tinting/shading.", real_depth);
return;
}
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
v = XGetPixel(ximg, x, y);
r = ((((v >> br) & mr) * rm) >> 8) & 0xff;
g = ((((v >> bg) & mg) * gm) >> 8) & 0xff;
b = ((((v << bb) & mb) * bm) >> 8) & 0xff;
v = ((r & mr) << br) | ((g & mg) << bg) | ((b & mb) >> bb);
XPutPixel(ximg, x, y, v);
}
}
}
XPutImage(Xdisplay, p, gc, ximg, 0, 0, 0, 0, w, h);
XDestroyImage(ximg);
}
Window
get_desktop_window(void)
{
Atom prop, type, prop2;
int format;
unsigned long length, after;
unsigned char *data;
unsigned int nchildren;
Window w, root, *children, parent;
if ((prop = XInternAtom(Xdisplay, "_XROOTPMAP_ID", True)) == None) {
D_PIXMAP(("No _XROOTPMAP_ID found.\n"));
}
if ((prop2 = XInternAtom(Xdisplay, "_XROOTCOLOR_PIXEL", True)) == None) {
D_PIXMAP(("No _XROOTCOLOR_PIXEL found.\n"));
}
if (prop == None && prop2 == None) {
return None;
}
if ((desktop_window != None) && (desktop_window != Xroot)) {
XSelectInput(Xdisplay, desktop_window, None);
}
for (w = TermWin.parent; w; w = parent) {
D_PIXMAP(("Current window ID is: 0x%08x\n", w));
if ((XQueryTree(Xdisplay, w, &root, &parent, &children, &nchildren)) == False) {
D_PIXMAP((" Egad! XQueryTree() returned false!\n"));
return None;
}
D_PIXMAP((" Window is 0x%08x with %d children, root is 0x%08x, parent is 0x%08x\n",
w, nchildren, root, parent));
if (nchildren) {
XFree(children);
}
if (prop != None) {
XGetWindowProperty(Xdisplay, w, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data);
} else if (prop2 != None) {
XGetWindowProperty(Xdisplay, w, prop2, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data);
} else {
continue;
}
if (type != None) {
D_PIXMAP((" Found desktop as window 0x%08x\n", w));
if (w != Xroot) {
XSelectInput(Xdisplay, w, PropertyChangeMask);
}
return (desktop_window = w);
}
}
D_PIXMAP(("No suitable parent found.\n"));
return (desktop_window = None);
}
Pixmap
get_desktop_pixmap(void)
{
Pixmap p;
Atom prop, type, prop2;
int format;
unsigned long length, after;
unsigned char *data;
if (desktop_window == None)
return None;
prop = XInternAtom(Xdisplay, "_XROOTPMAP_ID", True);
prop2 = XInternAtom(Xdisplay, "_XROOTCOLOR_PIXEL", True);
if (prop == None && prop2 == None) {
return None;
}
if (prop != None) {
XGetWindowProperty(Xdisplay, desktop_window, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data);
if (type == XA_PIXMAP) {
p = *((Pixmap *) data);
D_PIXMAP((" Found pixmap 0x%08x\n", p));
return p;
}
}
if (prop2 != None) {
XGetWindowProperty(Xdisplay, desktop_window, prop2, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data);
if (type == XA_CARDINAL) {
D_PIXMAP((" Solid color not yet supported.\n"));
return None;
}
}
D_PIXMAP(("No suitable attribute found.\n"));
return None;
}
# endif /* PIXMAP_OFFSET */
void
shaped_window_apply_mask(Window win, Pixmap mask)
{
static signed char have_shape = -1;
REQUIRE(win != None && mask != None);
D_PIXMAP(("shaped_window_apply_mask(win [0x%08x], mask [0x%08x]) called.\n", win, mask));
# ifdef HAVE_X_SHAPE_EXT
if (have_shape == -1) { /* Don't know yet. */
int unused;
D_PIXMAP(("shaped_window_apply_mask(): Looking for shape extension.\n"));
if (XQueryExtension(Xdisplay, "SHAPE", &unused, &unused, &unused)) {
have_shape = 1;
} else {
have_shape = 0;
}
}
if (have_shape == 1) {
D_PIXMAP(("shaped_window_apply_mask(): Shape extension available, applying mask.\n"));
XShapeCombineMask(Xdisplay, win, ShapeBounding, 0, 0, mask, ShapeSet);
} else if (have_shape == 0) {
D_PIXMAP(("shaped_window_apply_mask(): Shape extension not available.\n"));
return;
}
# else
D_PIXMAP(("shaped_window_apply_mask(): Shape support disabled.\n"));
# endif
}
void
set_icon_pixmap(char *filename, XWMHints * pwm_hints)
{
const char *icon_path;
ImlibImage *temp_im;
XWMHints *wm_hints;
if (pwm_hints) {
wm_hints = pwm_hints;
} else {
wm_hints = XGetWMHints(Xdisplay, TermWin.parent);
}
if (filename && *filename) {
if ((icon_path = search_path(rs_path, filename, NULL)) == NULL)
icon_path = search_path(getenv(PATH_ENV), filename, NULL);
if (icon_path != NULL) {
XIconSize *icon_sizes;
int count, i, w = 8, h = 8; /* At least 8x8 */
temp_im = Imlib_load_image(imlib_id, (char *) icon_path);
/* If we're going to render the image anyway, might as well be nice and give it to the WM in a size it likes. */
if (XGetIconSizes(Xdisplay, Xroot, &icon_sizes, &count)) {
for (i = 0; i < count; i++) {
D_PIXMAP(("Got icon sizes: Width %d to %d +/- %d, Height %d to %d +/- %d\n", icon_sizes[i].min_width, icon_sizes[i].max_width,
icon_sizes[i].width_inc, icon_sizes[i].min_height, icon_sizes[i].max_height, icon_sizes[i].height_inc));
if (icon_sizes[i].max_width > 64 || icon_sizes[i].max_height > 64) {
continue;
}
/* Find the largest supported size <= 64 */
w = MAX(icon_sizes[i].max_width, w);
h = MAX(icon_sizes[i].max_height, h);
}
fflush(stdout);
XFree(icon_sizes);
} else {
w = h = 48;
}
MIN_IT(w, 64);
MIN_IT(h, 64);
Imlib_render(imlib_id, temp_im, w, h);
wm_hints->icon_pixmap = Imlib_copy_image(imlib_id, temp_im);
wm_hints->icon_mask = Imlib_copy_mask(imlib_id, temp_im);
wm_hints->icon_window = XCreateSimpleWindow(Xdisplay, TermWin.parent, 0, 0, w, h, 0, 0L, 0L);
shaped_window_apply_mask(wm_hints->icon_window, wm_hints->icon_mask);
XSetWindowBackgroundPixmap(Xdisplay, wm_hints->icon_window, wm_hints->icon_pixmap);
wm_hints->flags |= IconWindowHint;
Imlib_destroy_image(imlib_id, temp_im);
}
} else {
/* Use the default. It's 48x48, so if the WM doesn't like it, tough cookies. Pixmap -> ImlibImage -> Render -> Pixmap would be
too expensive, IMHO. */
Imlib_data_to_pixmap(imlib_id, Eterm_xpm, &wm_hints->icon_pixmap, &wm_hints->icon_mask);
wm_hints->icon_window = XCreateSimpleWindow(Xdisplay, TermWin.parent, 0, 0, 48, 48, 0, 0L, 0L);
shaped_window_apply_mask(wm_hints->icon_window, wm_hints->icon_mask);
XSetWindowBackgroundPixmap(Xdisplay, wm_hints->icon_window, wm_hints->icon_pixmap);
wm_hints->flags |= IconWindowHint;
}
/* Only set the hints ourselves if we were passed a NULL pointer for pwm_hints */
if (!pwm_hints) {
XSetWMHints(Xdisplay, TermWin.parent, wm_hints);
XFree(wm_hints);
}
}
# ifdef USE_EFFECTS
int
fade_in(ImlibImage *img, int frames)
{
static int i = 0;
register int f = frames;
ImlibColorModifier mod;
double gamma, brightness, contrast;
Imlib_get_image_modifier(imlib_id, img, &mod);
if (i < f) {
i++;
gamma = (double) mod.gamma / i;
brightness = (double) mod.brightness / i;
contrast = (double) mod.contrast / i;
Imlib_set_image_modifier(imlib_id, img, &mod);
} else if (i == f) {
i = 0;
}
/* how many frames to go */
return (f - i);
}
# endif /* USE_EFFECTS */
#endif /* PIXMAP_SUPPORT */