mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-24 07:02:30 +01:00
---------------
- Added retain/release mechanism to RImage by adding RRetainImage() and
RReleaseImage(). RDestroyImage() is an alias to RReleaseImage() now, but
will be removed in a future release because it no longer fits with the
semantics. Will be kept for a while to allow a smoother transition.
More about in wrlib/NEWS
For WINGs:
----------
- Small API change:
1. Renamed WMSetApplicationIconImage(), WMGetApplicationIconImage() and
WMSetWindowMiniwindowImage() to respectively WMSetApplicationIconPixmap(),
WMGetApplicationIconPixmap() and WMSetWindowMiniwindowPixmap()
They operate on a WMPixmap which is practically an X Pixmap with no alpha
channel information and the new name is more suggestive and also leaves
room for the new functions added for operating on images with alpha info.
2. Added WMSetApplicationIconImage() and WMGetApplicationIconImage() which
operate on an RImage and store alpha information too.
3. Added WMGetApplicationIconBlendedPixmap() which will take the image with
alpha set by WMSetApplicationIconImage() and will blend it with a color.
If color is NULL it will blend using the default panel color (#aeaaae)
All these changes will allow WINGs to handle images with alpha blending
correctly in panels and wherever else needed. More about in WINGs/NEWS.
- updated panels to use the newly available RImages if present and fallback
to old WMPixmaps if not, to properly show alpha blended images.
- replaced some still left malloc's with wmalloc's.
For Window Maker:
-----------------
- Fixed wrong mapping position of the "Docked Applications Panel" for some
icons.
- Smoother animation for the smiley =)
- Made images with alpha blending be shown correctly in the panels and the
icon chooser.
- The icon image set to be shown in panels ("Logo.WMPanel") will be
automatically updated if its entry in WMWindowAttributes changes (without
a need to restart as until now).
*** Note!!! ***
If you are developing applications with one of libwraster or libWINGs
then you should look to wrlib/NEWS and WINGs/NEWS to see what changed
and how should you update your code.
972 lines
24 KiB
C
972 lines
24 KiB
C
/* icon.c - window icon and dock and appicon parent
|
|
*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1997, 1998 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 <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <wraster.h>
|
|
#include <sys/stat.h>
|
|
|
|
#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"
|
|
|
|
/**** Global variables ****/
|
|
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)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
|
|
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);
|
|
}
|
|
|
|
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 = wIconValidateIconSize(icon->core->screen_ptr, 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))) {
|
|
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) {
|
|
suffix = wmalloc(strlen(wwin->wm_class)+strlen(wwin->wm_instance)+2);
|
|
sprintf(suffix, "%s.%s", wwin->wm_instance, wwin->wm_class);
|
|
} else if (wwin->wm_class) {
|
|
suffix = wmalloc(strlen(wwin->wm_class)+1);
|
|
strcpy(suffix, wwin->wm_class);
|
|
} else if (wwin->wm_instance) {
|
|
suffix = wmalloc(strlen(wwin->wm_instance)+1);
|
|
strcpy(suffix, wwin->wm_instance);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
prefix = wusergnusteppath();
|
|
len = strlen(prefix)+64+strlen(suffix);
|
|
path = wmalloc(len+1);
|
|
sprintf(path, "%s/.AppInfo", 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, "/WindowMaker");
|
|
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/.AppInfo/WindowMaker
|
|
* 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))
|
|
goto user_icon;
|
|
|
|
/* use client specified icon window */
|
|
if (icon->icon_win!=None) {
|
|
XWindowAttributes attr;
|
|
int resize=0;
|
|
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;
|
|
GC gc = scr->icon_title_gc;
|
|
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, gc,
|
|
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;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|