/* * Copyright (C) 1997-2009, Michael Jennings * * 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. */ static const char cvs_ident[] = "$Id$"; #include "config.h" #include "feature.h" #include #include #include #include #include #ifdef HAVE_X_SHAPE_EXT # include # include # include # include #endif #include "buttons.h" #include "command.h" #include "draw.h" #include "e.h" #include "icon.h" #include "menus.h" #include "options.h" #include "pixmap.h" #include "screen.h" #include "scrollbar.h" #include "startup.h" #include "term.h" #include "windows.h" /* FIXME: Workaround for older versions of libast. */ #ifndef WORDS_BIGENDIAN # define WORDS_BIGENDIAN 0 #endif /* Optimized check for rm, gm, and bm all < 256 */ #define COLORMODS_HAVE_SATURATION(rm, gm, bm) ((rm|gm|bm) >> 8) /* Assembler routines for 32 bit cpu with mmx */ extern void shade_ximage_15_mmx(void *data, int bpl, int w, int h, int rm, int gm, int bm); extern void shade_ximage_16_mmx(void *data, int bpl, int w, int h, int rm, int gm, int bm); extern void shade_ximage_32_mmx(void *data, int bpl, int w, int h, int rm, int gm, int bm); /* Assembler routines for 64 bit cpu with sse2 */ extern void shade_ximage_15_sse2(void *data, int bpl, int w, int h, int rm, int gm, int bm); extern void shade_ximage_16_sse2(void *data, int bpl, int w, int h, int rm, int gm, int bm); extern void shade_ximage_32_sse2(void *data, int bpl, int w, int h, int rm, int gm, int bm); #ifdef PIXMAP_SUPPORT static Imlib_Border bord_none = { 0, 0, 0, 0 }; #endif Pixmap buffer_pixmap = None; #ifdef PIXMAP_OFFSET Pixmap desktop_pixmap = None, viewport_pixmap = None; Window desktop_window = None; unsigned char desktop_pixmap_is_mine = 0; #endif image_t images[image_max] = { {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL}, {None, 0, 0, NULL, NULL, NULL, NULL, NULL} }; #ifdef PIXMAP_SUPPORT static const char *get_iclass_name(unsigned char); #endif static void copy_buffer_pixmap(unsigned char mode, unsigned long fill, unsigned short width, unsigned short height); const char * get_image_type(unsigned char 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; case image_sb: return "image_sb"; break; case image_sa: return "image_sa"; break; case image_st: return "image_st"; break; case image_menu: return "image_menu"; break; case image_menuitem: return "image_menuitem"; break; case image_submenu: return "image_submenu"; break; case image_button: return "image_button"; break; case image_bbar: return "image_bbar"; break; case image_gbar: return "image_gbar"; break; case image_dialog: return "image_dialog"; break; case image_max: default: return "image_max"; break; } ASSERT_NOTREACHED_RVAL(""); } unsigned char image_mode_any(unsigned char mode) { unsigned char ismode = 0; FOREACH_IMAGE(if (image_mode_is(idx, mode)) ismode = 1;); return ismode; } #ifdef PIXMAP_SUPPORT const char * imlib_strerror(Imlib_Load_Error err) { switch (err) { case IMLIB_LOAD_ERROR_NONE: return "Success"; break; case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: return "No such file or directory"; break; case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY: return "Is a directory"; break; case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ: return "Permission denied"; break; case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT: return "No loader available for that file format"; break; case IMLIB_LOAD_ERROR_PATH_TOO_LONG: return "Path too long"; break; case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT: return "Path component does not exist"; break; case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY: return "Path component is not a directory"; break; case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE: return "Path points outside address space"; break; case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS: return "Too many symbolic links in path"; break; case IMLIB_LOAD_ERROR_OUT_OF_MEMORY: return "Out of memory"; break; case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS: return "No more file descriptors"; break; case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE: return "Permission denied"; break; case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: return "Disk full"; break; case IMLIB_LOAD_ERROR_UNKNOWN: default: return "Unknown error"; break; } ASSERT_NOTREACHED_RVAL(""); } 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 = (char *) strsep(&str, ":"));) { if (!BEG_STRCASECMP(token, "tile")) { op |= OP_TILE; } else if (!BEG_STRCASECMP(token, "hscale")) { op |= OP_HSCALE; } else if (!BEG_STRCASECMP(token, "vscale")) { op |= OP_VSCALE; } else if (!BEG_STRCASECMP(token, "scale")) { op |= OP_SCALE; } else if (!BEG_STRCASECMP(token, "propscale")) { op |= OP_PROPSCALE; } } return (op); } unsigned short set_pixmap_scale(const char *geom, pixmap_t *pmap) { static char str[GEOM_LEN + 1] = { '\0' }; unsigned int w = 0, h = 0; int x = 0, y = 0; unsigned short op; int flags; unsigned short changed = 0; char *p, *opstr; int n; if (!geom) 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(ESCSEQ_XTERM_TITLE, str); return 0; } if ((opstr = strchr(geom, ':'))) { *opstr++ = '\0'; op = parse_pixmap_ops(opstr); } else { op = pmap->op; } if (!(p = strchr(geom, ';'))) 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 & XValue)) { x = 50; } if (!(flags & HeightValue)) { h = w; } if (!(flags & YValue)) { if (flags & XNegative) flags |= YNegative; y = x; } if (flags & (WidthValue | HeightValue)) { 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 (pmap->w != (int) w) { pmap->w = (int) w; changed++; } if (pmap->h != (int) h) { pmap->h = (int) h; changed++; } if (!(flags & WidthValue) && geom[0] != '=') { x += pmap->x; y += pmap->y; } else { if (flags & XNegative) x += 100; if (flags & YNegative) y += 100; } BOUND(x, 0, 100); BOUND(y, 0, 100); 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(("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; } image_t *create_eterm_image(void) { image_t *i; i = (image_t *) MALLOC(sizeof(image_t)); memset(i, 0, sizeof(image_t)); return (i); } void reset_eterm_image(image_t *img, unsigned long mask) { ASSERT(img != NULL); D_PIXMAP(("reset_image(%8p, 0x%08x)\n", img, mask)); if ((mask & RESET_NORM) && img->norm) { reset_simage(img->norm, mask); } if ((mask & RESET_SELECTED) && img->selected) { reset_simage(img->selected, mask); } if ((mask & RESET_CLICKED) && img->clicked) { reset_simage(img->clicked, mask); } if ((mask & RESET_DISABLED) && img->disabled) { reset_simage(img->disabled, mask); } if (mask & RESET_MODE) { img->mode = 0; } if (mask & RESET_ALL) { img->userdef = 0; img->win = None; img->current = img->norm; } } void free_eterm_image(image_t *img) { if (img->selected == img->norm) { img->selected = NULL; } if (img->clicked == img->norm) { img->clicked = NULL; } if (img->disabled == img->norm) { img->disabled = NULL; } free_simage(img->norm); if (img->clicked == img->selected) { img->clicked = NULL; } if (img->disabled == img->selected || img->disabled == img->clicked) { img->disabled = NULL; } if (img->selected) { free_simage(img->selected); } if (img->clicked) { free_simage(img->clicked); } if (img->disabled) { free_simage(img->disabled); } #if 0 /* FIXME: There should really be an option to specify whether or not to free the image itself, but since we never MALLOC() an entire image_t, it's not really needed at this point. And I'm lazy. :-) */ FREE(img); #endif } simage_t *create_simage(void) { simage_t *s; s = (simage_t *) MALLOC(sizeof(simage_t)); memset(s, 0, sizeof(simage_t)); s->pmap = (pixmap_t *) MALLOC(sizeof(pixmap_t)); s->iml = (imlib_t *) MALLOC(sizeof(imlib_t)); memset(s->pmap, 0, sizeof(pixmap_t)); memset(s->iml, 0, sizeof(imlib_t)); return s; } void reset_simage(simage_t *simg, unsigned long mask) { ASSERT(simg != NULL); D_PIXMAP(("reset_simage(%8p, 0x%08x)\n", simg, mask)); if ((mask & RESET_PMAP_PIXMAP) && simg->pmap->pixmap != None) { IMLIB_FREE_PIXMAP(simg->pmap->pixmap); simg->pmap->pixmap = None; simg->pmap->mask = None; } if ((mask & RESET_IMLIB_IM) && simg->iml->im) { imlib_context_set_image(simg->iml->im); imlib_free_image_and_decache(); simg->iml->im = NULL; } if ((mask & RESET_IMLIB_BORDER) && simg->iml->border) { FREE(simg->iml->border); simg->iml->border = NULL; } if ((mask & RESET_IMLIB_BEVEL) && simg->iml->bevel) { FREE(simg->iml->bevel->edges); FREE(simg->iml->bevel); simg->iml->bevel = NULL; } if ((mask & RESET_IMLIB_PAD) && simg->iml->pad) { FREE(simg->iml->pad); simg->iml->pad = 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) { if (simg->iml->rmod->imlib_mod) { imlib_context_set_color_modifier(simg->iml->rmod->imlib_mod); imlib_free_color_modifier(); } FREE(simg->iml->rmod); simg->iml->rmod = NULL; } if ((mask & RESET_IMLIB_GMOD) && simg->iml->gmod) { if (simg->iml->gmod->imlib_mod) { imlib_context_set_color_modifier(simg->iml->gmod->imlib_mod); imlib_free_color_modifier(); } FREE(simg->iml->gmod); simg->iml->gmod = NULL; } if ((mask & RESET_IMLIB_BMOD) && simg->iml->bmod) { if (simg->iml->bmod->imlib_mod) { imlib_context_set_color_modifier(simg->iml->bmod->imlib_mod); imlib_free_color_modifier(); } 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 free_simage(simage_t *s) { reset_simage(s, RESET_ALL_SIMG); FREE(s->iml); FREE(s->pmap); FREE(s); } colormod_t *create_colormod(void) { colormod_t *cmod; cmod = (colormod_t *) MALLOC(sizeof(colormod_t)); cmod->brightness = cmod->contrast = cmod->gamma = 0x100; cmod->imlib_mod = NULL; return cmod; } void reset_colormod(colormod_t *cmod) { ASSERT(cmod != NULL); cmod->brightness = cmod->contrast = cmod->gamma = 0x100; if (cmod->imlib_mod) { imlib_context_set_color_modifier(cmod->imlib_mod); imlib_reset_color_modifier(); } } void free_colormod(colormod_t *cmod) { ASSERT(cmod != NULL); if (cmod->imlib_mod) { imlib_context_set_color_modifier(cmod->imlib_mod); imlib_free_color_modifier(); } FREE(cmod); } static const char * get_iclass_name(unsigned char which) { switch (which) { case image_bg: return "ETERM_BG"; break; case image_up: return "ETERM_ARROW_UP"; break; case image_down: return "ETERM_ARROW_DOWN"; break; case image_left: return "ETERM_ARROW_LEFT"; break; case image_right: return "ETERM_ARROW_RIGHT"; break; case image_sb: return "ETERM_TROUGH"; break; case image_sa: return "ETERM_ANCHOR"; break; case image_st: return "ETERM_THUMB"; break; case image_menu: return "ETERM_MENU_ITEM"; break; /* FIXME: This should be ETERM_MENU_BOX */ case image_menuitem: return "ETERM_MENU_ITEM"; break; case image_submenu: return "ETERM_MENU_SUBMENU"; break; case image_button: return "ETERM_MENU_ITEM"; break; /* FIXME: These four should */ case image_bbar: return "ETERM_MENU_BOX"; break; /* have their own image classes */ case image_gbar: return "ETERM_ANCHOR"; break; case image_dialog: return "ETERM_MENU_BOX"; break; default: ASSERT_NOTREACHED_RVAL(NULL); break; } } unsigned char check_image_ipc(unsigned char reset) { static unsigned char checked = 0; register unsigned short i; char buff[255], *reply; const char *iclass; if (reset) { checked = 0; } if (checked) { return ((checked == 1) ? 1 : 0); } for (i = 0; i < image_max; i++) { if (!image_mode_is(i, MODE_AUTO)) { continue; } iclass = get_iclass_name(i); snprintf(buff, sizeof(buff), "imageclass %s query", iclass); reply = enl_send_and_wait(buff); if (strstr(reply, "not")) { libast_print_error("ImageClass \"%s\" is not defined in Enlightenment. Disallowing \"auto\" mode for this image.\n", iclass); image_mode_fallback(i); } else if (strstr(reply, "Error")) { /* *INDENT-OFF* */ FOREACH_IMAGE( if (image_mode_is(idx, MODE_AUTO)) { if (image_mode_is(idx, ALLOW_IMAGE)) { image_set_mode(idx, MODE_IMAGE); } else { image_set_mode(idx, MODE_SOLID); } } if (image_mode_is(idx, ALLOW_AUTO)) { image_disallow_mode(idx, ALLOW_AUTO); } ); /* *INDENT-ON* */ libast_print_error("Looks like this version of Enlightenment doesn't support the IPC " "commands I need. Disallowing \"auto\" mode for all images.\n"); FREE(reply); checked = 2; return 0; } FREE(reply); } checked = 1; return 1; } Pixmap create_trans_pixmap(simage_t *simg, unsigned char which, Drawable d, int x, int y, unsigned short width, unsigned short height) { int pw, ph; Window dummy; Screen *scr; Pixmap p = None; GC gc; D_PIXMAP(("create_trans_pixmap(%8p, 0x%08x, %u, %d, %d, %hu, %hu) called.\n", simg, d, which, x, y, width, height)); scr = ScreenOfDisplay(Xdisplay, Xscreen); if (!scr) return None; if (!update_desktop_info(&pw, &ph)) { D_PIXMAP(("update_desktop_info() failed.\n")); return None; } if (refresh_type == NO_REFRESH) { /* If we're hidden/shaded, translated coordinates to be parent relative, then use the internal cache data to tell where we are on the desktop. Otherwise, just ask X. */ XTranslateCoordinates(Xdisplay, d, TermWin.parent, x, y, &x, &y, &dummy); x += TermWin.x; y += TermWin.y; } else { XTranslateCoordinates(Xdisplay, d, desktop_window, x, y, &x, &y, &dummy); } p = LIBAST_X_CREATE_PIXMAP(width, height); gc = LIBAST_X_CREATE_GC(0, NULL); D_PIXMAP(("Created p [0x%08x] as a %hux%hu pixmap at %d, %d relative to window 0x%08x\n", p, width, height, x, y, desktop_window)); if (p != None) { D_PIXMAP(("Tiling %ux%u desktop pixmap 0x%08x onto p.\n", pw, ph, desktop_pixmap)); XSetTile(Xdisplay, gc, desktop_pixmap); XSetTSOrigin(Xdisplay, gc, pw - (x % pw), ph - (y % ph)); XSetFillStyle(Xdisplay, gc, FillTiled); XFillRectangle(Xdisplay, p, gc, 0, 0, width, height); if ((which != image_bg || (BITFIELD_IS_SET(image_options, IMAGE_OPTIONS_ITRANS)) || images[image_bg].current != images[image_bg].norm) && need_colormod(simg->iml)) { colormod_trans(p, simg->iml, gc, width, height); } if (simg->iml->bevel) { D_PIXMAP(("Beveling pixmap 0x%08x with edges %d, %d, %d, %d\n", p, simg->iml->bevel->edges->left, simg->iml->bevel->edges->top, simg->iml->bevel->edges->right, simg->iml->bevel->edges->bottom)); bevel_pixmap(p, width, height, simg->iml->bevel->edges, simg->iml->bevel->up); } } LIBAST_X_FREE_GC(gc); return p; } Pixmap create_viewport_pixmap(simage_t *simg, Drawable d, int x, int y, unsigned short width, unsigned short height) { short xsize, ysize; Window dummy; unsigned int pw, ph, pb, pd; int px, py; Pixmap p = None, mask = None; GC gc; Screen *scr; D_PIXMAP(("create_viewport_pixmap(%8p, 0x%08x, %d, %d, %hu, %hu) called.\n", simg, d, x, y, width, height)); scr = ScreenOfDisplay(Xdisplay, Xscreen); if (!scr) return None; if (desktop_window == None) { get_desktop_window(); if (desktop_window == None) { D_PIXMAP(("No desktop window found.\n")); return None; } } if (viewport_pixmap == None) { imlib_t *tmp_iml = images[image_bg].current->iml; imlib_context_set_image(tmp_iml->im); imlib_context_set_drawable(d); imlib_image_set_has_alpha(0); imlib_context_set_anti_alias(1); imlib_context_set_dither(1); imlib_context_set_blend(0); xsize = imlib_image_get_width(); ysize = imlib_image_get_height(); if (tmp_iml->border) { imlib_image_set_border(tmp_iml->border); } else { imlib_image_set_border(&bord_none); } imlib_context_set_color_modifier((tmp_iml->mod && tmp_iml->mod->imlib_mod) ? tmp_iml->mod->imlib_mod : NULL); 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_pixmaps_for_whole_image_at_size(&viewport_pixmap, &mask, scr->width, scr->height); } else { D_PIXMAP(("Tiling image at %dx%d\n", xsize, ysize)); imlib_render_pixmaps_for_whole_image(&viewport_pixmap, &mask); } if (viewport_pixmap == None) { libast_print_error("Delayed image load failure for \"%s\". Using solid color mode.\n", imlib_image_get_filename()); image_set_mode(image_bg, MODE_SOLID); reset_simage(simg, RESET_ALL_SIMG); return None; } IMLIB_REGISTER_PIXMAP(viewport_pixmap); 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(simg->pmap->pixmap); simg->pmap->pixmap = None; } else { p = simg->pmap->pixmap; } } if (p == None) { p = LIBAST_X_CREATE_PIXMAP(width, height); D_PIXMAP(("Created p == 0x%08x\n", p)); } gc = LIBAST_X_CREATE_GC(0, NULL); XTranslateCoordinates(Xdisplay, d, desktop_window, x, y, &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, p, gc, x, y, width, height, 0, 0); } else { XSetTile(Xdisplay, gc, viewport_pixmap); XSetTSOrigin(Xdisplay, gc, xsize - (x % xsize), ysize - (y % ysize)); XSetFillStyle(Xdisplay, gc, FillTiled); XFillRectangle(Xdisplay, p, gc, 0, 0, width, height); } LIBAST_X_FREE_GC(gc); return p; } void paste_simage(simage_t *simg, unsigned char which, Window win, Drawable d, unsigned short x, unsigned short y, unsigned short w, unsigned short h) { Pixmap pmap = None, mask = None; GC gc; ASSERT(simg != NULL); D_PIXMAP(("paste_simage(%8p, %s, 0x%08x, 0x%08x, %hd, %hd, %hd, %hd) called.\n", simg, get_image_type(which), (int) win, (int) d, x, y, w, h)); REQUIRE(d != None); REQUIRE(w > 0); REQUIRE(h > 0); if (which != image_max) { if (image_mode_is(which, MODE_AUTO) && image_mode_is(which, ALLOW_AUTO)) { char buff[255], *reply; const char *iclass, *state; check_image_ipc(0); if (image_mode_is(which, MODE_AUTO)) { iclass = get_iclass_name(which); if (simg == images[which].selected) { state = "hilited"; } else if (simg == images[which].clicked) { state = "clicked"; } else { state = "normal"; } D_PIXMAP((" -> iclass == \"%s\", state == \"%s\"\n", NONULL(iclass), NONULL(state))); if (iclass) { snprintf(buff, sizeof(buff), "imageclass %s apply_copy 0x%x %s %hd %hd", iclass, (int) d, state, w, h); reply = enl_send_and_wait(buff); if (strstr(reply, "Error")) { libast_print_error ("Enlightenment didn't seem to like something about my syntax. Disallowing \"auto\" mode for this image.\n"); image_mode_fallback(which); FREE(reply); } else { pmap = (Pixmap) strtoul(reply, (char **) NULL, 0); mask = (Pixmap) strtoul(spiftool_get_pword(2, reply), (char **) NULL, 0); FREE(reply); enl_ipc_sync(); if (pmap) { gc = LIBAST_X_CREATE_GC(0, NULL); XSetClipMask(Xdisplay, gc, mask); XSetClipOrigin(Xdisplay, gc, x, y); XCopyArea(Xdisplay, pmap, d, gc, 0, 0, w, h, x, y); snprintf(buff, sizeof(buff), "imageclass %s free_pixmap 0x%08x", iclass, (int) pmap); enl_ipc_send(buff); LIBAST_X_FREE_GC(gc); return; } else { libast_print_error ("Enlightenment returned a null pixmap, which I can't use. Disallowing \"auto\" mode for this image.\n"); FREE(reply); image_mode_fallback(which); } } } } } else if (image_mode_is(which, MODE_TRANS) && image_mode_is(which, ALLOW_TRANS)) { Pixmap p; gc = LIBAST_X_CREATE_GC(0, NULL); p = create_trans_pixmap(simg, which, win, x, y, w, h); if (p != None) { XCopyArea(Xdisplay, p, d, gc, 0, 0, w, h, x, y); if (p != desktop_pixmap) { LIBAST_X_FREE_PIXMAP(p); } } LIBAST_X_FREE_GC(gc); } else if (image_mode_is(which, MODE_VIEWPORT) && image_mode_is(which, ALLOW_VIEWPORT)) { Pixmap p; gc = LIBAST_X_CREATE_GC(0, NULL); p = create_viewport_pixmap(simg, win, x, y, w, h); if (simg->iml->bevel) { bevel_pixmap(p, w, h, simg->iml->bevel->edges, simg->iml->bevel->up); } XCopyArea(Xdisplay, p, d, gc, 0, 0, w, h, x, y); LIBAST_X_FREE_PIXMAP(p); LIBAST_X_FREE_GC(gc); } } if (((which == image_max) || (image_mode_is(which, MODE_IMAGE) && image_mode_is(which, ALLOW_IMAGE))) && (simg->iml)) { imlib_context_set_image(simg->iml->im); imlib_context_set_drawable(d); imlib_context_set_anti_alias(1); imlib_context_set_dither(1); imlib_context_set_blend(0); if (simg->iml->border) { imlib_image_set_border(simg->iml->border); } else { imlib_image_set_border(&bord_none); } imlib_context_set_color_modifier((simg->iml->mod && simg->iml->mod->imlib_mod) ? simg->iml->mod->imlib_mod : NULL); if (w == imlib_image_get_width() && h == imlib_image_get_height()) { imlib_render_pixmaps_for_whole_image(&pmap, &mask); } else { imlib_render_pixmaps_for_whole_image_at_size(&pmap, &mask, w, h); } if (pmap == None) { libast_print_error("Delayed image load failure for \"%s\".\n", NONULL(imlib_image_get_filename())); reset_simage(simg, RESET_ALL_SIMG); return; } IMLIB_REGISTER_PIXMAP(pmap); gc = LIBAST_X_CREATE_GC(0, NULL); if (mask) { XSetClipMask(Xdisplay, gc, mask); XSetClipOrigin(Xdisplay, gc, x, y); } XCopyArea(Xdisplay, pmap, d, gc, 0, 0, w, h, x, y); IMLIB_FREE_PIXMAP(pmap); LIBAST_X_FREE_GC(gc); } } 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: scrollbar_draw_uparrow(IMAGE_STATE_CURRENT, MODE_MASK); break; case image_down: scrollbar_draw_downarrow(IMAGE_STATE_CURRENT, MODE_MASK); break; case image_sb: scrollbar_draw_trough(IMAGE_STATE_CURRENT, MODE_MASK); break; case image_sa: case image_st: scrollbar_draw_anchor(IMAGE_STATE_CURRENT, MODE_MASK); break; case image_button: case image_bbar: case image_gbar: bbar_draw_all(IMAGE_STATE_CURRENT, MODE_MASK); break; default: D_PIXMAP(("Bad value %u\n", which)); break; } } void redraw_images_by_mode(unsigned char mode) { if (mode == MODE_SOLID) { redraw_all_images(); } else { if (image_mode_is(image_bg, mode)) { render_simage(images[image_bg].current, TermWin.vt, TermWin_TotalWidth(), TermWin_TotalHeight(), image_bg, 0); scr_touch(); } scrollbar_draw(IMAGE_STATE_CURRENT, mode); bbar_draw_all(IMAGE_STATE_CURRENT, mode); } } #endif /* PIXMAP_SUPPORT */ static void copy_buffer_pixmap(unsigned char mode, unsigned long fill, unsigned short width, unsigned short height) { GC gc; XGCValues gcvalue; ASSERT(buffer_pixmap == None); buffer_pixmap = LIBAST_X_CREATE_PIXMAP(width, height); gcvalue.foreground = (Pixel) fill; gc = LIBAST_X_CREATE_GC(GCForeground, &gcvalue); XSetGraphicsExposures(Xdisplay, gc, False); if (mode == MODE_SOLID) { simage_t *simg; simg = images[image_bg].current; if (simg->pmap->pixmap) { LIBAST_X_FREE_PIXMAP(simg->pmap->pixmap); } simg->pmap->pixmap = LIBAST_X_CREATE_PIXMAP(width, height); XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, width, height); XCopyArea(Xdisplay, simg->pmap->pixmap, buffer_pixmap, gc, 0, 0, width, height, 0, 0); } else { XCopyArea(Xdisplay, (Pixmap) fill, buffer_pixmap, gc, 0, 0, width, height, 0, 0); } LIBAST_X_FREE_GC(gc); } void render_simage(simage_t *simg, Window win, unsigned short width, unsigned short height, unsigned char which, renderop_t renderop) { XGCValues gcvalue; GC gc; Pixmap pixmap = None; Screen *scr; #ifdef PIXMAP_SUPPORT short xsize, ysize; short xpos = 0, ypos = 0; unsigned short rendered = 0; unsigned short xscaled = 0, yscaled = 0; #endif scr = ScreenOfDisplay(Xdisplay, Xscreen); if (!scr) return; ASSERT(simg != NULL); ASSERT(simg->iml != NULL); ASSERT(simg->pmap != NULL); REQUIRE(win != None); D_PIXMAP(("Rendering simg->iml->im %8p (%s) at %hux%hu onto window 0x%08x\n", simg->iml->im, get_image_type(which), width, height, win)); D_PIXMAP(("Image mode is 0x%02x\n", images[which].mode)); #ifdef PIXMAP_SUPPORT if ((which == image_bg) && image_mode_is(image_bg, MODE_VIEWPORT)) { width = scr->width; height = scr->height; } #endif if (!(width) || !(height)) return; gcvalue.foreground = gcvalue.background = PixColors[bgColor]; gc = LIBAST_X_CREATE_GC(GCForeground | GCBackground, &gcvalue); pixmap = simg->pmap->pixmap; /* Save this for later */ if ((which == image_bg) && (buffer_pixmap != None)) { LIBAST_X_FREE_PIXMAP(buffer_pixmap); buffer_pixmap = None; } #ifdef PIXMAP_SUPPORT /* Reset window shape mask. */ shaped_window_apply_mask(win, None); if ((images[which].mode & MODE_AUTO) && (images[which].mode & ALLOW_AUTO)) { char buff[255]; const char *iclass, *state; check_image_ipc(0); if (image_mode_is(which, MODE_AUTO)) { iclass = get_iclass_name(which); if (simg == images[which].selected) { state = "hilited"; } else if (simg == images[which].clicked) { state = "clicked"; } else { state = "normal"; } if (iclass) { if (renderop & RENDER_FORCE_PIXMAP) { char *reply; snprintf(buff, sizeof(buff), "imageclass %s apply_copy 0x%x %s %hd %hd", iclass, (int) win, state, width, height); reply = enl_send_and_wait(buff); if (strstr(reply, "Error")) { libast_print_error ("Enlightenment didn't seem to like something about my syntax. Disallowing \"auto\" mode for this image.\n"); image_mode_fallback(which); FREE(reply); } else { Pixmap pmap, mask; pmap = (Pixmap) strtoul(reply, (char **) NULL, 0); mask = (Pixmap) strtoul(spiftool_get_pword(2, reply), (char **) NULL, 0); FREE(reply); enl_ipc_sync(); if (pmap) { if (mask) { XSetClipMask(Xdisplay, gc, mask); XSetClipOrigin(Xdisplay, gc, 0, 0); } if (simg->pmap->pixmap != None) { LIBAST_X_FREE_PIXMAP(simg->pmap->pixmap); simg->pmap->pixmap = None; } if (renderop & RENDER_FORCE_PIXMAP) { simg->pmap->pixmap = LIBAST_X_CREATE_PIXMAP(width, height); XCopyArea(Xdisplay, pmap, simg->pmap->pixmap, gc, 0, 0, width, height, 0, 0); XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap); } else { XSetWindowBackgroundPixmap(Xdisplay, win, pmap); } snprintf(buff, sizeof(buff), "imageclass %s free_pixmap 0x%08x", iclass, (int) pmap); enl_ipc_send(buff); } else { libast_print_error ("Enlightenment returned a null pixmap, which I can't use. Disallowing \"auto\" mode for this image.\n"); FREE(reply); image_mode_fallback(which); } } } else { snprintf(buff, sizeof(buff), "imageclass %s apply 0x%x %s", iclass, (int) win, state); enl_ipc_send(buff); LIBAST_X_FREE_GC(gc); return; } } } } # ifdef PIXMAP_OFFSET if (image_mode_is(which, MODE_TRANS) && image_mode_is(which, ALLOW_TRANS)) { if (simg->pmap->pixmap != None) { LIBAST_X_FREE_PIXMAP(simg->pmap->pixmap); } simg->pmap->pixmap = create_trans_pixmap(simg, which, win, 0, 0, width, height); if (simg->pmap->pixmap != None) { if ((which == image_bg) && (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_DOUBLE_BUFFER))) { copy_buffer_pixmap(MODE_TRANS, (unsigned long) simg->pmap->pixmap, width, height); XSetWindowBackgroundPixmap(Xdisplay, win, buffer_pixmap); } else { XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap); if (!(renderop & RENDER_FORCE_PIXMAP)) { IMLIB_FREE_PIXMAP(simg->pmap->pixmap); simg->pmap->pixmap = None; } } } else { image_mode_fallback(which); } } else if (image_mode_is(which, MODE_VIEWPORT) && image_mode_is(which, ALLOW_VIEWPORT)) { Pixmap p; D_PIXMAP(("Viewport mode enabled. viewport_pixmap == 0x%08x and simg->pmap->pixmap == 0x%08x\n", viewport_pixmap, simg->pmap->pixmap)); p = create_viewport_pixmap(simg, win, 0, 0, width, height); if (p && (p != simg->pmap->pixmap)) { if (simg->pmap->pixmap != None) { LIBAST_X_FREE_PIXMAP(simg->pmap->pixmap); } simg->pmap->pixmap = p; } if (simg->pmap->pixmap != None) { D_PIXMAP(("Setting background of window 0x%08x to 0x%08x\n", win, simg->pmap->pixmap)); if ((which == image_bg) && (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_DOUBLE_BUFFER))) { copy_buffer_pixmap(MODE_VIEWPORT, (unsigned long) simg->pmap->pixmap, width, height); XSetWindowBackgroundPixmap(Xdisplay, win, buffer_pixmap); } else { XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap); if (!(renderop & RENDER_FORCE_PIXMAP)) { IMLIB_FREE_PIXMAP(simg->pmap->pixmap); simg->pmap->pixmap = None; } } } else { image_mode_fallback(which); } } # 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; imlib_context_set_image(simg->iml->im); imlib_context_set_drawable(win); imlib_context_set_anti_alias(1); imlib_context_set_dither(1); imlib_context_set_blend(0); xsize = imlib_image_get_width(); ysize = imlib_image_get_height(); D_PIXMAP(("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) && w && h) { 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 && BITFIELD_IS_SET(simg->pmap->op, OP_HSCALE)) { w = 100; } if (!h && BITFIELD_IS_SET(simg->pmap->op, OP_VSCALE)) { h = 100; } 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(("Calculated scaled size as %hux%hu with origin at (%hd, %hd)\n", xscaled, yscaled, xpos, ypos)); if (simg->iml->border) { D_PIXMAP(("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_image_set_border(simg->iml->border); } else { imlib_image_set_border(&bord_none); } imlib_context_set_color_modifier((simg->iml->mod && simg->iml->mod->imlib_mod) ? simg->iml->mod->imlib_mod : NULL); D_PIXMAP(("Rendering image simg->iml->im [%8p] to %hdx%hd pixmap\n", simg->iml->im, xscaled, yscaled)); imlib_render_pixmaps_for_whole_image_at_size(&simg->pmap->pixmap, &simg->pmap->mask, xscaled, yscaled); rendered = 1; if (simg->pmap->pixmap != None) { IMLIB_REGISTER_PIXMAP(simg->pmap->pixmap); if (pixmap != None && pixmap != simg->pmap->pixmap) { IMLIB_FREE_PIXMAP(pixmap); } if (xscaled != width || yscaled != height || xpos != 0 || ypos != 0) { unsigned char single; /* This tells us if we have a single, non-tiled image which does not entirely fill the window */ single = ((xscaled < width || yscaled < height) && !(simg->pmap->op & OP_TILE)) ? 1 : 0; pixmap = simg->pmap->pixmap; simg->pmap->pixmap = LIBAST_X_CREATE_PIXMAP(width, height); 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(pixmap); } else if (renderop & RENDER_FORCE_PIXMAP) { pixmap = simg->pmap->pixmap; simg->pmap->pixmap = LIBAST_X_CREATE_PIXMAP(width, height); D_PIXMAP(("Replacing pixmap 0x%08x with new pixmap 0x%08x.\n", pixmap, simg->pmap->pixmap)); XCopyArea(Xdisplay, pixmap, simg->pmap->pixmap, gc, 0, 0, width, height, 0, 0); IMLIB_FREE_PIXMAP(pixmap); } else { shaped_window_apply_mask(win, simg->pmap->mask); } if (simg->iml->bevel) { bevel_pixmap(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)); if ((which == image_bg) && (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_DOUBLE_BUFFER))) { copy_buffer_pixmap(MODE_VIEWPORT, (unsigned long) simg->pmap->pixmap, width, height); XSetWindowBackgroundPixmap(Xdisplay, win, buffer_pixmap); } else { /* FIXME: For efficiency, just fill the window with the pixmap and handle exposes by copying from simg->pmap->pixmap. */ XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap); if (!(renderop & RENDER_FORCE_PIXMAP)) { IMLIB_FREE_PIXMAP(simg->pmap->pixmap); simg->pmap->pixmap = None; } } } else { libast_print_error("Delayed image load failure for \"%s\". Using solid color mode.\n", imlib_image_get_filename()); image_set_mode(which, MODE_SOLID); reset_simage(simg, RESET_ALL_SIMG); } } else { image_set_mode(which, MODE_SOLID); reset_simage(simg, RESET_ALL_SIMG); } } #endif /* Fall back to solid mode if all else fails. */ if (!image_mode_is(which, MODE_MASK)) { if ((which == image_bg) && (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_DOUBLE_BUFFER))) { copy_buffer_pixmap(MODE_SOLID, (unsigned long) PixColors[bgColor], width, height); XSetWindowBackgroundPixmap(Xdisplay, win, buffer_pixmap); } else { if ((renderop & RENDER_FORCE_PIXMAP) || (simg->iml->bevel)) { if (simg->pmap->pixmap != None) { LIBAST_X_FREE_PIXMAP(simg->pmap->pixmap); } simg->pmap->pixmap = LIBAST_X_CREATE_PIXMAP(width, height); XSetForeground(Xdisplay, gc, ((which == image_bg) ? (PixColors[bgColor]) : (simg->bg))); XFillRectangle(Xdisplay, simg->pmap->pixmap, gc, 0, 0, width, height); if (simg->iml->bevel && simg->iml->bevel->edges) { DRAW_SOLID_BEVEL(simg->pmap->pixmap, width, height, simg->bg, simg->iml->bevel->up, simg->iml->bevel->edges->left); } /* FIXME: For efficiency, just fill the window with the pixmap and handle exposes by copying from simg->pmap->pixmap. */ XSetWindowBackgroundPixmap(Xdisplay, win, simg->pmap->pixmap); } else { XSetWindowBackground(Xdisplay, win, ((which == image_bg) ? (PixColors[bgColor]) : (simg->bg))); } } } XClearWindow(Xdisplay, win); LIBAST_X_FREE_GC(gc); return; } #ifdef PIXMAP_SUPPORT const char * search_path(const char *pathlist, const char *file) { 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); } getcwd(name, PATH_MAX); len = strlen(name); D_OPTIONS(("search_path(\"%s\", \"%s\") called from \"%s\".\n", pathlist, file, name)); if (len < PATH_MAX - 1) { strcat(name, "/"); strncat(name, file, PATH_MAX - len - 2); } D_OPTIONS(("Checking for file \"%s\"\n", name)); if (!access(name, R_OK)) { if (stat(name, &fst)) { D_OPTIONS(("Unable to stat %s -- %s\n", name, 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 name; } else { D_OPTIONS(("%s is a directory.\n", name)); } } else { D_OPTIONS(("Unable to access %s -- %s\n", name, strerror(errno))); } if (!(p = strchr(file, '@'))) p = strchr(file, '\0'); len = (p - file); /* leave room for an extra '/' and trailing '\0' */ maxpath = sizeof(name) - (len + 2); if (maxpath <= 0) return NULL; /* check if we can find it now */ strncpy(name, file, len); name[len] = '\0'; D_OPTIONS(("Checking for file \"%s\"\n", name)); if (!access(name, R_OK)) { if (stat(name, &fst)) { D_OPTIONS(("Unable to stat %s -- %s\n", name, 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 name; } else { D_OPTIONS(("%s is a directory.\n", name)); } } else { D_OPTIONS(("Unable to access %s -- %s\n", name, strerror(errno))); } for (path = pathlist; path && *path != '\0'; path = p) { int n; /* colon delimited */ if (!(p = strchr(path, ':'))) p = strchr(path, '\0'); n = (p - path); if (*p != '\0') p++; if (n > 0 && n <= maxpath) { if (*path == '~') { unsigned int l; char *home_dir = getenv("HOME"); if (home_dir && *home_dir) { l = strlen(home_dir); if (l + n < (unsigned) maxpath) { strcpy(name, home_dir); strncat(name, path + 1, n - 1); n += l - 1; } } } else { strncpy(name, path, n); } if (name[n - 1] != '/') name[n++] = '/'; name[n] = '\0'; strncat(name, file, len); D_OPTIONS(("Checking for file \"%s\"\n", name)); if (!access(name, R_OK)) { if (stat(name, &fst)) { D_OPTIONS(("Unable to stat %s -- %s\n", name, 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 name; } else { D_OPTIONS(("%s is a directory.\n", name)); } } else { D_OPTIONS(("Unable to access %s -- %s\n", name, strerror(errno))); } } } D_OPTIONS(("File \"%s\" not found in path.\n", file)); return ((const char *) NULL); } unsigned char load_image(const char *file, simage_t *simg) { const char *f; Imlib_Image *im; Imlib_Load_Error im_err; char *geom; ASSERT_RVAL(file != NULL, 0); ASSERT_RVAL(simg != NULL, 0); D_PIXMAP(("load_image(%s, %8p)\n", file, simg)); if (*file != '\0') { if ((geom = strchr(file, '@'))) { *geom++ = 0; } else if ((geom = strchr(file, ';'))) { *geom++ = 0; } if (geom) { set_pixmap_scale(geom, simg->pmap); } if (!(f = search_path(rs_path, file))) { f = search_path(getenv(PATH_ENV), file); } if (f) { im = imlib_load_image_with_error_return(f, &im_err); if (!im) { libast_print_error("Unable to load image file \"%s\" -- %s\n", file, imlib_strerror(im_err)); return 0; } else { reset_simage(simg, (RESET_IMLIB_IM | RESET_PMAP_PIXMAP | RESET_PMAP_MASK)); simg->iml->im = im; } D_PIXMAP(("Found image %8p.\n", im)); return 1; } else { libast_print_error("Unable to locate file \"%s\" in image path.\n"); } } reset_simage(simg, RESET_ALL_SIMG); return 0; } void update_cmod(colormod_t *cmod) { ASSERT(cmod != NULL); /* When a particular R/G/B color modifier is changed, this function must be called to resync the Imlib2 color modifier (imlib_mod) with our new brightness, contrast, and gamma values. */ if (cmod->imlib_mod) { imlib_context_set_color_modifier(cmod->imlib_mod); imlib_reset_color_modifier(); } else { cmod->imlib_mod = imlib_create_color_modifier(); imlib_context_set_color_modifier(cmod->imlib_mod); } if (cmod->brightness != 0x100) { imlib_modify_color_modifier_brightness((double) (cmod->brightness - 255.0) / 255.0); } if (cmod->contrast != 0x100) { imlib_modify_color_modifier_contrast((double) (cmod->contrast - 255.0) / 255.0); } if (cmod->gamma != 0x100) { imlib_modify_color_modifier_gamma((double) (cmod->gamma - 255.0) / 255.0); } imlib_context_set_color_modifier(NULL); } void update_cmod_tables(imlib_t *iml) { colormod_t *mod = iml->mod, *rmod = iml->rmod, *gmod = iml->gmod, *bmod = iml->bmod; DATA8 rt[256], gt[256], bt[256]; REQUIRE(mod || rmod || gmod || bmod); /* When any changes is made to any individual color modifier for an image, this function must be called to update the overall Imlib2 color modifier. */ D_PIXMAP(("Updating color modifier tables for %8p\n", iml)); if (!mod) { mod = iml->mod = create_colormod(); iml->mod->imlib_mod = imlib_create_color_modifier(); imlib_context_set_color_modifier(mod->imlib_mod); } else if (!mod->imlib_mod) { mod->imlib_mod = imlib_create_color_modifier(); imlib_context_set_color_modifier(mod->imlib_mod); } else { imlib_context_set_color_modifier(mod->imlib_mod); imlib_reset_color_modifier(); } imlib_get_color_modifier_tables(rt, gt, bt, NULL); if (rmod && rmod->imlib_mod) { imlib_context_set_color_modifier(rmod->imlib_mod); imlib_get_color_modifier_tables(rt, NULL, NULL, NULL); } if (gmod && gmod->imlib_mod) { imlib_context_set_color_modifier(gmod->imlib_mod); imlib_get_color_modifier_tables(NULL, gt, NULL, NULL); } if (bmod && bmod->imlib_mod) { imlib_context_set_color_modifier(bmod->imlib_mod); imlib_get_color_modifier_tables(NULL, NULL, bt, NULL); } imlib_context_set_color_modifier(mod->imlib_mod); imlib_set_color_modifier_tables(rt, gt, bt, NULL); if (mod->brightness != 0x100) { imlib_modify_color_modifier_brightness((double) (mod->brightness - 255.0) / 255.0); } if (mod->contrast != 0x100) { imlib_modify_color_modifier_contrast((double) (mod->contrast - 255.0) / 255.0); } if (mod->gamma != 0x100) { imlib_modify_color_modifier_gamma((double) (mod->gamma - 255.0) / 255.0); } } # define MOD_IS_SET(mod) ((mod) && ((mod)->brightness != 0x100 || (mod)->contrast != 0x100 || (mod)->gamma != 0x100)) unsigned char need_colormod(register imlib_t *iml) { if (MOD_IS_SET(iml->mod) || MOD_IS_SET(iml->rmod) || MOD_IS_SET(iml->gmod) || MOD_IS_SET(iml->bmod)) { D_PIXMAP(("Color modifier active.\n")); return 1; } else { D_PIXMAP(("No color modifier active.\n")); return 0; } } /* New optimized routines for tinting XImages written by Willem Monsuwe */ #if !defined HAVE_MMX && !defined HAVE_SSE2 /* RGB 15 */ static void shade_ximage_15(void *data, int bpl, int w, int h, int rm, int gm, int bm) { unsigned char *ptr; int x, y; ptr = (unsigned char *) data + (w * sizeof(DATA16)); if (!COLORMODS_HAVE_SATURATION(rm, gm, bm)) { /* No saturation */ for (y = h; --y >= 0;) { for (x = -w; x < 0; x++) { int r, g, b; b = ((DATA16 *) ptr)[x]; r = (b & 0x7c00) * rm; g = (b & 0x3e0) * gm; b = (b & 0x1f) * bm; ((DATA16 *) ptr)[x] = ((r >> 8) & 0x7c00) | ((g >> 8) & 0x3e0) | ((b >> 8) & 0x1f); } ptr += bpl; } } else { for (y = h; --y >= 0;) { for (x = -w; x < 0; x++) { int r, g, b; b = ((DATA16 *) ptr)[x]; r = (((b >> 10) & 0x001f ) * rm) >> 8; r = (r > 0x001f) ? 0x7c00 : (r << 10); g = (((b >> 5) & 0x001f ) * gm) >> 8; g = (g > 0x001f) ? 0x03e0 : (g << 5); b = (((b >> 0) & 0x001f ) * bm) >> 8; b = (b > 0x001f) ? 0x001f : (b << 0); ((DATA16 *) ptr)[x] = (r|g|b); } ptr += bpl; } } } /* RGB 16 */ static void shade_ximage_16(void *data, int bpl, int w, int h, int rm, int gm, int bm) { unsigned char *ptr; int x, y; ptr = (unsigned char *) data + (w * sizeof(DATA16)); if (!COLORMODS_HAVE_SATURATION(rm, gm, bm)) { /* No saturation */ for (y = h; --y >= 0;) { for (x = -w; x < 0; x++) { int r, g, b; b = ((DATA16 *) ptr)[x]; r = (b & 0xf800) * rm; g = (b & 0x7e0) * gm; b = (b & 0x1f) * bm; ((DATA16 *) ptr)[x] = ((r >> 8) & 0xf800) | ((g >> 8) & 0x7e0) | ((b >> 8) & 0x1f); } ptr += bpl; } } else { for (y = h; --y >= 0;) { for (x = -w; x < 0; x++) { int r, g, b; b = ((DATA16 *) ptr)[x]; r = (((b >> 11) & 0x001f) * rm) >> 8; r = (r > 0x001f) ? 0xf800 : (r << 11); g = (((b >> 5) & 0x003f) * gm) >> 8; g = (g > 0x003f) ? 0x07e0 : (g << 5); b = (((b >> 0) & 0x001f) * bm) >> 8; b = (b > 0x001f) ? 0x001f : (b << 0); ((DATA16 *) ptr)[x] = (r|g|b); } ptr += bpl; } } } /* RGB 32 */ static void shade_ximage_32(void *data, int bpl, int w, int h, int rm, int gm, int bm) { unsigned char *ptr; int x, y; ptr = (unsigned char *) data + (w * 4); if (!COLORMODS_HAVE_SATURATION(rm, gm, bm)) { /* No saturation */ for (y = h; --y >= 0;) { for (x = -(w * 4); x < 0; x += 4) { # if WORDS_BIGENDIAN ptr[x + 1] = ((ptr[x + 1] * rm) >> 8); ptr[x + 2] = ((ptr[x + 2] * gm) >> 8); ptr[x + 3] = ((ptr[x + 3] * bm) >> 8); # else ptr[x + 2] = ((ptr[x + 2] * rm) >> 8); ptr[x + 1] = ((ptr[x + 1] * gm) >> 8); ptr[x + 0] = ((ptr[x + 0] * bm) >> 8); # endif } ptr += bpl; } } else { for (y = h; --y >= 0;) { for (x = -(w * 4); x < 0; x += 4) { int r, g, b; # if WORDS_BIGENDIAN r = (ptr[x + 1] * rm) >> 8; ptr[x + 1] = r|(!(r >> 8) - 1); g = (ptr[x + 2] * gm) >> 8; ptr[x + 2] = g|(!(g >> 8) - 1); b = (ptr[x + 3] * bm) >> 8; ptr[x + 3] = b|(!(b >> 8) - 1); # else r = (ptr[x + 2] * rm) >> 8; ptr[x + 2] = r|(!(r >> 8) - 1); g = (ptr[x + 1] * gm) >> 8; ptr[x + 1] = g|(!(g >> 8) - 1); b = (ptr[x + 0] * bm) >> 8; ptr[x + 0] = b|(!(b >> 8) - 1); # endif } ptr += bpl; } } } #endif /* RGB 24 */ static void shade_ximage_24(void *data, int bpl, int w, int h, int rm, int gm, int bm) { unsigned char *ptr; int x, y; ptr = (unsigned char *) data + (w * 3); if (!COLORMODS_HAVE_SATURATION(rm, gm, bm)) { /* No saturation */ for (y = h; --y >= 0;) { for (x = -(w * 3); x < 0; x += 3) { # if WORDS_BIGENDIAN ptr[x + 0] = (ptr[x + 0] * rm) >> 8; ptr[x + 1] = (ptr[x + 1] * gm) >> 8; ptr[x + 2] = (ptr[x + 2] * bm) >> 8; # else ptr[x + 2] = (ptr[x + 2] * rm) >> 8; ptr[x + 1] = (ptr[x + 1] * gm) >> 8; ptr[x + 0] = (ptr[x + 0] * bm) >> 8; # endif } ptr += bpl; } } else { for (y = h; --y >= 0;) { for (x = -(w * 3); x < 0; x += 3) { int r, g, b; # if WORDS_BIGENDIAN r = (ptr[x + 0] * rm) >> 8; ptr[x + 0] = r|(!(r >> 8) - 1); g = (ptr[x + 1] * gm) >> 8; ptr[x + 1] = g|(!(g >> 8) - 1); b = (ptr[x + 2] * bm) >> 8; ptr[x + 2] = b|(!(b >> 8) - 1); # else r = (ptr[x + 2] * rm) >> 8; ptr[x + 2] = r|(!(r >> 8) - 1); g = (ptr[x + 1] * gm) >> 8; ptr[x + 1] = g|(!(g >> 8) - 1); b = (ptr[x + 0] * bm) >> 8; ptr[x + 0] = b|(!(b >> 8) - 1); # endif } ptr += bpl; } } } # ifdef PIXMAP_OFFSET void colormod_trans(Pixmap p, imlib_t *iml, GC gc, unsigned short w, unsigned short h) { XImage *ximg; register unsigned long i; #if 0 register unsigned long v; unsigned long x, y; int r, g, b; register int br, bg, bb; register unsigned int mr, mg, mb; #endif unsigned short rm, gm, bm, shade; Imlib_Color ctab[256]; int real_depth = 0; D_PIXMAP(("colormod_trans(p == 0x%08x, gc, w == %hu, h == %hu) called.\n", p, w, h)); REQUIRE(p != None); 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 */ } D_PIXMAP((" -> rm == %hu, gm == %hu, bm == %hu, shade == %hu\n", rm, gm, bm, shade)); 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].red = cols[i].red >> 8; ctab[i].green = cols[i].green >> 8; ctab[i].blue = cols[i].blue >> 8; } } else if (Xdepth == 16) { XWindowAttributes xattr; XGetWindowAttributes(Xdisplay, desktop_window, &xattr); if ((xattr.visual->green_mask == 0x3e0)) { real_depth = 15; } } if (!real_depth) { real_depth = Xdepth; } ximg = XGetImage(Xdisplay, p, 0, 0, w, h, -1, ZPixmap); if (!ximg) { libast_print_warning("XGetImage(Xdisplay, 0x%08x, 0, 0, %d, %d, -1, ZPixmap) returned NULL.\n", p, w, h); return; } D_PIXMAP(("XGetImage(Xdisplay, 0x%08x, 0, 0, %d, %d, -1, ZPixmap) returned %8p.\n", p, w, h, ximg)); if (Xdepth <= 8) { #if FIXME_BLOCK 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); } } #endif } else { D_PIXMAP(("Rendering high-depth image, depth == %d\n", real_depth)); /* Swap rm and bm for bgr */ { XWindowAttributes xattr; XGetWindowAttributes(Xdisplay, desktop_window, &xattr); if (xattr.visual->blue_mask > xattr.visual->red_mask) { unsigned short tmp; tmp = rm; rm = bm; bm = tmp; } } /* Determine bitshift and bitmask values */ switch (real_depth) { case 15: #ifdef HAVE_SSE2 D_PIXMAP(("Using SSE2 - 15 bit\n")); shade_ximage_15_sse2(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #elif defined HAVE_MMX D_PIXMAP(("Using MMX - 15 bit\n")); shade_ximage_15_mmx(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #else D_PIXMAP(("No MMX Found - 15 bit\n")); shade_ximage_15(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #endif break; case 16: #ifdef HAVE_SSE2 D_PIXMAP(("Using SSE2 - 16 bit\n")); shade_ximage_16_sse2(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #elif defined HAVE_MMX D_PIXMAP(("Using MMX - 16 bit\n")); shade_ximage_16_mmx(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #else D_PIXMAP(("No MMX Found - 16 bit\n")); shade_ximage_16(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #endif break; case 24: if (ximg->bits_per_pixel != 32) { D_PIXMAP(("Rendering 24 bit\n")); shade_ximage_24(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); break; } /* drop */ case 32: #ifdef HAVE_SSE2 D_PIXMAP(("Using SSE2 - 32 bit\n")); shade_ximage_32_sse2(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #elif defined HAVE_MMX D_PIXMAP(("Using MMX - 32 bit\n")); shade_ximage_32_mmx(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #else D_PIXMAP(("No MMX Found - 32 bit\n")); shade_ximage_32(ximg->data, ximg->bytes_per_line, w, h, rm, gm, bm); #endif break; default: libast_print_warning("Bit depth of %d is unsupported for tinting/shading.\n", real_depth); return; } } XPutImage(Xdisplay, p, gc, ximg, 0, 0, 0, 0, w, h); XDestroyImage(ximg); } unsigned char update_desktop_info(int *w, int *h) { unsigned int pw, ph, pb, pd; int px, py; Window dummy; if (w) { *w = 0; } if (h) { *h = 0; } if (desktop_window == None) { get_desktop_window(); } if (desktop_window == None) { libast_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."); return 0; } if (desktop_pixmap == None) { get_desktop_pixmap(); } if (desktop_pixmap == None) { return 0; } XGetGeometry(Xdisplay, desktop_pixmap, &dummy, &px, &py, &pw, &ph, &pb, &pd); if ((pw <= 0) || (ph <= 0)) { /* Reset and try again. */ get_desktop_window(); get_desktop_pixmap(); XGetGeometry(Xdisplay, desktop_pixmap, &dummy, &px, &py, &pw, &ph, &pb, &pd); } if ((pw <= 0) || (ph <= 0)) { libast_print_error("Value of desktop pixmap property is invalid. Please restart your \n" "window manager or use Esetroot to set a new one."); desktop_pixmap = None; return 0; } if (w) { *w = pw; } if (h) { *h = ph; } return 1; } Window get_desktop_window(void) { Atom type; int format; unsigned long length, after; unsigned char *data; unsigned int nchildren; Window w, root, *children, parent; D_PIXMAP(("Current desktop window is 0x%08x\n", (unsigned int) desktop_window)); 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 ((XGetWindowProperty (Xdisplay, w, props[PROP_TRANS_PIXMAP], 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data)) != Success) { if ((XGetWindowProperty (Xdisplay, w, props[PROP_TRANS_COLOR], 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data)) != Success) { continue; } } XFree(data); if (type != None) { D_PIXMAP(("Found desktop as window 0x%08x\n", w)); if (w != Xroot) { XSelectInput(Xdisplay, w, PropertyChangeMask); } if (desktop_window == w) { D_PIXMAP((" Desktop window has not changed.\n")); return ((Window) 1); } else { D_PIXMAP((" Desktop window has changed Updating desktop_window.\n")); return (desktop_window = w); } } } D_PIXMAP(("No suitable parent found.\n")); return (desktop_window = None); } Pixmap get_desktop_pixmap(void) { Pixmap p; Atom type; int format; static Pixmap color_pixmap = None, orig_desktop_pixmap; unsigned long length, after; unsigned char *data; D_PIXMAP(("Current desktop pixmap is 0x%08x\n", (unsigned int) desktop_pixmap)); if (desktop_pixmap == None) { orig_desktop_pixmap = None; /* Forced re-read. */ } if (desktop_window == None) { D_PIXMAP(("No desktop window. Aborting.\n")); free_desktop_pixmap(); return (None); } if (color_pixmap != None) { D_PIXMAP(("Removing old solid color pixmap 0x%08x.\n", color_pixmap)); LIBAST_X_FREE_PIXMAP(color_pixmap); color_pixmap = None; } XGetWindowProperty(Xdisplay, desktop_window, props[PROP_TRANS_PIXMAP], 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data); if (type == XA_PIXMAP) { p = *((Pixmap *) data); XFree(data); if (p != None) { D_PIXMAP((" Found pixmap 0x%08x\n", p)); if (orig_desktop_pixmap == p) { D_PIXMAP(("Desktop pixmap is unchanged.\n")); return ((Pixmap) 1); } else { D_PIXMAP(("Desktop pixmap has changed. Updating desktop_pixmap\n")); free_desktop_pixmap(); orig_desktop_pixmap = p; if (!(BITFIELD_IS_SET(image_options, IMAGE_OPTIONS_ITRANS)) && need_colormod(images[image_bg].current->iml)) { int px, py; unsigned int pw, ph, pb, pd; Window w; GC gc; XGCValues gcvalue; Screen *scr = ScreenOfDisplay(Xdisplay, Xscreen); gcvalue.foreground = gcvalue.background = PixColors[bgColor]; gc = LIBAST_X_CREATE_GC(GCForeground | GCBackground, &gcvalue); XGetGeometry(Xdisplay, p, &w, &px, &py, &pw, &ph, &pb, &pd); D_PIXMAP(("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 = LIBAST_X_CREATE_PIXMAP(pw, ph); XCopyArea(Xdisplay, p, desktop_pixmap, gc, 0, 0, pw, ph, 0, 0); colormod_trans(desktop_pixmap, images[image_bg].current->iml, gc, pw, ph); } else { desktop_pixmap = LIBAST_X_CREATE_PIXMAP(scr->width, scr->height); XCopyArea(Xdisplay, p, desktop_pixmap, gc, 0, 0, scr->width, scr->height, 0, 0); colormod_trans(desktop_pixmap, images[image_bg].current->iml, gc, scr->width, scr->height); } LIBAST_X_FREE_GC(gc); desktop_pixmap_is_mine = 1; D_PIXMAP(("Returning 0x%08x\n", (unsigned int) desktop_pixmap)); return (desktop_pixmap); } else { desktop_pixmap_is_mine = 0; D_PIXMAP(("Returning 0x%08x\n", (unsigned int) p)); return (desktop_pixmap = p); } } } } else { XFree(data); } XGetWindowProperty(Xdisplay, desktop_window, props[PROP_TRANS_COLOR], 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data); if (type == XA_CARDINAL) { XGCValues gcvalue; GC gc; Pixel pix; free_desktop_pixmap(); pix = *((Pixel *) data); XFree(data); D_PIXMAP((" Found solid color 0x%08x\n", pix)); gcvalue.foreground = pix; gcvalue.background = pix; gc = LIBAST_X_CREATE_GC(GCForeground | GCBackground, &gcvalue); color_pixmap = LIBAST_X_CREATE_PIXMAP(16, 16); XFillRectangle(Xdisplay, color_pixmap, gc, 0, 0, 16, 16); D_PIXMAP(("Created solid color pixmap 0x%08x for desktop_pixmap.\n", color_pixmap)); LIBAST_X_FREE_GC(gc); return (desktop_pixmap = color_pixmap); } else { XFree(data); } D_PIXMAP(("No suitable attribute found.\n")); free_desktop_pixmap(); return (desktop_pixmap = None); } void free_desktop_pixmap(void) { if (desktop_pixmap_is_mine && desktop_pixmap != None) { LIBAST_X_FREE_PIXMAP(desktop_pixmap); desktop_pixmap_is_mine = 0; } desktop_pixmap = None; } # endif /* PIXMAP_OFFSET */ void shaped_window_apply_mask(Drawable d, Pixmap mask) { static signed char have_shape = -1; REQUIRE(d != None); D_PIXMAP(("Applying mask 0x%08x to drawable 0x%08x\n", mask, d)); # ifdef HAVE_X_SHAPE_EXT if (have_shape == -1) { /* Don't know yet. */ int unused; D_PIXMAP(("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(("Shape extension available, applying mask.\n")); XShapeCombineMask(Xdisplay, d, ShapeBounding, 0, 0, mask, ShapeSet); } else if (have_shape == 0) { D_PIXMAP(("Shape extension not available.\n")); return; } # else D_PIXMAP(("Shape support disabled.\n")); # endif } void set_icon_pixmap(char *filename, XWMHints * pwm_hints) { const char *icon_path; Imlib_Image temp_im = (Imlib_Image) NULL; Imlib_Load_Error im_err; Imlib_Color_Modifier tmp_cmod; XWMHints *wm_hints; int w = 8, h = 8; if (pwm_hints) { wm_hints = pwm_hints; } else { wm_hints = XGetWMHints(Xdisplay, TermWin.parent); } /* Make sure no shading/tinting is applied to the icon. */ tmp_cmod = imlib_create_color_modifier(); imlib_context_set_color_modifier(tmp_cmod); imlib_reset_color_modifier(); if (filename && *filename) { if (!(icon_path = search_path(rs_path, filename))) icon_path = search_path(getenv(PATH_ENV), filename); if (icon_path) { XIconSize *icon_sizes; int count, i; temp_im = imlib_load_image_with_error_return(icon_path, &im_err); if (!temp_im) { libast_print_error("Unable to load icon file \"%s\" -- %s\n", icon_path, imlib_strerror(im_err)); } else { /* 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; } BOUND(w, 8, 64); BOUND(h, 8, 64); imlib_context_set_image(temp_im); } } } if (!temp_im) { w = h = 48; temp_im = imlib_create_image_using_data(48, 48, (DATA32 *) (icon_data + 2)); imlib_context_set_image(temp_im); imlib_image_set_has_alpha(1); } imlib_context_set_drawable(TermWin.parent); imlib_context_set_anti_alias(1); imlib_context_set_dither(1); imlib_context_set_blend(0); imlib_render_pixmaps_for_whole_image_at_size(&wm_hints->icon_pixmap, &wm_hints->icon_mask, w, h); #ifdef STRICT_ICCCM 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; #else wm_hints->flags |= IconPixmapHint | IconMaskHint; #endif /* Set the EWMH icon hint for _NET_WM-compliant WM's. */ XChangeProperty(Xdisplay, TermWin.parent, props[PROP_EWMH_ICON], XA_CARDINAL, 32, PropModeReplace, (unsigned char *) icon_data, sizeof(icon_data) / sizeof(CARD32)); imlib_free_image_and_decache(); /* 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); } } #endif /* PIXMAP_SUPPORT */