Change to the linux kernel coding style
[wmaker-crm.git] / src / icon.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001/* icon.c - window icon and dock and appicon parent
6830b057 dan2004-10-12 21:28:27 +00002 *
9af1c6c4 dan1998-10-21 14:43:47 +00003 * Window Maker window manager
6830b057 dan2004-10-12 21:28:27 +00004 *
4153e2fd dan2003-01-16 23:30:45 +00005 * Copyright (c) 1997-2003 Alfredo K. Kojima
6830b057 dan2004-10-12 21:28:27 +00006 *
9d2e6ef9 scottc1998-09-29 22:36:29 +00007 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
6830b057 dan2004-10-12 21:28:27 +000019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
9d2e6ef9 scottc1998-09-29 22:36:29 +000020 * USA.
21 */
22
23#include "wconfig.h"
24
25#include <X11/Xlib.h>
26#include <X11/Xutil.h>
27#include <stdlib.h>
28#include <stdio.h>
06f59b99 Carlos R. Mafra2008-11-06 01:37:44 +010029#include <stdint.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000030#include <string.h>
9af1c6c4 dan1998-10-21 14:43:47 +000031#include <unistd.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000032#include <ctype.h>
33#include <wraster.h>
9af1c6c4 dan1998-10-21 14:43:47 +000034#include <sys/stat.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000035
36#include "WindowMaker.h"
37#include "wcore.h"
38#include "texture.h"
39#include "window.h"
40#include "icon.h"
41#include "actions.h"
42#include "funcs.h"
43#include "stacking.h"
44#include "application.h"
45#include "defaults.h"
46#include "appicon.h"
70555308 kojima2004-10-16 22:05:04 +000047#include "wmspec.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +000048
70555308 kojima2004-10-16 22:05:04 +000049/**** Global varianebles ****/
9d2e6ef9 scottc1998-09-29 22:36:29 +000050extern WPreferences wPreferences;
51
52#define MOD_MASK wPreferences.modifier_mask
53
54extern Cursor wCursor[WCUR_LAST];
55
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020056static void miniwindowExpose(WObjDescriptor * desc, XEvent * event);
57static void miniwindowMouseDown(WObjDescriptor * desc, XEvent * event);
58static void miniwindowDblClick(WObjDescriptor * desc, XEvent * event);
9d2e6ef9 scottc1998-09-29 22:36:29 +000059
9df0e167 kojima1999-04-03 03:51:17 +000060/****** Notification Observers ******/
61
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020062static void appearanceObserver(void *self, WMNotification * notif)
9df0e167 kojima1999-04-03 03:51:17 +000063{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020064 WIcon *icon = (WIcon *) self;
65 int flags = (int)(uintptr_t) WMGetNotificationClientData(notif);
66
67 if (flags & WTextureSettings) {
68 icon->force_paint = 1;
69 }
70 if (flags & WFontSettings) {
71 icon->force_paint = 1;
72 }
73 /*
74 if (flags & WColorSettings) {
75 }
76 */
77
78 wIconPaint(icon);
79
80 /* so that the appicon expose handlers will paint the appicon specific
81 * stuff */
82 XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, icon->core->height, True);
9df0e167 kojima1999-04-03 03:51:17 +000083}
84
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020085static void tileObserver(void *self, WMNotification * notif)
9df0e167 kojima1999-04-03 03:51:17 +000086{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020087 WIcon *icon = (WIcon *) self;
9df0e167 kojima1999-04-03 03:51:17 +000088
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020089 icon->force_paint = 1;
90 wIconPaint(icon);
4a473b8a kojima1999-04-10 18:27:21 +000091
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020092 XClearArea(dpy, icon->core->window, 0, 0, 1, 1, True);
9df0e167 kojima1999-04-03 03:51:17 +000093}
94
95/************************************/
96
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020097INLINE static void getSize(Drawable d, unsigned int *w, unsigned int *h, unsigned int *dep)
9d2e6ef9 scottc1998-09-29 22:36:29 +000098{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020099 Window rjunk;
100 int xjunk, yjunk;
101 unsigned int bjunk;
6830b057 dan2004-10-12 21:28:27 +0000102
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200103 XGetGeometry(dpy, d, &rjunk, &xjunk, &yjunk, w, h, &bjunk, dep);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000104}
105
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200106WIcon *wIconCreate(WWindow * wwin)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000107{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200108 WScreen *scr = wwin->screen_ptr;
109 WIcon *icon;
110 char *file;
111 unsigned long vmask = 0;
112 XSetWindowAttributes attribs;
113
114 icon = wmalloc(sizeof(WIcon));
115 memset(icon, 0, sizeof(WIcon));
116 icon->core = wCoreCreateTopLevel(scr, wwin->icon_x, wwin->icon_y,
117 wPreferences.icon_size, wPreferences.icon_size, 0);
118
119 if (wPreferences.use_saveunders) {
120 vmask |= CWSaveUnder;
121 attribs.save_under = True;
122 }
123 /* a white border for selecting it */
124 vmask |= CWBorderPixel;
125 attribs.border_pixel = scr->white_pixel;
126
127 XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs);
128
129 /* will be overriden if this is an application icon */
130 icon->core->descriptor.handle_mousedown = miniwindowMouseDown;
131 icon->core->descriptor.handle_expose = miniwindowExpose;
132 icon->core->descriptor.parent_type = WCLASS_MINIWINDOW;
133 icon->core->descriptor.parent = icon;
134
135 icon->core->stacking = wmalloc(sizeof(WStacking));
136 icon->core->stacking->above = NULL;
137 icon->core->stacking->under = NULL;
138 icon->core->stacking->window_level = NORMAL_ICON_LEVEL;
139 icon->core->stacking->child_of = NULL;
140
141 icon->owner = wwin;
142 if (wwin->wm_hints && (wwin->wm_hints->flags & IconWindowHint)) {
143 if (wwin->client_win == wwin->main_window) {
144 WApplication *wapp;
145 /* do not let miniwindow steal app-icon's icon window */
146 wapp = wApplicationOf(wwin->client_win);
147 if (!wapp || wapp->app_icon == NULL)
148 icon->icon_win = wwin->wm_hints->icon_window;
149 } else {
150 icon->icon_win = wwin->wm_hints->icon_window;
151 }
152 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000153#ifdef NO_MINIWINDOW_TITLES
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200154 icon->show_title = 0;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000155#else
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200156 icon->show_title = 1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000157#endif
9aca0d5f dan2004-10-12 01:34:32 +0000158#ifdef NETWM_HINTS
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200159 if (!icon->image && !WFLAGP(wwin, always_user_icon))
160 icon->image = RRetainImage(wwin->net_icon_image);
161 if (!icon->image)
9aca0d5f dan2004-10-12 01:34:32 +0000162#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200163 icon->image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000164
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200165 file = wDefaultGetIconFile(scr, wwin->wm_instance, wwin->wm_class, False);
166 if (file) {
167 icon->file = wstrdup(file);
168 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000169
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200170 icon->icon_name = wNETWMGetIconName(wwin->client_win);
171 if (icon->icon_name)
172 wwin->flags.net_has_icon_title = 1;
173 else
174 wGetIconName(dpy, wwin->client_win, &icon->icon_name);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000175
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200176 icon->tile_type = TILE_NORMAL;
6830b057 dan2004-10-12 21:28:27 +0000177
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200178 wIconUpdate(icon);
6830b057 dan2004-10-12 21:28:27 +0000179
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200180 XFlush(dpy);
9df0e167 kojima1999-04-03 03:51:17 +0000181
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200182 WMAddNotificationObserver(appearanceObserver, icon, WNIconAppearanceSettingsChanged, icon);
183 WMAddNotificationObserver(tileObserver, icon, WNIconTileSettingsChanged, icon);
184 return icon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000185}
186
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200187WIcon *wIconCreateWithIconFile(WScreen * scr, char *iconfile, int tile)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000188{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200189 WIcon *icon;
190 unsigned long vmask = 0;
191 XSetWindowAttributes attribs;
192
193 icon = wmalloc(sizeof(WIcon));
194 memset(icon, 0, sizeof(WIcon));
195 icon->core = wCoreCreateTopLevel(scr, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0);
196 if (wPreferences.use_saveunders) {
197 vmask = CWSaveUnder;
198 attribs.save_under = True;
199 }
200 /* a white border for selecting it */
201 vmask |= CWBorderPixel;
202 attribs.border_pixel = scr->white_pixel;
203
204 XChangeWindowAttributes(dpy, icon->core->window, vmask, &attribs);
205
206 /* will be overriden if this is a application icon */
207 icon->core->descriptor.handle_mousedown = miniwindowMouseDown;
208 icon->core->descriptor.handle_expose = miniwindowExpose;
209 icon->core->descriptor.parent_type = WCLASS_MINIWINDOW;
210 icon->core->descriptor.parent = icon;
211
212 icon->core->stacking = wmalloc(sizeof(WStacking));
213 icon->core->stacking->above = NULL;
214 icon->core->stacking->under = NULL;
215 icon->core->stacking->window_level = NORMAL_ICON_LEVEL;
216 icon->core->stacking->child_of = NULL;
217
218 if (iconfile) {
219 icon->image = RLoadImage(scr->rcontext, iconfile, 0);
220 if (!icon->image) {
221 wwarning(_("error loading image file \"%s\""), iconfile, RMessageForError(RErrorCode));
222 }
223
224 icon->image = wIconValidateIconSize(scr, icon->image);
225
226 icon->file = wstrdup(iconfile);
227 }
228
229 icon->tile_type = tile;
230
231 wIconUpdate(icon);
232
233 WMAddNotificationObserver(appearanceObserver, icon, WNIconAppearanceSettingsChanged, icon);
234 WMAddNotificationObserver(tileObserver, icon, WNIconTileSettingsChanged, icon);
235
236 return icon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000237}
238
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200239void wIconDestroy(WIcon * icon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000240{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200241 WCoreWindow *core = icon->core;
242 WScreen *scr = core->screen_ptr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000243
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200244 WMRemoveNotificationObserver(icon);
9df0e167 kojima1999-04-03 03:51:17 +0000245
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200246 if (icon->handlerID)
247 WMDeleteTimerHandler(icon->handlerID);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000248
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200249 if (icon->icon_win) {
250 int x = 0, y = 0;
6830b057 dan2004-10-12 21:28:27 +0000251
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200252 if (icon->owner) {
253 x = icon->owner->icon_x;
254 y = icon->owner->icon_y;
255 }
256 XUnmapWindow(dpy, icon->icon_win);
257 XReparentWindow(dpy, icon->icon_win, scr->root_win, x, y);
258 }
259 if (icon->icon_name)
260 XFree(icon->icon_name);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000261
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200262 if (icon->pixmap)
263 XFreePixmap(dpy, icon->pixmap);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000264
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200265 if (icon->file)
266 wfree(icon->file);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000267
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200268 if (icon->image != NULL)
269 RReleaseImage(icon->image);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000270
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200271 wCoreDestroy(icon->core);
272 wfree(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000273}
274
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200275static void drawIconTitle(WScreen * scr, Pixmap pixmap, int height)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000276{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200277 XFillRectangle(dpy, pixmap, scr->icon_title_texture->normal_gc, 0, 0, wPreferences.icon_size, height + 1);
278 XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, wPreferences.icon_size, 0);
279 XDrawLine(dpy, pixmap, scr->icon_title_texture->light_gc, 0, 0, 0, height + 1);
280 XDrawLine(dpy, pixmap, scr->icon_title_texture->dim_gc,
281 wPreferences.icon_size - 1, 0, wPreferences.icon_size - 1, height + 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000282}
283
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200284static Pixmap makeIcon(WScreen * scr, RImage * icon, int titled, int shadowed, int tileType)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000285{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200286 RImage *tile;
287 Pixmap pixmap;
288 int x, y, sx, sy;
289 unsigned w, h;
290 int theight = WMFontHeight(scr->icon_title_font);
291
292 if (tileType == TILE_NORMAL)
293 tile = RCloneImage(scr->icon_tile);
294 else {
295 assert(scr->clip_tile);
296 tile = RCloneImage(scr->clip_tile);
297 }
298 if (icon) {
299 w = (icon->width > wPreferences.icon_size)
300 ? wPreferences.icon_size : icon->width;
301 x = (wPreferences.icon_size - w) / 2;
302 sx = (icon->width - w) / 2;
303
304 if (!titled) {
305 h = (icon->height > wPreferences.icon_size)
306 ? wPreferences.icon_size : icon->height;
307 y = (wPreferences.icon_size - h) / 2;
308 sy = (icon->height - h) / 2;
309 } else {
310 h = (icon->height + theight > wPreferences.icon_size
311 ? wPreferences.icon_size - theight : icon->height);
312 y = theight + ((int)wPreferences.icon_size - theight - h) / 2;
313 sy = (icon->height - h) / 2;
314 }
315 RCombineArea(tile, icon, sx, sy, w, h, x, y);
316 }
317
318 if (shadowed) {
319 RColor color;
320
321 color.red = scr->icon_back_texture->light.red >> 8;
322 color.green = scr->icon_back_texture->light.green >> 8;
323 color.blue = scr->icon_back_texture->light.blue >> 8;
324 color.alpha = 150; /* about 60% */
325 RClearImage(tile, &color);
326 }
327
328 if (!RConvertImage(scr->rcontext, tile, &pixmap)) {
329 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
330 }
331 RReleaseImage(tile);
332
333 if (titled)
334 drawIconTitle(scr, pixmap, theight);
335
336 return pixmap;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000337}
338
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200339void wIconChangeTitle(WIcon * icon, char *new_title)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000340{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200341 int changed;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000342
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200343 changed = (new_title == NULL && icon->icon_name != NULL)
344 || (new_title != NULL && icon->icon_name == NULL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200346 if (icon->icon_name != NULL)
347 XFree(icon->icon_name);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000348
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200349 icon->icon_name = new_title;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000350
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200351 if (changed)
352 icon->force_paint = 1;
353 wIconPaint(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000354}
355
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200356void wIconChangeImage(WIcon * icon, RImage * new_image)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000357{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200358 assert(icon != NULL);
6830b057 dan2004-10-12 21:28:27 +0000359
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200360 if (icon->image)
361 RReleaseImage(icon->image);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000362
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200363 icon->image = new_image;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000364
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200365 wIconUpdate(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000366}
367
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200368RImage *wIconValidateIconSize(WScreen * scr, RImage * icon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000369{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200370 RImage *tmp;
371 int w, h;
6830b057 dan2004-10-12 21:28:27 +0000372
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200373 if (!icon)
374 return NULL;
34cd5125 kojima2000-01-20 11:51:42 +0000375#ifndef DONT_SCALE_ICONS
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200376 if (wPreferences.icon_size != 64) {
377 w = wPreferences.icon_size * icon->width / 64;
378 h = wPreferences.icon_size * icon->height / 64;
379
380 tmp = RScaleImage(icon, w, h);
381 RReleaseImage(icon);
382 icon = tmp;
383 }
34cd5125 kojima2000-01-20 11:51:42 +0000384#endif
7698ba2f kojima1999-11-16 00:16:07 +0000385#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200386 if (icon->width > wPreferences.icon_size || icon->height > wPreferences.icon_size) {
387 if (icon->width > icon->height) {
388 w = wPreferences.icon_size - 4;
389 h = w * icon->height / icon->width;
390 } else {
391 h = wPreferences.icon_size - 4;
392 w = h * icon->width / icon->height;
393 }
394 tmp = RScaleImage(icon, w, h);
395 RReleaseImage(icon);
396 icon = tmp;
397 }
7698ba2f kojima1999-11-16 00:16:07 +0000398#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +0000399
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200400 return icon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000401}
402
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200403Bool wIconChangeImageFile(WIcon * icon, char *file)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000404{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200405 WScreen *scr = icon->core->screen_ptr;
406 RImage *image;
407 char *path;
408 int error = 0;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000409
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200410 if (!file) {
411 wIconChangeImage(icon, NULL);
412 return True;
413 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000414
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200415 path = FindImage(wPreferences.icon_path, file);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000416
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200417 if (path && (image = RLoadImage(scr->rcontext, path, 0))) {
418 image = wIconValidateIconSize(icon->core->screen_ptr, image);
c08b3c5f kojima2002-02-15 21:22:46 +0000419
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200420 wIconChangeImage(icon, image);
421 } else {
422 error = 1;
423 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000424
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200425 if (path)
426 wfree(path);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000427
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 return !error;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000429}
430
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200431static char *getnameforicon(WWindow * wwin)
9af1c6c4 dan1998-10-21 14:43:47 +0000432{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200433 char *prefix, *suffix;
434 char *path;
435 int len;
436
437 if (wwin->wm_class && wwin->wm_instance) {
438 int len = strlen(wwin->wm_class) + strlen(wwin->wm_instance) + 2;
439 suffix = wmalloc(len);
440 snprintf(suffix, len, "%s.%s", wwin->wm_instance, wwin->wm_class);
441 } else if (wwin->wm_class) {
442 int len = strlen(wwin->wm_class) + 1;
443 suffix = wmalloc(len);
444 snprintf(suffix, len, "%s", wwin->wm_class);
445 } else if (wwin->wm_instance) {
446 int len = strlen(wwin->wm_instance) + 1;
447 suffix = wmalloc(len);
448 snprintf(suffix, len, "%s", wwin->wm_instance);
449 } else {
450 return NULL;
451 }
452
453 prefix = wusergnusteppath();
454 len = strlen(prefix) + 64 + strlen(suffix);
455 path = wmalloc(len + 1);
456 snprintf(path, len, "%s/Library/WindowMaker", prefix);
457
458 if (access(path, F_OK) != 0) {
459 if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR)) {
460 wsyserror(_("could not create directory %s"), path);
461 wfree(path);
462 wfree(suffix);
463 return NULL;
464 }
465 }
466 strcat(path, "/CachedPixmaps");
467 if (access(path, F_OK) != 0) {
468 if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
469 wsyserror(_("could not create directory %s"), path);
470 wfree(path);
471 wfree(suffix);
472 return NULL;
473 }
474 }
475
476 strcat(path, "/");
477 strcat(path, suffix);
478 strcat(path, ".xpm");
479 wfree(suffix);
480
481 return path;
9af1c6c4 dan1998-10-21 14:43:47 +0000482}
483
9af1c6c4 dan1998-10-21 14:43:47 +0000484/*
485 * wIconStore--
25c37b76 kojima2005-03-11 01:58:55 +0000486 * Stores the client supplied icon at ~/GNUstep/Library/WindowMaker/CachedPixmaps
9af1c6c4 dan1998-10-21 14:43:47 +0000487 * and returns the path for that icon. Returns NULL if there is no
488 * client supplied icon or on failure.
6830b057 dan2004-10-12 21:28:27 +0000489 *
9af1c6c4 dan1998-10-21 14:43:47 +0000490 * Side effects:
491 * New directories might be created.
492 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200493char *wIconStore(WIcon * icon)
9af1c6c4 dan1998-10-21 14:43:47 +0000494{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200495 char *path;
496 RImage *image;
497 WWindow *wwin = icon->owner;
498
499 if (!wwin || !wwin->wm_hints || !(wwin->wm_hints->flags & IconPixmapHint)
500 || wwin->wm_hints->icon_pixmap == None)
501 return NULL;
502
503 path = getnameforicon(wwin);
504 if (!path)
505 return NULL;
506
507 image = RCreateImageFromDrawable(icon->core->screen_ptr->rcontext,
508 wwin->wm_hints->icon_pixmap, (wwin->wm_hints->flags & IconMaskHint)
509 ? wwin->wm_hints->icon_mask : None);
510 if (!image) {
511 wfree(path);
512 return NULL;
513 }
514
515 if (!RSaveImage(image, path, "XPM")) {
516 wfree(path);
517 path = NULL;
518 }
519 RReleaseImage(image);
520
521 return path;
9af1c6c4 dan1998-10-21 14:43:47 +0000522}
523
9d2e6ef9 scottc1998-09-29 22:36:29 +0000524/*
6830b057 dan2004-10-12 21:28:27 +0000525void wIconChangeIconWindow(WIcon *icon, Window new_window);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000526*/
527
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200528static void cycleColor(void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000529{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200530 WIcon *icon = (WIcon *) data;
531 WScreen *scr = icon->core->screen_ptr;
532 XGCValues gcv;
9af1c6c4 dan1998-10-21 14:43:47 +0000533
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200534 icon->step--;
535 gcv.dash_offset = icon->step;
536 XChangeGC(dpy, scr->icon_select_gc, GCDashOffset, &gcv);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000537
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200538 XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0,
539 icon->core->width - 1, icon->core->height - 1);
540 icon->handlerID = WMAddTimerHandler(COLOR_CYCLE_DELAY, cycleColor, icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000541}
542
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200543void wIconSetHighlited(WIcon * icon, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000544{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200545 if (icon->highlighted == flag) {
546 return;
547 }
6830b057 dan2004-10-12 21:28:27 +0000548
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200549 icon->highlighted = flag;
550 wIconPaint(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000551}
552
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200553void wIconSelect(WIcon * icon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000554{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200555 WScreen *scr = icon->core->screen_ptr;
556 icon->selected = !icon->selected;
557
558 if (icon->selected) {
559 icon->step = 0;
560 if (!wPreferences.dont_blink)
561 icon->handlerID = WMAddTimerHandler(10, cycleColor, icon);
562 else
563 XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0,
564 icon->core->width - 1, icon->core->height - 1);
565 } else {
566 if (icon->handlerID) {
567 WMDeleteTimerHandler(icon->handlerID);
568 icon->handlerID = NULL;
569 }
570 XClearArea(dpy, icon->core->window, 0, 0, icon->core->width, icon->core->height, True);
571 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000572}
573
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200574void wIconUpdate(WIcon * icon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000575{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200576 WScreen *scr = icon->core->screen_ptr;
577 int title_height = WMFontHeight(scr->icon_title_font);
578 WWindow *wwin = icon->owner;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000579
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200580 assert(scr->icon_tile != NULL);
6830b057 dan2004-10-12 21:28:27 +0000581
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200582 if (icon->pixmap != None)
583 XFreePixmap(dpy, icon->pixmap);
584 icon->pixmap = None;
6830b057 dan2004-10-12 21:28:27 +0000585
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200586 if (wwin && (WFLAGP(wwin, always_user_icon)
9aca0d5f dan2004-10-12 01:34:32 +0000587#ifdef NETWM_HINTS
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200588 || wwin->net_icon_image
9aca0d5f dan2004-10-12 01:34:32 +0000589#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200590 ))
591 goto user_icon;
592
593 /* use client specified icon window */
594 if (icon->icon_win != None) {
595 XWindowAttributes attr;
596 int resize = 0;
597 unsigned int width, height, depth;
598 int theight;
599 Pixmap pixmap;
600
601 getSize(icon->icon_win, &width, &height, &depth);
602
603 if (width > wPreferences.icon_size) {
604 resize = 1;
605 width = wPreferences.icon_size;
606 }
607 if (height > wPreferences.icon_size) {
608 resize = 1;
609 height = wPreferences.icon_size;
610 }
611 if (icon->show_title && (height + title_height < wPreferences.icon_size)) {
612 pixmap = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
613 wPreferences.icon_size, scr->w_depth);
614 XSetClipMask(dpy, scr->copy_gc, None);
615 XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0,
616 wPreferences.icon_size, wPreferences.icon_size, 0, 0);
617 drawIconTitle(scr, pixmap, title_height);
618 theight = title_height;
619 } else {
620 pixmap = None;
621 theight = 0;
622 XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->icon_tile_pixmap);
623 }
624
625 XSetWindowBorderWidth(dpy, icon->icon_win, 0);
626 XReparentWindow(dpy, icon->icon_win, icon->core->window,
627 (wPreferences.icon_size - width) / 2,
628 theight + (wPreferences.icon_size - height - theight) / 2);
629 if (resize)
630 XResizeWindow(dpy, icon->icon_win, width, height);
631
632 XMapWindow(dpy, icon->icon_win);
633
634 XAddToSaveSet(dpy, icon->icon_win);
635
636 icon->pixmap = pixmap;
637
638 if (XGetWindowAttributes(dpy, icon->icon_win, &attr)) {
639 if (attr.all_event_masks & ButtonPressMask) {
640 wHackedGrabButton(Button1, MOD_MASK, icon->core->window, True,
641 ButtonPressMask, GrabModeSync, GrabModeAsync,
642 None, wCursor[WCUR_ARROW]);
643 }
644 }
645 } else if (wwin && wwin->wm_hints && (wwin->wm_hints->flags & IconPixmapHint)) {
646 int x, y;
647 unsigned int w, h;
648 Window jw;
649 int ji, dotitle;
650 unsigned int ju, d;
651 Pixmap pixmap;
652
653 if (!XGetGeometry(dpy, wwin->wm_hints->icon_pixmap, &jw, &ji, &ji, &w, &h, &ju, &d)) {
654 icon->owner->wm_hints->flags &= ~IconPixmapHint;
655 goto user_icon;
656 }
657
658 pixmap = XCreatePixmap(dpy, icon->core->window, wPreferences.icon_size,
659 wPreferences.icon_size, scr->w_depth);
660 XSetClipMask(dpy, scr->copy_gc, None);
661 XCopyArea(dpy, scr->icon_tile_pixmap, pixmap, scr->copy_gc, 0, 0,
662 wPreferences.icon_size, wPreferences.icon_size, 0, 0);
663
664 if (w > wPreferences.icon_size)
665 w = wPreferences.icon_size;
666 x = (wPreferences.icon_size - w) / 2;
667
668 if (icon->show_title && (title_height < wPreferences.icon_size)) {
669 drawIconTitle(scr, pixmap, title_height);
670 dotitle = 1;
671
672 if (h > wPreferences.icon_size - title_height - 2) {
673 h = wPreferences.icon_size - title_height - 2;
674 y = title_height + 1;
675 } else {
676 y = (wPreferences.icon_size - h - title_height) / 2 + title_height + 1;
677 }
678 } else {
679 dotitle = 0;
680 if (w > wPreferences.icon_size)
681 w = wPreferences.icon_size;
682 y = (wPreferences.icon_size - h) / 2;
683 }
684
685 if (wwin->wm_hints->flags & IconMaskHint)
686 XSetClipMask(dpy, scr->copy_gc, wwin->wm_hints->icon_mask);
687
688 XSetClipOrigin(dpy, scr->copy_gc, x, y);
689
690 if (d != scr->w_depth) {
691 XSetForeground(dpy, scr->copy_gc, scr->black_pixel);
692 XSetBackground(dpy, scr->copy_gc, scr->white_pixel);
693 XCopyPlane(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, 0, 0, w, h, x, y, 1);
694 } else {
695 XCopyArea(dpy, wwin->wm_hints->icon_pixmap, pixmap, scr->copy_gc, 0, 0, w, h, x, y);
696 }
697
698 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
699
700 icon->pixmap = pixmap;
701 } else {
702 user_icon:
703
704 if (icon->image) {
705 icon->pixmap = makeIcon(scr, icon->image, icon->show_title,
706 icon->shadowed, icon->tile_type);
707 } else {
708 /* make default icons */
709
710 if (!scr->def_icon_pixmap) {
711 RImage *image = NULL;
712 char *path;
713 char *file;
714
715 file = wDefaultGetIconFile(scr, NULL, NULL, False);
716 if (file) {
717 path = FindImage(wPreferences.icon_path, file);
718 if (!path) {
719 wwarning(_("could not find default icon \"%s\""), file);
720 goto make_icons;
721 }
722
723 image = RLoadImage(scr->rcontext, path, 0);
724 if (!image) {
725 wwarning(_("could not load default icon \"%s\":%s"),
726 file, RMessageForError(RErrorCode));
727 }
728 wfree(path);
729 }
730 make_icons:
731
732 image = wIconValidateIconSize(scr, image);
733 scr->def_icon_pixmap = makeIcon(scr, image, False, False, icon->tile_type);
734 scr->def_ticon_pixmap = makeIcon(scr, image, True, False, icon->tile_type);
735 if (image)
736 RReleaseImage(image);
737 }
738
739 if (icon->show_title) {
740 XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->def_ticon_pixmap);
741 } else {
742 XSetWindowBackgroundPixmap(dpy, icon->core->window, scr->def_icon_pixmap);
743 }
744 icon->pixmap = None;
745 }
746 }
747 if (icon->pixmap != None) {
748 XSetWindowBackgroundPixmap(dpy, icon->core->window, icon->pixmap);
749 }
750 XClearWindow(dpy, icon->core->window);
751
752 wIconPaint(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000753}
754
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200755void wIconPaint(WIcon * icon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000756{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200757 WScreen *scr = icon->core->screen_ptr;
758 int x;
759 char *tmp;
760
761 if (icon->force_paint) {
762 icon->force_paint = 0;
763 wIconUpdate(icon);
764 return;
765 }
766
767 XClearWindow(dpy, icon->core->window);
768
769 /* draw the icon title */
770 if (icon->show_title && icon->icon_name != NULL) {
771 int l;
772 int w;
773
774 tmp = ShrinkString(scr->icon_title_font, icon->icon_name, wPreferences.icon_size - 4);
775 w = WMWidthOfString(scr->icon_title_font, tmp, l = strlen(tmp));
776
777 if (w > icon->core->width - 4)
778 x = (icon->core->width - 4) - w;
779 else
780 x = (icon->core->width - w) / 2;
781
782 WMDrawString(scr->wmscreen, icon->core->window, scr->icon_title_color,
783 scr->icon_title_font, x, 1, tmp, l);
784 wfree(tmp);
785 }
786
787 if (icon->selected)
788 XDrawRectangle(dpy, icon->core->window, scr->icon_select_gc, 0, 0,
789 icon->core->width - 1, icon->core->height - 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000790}
791
9d2e6ef9 scottc1998-09-29 22:36:29 +0000792/******************************************************************/
793
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200794static void miniwindowExpose(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000795{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200796 wIconPaint(desc->parent);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000797}
798
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200799static void miniwindowDblClick(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000800{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200801 WIcon *icon = desc->parent;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000802
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200803 assert(icon->owner != NULL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000804
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200805 wDeiconifyWindow(icon->owner);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000806}
807
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200808static void miniwindowMouseDown(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000809{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200810 WIcon *icon = desc->parent;
811 WWindow *wwin = icon->owner;
812 XEvent ev;
813 int x = wwin->icon_x, y = wwin->icon_y;
814 int dx = event->xbutton.x, dy = event->xbutton.y;
815 int grabbed = 0;
816 int clickButton = event->xbutton.button;
817
818 if (WCHECK_STATE(WSTATE_MODAL))
819 return;
820
821 if (IsDoubleClick(icon->core->screen_ptr, event)) {
822 miniwindowDblClick(desc, event);
823 return;
824 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000825#ifdef DEBUG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200826 puts("Moving miniwindow");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000827#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200828 if (event->xbutton.button == Button1) {
829 if (event->xbutton.state & MOD_MASK)
830 wLowerFrame(icon->core);
831 else
832 wRaiseFrame(icon->core);
833 if (event->xbutton.state & ShiftMask) {
834 wIconSelect(icon);
835 wSelectWindow(icon->owner, !wwin->flags.selected);
836 }
837 } else if (event->xbutton.button == Button3) {
838 WObjDescriptor *desc;
839
840 OpenMiniwindowMenu(wwin, event->xbutton.x_root, event->xbutton.y_root);
841
842 /* allow drag select of menu */
843 desc = &wwin->screen_ptr->window_menu->menu->descriptor;
844 event->xbutton.send_event = True;
845 (*desc->handle_mousedown) (desc, event);
846
847 return;
848 }
849
850 if (XGrabPointer(dpy, icon->core->window, False, ButtonMotionMask
851 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
852 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
9d2e6ef9 scottc1998-09-29 22:36:29 +0000853#ifdef DEBUG0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200854 wwarning("pointer grab failed for icon move");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000855#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200856 }
857 while (1) {
858 WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
859 | ButtonMotionMask | ExposureMask, &ev);
860 switch (ev.type) {
861 case Expose:
862 WMHandleEvent(&ev);
863 break;
864
865 case MotionNotify:
866 if (!grabbed) {
867 if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
868 || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
869 XChangeActivePointerGrab(dpy, ButtonMotionMask
870 | ButtonReleaseMask | ButtonPressMask,
871 wCursor[WCUR_MOVE], CurrentTime);
872 grabbed = 1;
873 } else {
874 break;
875 }
876 }
877 x = ev.xmotion.x_root - dx;
878 y = ev.xmotion.y_root - dy;
879 XMoveWindow(dpy, icon->core->window, x, y);
880 break;
881
882 case ButtonPress:
883 break;
884
885 case ButtonRelease:
886 if (ev.xbutton.button != clickButton)
887 break;
888
889 if (wwin->icon_x != x || wwin->icon_y != y)
890 wwin->flags.icon_moved = 1;
891
892 XMoveWindow(dpy, icon->core->window, x, y);
893
894 wwin->icon_x = x;
895 wwin->icon_y = y;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000896#ifdef DEBUG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200897 puts("End miniwindow move");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000898#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200899 XUngrabPointer(dpy, CurrentTime);
e7495baf dan1999-02-17 11:06:40 +0000900
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200901 if (wPreferences.auto_arrange_icons)
902 wArrangeIcons(wwin->screen_ptr, True);
903 return;
6830b057 dan2004-10-12 21:28:27 +0000904
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200905 }
906 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000907}