X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/src/icon.c diff --git a/src/icon.c b/src/icon.c dissimilarity index 91% index 3ff44ac5..e61c11f0 100644 --- a/src/icon.c +++ b/src/icon.c @@ -1,989 +1,907 @@ -/* icon.c - window icon and dock and appicon parent - * - * Window Maker window manager - * - * Copyright (c) 1997-2003 Alfredo K. Kojima - * - * 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. - */ - -#include "wconfig.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "WindowMaker.h" -#include "wcore.h" -#include "texture.h" -#include "window.h" -#include "icon.h" -#include "actions.h" -#include "funcs.h" -#include "stacking.h" -#include "application.h" -#include "defaults.h" -#include "appicon.h" -#include "wmspec.h" - -/**** Global varianebles ****/ -extern WPreferences wPreferences; - -#define MOD_MASK wPreferences.modifier_mask - -extern Cursor wCursor[WCUR_LAST]; - - -static void miniwindowExpose(WObjDescriptor *desc, XEvent *event); -static void miniwindowMouseDown(WObjDescriptor *desc, XEvent *event); -static void miniwindowDblClick(WObjDescriptor *desc, XEvent *event); - - -/****** Notification Observers ******/ - -static void -appearanceObserver(void *self, WMNotification *notif) -{ - WIcon *icon = (WIcon*)self; - int flags = (int)(uintptr_t)WMGetNotificationClientData(notif); - - if (flags & WTextureSettings) { - icon->force_paint = 1; - } - if (flags & WFontSettings) { - icon->force_paint = 1; - } - /* - if (flags & WColorSettings) { - } - */ - - wIconPaint(icon); - - /* so that the appicon expose handlers will paint the appicon specific - * stuff */ - XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, - icon->core->height, True); -} - - -static void -tileObserver(void *self, WMNotification *notif) -{ - WIcon *icon = (WIcon*)self; - - icon->force_paint = 1; - wIconPaint(icon); - - XClearArea(dpy, icon->core->window, 0, 0, 1, 1, True); -} - -/************************************/ - - - -INLINE static void -getSize(Drawable d, unsigned int *w, unsigned int *h, unsigned int *dep) -{ - Window rjunk; - int xjunk, yjunk; - unsigned int bjunk; - - XGetGeometry(dpy, d, &rjunk, &xjunk, &yjunk, w, h, &bjunk, dep); -} - - -WIcon* -wIconCreate(WWindow *wwin) -{ - WScreen *scr=wwin->screen_ptr; - WIcon *icon; - char *file; - unsigned long vmask = 0; - XSetWindowAttributes attribs; - - icon = wmalloc(sizeof(WIcon)); - memset(icon, 0, sizeof(WIcon)); - icon->core = wCoreCreateTopLevel(scr, wwin->icon_x, wwin->icon_y, - wPreferences.icon_size, - wPreferences.icon_size, 0); - - if (wPreferences.use_saveunders) { - vmask |= CWSaveUnder; - attribs.save_under = True; - } - /* a white border for selecting it */ - vmask |= CWBorderPixel; - attribs.border_pixel = scr->white_pixel; - - XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs); - - - /* will be overriden if this is an application icon */ - icon->core->descriptor.handle_mousedown = miniwindowMouseDown; - icon->core->descriptor.handle_expose = miniwindowExpose; - icon->core->descriptor.parent_type = WCLASS_MINIWINDOW; - icon->core->descriptor.parent = icon; - - icon->core->stacking = wmalloc(sizeof(WStacking)); - icon->core->stacking->above = NULL; - icon->core->stacking->under = NULL; - icon->core->stacking->window_level = NORMAL_ICON_LEVEL; - icon->core->stacking->child_of = NULL; - - icon->owner = wwin; - if (wwin->wm_hints && (wwin->wm_hints->flags & IconWindowHint)) { - if (wwin->client_win == wwin->main_window) { - WApplication *wapp; - /* do not let miniwindow steal app-icon's icon window */ - wapp = wApplicationOf(wwin->client_win); - if (!wapp || wapp->app_icon==NULL) - icon->icon_win = wwin->wm_hints->icon_window; - } else { - icon->icon_win = wwin->wm_hints->icon_window; - } - } -#ifdef NO_MINIWINDOW_TITLES - icon->show_title = 0; -#else - icon->show_title = 1; -#endif -#ifdef NETWM_HINTS - if (!icon->image && !WFLAGP(wwin, always_user_icon)) - icon->image = RRetainImage(wwin->net_icon_image); - if (!icon->image) -#endif - icon->image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class); - - file = wDefaultGetIconFile(scr, wwin->wm_instance, wwin->wm_class, - False); - if (file) { - icon->file = wstrdup(file); - } - - icon->icon_name = wNETWMGetIconName(wwin->client_win); - if (icon->icon_name) - wwin->flags.net_has_icon_title= 1; - else - wGetIconName(dpy, wwin->client_win, &icon->icon_name); - - icon->tile_type = TILE_NORMAL; - - wIconUpdate(icon); - - XFlush(dpy); - - WMAddNotificationObserver(appearanceObserver, icon, - WNIconAppearanceSettingsChanged, icon); - WMAddNotificationObserver(tileObserver, icon, - WNIconTileSettingsChanged, icon); - return icon; -} - - -WIcon* -wIconCreateWithIconFile(WScreen *scr, char *iconfile, int tile) -{ - WIcon *icon; - unsigned long vmask = 0; - XSetWindowAttributes attribs; - - icon = wmalloc(sizeof(WIcon)); - memset(icon, 0, sizeof(WIcon)); - icon->core = wCoreCreateTopLevel(scr, 0, 0, wPreferences.icon_size, - wPreferences.icon_size, 0); - if (wPreferences.use_saveunders) { - vmask = CWSaveUnder; - attribs.save_under = True; - } - /* a white border for selecting it */ - vmask |= CWBorderPixel; - attribs.border_pixel = scr->white_pixel; - - XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs); - - /* will be overriden if this is a application icon */ - icon->core->descriptor.handle_mousedown = miniwindowMouseDown; - icon->core->descriptor.handle_expose = miniwindowExpose; - icon->core->descriptor.parent_type = WCLASS_MINIWINDOW; - icon->core->descriptor.parent = icon; - - icon->core->stacking = wmalloc(sizeof(WStacking)); - icon->core->stacking->above = NULL; - icon->core->stacking->under = NULL; - icon->core->stacking->window_level = NORMAL_ICON_LEVEL; - icon->core->stacking->child_of = NULL; - - if (iconfile) { - icon->image = RLoadImage(scr->rcontext, iconfile, 0); - if (!icon->image) { - wwarning(_("error loading image file \"%s\""), iconfile, RMessageForError(RErrorCode)); - } - - icon->image = wIconValidateIconSize(scr, icon->image); - - icon->file = wstrdup(iconfile); - } - - icon->tile_type = tile; - - wIconUpdate(icon); - - WMAddNotificationObserver(appearanceObserver, icon, - WNIconAppearanceSettingsChanged, icon); - WMAddNotificationObserver(tileObserver, icon, - WNIconTileSettingsChanged, icon); - - return icon; -} - - - -void -wIconDestroy(WIcon *icon) -{ - WCoreWindow *core = icon->core; - WScreen *scr = core->screen_ptr; - - WMRemoveNotificationObserver(icon); - - if (icon->handlerID) - WMDeleteTimerHandler(icon->handlerID); - - if (icon->icon_win) { - int x=0, y=0; - - if (icon->owner) { - x = icon->owner->icon_x; - y = icon->owner->icon_y; - } - XUnmapWindow(dpy, icon->icon_win); - XReparentWindow(dpy, icon->icon_win, scr->root_win, x, y); - } - if (icon->icon_name) - XFree(icon->icon_name); - - if (icon->pixmap) - XFreePixmap(dpy, icon->pixmap); - - if (icon->file) - wfree(icon->file); - - if (icon->image!=NULL) - RReleaseImage(icon->image); - - wCoreDestroy(icon->core); - wfree(icon); -} - - - -static void -drawIconTitle(WScreen *scr, Pixmap pixmap, int height) -{ - XFillRectangle(dpy, pixmap, scr->icon_title_texture->normal_gc, - 0, 0, wPreferences.icon_size, height+1); - XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, - wPreferences.icon_size, 0); - XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, - 0, height+1); - XDrawLine(dpy, pixmap, scr->icon_title_texture->dim_gc, - wPreferences.icon_size-1, 0, wPreferences.icon_size-1, height+1); -} - - -static Pixmap -makeIcon(WScreen *scr, RImage *icon, int titled, int shadowed, int tileType) -{ - RImage *tile; - Pixmap pixmap; - int x, y, sx, sy; - unsigned w, h; - int theight = WMFontHeight(scr->icon_title_font); - - if (tileType == TILE_NORMAL) - tile = RCloneImage(scr->icon_tile); - else { - assert(scr->clip_tile); - tile = RCloneImage(scr->clip_tile); - } - if (icon) { - w = (icon->width > wPreferences.icon_size) - ? wPreferences.icon_size : icon->width; - x = (wPreferences.icon_size - w) / 2; - sx = (icon->width - w)/2; - - if (!titled) { - h = (icon->height > wPreferences.icon_size) - ? wPreferences.icon_size : icon->height; - y = (wPreferences.icon_size - h) / 2; - sy = (icon->height - h)/2; - } else { - h = (icon->height+theight > wPreferences.icon_size - ? wPreferences.icon_size-theight : icon->height); - y = theight+((int)wPreferences.icon_size-theight-h)/2; - sy = (icon->height - h)/2; - } - RCombineArea(tile, icon, sx, sy, w, h, x, y); - } - - if (shadowed) { - RColor color; - - color.red = scr->icon_back_texture->light.red >> 8; - color.green = scr->icon_back_texture->light.green >> 8; - color.blue = scr->icon_back_texture->light.blue >> 8; - color.alpha = 150; /* about 60% */ - RClearImage(tile, &color); - } - - if (!RConvertImage(scr->rcontext, tile, &pixmap)) { - wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode)); - } - RReleaseImage(tile); - - if (titled) - drawIconTitle(scr, pixmap, theight); - - return pixmap; -} - - -void -wIconChangeTitle(WIcon *icon, char *new_title) -{ - int changed; - - changed = (new_title==NULL && icon->icon_name!=NULL) - || (new_title!=NULL && icon->icon_name==NULL); - - if (icon->icon_name!=NULL) - XFree(icon->icon_name); - - icon->icon_name = new_title; - - if (changed) - icon->force_paint = 1; - wIconPaint(icon); -} - - -void -wIconChangeImage(WIcon *icon, RImage *new_image) -{ - assert(icon != NULL); - - if (icon->image) - RReleaseImage(icon->image); - - icon->image = new_image; - - wIconUpdate(icon); -} - - -RImage* -wIconValidateIconSize(WScreen *scr, RImage *icon) -{ - RImage *tmp; - int w, h; - - if (!icon) - return NULL; -#ifndef DONT_SCALE_ICONS - if (wPreferences.icon_size != 64) { - w = wPreferences.icon_size * icon->width / 64; - h = wPreferences.icon_size * icon->height / 64; - - tmp = RScaleImage(icon, w, h); - RReleaseImage(icon); - icon = tmp; - } -#endif -#if 0 - if (icon->width > wPreferences.icon_size - || icon->height > wPreferences.icon_size) { - if (icon->width > icon->height) { - w = wPreferences.icon_size - 4; - h = w*icon->height/icon->width; - } else { - h = wPreferences.icon_size - 4; - w = h*icon->width/icon->height; - } - tmp = RScaleImage(icon, w, h); - RReleaseImage(icon); - icon = tmp; - } -#endif - - return icon; -} - - -Bool -wIconChangeImageFile(WIcon *icon, char *file) -{ - WScreen *scr = icon->core->screen_ptr; - RImage *image; - char *path; - int error = 0; - - if (!file) { - wIconChangeImage(icon, NULL); - return True; - } - - path = FindImage(wPreferences.icon_path, file); - - if (path && (image = RLoadImage(scr->rcontext, path, 0))) { - image = wIconValidateIconSize(icon->core->screen_ptr, image); - - wIconChangeImage(icon, image); - } else { - error = 1; - } - - if (path) - wfree(path); - - return !error; -} - - - -static char* -getnameforicon(WWindow *wwin) -{ - char *prefix, *suffix; - char *path; - int len; - - if (wwin->wm_class && wwin->wm_instance) { - int len = strlen(wwin->wm_class)+strlen(wwin->wm_instance)+2; - suffix = wmalloc(len); - snprintf(suffix, len, "%s.%s", wwin->wm_instance, wwin->wm_class); - } else if (wwin->wm_class) { - int len = strlen(wwin->wm_class)+1; - suffix = wmalloc(len); - snprintf(suffix, len, "%s", wwin->wm_class); - } else if (wwin->wm_instance) { - int len = strlen(wwin->wm_instance)+1; - suffix = wmalloc(len); - snprintf(suffix, len, "%s", wwin->wm_instance); - } else { - return NULL; - } - - prefix = wusergnusteppath(); - len = strlen(prefix)+64+strlen(suffix); - path = wmalloc(len+1); - snprintf(path, len, "%s/Library/WindowMaker", prefix); - - if (access(path, F_OK)!=0) { - if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR)) { - wsyserror(_("could not create directory %s"), path); - wfree(path); - wfree(suffix); - return NULL; - } - } - strcat(path, "/CachedPixmaps"); - if (access(path, F_OK)!=0) { - if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR)!=0) { - wsyserror(_("could not create directory %s"), path); - wfree(path); - wfree(suffix); - return NULL; - } - } - - strcat(path, "/"); - strcat(path, suffix); - strcat(path, ".xpm"); - wfree(suffix); - - return path; -} - - -/* - * wIconStore-- - * Stores the client supplied icon at ~/GNUstep/Library/WindowMaker/CachedPixmaps - * and returns the path for that icon. Returns NULL if there is no - * client supplied icon or on failure. - * - * Side effects: - * New directories might be created. - */ -char* -wIconStore(WIcon *icon) -{ - char *path; - RImage *image; - WWindow *wwin = icon->owner; - - if (!wwin || !wwin->wm_hints || !(wwin->wm_hints->flags & IconPixmapHint) - || wwin->wm_hints->icon_pixmap == None) - return NULL; - - path = getnameforicon(wwin); - if (!path) - return NULL; - - image = RCreateImageFromDrawable(icon->core->screen_ptr->rcontext, - wwin->wm_hints->icon_pixmap, - (wwin->wm_hints->flags & IconMaskHint) - ? wwin->wm_hints->icon_mask : None); - if (!image) { - wfree(path); - return NULL; - } - - if (!RSaveImage(image, path, "XPM")) { - wfree(path); - path = NULL; - } - RReleaseImage(image); - - return path; -} - - -/* -void wIconChangeIconWindow(WIcon *icon, Window new_window); -*/ - -static void -cycleColor(void *data) -{ - WIcon *icon = (WIcon*)data; - WScreen *scr = icon->core->screen_ptr; - XGCValues gcv; - - icon->step--; - gcv.dash_offset = icon->step; - XChangeGC(dpy, scr->icon_select_gc, GCDashOffset, &gcv); - - XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, - icon->core->width-1, icon->core->height-1); - icon->handlerID = WMAddTimerHandler(COLOR_CYCLE_DELAY, cycleColor, icon); -} - - -void -wIconSetHighlited(WIcon *icon, Bool flag) -{ - if (icon->highlighted == flag) { - return; - } - - icon->highlighted = flag; - wIconPaint(icon); -} - - - -void -wIconSelect(WIcon *icon) -{ - WScreen *scr = icon->core->screen_ptr; - icon->selected = !icon->selected; - - if (icon->selected) { - icon->step = 0; - if (!wPreferences.dont_blink) - icon->handlerID = WMAddTimerHandler(10, cycleColor, icon); - else - XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, - icon->core->width-1, icon->core->height-1); - } else { - if (icon->handlerID) { - WMDeleteTimerHandler(icon->handlerID); - icon->handlerID = NULL; - } - XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, - icon->core->height, True); - } -} - - -void -wIconUpdate(WIcon *icon) -{ - WScreen *scr = icon->core->screen_ptr; - int title_height = WMFontHeight(scr->icon_title_font); - WWindow *wwin = icon->owner; - - assert(scr->icon_tile!=NULL); - - if (icon->pixmap!=None) - XFreePixmap(dpy, icon->pixmap); - icon->pixmap = None; - - - if (wwin && (WFLAGP(wwin, always_user_icon) -#ifdef NETWM_HINTS - || wwin->net_icon_image -#endif - )) - goto user_icon; - - /* use client specified icon window */ - if (icon->icon_win!=None) { - XWindowAttributes attr; - int resize=0; - unsigned int width, height, depth; - int theight; - Pixmap pixmap; - - getSize(icon->icon_win, &width, &height, &depth); - - if (width > wPreferences.icon_size) { - resize = 1; - width = wPreferences.icon_size; - } - if (height > wPreferences.icon_size) { - resize = 1; - height = wPreferences.icon_size; - } - if (icon->show_title - && (height+title_height < wPreferences.icon_size)) { - pixmap = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, - wPreferences.icon_size, scr->w_depth); - XSetClipMask(dpy, scr->copy_gc, None); - XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0, - wPreferences.icon_size, wPreferences.icon_size, 0, 0); - drawIconTitle(scr, pixmap, title_height); - theight = title_height; - } else { - pixmap = None; - theight = 0; - XSetWindowBackgroundPixmap(dpy, icon->core->window, - scr->icon_tile_pixmap); - } - - XSetWindowBorderWidth(dpy, icon->icon_win, 0); - XReparentWindow(dpy, icon->icon_win, icon->core->window, - (wPreferences.icon_size-width)/2, - theight+(wPreferences.icon_size-height-theight)/2); - if (resize) - XResizeWindow(dpy, icon->icon_win, width, height); - - XMapWindow(dpy, icon->icon_win); - - XAddToSaveSet(dpy, icon->icon_win); - - icon->pixmap = pixmap; - - if (XGetWindowAttributes(dpy, icon->icon_win, &attr)) { - if (attr.all_event_masks & ButtonPressMask) { - wHackedGrabButton(Button1, MOD_MASK, icon->core->window, True, - ButtonPressMask, GrabModeSync, GrabModeAsync, - None, wCursor[WCUR_ARROW]); - } - } - } else if (wwin && wwin->wm_hints - && (wwin->wm_hints->flags & IconPixmapHint)) { - int x, y; - unsigned int w, h; - Window jw; - int ji, dotitle; - unsigned int ju, d; - Pixmap pixmap; - - if (!XGetGeometry(dpy, wwin->wm_hints->icon_pixmap, &jw, - &ji, &ji, &w, &h, &ju, &d)) { - icon->owner->wm_hints->flags &= ~IconPixmapHint; - goto user_icon; - } - - pixmap = XCreatePixmap(dpy, icon->core->window, wPreferences.icon_size, - wPreferences.icon_size, scr->w_depth); - XSetClipMask(dpy, scr->copy_gc, None); - XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0, - wPreferences.icon_size, wPreferences.icon_size, 0, 0); - - if (w > wPreferences.icon_size) - w = wPreferences.icon_size; - x = (wPreferences.icon_size-w)/2; - - if (icon->show_title && (title_height < wPreferences.icon_size)) { - drawIconTitle(scr, pixmap, title_height); - dotitle = 1; - - if (h > wPreferences.icon_size - title_height - 2) { - h = wPreferences.icon_size - title_height - 2; - y = title_height + 1; - } else { - y = (wPreferences.icon_size-h-title_height)/2+title_height + 1; - } - } else { - dotitle = 0; - if (w > wPreferences.icon_size) - w = wPreferences.icon_size; - y = (wPreferences.icon_size-h)/2; - } - - if (wwin->wm_hints->flags & IconMaskHint) - XSetClipMask(dpy, scr->copy_gc, wwin->wm_hints->icon_mask); - - XSetClipOrigin(dpy, scr->copy_gc, x, y); - - if (d != scr->w_depth) { - XSetForeground(dpy, scr->copy_gc, scr->black_pixel); - XSetBackground(dpy, scr->copy_gc, scr->white_pixel); - XCopyPlane(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, - 0, 0, w, h, x, y, 1); - } else { - XCopyArea(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, - 0, 0, w, h, x, y); - } - - XSetClipOrigin(dpy, scr->copy_gc, 0, 0); - - icon->pixmap = pixmap; - } else { - user_icon: - - if (icon->image) { - icon->pixmap = makeIcon(scr, icon->image, icon->show_title, - icon->shadowed, icon->tile_type); - } else { - /* make default icons */ - - if (!scr->def_icon_pixmap) { - RImage *image = NULL; - char *path; - char *file; - - file = wDefaultGetIconFile(scr, NULL, NULL, False); - if (file) { - path = FindImage(wPreferences.icon_path, file); - if (!path) { - wwarning(_("could not find default icon \"%s\""),file); - goto make_icons; - } - - image = RLoadImage(scr->rcontext, path, 0); - if (!image) { - wwarning(_("could not load default icon \"%s\":%s"), - file, RMessageForError(RErrorCode)); - } - wfree(path); - } - make_icons: - - image = wIconValidateIconSize(scr, image); - scr->def_icon_pixmap = makeIcon(scr, image, False, False, - icon->tile_type); - scr->def_ticon_pixmap = makeIcon(scr, image, True, False, - icon->tile_type); - if (image) - RReleaseImage(image); - } - - if (icon->show_title) { - XSetWindowBackgroundPixmap(dpy, icon->core->window, - scr->def_ticon_pixmap); - } else { - XSetWindowBackgroundPixmap(dpy, icon->core->window, - scr->def_icon_pixmap); - } - icon->pixmap = None; - } - } - if (icon->pixmap != None) { - XSetWindowBackgroundPixmap(dpy, icon->core->window, icon->pixmap); - } - XClearWindow(dpy, icon->core->window); - - wIconPaint(icon); -} - - - -void -wIconPaint(WIcon *icon) -{ - WScreen *scr=icon->core->screen_ptr; - int x; - char *tmp; - - if (icon->force_paint) { - icon->force_paint = 0; - wIconUpdate(icon); - return; - } - - XClearWindow(dpy, icon->core->window); - - /* draw the icon title */ - if (icon->show_title && icon->icon_name!=NULL) { - int l; - int w; - - tmp = ShrinkString(scr->icon_title_font, icon->icon_name, - wPreferences.icon_size-4); - w = WMWidthOfString(scr->icon_title_font, tmp, l=strlen(tmp)); - - if (w > icon->core->width - 4) - x = (icon->core->width - 4) - w; - else - x = (icon->core->width - w)/2; - - WMDrawString(scr->wmscreen, icon->core->window, scr->icon_title_color, - scr->icon_title_font, x, 1, tmp, l); - wfree(tmp); - } - - if (icon->selected) - XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, - icon->core->width-1, icon->core->height-1); -} - - -/******************************************************************/ - -static void -miniwindowExpose(WObjDescriptor *desc, XEvent *event) -{ - wIconPaint(desc->parent); -} - - -static void -miniwindowDblClick(WObjDescriptor *desc, XEvent *event) -{ - WIcon *icon = desc->parent; - - assert(icon->owner!=NULL); - - wDeiconifyWindow(icon->owner); -} - - -static void -miniwindowMouseDown(WObjDescriptor *desc, XEvent *event) -{ - WIcon *icon = desc->parent; - WWindow *wwin = icon->owner; - XEvent ev; - int x=wwin->icon_x, y=wwin->icon_y; - int dx=event->xbutton.x, dy=event->xbutton.y; - int grabbed=0; - int clickButton=event->xbutton.button; - - if (WCHECK_STATE(WSTATE_MODAL)) - return; - - if (IsDoubleClick(icon->core->screen_ptr, event)) { - miniwindowDblClick(desc, event); - return; - } - -#ifdef DEBUG - puts("Moving miniwindow"); -#endif - if (event->xbutton.button == Button1) { - if (event->xbutton.state & MOD_MASK) - wLowerFrame(icon->core); - else - wRaiseFrame(icon->core); - if (event->xbutton.state & ShiftMask) { - wIconSelect(icon); - wSelectWindow(icon->owner, !wwin->flags.selected); - } - } else if (event->xbutton.button == Button3) { - WObjDescriptor *desc; - - OpenMiniwindowMenu(wwin, event->xbutton.x_root, - event->xbutton.y_root); - - /* allow drag select of menu */ - desc = &wwin->screen_ptr->window_menu->menu->descriptor; - event->xbutton.send_event = True; - (*desc->handle_mousedown)(desc, event); - - return; - } - - if (XGrabPointer(dpy, icon->core->window, False, ButtonMotionMask - |ButtonReleaseMask|ButtonPressMask, GrabModeAsync, - GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) { -#ifdef DEBUG0 - wwarning("pointer grab failed for icon move"); -#endif - } - while(1) { - WMMaskEvent(dpy, PointerMotionMask|ButtonReleaseMask|ButtonPressMask - |ButtonMotionMask|ExposureMask, &ev); - switch (ev.type) { - case Expose: - WMHandleEvent(&ev); - break; - - case MotionNotify: - if (!grabbed) { - if (abs(dx-ev.xmotion.x)>=MOVE_THRESHOLD - || abs(dy-ev.xmotion.y)>=MOVE_THRESHOLD) { - XChangeActivePointerGrab(dpy, ButtonMotionMask - |ButtonReleaseMask|ButtonPressMask, - wCursor[WCUR_MOVE], CurrentTime); - grabbed=1; - } else { - break; - } - } - x = ev.xmotion.x_root - dx; - y = ev.xmotion.y_root - dy; - XMoveWindow(dpy, icon->core->window, x, y); - break; - - case ButtonPress: - break; - - case ButtonRelease: - if (ev.xbutton.button != clickButton) - break; - - if (wwin->icon_x!=x || wwin->icon_y!=y) - wwin->flags.icon_moved = 1; - - XMoveWindow(dpy, icon->core->window, x, y); - - wwin->icon_x = x; - wwin->icon_y = y; -#ifdef DEBUG - puts("End miniwindow move"); -#endif - XUngrabPointer(dpy, CurrentTime); - - if (wPreferences.auto_arrange_icons) - wArrangeIcons(wwin->screen_ptr, True); - return; - - } - } -} - - +/* icon.c - window icon and dock and appicon parent + * + * Window Maker window manager + * + * Copyright (c) 1997-2003 Alfredo K. Kojima + * + * 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. + */ + +#include "wconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "WindowMaker.h" +#include "wcore.h" +#include "texture.h" +#include "window.h" +#include "icon.h" +#include "actions.h" +#include "funcs.h" +#include "stacking.h" +#include "application.h" +#include "defaults.h" +#include "appicon.h" +#include "wmspec.h" + +/**** Global varianebles ****/ +extern WPreferences wPreferences; + +#define MOD_MASK wPreferences.modifier_mask + +extern Cursor wCursor[WCUR_LAST]; + +static void miniwindowExpose(WObjDescriptor * desc, XEvent * event); +static void miniwindowMouseDown(WObjDescriptor * desc, XEvent * event); +static void miniwindowDblClick(WObjDescriptor * desc, XEvent * event); + +/****** Notification Observers ******/ + +static void appearanceObserver(void *self, WMNotification * notif) +{ + WIcon *icon = (WIcon *) self; + int flags = (int)(uintptr_t) WMGetNotificationClientData(notif); + + if (flags & WTextureSettings) { + icon->force_paint = 1; + } + if (flags & WFontSettings) { + icon->force_paint = 1; + } + /* + if (flags & WColorSettings) { + } + */ + + wIconPaint(icon); + + /* so that the appicon expose handlers will paint the appicon specific + * stuff */ + XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, icon->core->height, True); +} + +static void tileObserver(void *self, WMNotification * notif) +{ + WIcon *icon = (WIcon *) self; + + icon->force_paint = 1; + wIconPaint(icon); + + XClearArea(dpy, icon->core->window, 0, 0, 1, 1, True); +} + +/************************************/ + +INLINE static void getSize(Drawable d, unsigned int *w, unsigned int *h, unsigned int *dep) +{ + Window rjunk; + int xjunk, yjunk; + unsigned int bjunk; + + XGetGeometry(dpy, d, &rjunk, &xjunk, &yjunk, w, h, &bjunk, dep); +} + +WIcon *wIconCreate(WWindow * wwin) +{ + WScreen *scr = wwin->screen_ptr; + WIcon *icon; + char *file; + unsigned long vmask = 0; + XSetWindowAttributes attribs; + + icon = wmalloc(sizeof(WIcon)); + memset(icon, 0, sizeof(WIcon)); + icon->core = wCoreCreateTopLevel(scr, wwin->icon_x, wwin->icon_y, + wPreferences.icon_size, wPreferences.icon_size, 0); + + if (wPreferences.use_saveunders) { + vmask |= CWSaveUnder; + attribs.save_under = True; + } + /* a white border for selecting it */ + vmask |= CWBorderPixel; + attribs.border_pixel = scr->white_pixel; + + XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs); + + /* will be overriden if this is an application icon */ + icon->core->descriptor.handle_mousedown = miniwindowMouseDown; + icon->core->descriptor.handle_expose = miniwindowExpose; + icon->core->descriptor.parent_type = WCLASS_MINIWINDOW; + icon->core->descriptor.parent = icon; + + icon->core->stacking = wmalloc(sizeof(WStacking)); + icon->core->stacking->above = NULL; + icon->core->stacking->under = NULL; + icon->core->stacking->window_level = NORMAL_ICON_LEVEL; + icon->core->stacking->child_of = NULL; + + icon->owner = wwin; + if (wwin->wm_hints && (wwin->wm_hints->flags & IconWindowHint)) { + if (wwin->client_win == wwin->main_window) { + WApplication *wapp; + /* do not let miniwindow steal app-icon's icon window */ + wapp = wApplicationOf(wwin->client_win); + if (!wapp || wapp->app_icon == NULL) + icon->icon_win = wwin->wm_hints->icon_window; + } else { + icon->icon_win = wwin->wm_hints->icon_window; + } + } +#ifdef NO_MINIWINDOW_TITLES + icon->show_title = 0; +#else + icon->show_title = 1; +#endif +#ifdef NETWM_HINTS + if (!icon->image && !WFLAGP(wwin, always_user_icon)) + icon->image = RRetainImage(wwin->net_icon_image); + if (!icon->image) +#endif + icon->image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class); + + file = wDefaultGetIconFile(scr, wwin->wm_instance, wwin->wm_class, False); + if (file) { + icon->file = wstrdup(file); + } + + icon->icon_name = wNETWMGetIconName(wwin->client_win); + if (icon->icon_name) + wwin->flags.net_has_icon_title = 1; + else + wGetIconName(dpy, wwin->client_win, &icon->icon_name); + + icon->tile_type = TILE_NORMAL; + + wIconUpdate(icon); + + XFlush(dpy); + + WMAddNotificationObserver(appearanceObserver, icon, WNIconAppearanceSettingsChanged, icon); + WMAddNotificationObserver(tileObserver, icon, WNIconTileSettingsChanged, icon); + return icon; +} + +WIcon *wIconCreateWithIconFile(WScreen * scr, char *iconfile, int tile) +{ + WIcon *icon; + unsigned long vmask = 0; + XSetWindowAttributes attribs; + + icon = wmalloc(sizeof(WIcon)); + memset(icon, 0, sizeof(WIcon)); + icon->core = wCoreCreateTopLevel(scr, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0); + if (wPreferences.use_saveunders) { + vmask = CWSaveUnder; + attribs.save_under = True; + } + /* a white border for selecting it */ + vmask |= CWBorderPixel; + attribs.border_pixel = scr->white_pixel; + + XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs); + + /* will be overriden if this is a application icon */ + icon->core->descriptor.handle_mousedown = miniwindowMouseDown; + icon->core->descriptor.handle_expose = miniwindowExpose; + icon->core->descriptor.parent_type = WCLASS_MINIWINDOW; + icon->core->descriptor.parent = icon; + + icon->core->stacking = wmalloc(sizeof(WStacking)); + icon->core->stacking->above = NULL; + icon->core->stacking->under = NULL; + icon->core->stacking->window_level = NORMAL_ICON_LEVEL; + icon->core->stacking->child_of = NULL; + + if (iconfile) { + icon->image = RLoadImage(scr->rcontext, iconfile, 0); + if (!icon->image) { + wwarning(_("error loading image file \"%s\""), iconfile, RMessageForError(RErrorCode)); + } + + icon->image = wIconValidateIconSize(scr, icon->image); + + icon->file = wstrdup(iconfile); + } + + icon->tile_type = tile; + + wIconUpdate(icon); + + WMAddNotificationObserver(appearanceObserver, icon, WNIconAppearanceSettingsChanged, icon); + WMAddNotificationObserver(tileObserver, icon, WNIconTileSettingsChanged, icon); + + return icon; +} + +void wIconDestroy(WIcon * icon) +{ + WCoreWindow *core = icon->core; + WScreen *scr = core->screen_ptr; + + WMRemoveNotificationObserver(icon); + + if (icon->handlerID) + WMDeleteTimerHandler(icon->handlerID); + + if (icon->icon_win) { + int x = 0, y = 0; + + if (icon->owner) { + x = icon->owner->icon_x; + y = icon->owner->icon_y; + } + XUnmapWindow(dpy, icon->icon_win); + XReparentWindow(dpy, icon->icon_win, scr->root_win, x, y); + } + if (icon->icon_name) + XFree(icon->icon_name); + + if (icon->pixmap) + XFreePixmap(dpy, icon->pixmap); + + if (icon->file) + wfree(icon->file); + + if (icon->image != NULL) + RReleaseImage(icon->image); + + wCoreDestroy(icon->core); + wfree(icon); +} + +static void drawIconTitle(WScreen * scr, Pixmap pixmap, int height) +{ + XFillRectangle(dpy, pixmap, scr->icon_title_texture->normal_gc, 0, 0, wPreferences.icon_size, height + 1); + XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, wPreferences.icon_size, 0); + XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, 0, height + 1); + XDrawLine(dpy, pixmap, scr->icon_title_texture->dim_gc, + wPreferences.icon_size - 1, 0, wPreferences.icon_size - 1, height + 1); +} + +static Pixmap makeIcon(WScreen * scr, RImage * icon, int titled, int shadowed, int tileType) +{ + RImage *tile; + Pixmap pixmap; + int x, y, sx, sy; + unsigned w, h; + int theight = WMFontHeight(scr->icon_title_font); + + if (tileType == TILE_NORMAL) + tile = RCloneImage(scr->icon_tile); + else { + assert(scr->clip_tile); + tile = RCloneImage(scr->clip_tile); + } + if (icon) { + w = (icon->width > wPreferences.icon_size) + ? wPreferences.icon_size : icon->width; + x = (wPreferences.icon_size - w) / 2; + sx = (icon->width - w) / 2; + + if (!titled) { + h = (icon->height > wPreferences.icon_size) + ? wPreferences.icon_size : icon->height; + y = (wPreferences.icon_size - h) / 2; + sy = (icon->height - h) / 2; + } else { + h = (icon->height + theight > wPreferences.icon_size + ? wPreferences.icon_size - theight : icon->height); + y = theight + ((int)wPreferences.icon_size - theight - h) / 2; + sy = (icon->height - h) / 2; + } + RCombineArea(tile, icon, sx, sy, w, h, x, y); + } + + if (shadowed) { + RColor color; + + color.red = scr->icon_back_texture->light.red >> 8; + color.green = scr->icon_back_texture->light.green >> 8; + color.blue = scr->icon_back_texture->light.blue >> 8; + color.alpha = 150; /* about 60% */ + RClearImage(tile, &color); + } + + if (!RConvertImage(scr->rcontext, tile, &pixmap)) { + wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode)); + } + RReleaseImage(tile); + + if (titled) + drawIconTitle(scr, pixmap, theight); + + return pixmap; +} + +void wIconChangeTitle(WIcon * icon, char *new_title) +{ + int changed; + + changed = (new_title == NULL && icon->icon_name != NULL) + || (new_title != NULL && icon->icon_name == NULL); + + if (icon->icon_name != NULL) + XFree(icon->icon_name); + + icon->icon_name = new_title; + + if (changed) + icon->force_paint = 1; + wIconPaint(icon); +} + +void wIconChangeImage(WIcon * icon, RImage * new_image) +{ + assert(icon != NULL); + + if (icon->image) + RReleaseImage(icon->image); + + icon->image = new_image; + + wIconUpdate(icon); +} + +RImage *wIconValidateIconSize(WScreen * scr, RImage * icon) +{ + RImage *tmp; + int w, h; + + if (!icon) + return NULL; +#ifndef DONT_SCALE_ICONS + if (wPreferences.icon_size != 64) { + w = wPreferences.icon_size * icon->width / 64; + h = wPreferences.icon_size * icon->height / 64; + + tmp = RScaleImage(icon, w, h); + RReleaseImage(icon); + icon = tmp; + } +#endif +#if 0 + if (icon->width > wPreferences.icon_size || icon->height > wPreferences.icon_size) { + if (icon->width > icon->height) { + w = wPreferences.icon_size - 4; + h = w * icon->height / icon->width; + } else { + h = wPreferences.icon_size - 4; + w = h * icon->width / icon->height; + } + tmp = RScaleImage(icon, w, h); + RReleaseImage(icon); + icon = tmp; + } +#endif + + return icon; +} + +Bool wIconChangeImageFile(WIcon * icon, char *file) +{ + WScreen *scr = icon->core->screen_ptr; + RImage *image; + char *path; + int error = 0; + + if (!file) { + wIconChangeImage(icon, NULL); + return True; + } + + path = FindImage(wPreferences.icon_path, file); + + if (path && (image = RLoadImage(scr->rcontext, path, 0))) { + image = wIconValidateIconSize(icon->core->screen_ptr, image); + + wIconChangeImage(icon, image); + } else { + error = 1; + } + + if (path) + wfree(path); + + return !error; +} + +static char *getnameforicon(WWindow * wwin) +{ + char *prefix, *suffix; + char *path; + int len; + + if (wwin->wm_class && wwin->wm_instance) { + int len = strlen(wwin->wm_class) + strlen(wwin->wm_instance) + 2; + suffix = wmalloc(len); + snprintf(suffix, len, "%s.%s", wwin->wm_instance, wwin->wm_class); + } else if (wwin->wm_class) { + int len = strlen(wwin->wm_class) + 1; + suffix = wmalloc(len); + snprintf(suffix, len, "%s", wwin->wm_class); + } else if (wwin->wm_instance) { + int len = strlen(wwin->wm_instance) + 1; + suffix = wmalloc(len); + snprintf(suffix, len, "%s", wwin->wm_instance); + } else { + return NULL; + } + + prefix = wusergnusteppath(); + len = strlen(prefix) + 64 + strlen(suffix); + path = wmalloc(len + 1); + snprintf(path, len, "%s/Library/WindowMaker", prefix); + + if (access(path, F_OK) != 0) { + if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR)) { + wsyserror(_("could not create directory %s"), path); + wfree(path); + wfree(suffix); + return NULL; + } + } + strcat(path, "/CachedPixmaps"); + if (access(path, F_OK) != 0) { + if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { + wsyserror(_("could not create directory %s"), path); + wfree(path); + wfree(suffix); + return NULL; + } + } + + strcat(path, "/"); + strcat(path, suffix); + strcat(path, ".xpm"); + wfree(suffix); + + return path; +} + +/* + * wIconStore-- + * Stores the client supplied icon at ~/GNUstep/Library/WindowMaker/CachedPixmaps + * and returns the path for that icon. Returns NULL if there is no + * client supplied icon or on failure. + * + * Side effects: + * New directories might be created. + */ +char *wIconStore(WIcon * icon) +{ + char *path; + RImage *image; + WWindow *wwin = icon->owner; + + if (!wwin || !wwin->wm_hints || !(wwin->wm_hints->flags & IconPixmapHint) + || wwin->wm_hints->icon_pixmap == None) + return NULL; + + path = getnameforicon(wwin); + if (!path) + return NULL; + + image = RCreateImageFromDrawable(icon->core->screen_ptr->rcontext, + wwin->wm_hints->icon_pixmap, (wwin->wm_hints->flags & IconMaskHint) + ? wwin->wm_hints->icon_mask : None); + if (!image) { + wfree(path); + return NULL; + } + + if (!RSaveImage(image, path, "XPM")) { + wfree(path); + path = NULL; + } + RReleaseImage(image); + + return path; +} + +/* +void wIconChangeIconWindow(WIcon *icon, Window new_window); +*/ + +static void cycleColor(void *data) +{ + WIcon *icon = (WIcon *) data; + WScreen *scr = icon->core->screen_ptr; + XGCValues gcv; + + icon->step--; + gcv.dash_offset = icon->step; + XChangeGC(dpy, scr->icon_select_gc, GCDashOffset, &gcv); + + XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, + icon->core->width - 1, icon->core->height - 1); + icon->handlerID = WMAddTimerHandler(COLOR_CYCLE_DELAY, cycleColor, icon); +} + +void wIconSetHighlited(WIcon * icon, Bool flag) +{ + if (icon->highlighted == flag) { + return; + } + + icon->highlighted = flag; + wIconPaint(icon); +} + +void wIconSelect(WIcon * icon) +{ + WScreen *scr = icon->core->screen_ptr; + icon->selected = !icon->selected; + + if (icon->selected) { + icon->step = 0; + if (!wPreferences.dont_blink) + icon->handlerID = WMAddTimerHandler(10, cycleColor, icon); + else + XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, + icon->core->width - 1, icon->core->height - 1); + } else { + if (icon->handlerID) { + WMDeleteTimerHandler(icon->handlerID); + icon->handlerID = NULL; + } + XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, icon->core->height, True); + } +} + +void wIconUpdate(WIcon * icon) +{ + WScreen *scr = icon->core->screen_ptr; + int title_height = WMFontHeight(scr->icon_title_font); + WWindow *wwin = icon->owner; + + assert(scr->icon_tile != NULL); + + if (icon->pixmap != None) + XFreePixmap(dpy, icon->pixmap); + icon->pixmap = None; + + if (wwin && (WFLAGP(wwin, always_user_icon) +#ifdef NETWM_HINTS + || wwin->net_icon_image +#endif + )) + goto user_icon; + + /* use client specified icon window */ + if (icon->icon_win != None) { + XWindowAttributes attr; + int resize = 0; + unsigned int width, height, depth; + int theight; + Pixmap pixmap; + + getSize(icon->icon_win, &width, &height, &depth); + + if (width > wPreferences.icon_size) { + resize = 1; + width = wPreferences.icon_size; + } + if (height > wPreferences.icon_size) { + resize = 1; + height = wPreferences.icon_size; + } + if (icon->show_title && (height + title_height < wPreferences.icon_size)) { + pixmap = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, + wPreferences.icon_size, scr->w_depth); + XSetClipMask(dpy, scr->copy_gc, None); + XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0, + wPreferences.icon_size, wPreferences.icon_size, 0, 0); + drawIconTitle(scr, pixmap, title_height); + theight = title_height; + } else { + pixmap = None; + theight = 0; + XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->icon_tile_pixmap); + } + + XSetWindowBorderWidth(dpy, icon->icon_win, 0); + XReparentWindow(dpy, icon->icon_win, icon->core->window, + (wPreferences.icon_size - width) / 2, + theight + (wPreferences.icon_size - height - theight) / 2); + if (resize) + XResizeWindow(dpy, icon->icon_win, width, height); + + XMapWindow(dpy, icon->icon_win); + + XAddToSaveSet(dpy, icon->icon_win); + + icon->pixmap = pixmap; + + if (XGetWindowAttributes(dpy, icon->icon_win, &attr)) { + if (attr.all_event_masks & ButtonPressMask) { + wHackedGrabButton(Button1, MOD_MASK, icon->core->window, True, + ButtonPressMask, GrabModeSync, GrabModeAsync, + None, wCursor[WCUR_ARROW]); + } + } + } else if (wwin && wwin->wm_hints && (wwin->wm_hints->flags & IconPixmapHint)) { + int x, y; + unsigned int w, h; + Window jw; + int ji, dotitle; + unsigned int ju, d; + Pixmap pixmap; + + if (!XGetGeometry(dpy, wwin->wm_hints->icon_pixmap, &jw, &ji, &ji, &w, &h, &ju, &d)) { + icon->owner->wm_hints->flags &= ~IconPixmapHint; + goto user_icon; + } + + pixmap = XCreatePixmap(dpy, icon->core->window, wPreferences.icon_size, + wPreferences.icon_size, scr->w_depth); + XSetClipMask(dpy, scr->copy_gc, None); + XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0, + wPreferences.icon_size, wPreferences.icon_size, 0, 0); + + if (w > wPreferences.icon_size) + w = wPreferences.icon_size; + x = (wPreferences.icon_size - w) / 2; + + if (icon->show_title && (title_height < wPreferences.icon_size)) { + drawIconTitle(scr, pixmap, title_height); + dotitle = 1; + + if (h > wPreferences.icon_size - title_height - 2) { + h = wPreferences.icon_size - title_height - 2; + y = title_height + 1; + } else { + y = (wPreferences.icon_size - h - title_height) / 2 + title_height + 1; + } + } else { + dotitle = 0; + if (w > wPreferences.icon_size) + w = wPreferences.icon_size; + y = (wPreferences.icon_size - h) / 2; + } + + if (wwin->wm_hints->flags & IconMaskHint) + XSetClipMask(dpy, scr->copy_gc, wwin->wm_hints->icon_mask); + + XSetClipOrigin(dpy, scr->copy_gc, x, y); + + if (d != scr->w_depth) { + XSetForeground(dpy, scr->copy_gc, scr->black_pixel); + XSetBackground(dpy, scr->copy_gc, scr->white_pixel); + XCopyPlane(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, 0, 0, w, h, x, y, 1); + } else { + XCopyArea(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, 0, 0, w, h, x, y); + } + + XSetClipOrigin(dpy, scr->copy_gc, 0, 0); + + icon->pixmap = pixmap; + } else { + user_icon: + + if (icon->image) { + icon->pixmap = makeIcon(scr, icon->image, icon->show_title, + icon->shadowed, icon->tile_type); + } else { + /* make default icons */ + + if (!scr->def_icon_pixmap) { + RImage *image = NULL; + char *path; + char *file; + + file = wDefaultGetIconFile(scr, NULL, NULL, False); + if (file) { + path = FindImage(wPreferences.icon_path, file); + if (!path) { + wwarning(_("could not find default icon \"%s\""), file); + goto make_icons; + } + + image = RLoadImage(scr->rcontext, path, 0); + if (!image) { + wwarning(_("could not load default icon \"%s\":%s"), + file, RMessageForError(RErrorCode)); + } + wfree(path); + } + make_icons: + + image = wIconValidateIconSize(scr, image); + scr->def_icon_pixmap = makeIcon(scr, image, False, False, icon->tile_type); + scr->def_ticon_pixmap = makeIcon(scr, image, True, False, icon->tile_type); + if (image) + RReleaseImage(image); + } + + if (icon->show_title) { + XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->def_ticon_pixmap); + } else { + XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->def_icon_pixmap); + } + icon->pixmap = None; + } + } + if (icon->pixmap != None) { + XSetWindowBackgroundPixmap(dpy, icon->core->window, icon->pixmap); + } + XClearWindow(dpy, icon->core->window); + + wIconPaint(icon); +} + +void wIconPaint(WIcon * icon) +{ + WScreen *scr = icon->core->screen_ptr; + int x; + char *tmp; + + if (icon->force_paint) { + icon->force_paint = 0; + wIconUpdate(icon); + return; + } + + XClearWindow(dpy, icon->core->window); + + /* draw the icon title */ + if (icon->show_title && icon->icon_name != NULL) { + int l; + int w; + + tmp = ShrinkString(scr->icon_title_font, icon->icon_name, wPreferences.icon_size - 4); + w = WMWidthOfString(scr->icon_title_font, tmp, l = strlen(tmp)); + + if (w > icon->core->width - 4) + x = (icon->core->width - 4) - w; + else + x = (icon->core->width - w) / 2; + + WMDrawString(scr->wmscreen, icon->core->window, scr->icon_title_color, + scr->icon_title_font, x, 1, tmp, l); + wfree(tmp); + } + + if (icon->selected) + XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0, + icon->core->width - 1, icon->core->height - 1); +} + +/******************************************************************/ + +static void miniwindowExpose(WObjDescriptor * desc, XEvent * event) +{ + wIconPaint(desc->parent); +} + +static void miniwindowDblClick(WObjDescriptor * desc, XEvent * event) +{ + WIcon *icon = desc->parent; + + assert(icon->owner != NULL); + + wDeiconifyWindow(icon->owner); +} + +static void miniwindowMouseDown(WObjDescriptor * desc, XEvent * event) +{ + WIcon *icon = desc->parent; + WWindow *wwin = icon->owner; + XEvent ev; + int x = wwin->icon_x, y = wwin->icon_y; + int dx = event->xbutton.x, dy = event->xbutton.y; + int grabbed = 0; + int clickButton = event->xbutton.button; + + if (WCHECK_STATE(WSTATE_MODAL)) + return; + + if (IsDoubleClick(icon->core->screen_ptr, event)) { + miniwindowDblClick(desc, event); + return; + } +#ifdef DEBUG + puts("Moving miniwindow"); +#endif + if (event->xbutton.button == Button1) { + if (event->xbutton.state & MOD_MASK) + wLowerFrame(icon->core); + else + wRaiseFrame(icon->core); + if (event->xbutton.state & ShiftMask) { + wIconSelect(icon); + wSelectWindow(icon->owner, !wwin->flags.selected); + } + } else if (event->xbutton.button == Button3) { + WObjDescriptor *desc; + + OpenMiniwindowMenu(wwin, event->xbutton.x_root, event->xbutton.y_root); + + /* allow drag select of menu */ + desc = &wwin->screen_ptr->window_menu->menu->descriptor; + event->xbutton.send_event = True; + (*desc->handle_mousedown) (desc, event); + + return; + } + + if (XGrabPointer(dpy, icon->core->window, False, ButtonMotionMask + | ButtonReleaseMask | ButtonPressMask, GrabModeAsync, + GrabModeAsync, None, None, CurrentTime) != GrabSuccess) { +#ifdef DEBUG0 + wwarning("pointer grab failed for icon move"); +#endif + } + while (1) { + WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask + | ButtonMotionMask | ExposureMask, &ev); + switch (ev.type) { + case Expose: + WMHandleEvent(&ev); + break; + + case MotionNotify: + if (!grabbed) { + if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD + || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) { + XChangeActivePointerGrab(dpy, ButtonMotionMask + | ButtonReleaseMask | ButtonPressMask, + wCursor[WCUR_MOVE], CurrentTime); + grabbed = 1; + } else { + break; + } + } + x = ev.xmotion.x_root - dx; + y = ev.xmotion.y_root - dy; + XMoveWindow(dpy, icon->core->window, x, y); + break; + + case ButtonPress: + break; + + case ButtonRelease: + if (ev.xbutton.button != clickButton) + break; + + if (wwin->icon_x != x || wwin->icon_y != y) + wwin->flags.icon_moved = 1; + + XMoveWindow(dpy, icon->core->window, x, y); + + wwin->icon_x = x; + wwin->icon_y = y; +#ifdef DEBUG + puts("End miniwindow move"); +#endif + XUngrabPointer(dpy, CurrentTime); + + if (wPreferences.auto_arrange_icons) + wArrangeIcons(wwin->screen_ptr, True); + return; + + } + } +}