Change to the linux kernel coding style
[wmaker-crm.git] / src / appicon.c
1 /* appicon.c- icon for applications (not mini-window)
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
7 *
8 * 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
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 * 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"
47 #ifdef XDND
48 #include "xdnd.h"
49 #endif
50 #include "wsound.h"
51
52 /*
53 * icon_file for the dock is got from the preferences file by
54 * using the classname/instancename
55 */
56
57 /**** Global variables ****/
58 extern Cursor wCursor[WCUR_LAST];
59 extern WPreferences wPreferences;
60
61 #define MOD_MASK wPreferences.modifier_mask
62
63 void appIconMouseDown(WObjDescriptor * desc, XEvent * event);
64 static void iconDblClick(WObjDescriptor * desc, XEvent * event);
65 static void iconExpose(WObjDescriptor * desc, XEvent * event);
66
67 WAppIcon *wAppIconCreateForDock(WScreen * scr, char *command, char *wm_instance, char *wm_class, int tile)
68 {
69 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);
106 #ifdef XDND
107 wXDNDMakeAwareness(dicon->icon->core->window);
108 #endif
109
110 #ifdef DEMATERIALIZE_ICON
111 {
112 XSetWindowAttributes attribs;
113 attribs.save_under = True;
114 XChangeWindowAttributes(dpy, dicon->icon->core->window, CWSaveUnder, &attribs);
115 }
116 #endif
117
118 /* 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);
124
125 return dicon;
126 }
127
128 WAppIcon *wAppIconCreate(WWindow * leader_win)
129 {
130 WAppIcon *aicon;
131 WScreen *scr = leader_win->screen_ptr;
132
133 aicon = wmalloc(sizeof(WAppIcon));
134 wretain(aicon);
135 memset(aicon, 0, sizeof(WAppIcon));
136
137 aicon->yindex = -1;
138 aicon->xindex = -1;
139
140 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;
146
147 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);
151
152 aicon->icon = wIconCreate(leader_win);
153 #ifdef DEMATERIALIZE_ICON
154 {
155 XSetWindowAttributes attribs;
156 attribs.save_under = True;
157 XChangeWindowAttributes(dpy, aicon->icon->core->window, CWSaveUnder, &attribs);
158 }
159 #endif
160 #ifdef XDND
161 wXDNDMakeAwareness(aicon->icon->core->window);
162 #endif
163
164 /* 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);
172
173 return aicon;
174 }
175
176 void wAppIconDestroy(WAppIcon * aicon)
177 {
178 WScreen *scr = aicon->icon->core->screen_ptr;
179
180 RemoveFromStackList(aicon->icon->core);
181 wIconDestroy(aicon->icon);
182 if (aicon->command)
183 wfree(aicon->command);
184 #ifdef XDND
185 if (aicon->dnd_command)
186 wfree(aicon->dnd_command);
187 #endif
188 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);
206 }
207
208 #ifdef NEWAPPICON
209 static void drawCorner(WIcon * icon, WWindow * wwin, int active)
210 {
211 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);
227 }
228 #endif /* NEWAPPICON */
229
230 static void drawCorner(WIcon * icon)
231 {
232 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 */
246 #if 0
247 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);
249 #endif
250 }
251
252 void wAppIconMove(WAppIcon * aicon, int x, int y)
253 {
254 XMoveWindow(dpy, aicon->icon->core->window, x, y);
255 aicon->x_pos = x;
256 aicon->y_pos = y;
257 }
258
259 #ifdef WS_INDICATOR
260 static void updateDockNumbers(WScreen * scr)
261 {
262 int length;
263 char *ws_numbers;
264 WAppIcon *dicon = scr->dock->icon_array[0];
265
266 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);
269
270 XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
271
272 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
273 scr->icon_title_font, 4, 3, ws_numbers, length);
274
275 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
276 scr->icon_title_font, 3, 2, ws_numbers, length);
277
278 wfree(ws_numbers);
279 }
280 #endif /* WS_INDICATOR */
281
282 void wAppIconPaint(WAppIcon * aicon)
283 {
284 WApplication *wapp;
285 WScreen *scr = aicon->icon->core->screen_ptr;
286
287 if (aicon->icon->owner)
288 wapp = wApplicationOf(aicon->icon->owner->main_window);
289 else
290 wapp = NULL;
291
292 wIconPaint(aicon->icon);
293
294 # ifdef WS_INDICATOR
295 if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
296 updateDockNumbers(scr);
297 # endif
298 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 }
304 #ifdef HIDDENDOT
305 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 }
321 }
322
323 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
324
325 static void hideCallback(WMenu * menu, WMenuEntry * entry)
326 {
327 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 }
335 }
336
337 static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
338 {
339 WApplication *wapp = (WApplication *) entry->clientdata;
340
341 wUnhideApplication(wapp, False, True);
342 }
343
344 static void setIconCallback(WMenu * menu, WMenuEntry * entry)
345 {
346 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);
379 }
380
381 static void killCallback(WMenu * menu, WMenuEntry * entry)
382 {
383 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);
424 }
425
426 static WMenu *createApplicationMenu(WScreen * scr)
427 {
428 WMenu *menu;
429
430 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);
435
436 return menu;
437 }
438
439 static void openApplicationMenu(WApplication * wapp, int x, int y)
440 {
441 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);
472 }
473
474 /******************************************************************/
475
476 static void iconExpose(WObjDescriptor * desc, XEvent * event)
477 {
478 wAppIconPaint(desc->parent);
479 }
480
481 static void iconDblClick(WObjDescriptor * desc, XEvent * event)
482 {
483 WAppIcon *aicon = desc->parent;
484 WApplication *wapp;
485 WScreen *scr = aicon->icon->core->screen_ptr;
486 int unhideHere;
487
488 assert(aicon->icon->owner != NULL);
489
490 wapp = wApplicationOf(aicon->icon->owner->main_window);
491 #ifdef DEBUG0
492 if (!wapp) {
493 wwarning("could not find application descriptor for app icon!!");
494 return;
495 }
496 #endif
497
498 unhideHere = (event->xbutton.state & ShiftMask);
499
500 /* 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);
503
504 wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
505
506 if (event->xbutton.state & MOD_MASK) {
507 wHideOtherApplications(aicon->icon->owner);
508 }
509 }
510
511 void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
512 {
513 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 }
563 #ifdef DEBUG
564 puts("Moving icon");
565 #endif
566 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 }
741 #ifdef DEBUG
742 puts("End icon move");
743 #endif
744
745 }