forked from vitrine/wmaker
- Fixed bug in icon chooser dialog that could cause a segmentation fault in some cases (Pascal Hofstee <caelian@gmail.com>) - Fixed crash in asm code in wrlib, with new versions of gcc. - Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly used the r, g, b fields in the conversion. - Fixed x86 ASM code in wrlib to work on 64 bit architectures. - Fixed the focus flicker seen with some apps (notably gtk2) (Alexey Spiridonov <snarkmaster@gmail.com>) - Fixed all crashing bugs that were generated by wmaker starting with the WMState file missing. - Added NetWM support (a modified version of the patch originaly written by Peter Zijlstra <a.p.zijlstra@chello.nl>) - Applied patch to enhance the Virtual Desktop behaviour, and to integrate it with the NetWM code (Peter Zijlstra <a.p.zijlstra@chello.nl>) - Applied a few xinerama and placement fixes (Peter Zijlstra <a.p.zijlstra@chello.nl>) - Fixed memory leak in dock code. - Fixed and enhanced the text wrapping in WINGs. - Fixed the layout of some elements in WPrefs.app - Added workaround for aplications that don't set the required hints on the client leader window, but they set them on normal windows (observer with KDE 3.3.0 mainly). This will allow these apps to get an appicon again. (they should be fixed still) - Added workaround for applications that do not set a command with XSetCommand(), but instead they set the _NET_WM_PID property. This works with operating systems that offer a /proc interface similar to what linux has. (This also is to fix problems with KDE 3.3.0 apps, but not only them). - Fixed bug with autostart and exit scripts not being executed if user GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT) - Added utf8 support in WINGs (removed old X core font code) - Added utility to convert old font names to new font names in style files
985 lines
24 KiB
C
985 lines
24 KiB
C
/* 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 <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
|
|
#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);
|
|
}
|
|
|
|
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/.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)
|
|
#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;
|
|
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;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|