mirror of
https://github.com/gryf/wmaker.git
synced 2026-01-03 04:14:20 +01:00
The icons should be scaled if their size is "max_size - ~3 pixels". Tipically, max_size is 64 pixels. With the current wIconValidateIconSize the max size for an icon is "64 pixels", then the icon don't have border and is ugly. This problem is in the dock icons and in the switchpanel. The new wIconValidateIconSize function don't use the fixel value of 64 pixels, uses the argument max_size to get the final icon size. The icon is scaled holding the aspect ratio and reserve ~2 or ~3 pixels to hold left space to the icon border. Now the icon is inside the icon space, with border. This patch removes the preprocessor option of DONT_SCALE_ICONS, because all the icons should be scaled if needed, to hold a beatiful interface.
913 lines
23 KiB
C
913 lines
23 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.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.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"
|
|
#include "wmspec.h"
|
|
|
|
/**** Global varianebles ****/
|
|
extern WPreferences wPreferences;
|
|
|
|
#define MOD_MASK wPreferences.modifier_mask
|
|
#define CACHE_ICON_PATH "/Library/WindowMaker/CachedPixmaps"
|
|
#define ICON_BORDER 3
|
|
|
|
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);
|
|
|
|
static WIcon *wIconCreateCore(WScreen *scr, int coord_x, int coord_y);
|
|
|
|
void get_pixmap_icon_from_icon_win(WIcon *icon);
|
|
int get_pixmap_icon_from_wm_hints(WScreen *scr, WWindow *wwin, WIcon *icon);
|
|
void get_pixmap_icon_from_user_icon(WScreen *scr, WIcon * icon);
|
|
/****** Notification Observers ******/
|
|
|
|
static void appearanceObserver(void *self, WMNotification * notif)
|
|
{
|
|
WIcon *icon = (WIcon *) self;
|
|
uintptr_t flags = (uintptr_t)WMGetNotificationClientData(notif);
|
|
|
|
if ((flags & WTextureSettings) || (flags & WFontSettings))
|
|
icon->force_paint = 1;
|
|
|
|
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;
|
|
|
|
icon = wIconCreateCore(scr, wwin->icon_x, wwin->icon_y);
|
|
|
|
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->file_image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class, wPreferences.icon_size);
|
|
|
|
file = wDefaultGetIconFile(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;
|
|
|
|
icon = wIconCreateCore(scr, 0, 0);
|
|
|
|
if (iconfile) {
|
|
icon->file_image = RLoadImage(scr->rcontext, iconfile, 0);
|
|
if (!icon->file_image)
|
|
wwarning(_("error loading image file \"%s\": %s"), iconfile, RMessageForError(RErrorCode));
|
|
|
|
icon->file_image = wIconValidateIconSize(scr, icon->file_image, wPreferences.icon_size);
|
|
|
|
icon->file = wstrdup(iconfile);
|
|
}
|
|
|
|
icon->tile_type = tile;
|
|
|
|
wIconUpdate(icon);
|
|
|
|
WMAddNotificationObserver(appearanceObserver, icon, WNIconAppearanceSettingsChanged, icon);
|
|
WMAddNotificationObserver(tileObserver, icon, WNIconTileSettingsChanged, icon);
|
|
|
|
return icon;
|
|
}
|
|
|
|
static WIcon *wIconCreateCore(WScreen *scr, int coord_x, int coord_y)
|
|
{
|
|
WIcon *icon;
|
|
unsigned long vmask = 0;
|
|
XSetWindowAttributes attribs;
|
|
|
|
icon = wmalloc(sizeof(WIcon));
|
|
icon->core = wCoreCreateTopLevel(scr,
|
|
coord_x,
|
|
coord_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 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;
|
|
|
|
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->file_image != NULL)
|
|
RReleaseImage(icon->file_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, int highlighted)
|
|
{
|
|
RImage *tile;
|
|
Pixmap pixmap;
|
|
int x, y, sx, sy;
|
|
unsigned w, h;
|
|
int theight = 0;
|
|
|
|
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)
|
|
theight = WMFontHeight(scr->icon_title_font);
|
|
|
|
h = (icon->height + theight > wPreferences.icon_size
|
|
? wPreferences.icon_size - theight : icon->height);
|
|
y = theight + (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 (highlighted) {
|
|
RColor color;
|
|
|
|
color.red = color.green = color.blue = 0;
|
|
color.alpha = 160;
|
|
RLightImage(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);
|
|
}
|
|
|
|
RImage *wIconValidateIconSize(WScreen *scr, RImage *icon, int max_size)
|
|
{
|
|
RImage *nimage;
|
|
|
|
if (!icon)
|
|
return NULL;
|
|
|
|
/* We should hold "ICON_BORDER" (~2) pixels to include the icon border */
|
|
if ((icon->width - max_size) > -ICON_BORDER ||
|
|
(icon->height - max_size) > -ICON_BORDER) {
|
|
nimage = RScaleImage(icon, max_size - ICON_BORDER,
|
|
(icon->height * (max_size - ICON_BORDER) / icon->width));
|
|
RReleaseImage(icon);
|
|
icon = nimage;
|
|
}
|
|
|
|
return icon;
|
|
}
|
|
|
|
Bool wIconChangeImageFile(WIcon * icon, char *file)
|
|
{
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
RImage *image;
|
|
char *path;
|
|
int error = 0;
|
|
|
|
if (icon->file_image)
|
|
RReleaseImage(icon->file_image);
|
|
|
|
if (!file) {
|
|
icon->file_image = NULL;
|
|
wIconUpdate(icon);
|
|
return True;
|
|
}
|
|
|
|
path = FindImage(wPreferences.icon_path, file);
|
|
|
|
if (path && (image = RLoadImage(scr->rcontext, path, 0))) {
|
|
icon->file_image = wIconValidateIconSize(icon->core->screen_ptr, image, wPreferences.icon_size);
|
|
wIconUpdate(icon);
|
|
} else {
|
|
error = 1;
|
|
}
|
|
|
|
if (path)
|
|
wfree(path);
|
|
|
|
return !error;
|
|
}
|
|
|
|
static char *get_name_for_wwin(WWindow *wwin)
|
|
{
|
|
return get_name_for_instance_class(wwin->wm_instance, wwin->wm_class);
|
|
}
|
|
|
|
char *get_name_for_instance_class(char *wm_instance, char *wm_class)
|
|
{
|
|
char *suffix;
|
|
int len;
|
|
|
|
if (wm_class && wm_instance) {
|
|
len = strlen(wm_class) + strlen(wm_instance) + 2;
|
|
suffix = wmalloc(len);
|
|
snprintf(suffix, len, "%s.%s", wm_instance, wm_class);
|
|
} else if (wm_class) {
|
|
len = strlen(wm_class) + 1;
|
|
suffix = wmalloc(len);
|
|
snprintf(suffix, len, "%s", wm_class);
|
|
} else if (wm_instance) {
|
|
len = strlen(wm_instance) + 1;
|
|
suffix = wmalloc(len);
|
|
snprintf(suffix, len, "%s", wm_instance);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
return suffix;
|
|
}
|
|
|
|
static char *get_icon_cache_path(void)
|
|
{
|
|
char *prefix, *path;
|
|
int len, ret;
|
|
|
|
prefix = wusergnusteppath();
|
|
len = strlen(prefix) + strlen(CACHE_ICON_PATH) + 2;
|
|
path = wmalloc(len);
|
|
snprintf(path, len, "%s%s/", prefix, CACHE_ICON_PATH);
|
|
|
|
/* If the folder exists, exit */
|
|
if (access(path, F_OK) == 0)
|
|
return path;
|
|
|
|
/* Create the folder */
|
|
ret = wmkdirhier((const char *) path);
|
|
|
|
/* Exit 1 on success, 0 on failure */
|
|
if (ret == 1)
|
|
return path;
|
|
|
|
/* Fail */
|
|
wfree(path);
|
|
return NULL;
|
|
}
|
|
|
|
static RImage *get_wwindow_image_from_wmhints(WWindow *wwin, WIcon *icon)
|
|
{
|
|
RImage *image = NULL;
|
|
XWMHints *hints = wwin->wm_hints;
|
|
|
|
if (hints && (hints->flags & IconPixmapHint) && hints->icon_pixmap != None)
|
|
image = RCreateImageFromDrawable(icon->core->screen_ptr->rcontext,
|
|
hints->icon_pixmap,
|
|
(hints->flags & IconMaskHint)
|
|
? hints->icon_mask : None);
|
|
|
|
return image;
|
|
}
|
|
|
|
/*
|
|
* wIconStore--
|
|
* Stores the client supplied icon at CACHE_ICON_PATH
|
|
* 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, *dir_path, *file;
|
|
int len = 0;
|
|
RImage *image = NULL;
|
|
WWindow *wwin = icon->owner;
|
|
|
|
if (!wwin)
|
|
return NULL;
|
|
|
|
dir_path = get_icon_cache_path();
|
|
if (!dir_path)
|
|
return NULL;
|
|
|
|
file = get_name_for_wwin(wwin);
|
|
if (!file) {
|
|
wfree(dir_path);
|
|
return NULL;
|
|
}
|
|
|
|
len = strlen(dir_path) + strlen(file) + 5;
|
|
path = wmalloc(len);
|
|
snprintf(path, len, "%s%s.xpm", dir_path, file);
|
|
wfree(dir_path);
|
|
wfree(file);
|
|
|
|
/* If icon exists, exit */
|
|
if (access(path, F_OK) == 0)
|
|
return path;
|
|
|
|
if (wwin->net_icon_image)
|
|
image = RRetainImage(wwin->net_icon_image);
|
|
else
|
|
image = get_wwindow_image_from_wmhints(wwin, icon);
|
|
|
|
if (!image) {
|
|
wfree(path);
|
|
return NULL;
|
|
}
|
|
|
|
if (!RSaveImage(image, path, "XPM")) {
|
|
wfree(path);
|
|
path = NULL;
|
|
}
|
|
|
|
RReleaseImage(image);
|
|
|
|
return path;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
#ifdef NEWAPPICON
|
|
void wIconSetHighlited(WIcon *icon, Bool flag)
|
|
{
|
|
if (icon->highlighted == flag)
|
|
return;
|
|
|
|
icon->highlighted = flag;
|
|
icon->force_paint = True;
|
|
wIconPaint(icon);
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
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)) {
|
|
/* Forced use user_icon */
|
|
get_pixmap_icon_from_user_icon(scr, icon);
|
|
} else if (icon->icon_win != None) {
|
|
/* Get the Pixmap from the WIcon */
|
|
get_pixmap_icon_from_icon_win(icon);
|
|
} else if (wwin && wwin->net_icon_image) {
|
|
/* Use _NET_WM_ICON icon */
|
|
icon->pixmap = makeIcon(scr, wwin->net_icon_image, icon->show_title,
|
|
icon->shadowed, icon->tile_type, icon->highlighted);
|
|
} else if (wwin && wwin->wm_hints && (wwin->wm_hints->flags & IconPixmapHint)) {
|
|
/* Get the Pixmap from the wm_hints, else, from the user */
|
|
if (get_pixmap_icon_from_wm_hints(scr, wwin, icon))
|
|
get_pixmap_icon_from_user_icon(scr, icon);
|
|
} else {
|
|
/* Get the Pixmap from the user */
|
|
get_pixmap_icon_from_user_icon(scr, icon);
|
|
}
|
|
|
|
/* No pixmap, set default background */
|
|
if (icon->pixmap != None)
|
|
XSetWindowBackgroundPixmap(dpy, icon->core->window, icon->pixmap);
|
|
|
|
/* Paint it */
|
|
XClearWindow(dpy, icon->core->window);
|
|
wIconPaint(icon);
|
|
}
|
|
|
|
void get_pixmap_icon_from_user_icon(WScreen *scr, WIcon * icon)
|
|
{
|
|
RImage *image = NULL;
|
|
char *path;
|
|
char *file;
|
|
|
|
if (icon->file_image) {
|
|
icon->pixmap = makeIcon(scr, icon->file_image, icon->show_title,
|
|
icon->shadowed, icon->tile_type, icon->highlighted);
|
|
} else {
|
|
/* make default icons */
|
|
if (!scr->def_icon_pixmap) {
|
|
file = wDefaultGetIconFile(NULL, NULL, False);
|
|
if (file) {
|
|
path = FindImage(wPreferences.icon_path, file);
|
|
if (path) {
|
|
image = RLoadImage(scr->rcontext, path, 0);
|
|
if (!image)
|
|
wwarning(_("could not load default icon \"%s\":%s"),
|
|
file, RMessageForError(RErrorCode));
|
|
wfree(path);
|
|
} else {
|
|
wwarning(_("could not find default icon \"%s\""), file);
|
|
}
|
|
}
|
|
|
|
image = wIconValidateIconSize(scr, image, wPreferences.icon_size);
|
|
scr->def_icon_pixmap = makeIcon(scr, image, False, False, icon->tile_type, icon->highlighted);
|
|
scr->def_ticon_pixmap = makeIcon(scr, image, True, False, icon->tile_type, icon->highlighted);
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* Get the Pixmap from the WIcon of the WWindow */
|
|
void get_pixmap_icon_from_icon_win(WIcon * icon)
|
|
{
|
|
XWindowAttributes attr;
|
|
WScreen *scr = icon->core->screen_ptr;
|
|
int title_height = WMFontHeight(scr->icon_title_font);
|
|
unsigned int width, height, depth;
|
|
int theight;
|
|
int resize = 0;
|
|
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);
|
|
|
|
/* Save it */
|
|
icon->pixmap = pixmap;
|
|
|
|
if ((XGetWindowAttributes(dpy, icon->icon_win, &attr)) &&
|
|
(attr.all_event_masks & ButtonPressMask))
|
|
wHackedGrabButton(Button1, MOD_MASK, icon->core->window, True,
|
|
ButtonPressMask, GrabModeSync, GrabModeAsync,
|
|
None, wCursor[WCUR_ARROW]);
|
|
}
|
|
|
|
/* Get the Pixmap from the XWindow wm_hints */
|
|
int get_pixmap_icon_from_wm_hints(WScreen *scr, WWindow *wwin, WIcon *icon)
|
|
{
|
|
Window jw;
|
|
Pixmap pixmap;
|
|
unsigned int w, h, ju, d;
|
|
int ji, x, y;
|
|
int title_height = WMFontHeight(scr->icon_title_font);
|
|
|
|
if (!XGetGeometry(dpy, wwin->wm_hints->icon_pixmap, &jw, &ji, &ji, &w, &h, &ju, &d)) {
|
|
icon->owner->wm_hints->flags &= ~IconPixmapHint;
|
|
return 1;
|
|
}
|
|
|
|
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);
|
|
|
|
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 {
|
|
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;
|
|
return (0);
|
|
}
|
|
|
|
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;
|
|
Bool hasMoved = False;
|
|
|
|
if (WCHECK_STATE(WSTATE_MODAL))
|
|
return;
|
|
|
|
if (IsDoubleClick(icon->core->screen_ptr, event)) {
|
|
miniwindowDblClick(desc, event);
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
}
|
|
while (1) {
|
|
WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
|
|
| ButtonMotionMask | ExposureMask, &ev);
|
|
switch (ev.type) {
|
|
case Expose:
|
|
WMHandleEvent(&ev);
|
|
break;
|
|
|
|
case MotionNotify:
|
|
hasMoved = True;
|
|
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;
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
|
|
if (wPreferences.auto_arrange_icons)
|
|
wArrangeIcons(wwin->screen_ptr, True);
|
|
if (wPreferences.single_click && !hasMoved)
|
|
miniwindowDblClick(desc, event);
|
|
return;
|
|
|
|
}
|
|
}
|
|
}
|