Fixed possible null pointer dereference
[wmaker-crm.git] / src / appicon.c
blob9bac0ef652976caa027fc5fcf2a65966b5ecbb8b
1 /* appicon.c- icon for applications (not mini-window)
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
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.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <errno.h>
33 #include "WindowMaker.h"
34 #include "window.h"
35 #include "icon.h"
36 #include "application.h"
37 #include "appicon.h"
38 #include "actions.h"
39 #include "stacking.h"
40 #include "dock.h"
41 #include "main.h"
42 #include "defaults.h"
43 #include "workspace.h"
44 #include "superfluous.h"
45 #include "menu.h"
46 #include "framewin.h"
47 #include "dialog.h"
48 #include "xinerama.h"
49 #include "client.h"
50 #ifdef XDND
51 #include "xdnd.h"
52 #endif
55 * icon_file for the dock is got from the preferences file by
56 * using the classname/instancename
59 /**** Global variables ****/
60 extern Cursor wCursor[WCUR_LAST];
61 extern WPreferences wPreferences;
62 extern WDDomain *WDWindowAttributes;
64 #define MOD_MASK wPreferences.modifier_mask
66 void appIconMouseDown(WObjDescriptor * desc, XEvent * event);
67 static void iconDblClick(WObjDescriptor * desc, XEvent * event);
68 static void iconExpose(WObjDescriptor * desc, XEvent * event);
69 static void wApplicationSaveIconPathFor(char *iconPath, char *wm_instance, char *wm_class);
70 static WAppIcon *wAppIconCreate(WWindow * leader_win);
71 static void add_to_appicon_list(WScreen *scr, WAppIcon *appicon);
72 static void remove_from_appicon_list(WScreen *scr, WAppIcon *appicon);
74 /* This function is used if the application is a .app. It checks if it has an icon in it
75 * like for example /usr/local/GNUstep/Applications/WPrefs.app/WPrefs.tiff
77 void wApplicationExtractDirPackIcon(WScreen * scr, char *path, char *wm_instance, char *wm_class)
79 char *iconPath = NULL;
80 char *tmp = NULL;
82 if (strstr(path, ".app")) {
83 tmp = wmalloc(strlen(path) + 16);
85 if (scr->flags.supports_tiff) {
86 strcpy(tmp, path);
87 strcat(tmp, ".tiff");
88 if (access(tmp, R_OK) == 0)
89 iconPath = tmp;
92 if (!iconPath) {
93 strcpy(tmp, path);
94 strcat(tmp, ".xpm");
95 if (access(tmp, R_OK) == 0)
96 iconPath = tmp;
99 if (!iconPath)
100 wfree(tmp);
102 if (iconPath) {
103 wApplicationSaveIconPathFor(iconPath, wm_instance, wm_class);
104 wfree(iconPath);
109 WAppIcon *wAppIconCreateForDock(WScreen *scr, char *command, char *wm_instance, char *wm_class, int tile)
111 WAppIcon *aicon;
113 aicon = wmalloc(sizeof(WAppIcon));
114 wretain(aicon);
115 aicon->yindex = -1;
116 aicon->xindex = -1;
118 add_to_appicon_list(scr, aicon);
120 if (command)
121 aicon->command = wstrdup(command);
123 if (wm_class)
124 aicon->wm_class = wstrdup(wm_class);
126 if (wm_instance)
127 aicon->wm_instance = wstrdup(wm_instance);
129 aicon->icon = icon_create_for_dock(scr, command, wm_instance, wm_class, tile);
131 #ifdef XDND
132 wXDNDMakeAwareness(aicon->icon->core->window);
133 #endif
135 /* will be overriden by dock */
136 aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
137 aicon->icon->core->descriptor.handle_expose = iconExpose;
138 aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
139 aicon->icon->core->descriptor.parent = aicon;
140 AddToStackList(aicon->icon->core);
142 return aicon;
145 void makeAppIconFor(WApplication *wapp)
147 /* If app_icon, work is done, return */
148 if (wapp->app_icon)
149 return;
151 /* Create the icon */
152 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
153 wIconUpdate(wapp->app_icon->icon);
155 /* Now, paint the icon */
156 if (!WFLAGP(wapp->main_window_desc, no_appicon))
157 paint_app_icon(wapp);
160 void unpaint_app_icon(WApplication *wapp)
162 WAppIcon *aicon;
163 WScreen *scr;
164 WDock *clip;
166 if (!wapp || !wapp->app_icon)
167 return;
169 aicon = wapp->app_icon;
171 /* If the icon is docked, don't continue */
172 if (aicon->docked)
173 return;
175 scr = wapp->main_window_desc->screen_ptr;
176 clip = scr->workspaces[scr->current_workspace]->clip;
178 if (!clip || !aicon->attracted || !clip->collapsed)
179 XUnmapWindow(dpy, aicon->icon->core->window);
181 /* We want to avoid having it on the list because otherwise
182 * there will be a hole when the icons are arranged with
183 * wArrangeIcons() */
184 remove_from_appicon_list(scr, aicon);
186 if (wPreferences.auto_arrange_icons && !aicon->attracted)
187 wArrangeIcons(scr, True);
190 void paint_app_icon(WApplication *wapp)
192 WIcon *icon;
193 WScreen *scr = wapp->main_window_desc->screen_ptr;
194 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
195 int x = 0, y = 0;
197 if (!wapp || !wapp->app_icon)
198 return;
200 icon = wapp->app_icon->icon;
201 wapp->app_icon->main_window = wapp->main_window;
203 /* If the icon is docked, don't continue */
204 if (wapp->app_icon->docked)
205 return;
207 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
208 wapp->app_icon->attracted = 1;
209 if (!icon->shadowed) {
210 icon->shadowed = 1;
211 icon->force_paint = 1;
213 wDockAttachIcon(clip, wapp->app_icon, x, y);
214 } else {
215 /* We must know if the icon is painted in the screen,
216 * because if painted, then PlaceIcon will return the next
217 * space on the screen, and the icon will move */
218 if (wapp->app_icon->next == NULL && wapp->app_icon->prev == NULL) {
219 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wapp->main_window_desc));
220 wAppIconMove(wapp->app_icon, x, y);
221 wLowerFrame(icon->core);
225 /* If we want appicon (no_appicon is not set) and the icon is not
226 * in the appicon_list, we must add it. Else, we want to avoid
227 * having it on the list */
228 if (!WFLAGP(wapp->main_window_desc, no_appicon) &&
229 wapp->app_icon->next == NULL && wapp->app_icon->prev == NULL)
230 add_to_appicon_list(scr, wapp->app_icon);
232 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
233 XMapWindow(dpy, icon->core->window);
235 if (wPreferences.auto_arrange_icons && !wapp->app_icon->attracted)
236 wArrangeIcons(scr, True);
239 void removeAppIconFor(WApplication * wapp)
241 if (!wapp->app_icon)
242 return;
244 if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
245 wapp->app_icon->running = 0;
246 /* since we keep it, we don't care if it was attracted or not */
247 wapp->app_icon->attracted = 0;
248 wapp->app_icon->icon->shadowed = 0;
249 wapp->app_icon->main_window = None;
250 wapp->app_icon->pid = 0;
251 wapp->app_icon->icon->owner = NULL;
252 wapp->app_icon->icon->icon_win = None;
253 wapp->app_icon->icon->force_paint = 1;
254 wAppIconPaint(wapp->app_icon);
255 } else if (wapp->app_icon->docked) {
256 wapp->app_icon->running = 0;
257 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
258 } else {
259 wAppIconDestroy(wapp->app_icon);
262 wapp->app_icon = NULL;
264 if (wPreferences.auto_arrange_icons)
265 wArrangeIcons(wapp->main_window_desc->screen_ptr, True);
268 static WAppIcon *wAppIconCreate(WWindow *leader_win)
270 WAppIcon *aicon;
272 aicon = wmalloc(sizeof(WAppIcon));
273 wretain(aicon);
274 aicon->yindex = -1;
275 aicon->xindex = -1;
276 aicon->prev = NULL;
277 aicon->next = NULL;
279 if (leader_win->wm_class)
280 aicon->wm_class = wstrdup(leader_win->wm_class);
282 if (leader_win->wm_instance)
283 aicon->wm_instance = wstrdup(leader_win->wm_instance);
285 aicon->icon = icon_create_for_wwindow(leader_win);
286 #ifdef XDND
287 wXDNDMakeAwareness(aicon->icon->core->window);
288 #endif
290 /* will be overriden if docked */
291 aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
292 aicon->icon->core->descriptor.handle_expose = iconExpose;
293 aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
294 aicon->icon->core->descriptor.parent = aicon;
295 AddToStackList(aicon->icon->core);
296 aicon->icon->show_title = 0;
298 return aicon;
301 void wAppIconDestroy(WAppIcon * aicon)
303 WScreen *scr = aicon->icon->core->screen_ptr;
305 RemoveFromStackList(aicon->icon->core);
306 wIconDestroy(aicon->icon);
307 if (aicon->command)
308 wfree(aicon->command);
309 #ifdef XDND
310 if (aicon->dnd_command)
311 wfree(aicon->dnd_command);
312 #endif
313 if (aicon->wm_instance)
314 wfree(aicon->wm_instance);
316 if (aicon->wm_class)
317 wfree(aicon->wm_class);
319 remove_from_appicon_list(scr, aicon);
321 aicon->destroyed = 1;
322 wrelease(aicon);
325 static void drawCorner(WIcon * icon)
327 WScreen *scr = icon->core->screen_ptr;
328 XPoint points[3];
330 points[0].x = 1;
331 points[0].y = 1;
332 points[1].x = 12;
333 points[1].y = 1;
334 points[2].x = 1;
335 points[2].y = 12;
336 XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
337 points, 3, Convex, CoordModeOrigin);
338 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 0, 12);
339 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 12, 0);
342 void wAppIconMove(WAppIcon * aicon, int x, int y)
344 XMoveWindow(dpy, aicon->icon->core->window, x, y);
345 aicon->x_pos = x;
346 aicon->y_pos = y;
349 #ifdef WS_INDICATOR
350 static void updateDockNumbers(WScreen * scr)
352 int length;
353 char *ws_numbers;
354 WAppIcon *dicon = scr->dock->icon_array[0];
356 ws_numbers = wmalloc(20);
357 snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace + 1, ((scr->current_workspace / 10) + 1));
358 length = strlen(ws_numbers);
360 XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
362 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
363 scr->icon_title_font, 4, 3, ws_numbers, length);
365 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
366 scr->icon_title_font, 3, 2, ws_numbers, length);
368 wfree(ws_numbers);
370 #endif /* WS_INDICATOR */
372 void wAppIconPaint(WAppIcon * aicon)
374 WApplication *wapp;
375 WScreen *scr = aicon->icon->core->screen_ptr;
377 if (aicon->icon->owner)
378 wapp = wApplicationOf(aicon->icon->owner->main_window);
379 else
380 wapp = NULL;
382 wIconPaint(aicon->icon);
384 # ifdef WS_INDICATOR
385 if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
386 updateDockNumbers(scr);
387 # endif
388 if (scr->dock_dots && aicon->docked && !aicon->running && aicon->command != NULL) {
389 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
390 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
391 XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
392 scr->copy_gc, 0, 0, scr->dock_dots->width, scr->dock_dots->height, 0, 0);
394 #ifdef HIDDENDOT
395 if (wapp && wapp->flags.hidden) {
396 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
397 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
398 XCopyArea(dpy, scr->dock_dots->image,
399 aicon->icon->core->window, scr->copy_gc, 0, 0, 7, scr->dock_dots->height, 0, 0);
401 #endif /* HIDDENDOT */
403 if (aicon->omnipresent)
404 drawCorner(aicon->icon);
406 XSetClipMask(dpy, scr->copy_gc, None);
407 if (aicon->launching)
408 XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
409 0, 0, wPreferences.icon_size, wPreferences.icon_size);
412 /* Save the application icon, if it's a dockapp then use it with dock = True */
413 void save_appicon(WAppIcon *aicon, Bool dock)
415 char *path;
417 if (!aicon)
418 return;
420 if (dock && (!aicon->docked || aicon->attracted))
421 return;
423 path = wIconStore(aicon->icon);
424 if (!path)
425 return;
427 wApplicationSaveIconPathFor(path, aicon->wm_instance, aicon->wm_class);
428 wfree(path);
431 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
433 /* main_window may not have the full command line; try to find one which does */
434 static void relaunchApplication(WApplication *wapp)
436 WScreen *scr;
437 WWindow *wlist, *next;
439 scr = wapp->main_window_desc->screen_ptr;
440 wlist = scr->focused_window;
441 if (! wlist)
442 return;
444 while (wlist->prev)
445 wlist = wlist->prev;
447 while (wlist) {
448 next = wlist->next;
450 if (wlist->main_window == wapp->main_window) {
451 if (RelaunchWindow(wlist))
452 return;
455 wlist = next;
459 static void relaunchCallback(WMenu * menu, WMenuEntry * entry)
461 WApplication *wapp = (WApplication *) entry->clientdata;
463 relaunchApplication(wapp);
466 static void hideCallback(WMenu * menu, WMenuEntry * entry)
468 WApplication *wapp = (WApplication *) entry->clientdata;
470 if (wapp->flags.hidden) {
471 wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
472 wUnhideApplication(wapp, False, False);
473 } else {
474 wHideApplication(wapp);
478 static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
480 WApplication *wapp = (WApplication *) entry->clientdata;
482 wUnhideApplication(wapp, False, True);
485 static void setIconCallback(WMenu * menu, WMenuEntry * entry)
487 WAppIcon *icon = ((WApplication *) entry->clientdata)->app_icon;
488 char *file = NULL;
489 WScreen *scr;
490 int result;
492 assert(icon != NULL);
494 if (icon->editing)
495 return;
497 icon->editing = 1;
498 scr = icon->icon->core->screen_ptr;
500 wretain(icon);
502 result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
504 if (result && !icon->destroyed) {
505 if (file && *file == 0) {
506 wfree(file);
507 file = NULL;
509 if (!wIconChangeImageFile(icon->icon, file)) {
510 wMessageDialog(scr, _("Error"),
511 _("Could not open specified icon file"), _("OK"), NULL, NULL);
512 } else {
513 wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
514 wAppIconPaint(icon);
516 if (file)
517 wfree(file);
519 icon->editing = 0;
520 wrelease(icon);
523 static void killCallback(WMenu * menu, WMenuEntry * entry)
525 WApplication *wapp = (WApplication *) entry->clientdata;
526 WFakeGroupLeader *fPtr;
527 char *buffer;
528 char *shortname;
529 char *basename(const char *shortname);
531 if (!WCHECK_STATE(WSTATE_NORMAL))
532 return;
534 WCHANGE_STATE(WSTATE_MODAL);
536 assert(entry->clientdata != NULL);
538 shortname = basename(wapp->app_icon->wm_instance);
540 buffer = wstrconcat(wapp->app_icon ? shortname : NULL,
541 _(" will be forcibly closed.\n"
542 "Any unsaved changes will be lost.\n" "Please confirm."));
544 fPtr = wapp->main_window_desc->fake_group;
546 wretain(wapp->main_window_desc);
547 if (wPreferences.dont_confirm_kill
548 || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
549 buffer, _("Yes"), _("No"), NULL) == WAPRDefault) {
550 if (fPtr != NULL) {
551 WWindow *wwin, *twin;
553 wwin = wapp->main_window_desc->screen_ptr->focused_window;
554 while (wwin) {
555 twin = wwin->prev;
556 if (wwin->fake_group == fPtr)
557 wClientKill(wwin);
558 wwin = twin;
560 } else if (!wapp->main_window_desc->flags.destroyed) {
561 wClientKill(wapp->main_window_desc);
564 wrelease(wapp->main_window_desc);
565 wfree(buffer);
566 WCHANGE_STATE(WSTATE_NORMAL);
569 static WMenu *createApplicationMenu(WScreen * scr)
571 WMenu *menu;
573 menu = wMenuCreate(scr, NULL, False);
574 wMenuAddCallback(menu, _("Launch"), relaunchCallback, NULL);
575 wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
576 wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
577 wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
578 wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
580 return menu;
583 static void openApplicationMenu(WApplication * wapp, int x, int y)
585 WMenu *menu;
586 WScreen *scr = wapp->main_window_desc->screen_ptr;
587 int i;
589 if (!scr->icon_menu) {
590 scr->icon_menu = createApplicationMenu(scr);
591 wfree(scr->icon_menu->entries[1]->text);
594 menu = scr->icon_menu;
596 if (wapp->flags.hidden)
597 menu->entries[1]->text = _("Unhide");
598 else
599 menu->entries[1]->text = _("Hide");
601 menu->flags.realized = 0;
602 wMenuRealize(menu);
604 x -= menu->frame->core->width / 2;
605 if (x + menu->frame->core->width > scr->scr_width)
606 x = scr->scr_width - menu->frame->core->width;
608 if (x < 0)
609 x = 0;
611 /* set client data */
612 for (i = 0; i < menu->entry_no; i++)
613 menu->entries[i]->clientdata = wapp;
615 wMenuMapAt(menu, x, y, False);
618 /******************************************************************/
620 static void iconExpose(WObjDescriptor * desc, XEvent * event)
622 wAppIconPaint(desc->parent);
625 static void iconDblClick(WObjDescriptor * desc, XEvent * event)
627 WAppIcon *aicon = desc->parent;
628 WApplication *wapp;
629 WScreen *scr = aicon->icon->core->screen_ptr;
630 int unhideHere;
632 assert(aicon->icon->owner != NULL);
634 wapp = wApplicationOf(aicon->icon->owner->main_window);
636 if (event->xbutton.state & ControlMask) {
637 relaunchApplication(wapp);
638 return;
641 unhideHere = (event->xbutton.state & ShiftMask);
642 /* go to the last workspace that the user worked on the app */
643 if (!unhideHere && wapp->last_workspace != scr->current_workspace)
644 wWorkspaceChange(scr, wapp->last_workspace);
646 wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
648 if (event->xbutton.state & MOD_MASK)
649 wHideOtherApplications(aicon->icon->owner);
652 void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
654 WAppIcon *aicon = desc->parent;
655 WIcon *icon = aicon->icon;
656 XEvent ev;
657 int x = aicon->x_pos, y = aicon->y_pos;
658 int dx = event->xbutton.x, dy = event->xbutton.y;
659 int grabbed = 0;
660 int done = 0;
661 int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
662 WScreen *scr = icon->core->screen_ptr;
663 WWorkspace *workspace = scr->workspaces[scr->current_workspace];
664 int shad_x = 0, shad_y = 0, docking = 0, dockable, collapsed = 0;
665 int ix, iy;
666 int clickButton = event->xbutton.button;
667 Pixmap ghost = None;
668 Window wins[2];
669 Bool movingSingle = False;
670 int oldX = x;
671 int oldY = y;
672 Bool hasMoved = False;
674 if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
675 return;
677 if (IsDoubleClick(scr, event)) {
678 /* Middle or right mouse actions were handled on first click */
679 if (event->xbutton.button == Button1)
680 iconDblClick(desc, event);
681 return;
684 if (event->xbutton.button == Button2) {
685 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
687 if (wapp)
688 relaunchApplication(wapp);
690 return;
693 if (event->xbutton.button == Button3) {
694 WObjDescriptor *desc;
695 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
697 if (!wapp)
698 return;
700 if (event->xbutton.send_event &&
701 XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
702 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
703 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
704 wwarning("pointer grab failed for appicon menu");
705 return;
708 openApplicationMenu(wapp, event->xbutton.x_root, event->xbutton.y_root);
710 /* allow drag select of menu */
711 desc = &scr->icon_menu->menu->descriptor;
712 event->xbutton.send_event = True;
713 (*desc->handle_mousedown) (desc, event);
714 return;
717 if (event->xbutton.state & MOD_MASK)
718 wLowerFrame(icon->core);
719 else
720 wRaiseFrame(icon->core);
722 if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
723 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
724 GrabModeAsync, None, None, CurrentTime) != GrabSuccess)
725 wwarning("pointer grab failed for appicon move");
727 if (wPreferences.flags.nodock && wPreferences.flags.noclip)
728 dockable = 0;
729 else
730 dockable = canBeDocked(icon->owner);
732 wins[0] = icon->core->window;
733 wins[1] = scr->dock_shadow;
734 XRestackWindows(dpy, wins, 2);
735 if (superfluous) {
736 if (icon->pixmap != None)
737 ghost = MakeGhostIcon(scr, icon->pixmap);
738 else
739 ghost = MakeGhostIcon(scr, icon->core->window);
740 XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
741 XClearWindow(dpy, scr->dock_shadow);
744 while (!done) {
745 WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
746 | ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
747 switch (ev.type) {
748 case Expose:
749 WMHandleEvent(&ev);
750 break;
752 case EnterNotify:
753 /* It means the cursor moved so fast that it entered
754 * something else (if moving slowly, it would have
755 * stayed in the appIcon that is being moved. Ignore
756 * such "spurious" EnterNotifiy's */
757 break;
759 case MotionNotify:
760 hasMoved = True;
761 if (!grabbed) {
762 if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
763 || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
764 XChangeActivePointerGrab(dpy, ButtonMotionMask
765 | ButtonReleaseMask | ButtonPressMask,
766 wCursor[WCUR_MOVE], CurrentTime);
767 grabbed = 1;
768 } else {
769 break;
772 x = ev.xmotion.x_root - dx;
773 y = ev.xmotion.y_root - dy;
775 if (movingSingle)
776 XMoveWindow(dpy, icon->core->window, x, y);
777 else
778 wAppIconMove(aicon, x, y);
780 if (dockable) {
781 if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y, &ix, &iy, False)) {
782 shad_x = scr->dock->x_pos + ix * wPreferences.icon_size;
783 shad_y = scr->dock->y_pos + iy * wPreferences.icon_size;
785 if (scr->last_dock != scr->dock && collapsed) {
786 scr->last_dock->collapsed = 1;
787 wDockHideIcons(scr->last_dock);
788 collapsed = 0;
790 if (!collapsed && (collapsed = scr->dock->collapsed)) {
791 scr->dock->collapsed = 0;
792 wDockShowIcons(scr->dock);
795 if (scr->dock->auto_raise_lower)
796 wDockRaise(scr->dock);
798 scr->last_dock = scr->dock;
800 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
801 if (!docking)
802 XMapWindow(dpy, scr->dock_shadow);
804 docking = 1;
805 } else if (workspace->clip &&
806 wDockSnapIcon(workspace->clip, aicon, x, y, &ix, &iy, False)) {
807 shad_x = workspace->clip->x_pos + ix * wPreferences.icon_size;
808 shad_y = workspace->clip->y_pos + iy * wPreferences.icon_size;
810 if (scr->last_dock != workspace->clip && collapsed) {
811 scr->last_dock->collapsed = 1;
812 wDockHideIcons(scr->last_dock);
813 collapsed = 0;
815 if (!collapsed && (collapsed = workspace->clip->collapsed)) {
816 workspace->clip->collapsed = 0;
817 wDockShowIcons(workspace->clip);
820 if (workspace->clip->auto_raise_lower)
821 wDockRaise(workspace->clip);
823 scr->last_dock = workspace->clip;
825 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
826 if (!docking)
827 XMapWindow(dpy, scr->dock_shadow);
829 docking = 1;
830 } else if (docking) {
831 XUnmapWindow(dpy, scr->dock_shadow);
832 docking = 0;
835 break;
837 case ButtonPress:
838 break;
840 case ButtonRelease:
841 if (ev.xbutton.button != clickButton)
842 break;
843 XUngrabPointer(dpy, CurrentTime);
845 if (docking) {
846 Bool docked;
848 /* icon is trying to be docked */
849 SlideWindow(icon->core->window, x, y, shad_x, shad_y);
850 XUnmapWindow(dpy, scr->dock_shadow);
851 docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
852 if (scr->last_dock->auto_collapse)
853 collapsed = 0;
855 if (workspace->clip &&
856 workspace->clip != scr->last_dock && workspace->clip->auto_raise_lower)
857 wDockLower(workspace->clip);
859 if (!docked) {
860 /* If icon could not be docked, slide it back to the old
861 * position */
862 SlideWindow(icon->core->window, x, y, oldX, oldY);
864 } else {
865 if (movingSingle) {
866 /* move back to its place */
867 SlideWindow(icon->core->window, x, y, oldX, oldY);
868 wAppIconMove(aicon, oldX, oldY);
869 } else {
870 XMoveWindow(dpy, icon->core->window, x, y);
871 aicon->x_pos = x;
872 aicon->y_pos = y;
874 if (workspace->clip && workspace->clip->auto_raise_lower)
875 wDockLower(workspace->clip);
877 if (collapsed) {
878 scr->last_dock->collapsed = 1;
879 wDockHideIcons(scr->last_dock);
880 collapsed = 0;
882 if (superfluous) {
883 if (ghost != None)
884 XFreePixmap(dpy, ghost);
885 XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
888 if (wPreferences.auto_arrange_icons)
889 wArrangeIcons(scr, True);
891 if (wPreferences.single_click && !hasMoved)
892 iconDblClick(desc, event);
894 done = 1;
895 break;
900 /* This function save the application icon and store the path in the Dictionary */
901 static void wApplicationSaveIconPathFor(char *iconPath, char *wm_instance, char *wm_class)
903 WMPropList *dict = WDWindowAttributes->dictionary;
904 WMPropList *adict, *key, *iconk;
905 WMPropList *val;
906 char *tmp;
908 tmp = get_name_for_instance_class(wm_instance, wm_class);
909 key = WMCreatePLString(tmp);
910 wfree(tmp);
912 adict = WMGetFromPLDictionary(dict, key);
913 iconk = WMCreatePLString("Icon");
915 if (adict) {
916 val = WMGetFromPLDictionary(adict, iconk);
917 } else {
918 /* no dictionary for app, so create one */
919 adict = WMCreatePLDictionary(NULL, NULL);
920 WMPutInPLDictionary(dict, key, adict);
921 WMReleasePropList(adict);
922 val = NULL;
925 if (!val) {
926 val = WMCreatePLString(iconPath);
927 WMPutInPLDictionary(adict, iconk, val);
928 WMReleasePropList(val);
929 } else {
930 val = NULL;
933 WMReleasePropList(key);
934 WMReleasePropList(iconk);
936 if (val && !wPreferences.flags.noupdates)
937 UpdateDomainFile(WDWindowAttributes);
940 static WAppIcon *findDockIconFor(WDock *dock, Window main_window)
942 WAppIcon *aicon = NULL;
944 aicon = wDockFindIconForWindow(dock, main_window);
945 if (!aicon) {
946 wDockTrackWindowLaunch(dock, main_window);
947 aicon = wDockFindIconForWindow(dock, main_window);
949 return aicon;
952 void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, Window main_window)
954 WScreen *scr = wwin->screen_ptr;
955 wapp->app_icon = NULL;
957 if (scr->last_dock)
958 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
960 /* check main dock if we did not find it in last dock */
961 if (!wapp->app_icon && scr->dock)
962 wapp->app_icon = findDockIconFor(scr->dock, main_window);
964 /* finally check clips */
965 if (!wapp->app_icon) {
966 int i;
967 for (i = 0; i < scr->workspace_count; i++) {
968 WDock *dock = scr->workspaces[i]->clip;
969 if (dock)
970 wapp->app_icon = findDockIconFor(dock, main_window);
971 if (wapp->app_icon)
972 break;
976 /* If created, then set some flags */
977 if (wapp->app_icon) {
978 WWindow *mainw = wapp->main_window_desc;
980 wapp->app_icon->running = 1;
981 wapp->app_icon->icon->force_paint = 1;
982 wapp->app_icon->icon->owner = mainw;
983 if (mainw->wm_hints && (mainw->wm_hints->flags & IconWindowHint))
984 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
986 wAppIconPaint(wapp->app_icon);
987 save_appicon(wapp->app_icon, True);
991 /* Add the appicon to the appiconlist */
992 static void add_to_appicon_list(WScreen *scr, WAppIcon *appicon)
994 appicon->prev = NULL;
995 appicon->next = scr->app_icon_list;
996 if (scr->app_icon_list)
997 scr->app_icon_list->prev = appicon;
999 scr->app_icon_list = appicon;
1002 /* Remove the appicon from the appiconlist */
1003 static void remove_from_appicon_list(WScreen *scr, WAppIcon *appicon)
1005 if (appicon == scr->app_icon_list) {
1006 if (appicon->next)
1007 appicon->next->prev = NULL;
1008 scr->app_icon_list = appicon->next;
1009 } else {
1010 if (appicon->next)
1011 appicon->next->prev = appicon->prev;
1012 if (appicon->prev)
1013 appicon->prev->next = appicon->next;
1016 appicon->prev = NULL;
1017 appicon->next = NULL;