Change to the linux kernel coding style
[wmaker-crm.git] / src / appicon.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001/* appicon.c- icon for applications (not mini-window)
2 *
9af1c6c4 dan1998-10-21 14:43:47 +00003 * Window Maker window manager
70a363de dan1999-05-14 23:49:07 +00004 *
4153e2fd dan2003-01-16 23:30:45 +00005 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
70a363de dan1999-05-14 23:49:07 +00007 *
9d2e6ef9 scottc1998-09-29 22:36:29 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
70a363de dan1999-05-14 23:49:07 +000020 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
9d2e6ef9 scottc1998-09-29 22:36:29 +000021 * USA.
22 */
23
24#include "wconfig.h"
25
26#include <X11/Xlib.h>
27#include <X11/Xutil.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "WindowMaker.h"
32#include "wcore.h"
33#include "window.h"
34#include "icon.h"
35#include "appicon.h"
36#include "actions.h"
37#include "stacking.h"
38#include "dock.h"
39#include "funcs.h"
40#include "defaults.h"
41#include "workspace.h"
42#include "superfluous.h"
43#include "menu.h"
44#include "framewin.h"
45#include "dialog.h"
46#include "client.h"
d4025072 id1999-05-17 20:21:43 +000047#ifdef XDND
48#include "xdnd.h"
49#endif
1b587b01 dan2001-01-18 01:33:44 +000050#include "wsound.h"
6d90da02 dan1999-07-04 19:58:35 +000051
70a363de dan1999-05-14 23:49:07 +000052/*
9d2e6ef9 scottc1998-09-29 22:36:29 +000053 * icon_file for the dock is got from the preferences file by
54 * using the classname/instancename
55 */
56
57/**** Global variables ****/
58extern Cursor wCursor[WCUR_LAST];
59extern WPreferences wPreferences;
60
61#define MOD_MASK wPreferences.modifier_mask
62
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020063void appIconMouseDown(WObjDescriptor * desc, XEvent * event);
64static void iconDblClick(WObjDescriptor * desc, XEvent * event);
65static void iconExpose(WObjDescriptor * desc, XEvent * event);
9d2e6ef9 scottc1998-09-29 22:36:29 +000066
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020067WAppIcon *wAppIconCreateForDock(WScreen * scr, char *command, char *wm_instance, char *wm_class, int tile)
9d2e6ef9 scottc1998-09-29 22:36:29 +000068{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020069 WAppIcon *dicon;
70 char *path;
71
72 dicon = wmalloc(sizeof(WAppIcon));
73 wretain(dicon);
74 memset(dicon, 0, sizeof(WAppIcon));
75 dicon->yindex = -1;
76 dicon->xindex = -1;
77
78 dicon->prev = NULL;
79 dicon->next = scr->app_icon_list;
80 if (scr->app_icon_list) {
81 scr->app_icon_list->prev = dicon;
82 }
83 scr->app_icon_list = dicon;
84
85 if (command) {
86 dicon->command = wstrdup(command);
87 }
88 if (wm_class)
89 dicon->wm_class = wstrdup(wm_class);
90 if (wm_instance)
91 dicon->wm_instance = wstrdup(wm_instance);
92
93 path = wDefaultGetIconFile(scr, wm_instance, wm_class, True);
94 if (!path && command) {
95 wApplicationExtractDirPackIcon(scr, command, wm_instance, wm_class);
96
97 path = wDefaultGetIconFile(scr, wm_instance, wm_class, False);
98 }
99
100 if (path)
101 path = FindImage(wPreferences.icon_path, path);
102
103 dicon->icon = wIconCreateWithIconFile(scr, path, tile);
104 if (path)
105 wfree(path);
d4025072 id1999-05-17 20:21:43 +0000106#ifdef XDND
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200107 wXDNDMakeAwareness(dicon->icon->core->window);
d4025072 id1999-05-17 20:21:43 +0000108#endif
7a491db6 kojima2001-02-11 02:18:26 +0000109
6c223520 id1999-04-16 19:56:08 +0000110#ifdef DEMATERIALIZE_ICON
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 {
112 XSetWindowAttributes attribs;
113 attribs.save_under = True;
114 XChangeWindowAttributes(dpy, dicon->icon->core->window, CWSaveUnder, &attribs);
115 }
6c223520 id1999-04-16 19:56:08 +0000116#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +0000117
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200118 /* will be overriden by dock */
119 dicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
120 dicon->icon->core->descriptor.handle_expose = iconExpose;
121 dicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
122 dicon->icon->core->descriptor.parent = dicon;
123 AddToStackList(dicon->icon->core);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000124
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200125 return dicon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000126}
127
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200128WAppIcon *wAppIconCreate(WWindow * leader_win)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000129{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200130 WAppIcon *aicon;
131 WScreen *scr = leader_win->screen_ptr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000132
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200133 aicon = wmalloc(sizeof(WAppIcon));
134 wretain(aicon);
135 memset(aicon, 0, sizeof(WAppIcon));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000136
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200137 aicon->yindex = -1;
138 aicon->xindex = -1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000139
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200140 aicon->prev = NULL;
141 aicon->next = scr->app_icon_list;
142 if (scr->app_icon_list) {
143 scr->app_icon_list->prev = aicon;
144 }
145 scr->app_icon_list = aicon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000146
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200147 if (leader_win->wm_class)
148 aicon->wm_class = wstrdup(leader_win->wm_class);
149 if (leader_win->wm_instance)
150 aicon->wm_instance = wstrdup(leader_win->wm_instance);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000151
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200152 aicon->icon = wIconCreate(leader_win);
6c223520 id1999-04-16 19:56:08 +0000153#ifdef DEMATERIALIZE_ICON
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200154 {
155 XSetWindowAttributes attribs;
156 attribs.save_under = True;
157 XChangeWindowAttributes(dpy, aicon->icon->core->window, CWSaveUnder, &attribs);
158 }
6c223520 id1999-04-16 19:56:08 +0000159#endif
d4025072 id1999-05-17 20:21:43 +0000160#ifdef XDND
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200161 wXDNDMakeAwareness(aicon->icon->core->window);
d4025072 id1999-05-17 20:21:43 +0000162#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +0000163
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200164 /* will be overriden if docked */
165 aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
166 aicon->icon->core->descriptor.handle_expose = iconExpose;
167 aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
168 aicon->icon->core->descriptor.parent = aicon;
169 AddToStackList(aicon->icon->core);
170 aicon->icon->show_title = 0;
171 wIconUpdate(aicon->icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000172
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200173 return aicon;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000174}
175
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200176void wAppIconDestroy(WAppIcon * aicon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000177{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200178 WScreen *scr = aicon->icon->core->screen_ptr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000179
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200180 RemoveFromStackList(aicon->icon->core);
181 wIconDestroy(aicon->icon);
182 if (aicon->command)
183 wfree(aicon->command);
879b00a5 kojima2004-10-13 05:09:08 +0000184#ifdef XDND
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200185 if (aicon->dnd_command)
186 wfree(aicon->dnd_command);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000187#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200188 if (aicon->wm_instance)
189 wfree(aicon->wm_instance);
190 if (aicon->wm_class)
191 wfree(aicon->wm_class);
192
193 if (aicon == scr->app_icon_list) {
194 if (aicon->next)
195 aicon->next->prev = NULL;
196 scr->app_icon_list = aicon->next;
197 } else {
198 if (aicon->next)
199 aicon->next->prev = aicon->prev;
200 if (aicon->prev)
201 aicon->prev->next = aicon->next;
202 }
203
204 aicon->destroyed = 1;
205 wrelease(aicon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000206}
207
9d2e6ef9 scottc1998-09-29 22:36:29 +0000208#ifdef NEWAPPICON
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200209static void drawCorner(WIcon * icon, WWindow * wwin, int active)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000210{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200211 WScreen *scr = wwin->screen_ptr;
212 XPoint points[3];
213 GC gc;
214
215 points[0].x = 2;
216 points[0].y = 2;
217 points[1].x = 12;
218 points[1].y = 2;
219 points[2].x = 2;
220 points[2].y = 12;
221 if (active) {
222 gc = scr->focused_texture->any.gc;
223 } else {
224 gc = scr->unfocused_texture->any.gc;
225 }
226 XFillPolygon(dpy, icon->core->window, gc, points, 3, Convex, CoordModeOrigin);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000227}
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200228#endif /* NEWAPPICON */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000229
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200230static void drawCorner(WIcon * icon)
38bb25a7 dan1999-06-01 08:47:25 +0000231{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200232 WScreen *scr = icon->core->screen_ptr;
233 XPoint points[3];
234
235 points[0].x = 1;
236 points[0].y = 1;
237 points[1].x = 12;
238 points[1].y = 1;
239 points[2].x = 1;
240 points[2].y = 12;
241 XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
242 points, 3, Convex, CoordModeOrigin);
243 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 0, 12);
244 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 12, 0);
245 /* drawing the second line gives a weird concave look. -Dan */
38bb25a7 dan1999-06-01 08:47:25 +0000246#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200247 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 1, 1, 1, 11);
248 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 1, 1, 11, 1);
38bb25a7 dan1999-06-01 08:47:25 +0000249#endif
250}
251
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200252void wAppIconMove(WAppIcon * aicon, int x, int y)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000253{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200254 XMoveWindow(dpy, aicon->icon->core->window, x, y);
255 aicon->x_pos = x;
256 aicon->y_pos = y;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000257}
258
9d2e6ef9 scottc1998-09-29 22:36:29 +0000259#ifdef WS_INDICATOR
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200260static void updateDockNumbers(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000261{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200262 int length;
263 char *ws_numbers;
264 WAppIcon *dicon = scr->dock->icon_array[0];
3d5f435b kojima1999-05-30 05:02:55 +0000265
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200266 ws_numbers = wmalloc(20);
267 snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace + 1, ((scr->current_workspace / 10) + 1));
268 length = strlen(ws_numbers);
6830b057 dan2004-10-12 21:28:27 +0000269
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200270 XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
6830b057 dan2004-10-12 21:28:27 +0000271
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200272 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
273 scr->icon_title_font, 4, 3, ws_numbers, length);
3d5f435b kojima1999-05-30 05:02:55 +0000274
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200275 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
276 scr->icon_title_font, 3, 2, ws_numbers, length);
3d5f435b kojima1999-05-30 05:02:55 +0000277
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200278 wfree(ws_numbers);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000279}
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200280#endif /* WS_INDICATOR */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000281
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200282void wAppIconPaint(WAppIcon * aicon)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000283{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200284 WApplication *wapp;
285 WScreen *scr = aicon->icon->core->screen_ptr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000286
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200287 if (aicon->icon->owner)
288 wapp = wApplicationOf(aicon->icon->owner->main_window);
289 else
290 wapp = NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000291
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200292 wIconPaint(aicon->icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000293
294# ifdef WS_INDICATOR
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200295 if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
296 updateDockNumbers(scr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000297# endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200298 if (scr->dock_dots && aicon->docked && !aicon->running && aicon->command != NULL) {
299 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
300 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
301 XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
302 scr->copy_gc, 0, 0, scr->dock_dots->width, scr->dock_dots->height, 0, 0);
303 }
7f9f8894 kojima1999-03-15 23:41:22 +0000304#ifdef HIDDENDOT
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200305 if (wapp && wapp->flags.hidden) {
306 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
307 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
308 XCopyArea(dpy, scr->dock_dots->image,
309 aicon->icon->core->window, scr->copy_gc, 0, 0, 7, scr->dock_dots->height, 0, 0);
310 }
311#endif /* HIDDENDOT */
312
313 if (aicon->omnipresent)
314 drawCorner(aicon->icon);
315
316 XSetClipMask(dpy, scr->copy_gc, None);
317 if (aicon->launching) {
318 XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
319 0, 0, wPreferences.icon_size, wPreferences.icon_size);
320 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000321}
322
9d2e6ef9 scottc1998-09-29 22:36:29 +0000323#define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
324
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200325static void hideCallback(WMenu * menu, WMenuEntry * entry)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000326{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200327 WApplication *wapp = (WApplication *) entry->clientdata;
328
329 if (wapp->flags.hidden) {
330 wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
331 wUnhideApplication(wapp, False, False);
332 } else {
333 wHideApplication(wapp);
334 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000335}
336
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200337static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000338{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200339 WApplication *wapp = (WApplication *) entry->clientdata;
70a363de dan1999-05-14 23:49:07 +0000340
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200341 wUnhideApplication(wapp, False, True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000342}
343
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200344static void setIconCallback(WMenu * menu, WMenuEntry * entry)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200346 WAppIcon *icon = ((WApplication *) entry->clientdata)->app_icon;
347 char *file = NULL;
348 WScreen *scr;
349 int result;
350
351 assert(icon != NULL);
352
353 if (icon->editing)
354 return;
355 icon->editing = 1;
356 scr = icon->icon->core->screen_ptr;
357
358 wretain(icon);
359
360 result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
361
362 if (result && !icon->destroyed) {
363 if (file && *file == 0) {
364 wfree(file);
365 file = NULL;
366 }
367 if (!wIconChangeImageFile(icon->icon, file)) {
368 wMessageDialog(scr, _("Error"),
369 _("Could not open specified icon file"), _("OK"), NULL, NULL);
370 } else {
371 wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
372 wAppIconPaint(icon);
373 }
374 if (file)
375 wfree(file);
376 }
377 icon->editing = 0;
378 wrelease(icon);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000379}
380
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200381static void killCallback(WMenu * menu, WMenuEntry * entry)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000382{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200383 WApplication *wapp = (WApplication *) entry->clientdata;
384 WFakeGroupLeader *fPtr;
385 char *buffer;
386
387 if (!WCHECK_STATE(WSTATE_NORMAL))
388 return;
389
390 WCHANGE_STATE(WSTATE_MODAL);
391
392 assert(entry->clientdata != NULL);
393
394 buffer = wstrconcat(wapp->app_icon ? wapp->app_icon->wm_class : NULL,
395 _(" will be forcibly closed.\n"
396 "Any unsaved changes will be lost.\n" "Please confirm."));
397
398 fPtr = wapp->main_window_desc->fake_group;
399
400 wretain(wapp->main_window_desc);
401 if (wPreferences.dont_confirm_kill
402 || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
403 buffer, _("Yes"), _("No"), NULL) == WAPRDefault) {
404 if (fPtr != NULL) {
405 WWindow *wwin, *twin;
406
407 wwin = wapp->main_window_desc->screen_ptr->focused_window;
408 while (wwin) {
409 twin = wwin->prev;
410 if (wwin->fake_group == fPtr) {
411 wClientKill(wwin);
412 }
413 wwin = twin;
414 }
415 } else if (!wapp->main_window_desc->flags.destroyed) {
416 wClientKill(wapp->main_window_desc);
417 }
418 }
419 wrelease(wapp->main_window_desc);
420
421 wfree(buffer);
422
423 WCHANGE_STATE(WSTATE_NORMAL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000424}
425
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200426static WMenu *createApplicationMenu(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000427{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 WMenu *menu;
70a363de dan1999-05-14 23:49:07 +0000429
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200430 menu = wMenuCreate(scr, NULL, False);
431 wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
432 wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
433 wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
434 wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
0261c326 dan1999-01-06 15:22:33 +0000435
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200436 return menu;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000437}
438
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200439static void openApplicationMenu(WApplication * wapp, int x, int y)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000440{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200441 WMenu *menu;
442 WScreen *scr = wapp->main_window_desc->screen_ptr;
443 int i;
444
445 if (!scr->icon_menu) {
446 scr->icon_menu = createApplicationMenu(scr);
447 wfree(scr->icon_menu->entries[1]->text);
448 }
449
450 menu = scr->icon_menu;
451
452 if (wapp->flags.hidden) {
453 menu->entries[1]->text = _("Unhide");
454 } else {
455 menu->entries[1]->text = _("Hide");
456 }
457
458 menu->flags.realized = 0;
459 wMenuRealize(menu);
460
461 x -= menu->frame->core->width / 2;
462 if (x + menu->frame->core->width > scr->scr_width)
463 x = scr->scr_width - menu->frame->core->width;
464 if (x < 0)
465 x = 0;
466
467 /* set client data */
468 for (i = 0; i < menu->entry_no; i++) {
469 menu->entries[i]->clientdata = wapp;
470 }
471 wMenuMapAt(menu, x, y, False);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000472}
473
9d2e6ef9 scottc1998-09-29 22:36:29 +0000474/******************************************************************/
475
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200476static void iconExpose(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000477{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200478 wAppIconPaint(desc->parent);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000479}
480
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200481static void iconDblClick(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000482{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200483 WAppIcon *aicon = desc->parent;
484 WApplication *wapp;
485 WScreen *scr = aicon->icon->core->screen_ptr;
486 int unhideHere;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000487
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200488 assert(aicon->icon->owner != NULL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000489
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200490 wapp = wApplicationOf(aicon->icon->owner->main_window);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000491#ifdef DEBUG0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200492 if (!wapp) {
493 wwarning("could not find application descriptor for app icon!!");
494 return;
495 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000496#endif
9eb4f894 kojima1999-04-17 23:11:34 +0000497
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200498 unhideHere = (event->xbutton.state & ShiftMask);
9eb4f894 kojima1999-04-17 23:11:34 +0000499
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200500 /* go to the last workspace that the user worked on the app */
501 if (!unhideHere && wapp->last_workspace != scr->current_workspace)
502 wWorkspaceChange(scr, wapp->last_workspace);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000503
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200504 wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
9eb4f894 kojima1999-04-17 23:11:34 +0000505
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200506 if (event->xbutton.state & MOD_MASK) {
507 wHideOtherApplications(aicon->icon->owner);
508 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000509}
510
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200511void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000512{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200513 WAppIcon *aicon = desc->parent;
514 WIcon *icon = aicon->icon;
515 XEvent ev;
516 int x = aicon->x_pos, y = aicon->y_pos;
517 int dx = event->xbutton.x, dy = event->xbutton.y;
518 int grabbed = 0;
519 int done = 0;
520 int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
521 WScreen *scr = icon->core->screen_ptr;
522 WWorkspace *workspace = scr->workspaces[scr->current_workspace];
523 int shad_x = 0, shad_y = 0, docking = 0, dockable, collapsed = 0;
524 int ix, iy;
525 int clickButton = event->xbutton.button;
526 Pixmap ghost = None;
527 Window wins[2];
528 Bool movingSingle = False;
529 int oldX = x;
530 int oldY = y;
531
532 if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
533 return;
534
535 if (IsDoubleClick(scr, event)) {
536 iconDblClick(desc, event);
537 return;
538 }
539
540 if (event->xbutton.button == Button3) {
541 WObjDescriptor *desc;
542 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
543
544 if (!wapp)
545 return;
546
547 if (event->xbutton.send_event &&
548 XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
549 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
550 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
551 wwarning("pointer grab failed for appicon menu");
552 return;
553 }
554
555 openApplicationMenu(wapp, event->xbutton.x_root, event->xbutton.y_root);
556
557 /* allow drag select of menu */
558 desc = &scr->icon_menu->menu->descriptor;
559 event->xbutton.send_event = True;
560 (*desc->handle_mousedown) (desc, event);
561 return;
562 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000563#ifdef DEBUG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200564 puts("Moving icon");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000565#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200566 if (event->xbutton.state & MOD_MASK)
567 wLowerFrame(icon->core);
568 else
569 wRaiseFrame(icon->core);
570
571 if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
572 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
573 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
574 wwarning("pointer grab failed for appicon move");
575 }
576
577 if (wPreferences.flags.nodock && wPreferences.flags.noclip)
578 dockable = 0;
579 else
580 dockable = canBeDocked(icon->owner);
581
582 wins[0] = icon->core->window;
583 wins[1] = scr->dock_shadow;
584 XRestackWindows(dpy, wins, 2);
585 if (superfluous) {
586 if (icon->pixmap != None)
587 ghost = MakeGhostIcon(scr, icon->pixmap);
588 else
589 ghost = MakeGhostIcon(scr, icon->core->window);
590 XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
591 XClearWindow(dpy, scr->dock_shadow);
592 }
593
594 while (!done) {
595 WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
596 | ButtonMotionMask | ExposureMask, &ev);
597 switch (ev.type) {
598 case Expose:
599 WMHandleEvent(&ev);
600 break;
601
602 case MotionNotify:
603 if (!grabbed) {
604 if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
605 || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
606 XChangeActivePointerGrab(dpy, ButtonMotionMask
607 | ButtonReleaseMask | ButtonPressMask,
608 wCursor[WCUR_MOVE], CurrentTime);
609 grabbed = 1;
610 } else {
611 break;
612 }
613 }
614 x = ev.xmotion.x_root - dx;
615 y = ev.xmotion.y_root - dy;
616
617 if (movingSingle) {
618 XMoveWindow(dpy, icon->core->window, x, y);
619 } else {
620 wAppIconMove(aicon, x, y);
621 }
622
623 if (dockable) {
624 if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y, &ix, &iy, False)) {
625 shad_x = scr->dock->x_pos + ix * wPreferences.icon_size;
626 shad_y = scr->dock->y_pos + iy * wPreferences.icon_size;
627
628 if (scr->last_dock != scr->dock && collapsed) {
629 scr->last_dock->collapsed = 1;
630 wDockHideIcons(scr->last_dock);
631 collapsed = 0;
632 }
633 if (!collapsed && (collapsed = scr->dock->collapsed)) {
634 scr->dock->collapsed = 0;
635 wDockShowIcons(scr->dock);
636 }
637
638 if (scr->dock->auto_raise_lower)
639 wDockRaise(scr->dock);
640
641 scr->last_dock = scr->dock;
642
643 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
644 if (!docking) {
645 XMapWindow(dpy, scr->dock_shadow);
646 }
647 docking = 1;
648 } else if (workspace->clip &&
649 wDockSnapIcon(workspace->clip, aicon, x, y, &ix, &iy, False)) {
650 shad_x = workspace->clip->x_pos + ix * wPreferences.icon_size;
651 shad_y = workspace->clip->y_pos + iy * wPreferences.icon_size;
652
653 if (scr->last_dock != workspace->clip && collapsed) {
654 scr->last_dock->collapsed = 1;
655 wDockHideIcons(scr->last_dock);
656 collapsed = 0;
657 }
658 if (!collapsed && (collapsed = workspace->clip->collapsed)) {
659 workspace->clip->collapsed = 0;
660 wDockShowIcons(workspace->clip);
661 }
662
663 if (workspace->clip->auto_raise_lower)
664 wDockRaise(workspace->clip);
665
666 scr->last_dock = workspace->clip;
667
668 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
669 if (!docking) {
670 XMapWindow(dpy, scr->dock_shadow);
671 }
672 docking = 1;
673 } else if (docking) {
674 XUnmapWindow(dpy, scr->dock_shadow);
675 docking = 0;
676 }
677 }
678
679 break;
680
681 case ButtonPress:
682 break;
683
684 case ButtonRelease:
685 if (ev.xbutton.button != clickButton)
686 break;
687 XUngrabPointer(dpy, CurrentTime);
688
689 if (docking) {
690 Bool docked;
691
692 /* icon is trying to be docked */
693 SlideWindow(icon->core->window, x, y, shad_x, shad_y);
694 XUnmapWindow(dpy, scr->dock_shadow);
695 docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
696 if (scr->last_dock->auto_collapse) {
697 collapsed = 0;
698 }
699 if (workspace->clip &&
700 workspace->clip != scr->last_dock && workspace->clip->auto_raise_lower)
701 wDockLower(workspace->clip);
702
703 if (!docked) {
704 /* If icon could not be docked, slide it back to the old
705 * position */
706 SlideWindow(icon->core->window, x, y, oldX, oldY);
707 }
708
709 wSoundPlay(WSOUND_DOCK);
710 } else {
711 if (movingSingle) {
712 /* move back to its place */
713 SlideWindow(icon->core->window, x, y, oldX, oldY);
714 wAppIconMove(aicon, oldX, oldY);
715 } else {
716 XMoveWindow(dpy, icon->core->window, x, y);
717 aicon->x_pos = x;
718 aicon->y_pos = y;
719 }
720 if (workspace->clip && workspace->clip->auto_raise_lower)
721 wDockLower(workspace->clip);
722 }
723 if (collapsed) {
724 scr->last_dock->collapsed = 1;
725 wDockHideIcons(scr->last_dock);
726 collapsed = 0;
727 }
728 if (superfluous) {
729 if (ghost != None)
730 XFreePixmap(dpy, ghost);
731 XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
732 }
733
734 if (wPreferences.auto_arrange_icons)
735 wArrangeIcons(scr, True);
736
737 done = 1;
738 break;
739 }
740 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000741#ifdef DEBUG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200742 puts("End icon move");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000743#endif
70a363de dan1999-05-14 23:49:07 +0000744
9d2e6ef9 scottc1998-09-29 22:36:29 +0000745}