save_app_icon WWindow argument removed
[wmaker-crm.git] / src / appicon.c
bloba2c47d3502739f8c0f48e70b3c83e83d417df135
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 "funcs.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);
70 /* This function is used if the application is a .app. It checks if it has an icon in it
71 * like for example /usr/local/GNUstep/Applications/WPrefs.app/WPrefs.tiff
73 void wApplicationExtractDirPackIcon(WScreen * scr, char *path, char *wm_instance, char *wm_class)
75 char *iconPath = NULL;
76 char *tmp = NULL;
78 if (strstr(path, ".app")) {
79 tmp = wmalloc(strlen(path) + 16);
81 if (scr->flags.supports_tiff) {
82 strcpy(tmp, path);
83 strcat(tmp, ".tiff");
84 if (access(tmp, R_OK) == 0)
85 iconPath = tmp;
88 if (!iconPath) {
89 strcpy(tmp, path);
90 strcat(tmp, ".xpm");
91 if (access(tmp, R_OK) == 0)
92 iconPath = tmp;
95 if (!iconPath)
96 wfree(tmp);
98 if (iconPath) {
99 wApplicationSaveIconPathFor(iconPath, wm_instance, wm_class);
100 wfree(iconPath);
105 WAppIcon *wAppIconCreateForDock(WScreen * scr, char *command, char *wm_instance, char *wm_class, int tile)
107 WAppIcon *dicon;
108 char *path;
110 dicon = wmalloc(sizeof(WAppIcon));
111 wretain(dicon);
112 dicon->yindex = -1;
113 dicon->xindex = -1;
115 dicon->prev = NULL;
116 dicon->next = scr->app_icon_list;
117 if (scr->app_icon_list)
118 scr->app_icon_list->prev = dicon;
120 scr->app_icon_list = dicon;
122 if (command)
123 dicon->command = wstrdup(command);
125 if (wm_class)
126 dicon->wm_class = wstrdup(wm_class);
128 if (wm_instance)
129 dicon->wm_instance = wstrdup(wm_instance);
131 path = wDefaultGetIconFile(scr, wm_instance, wm_class, True);
132 if (!path && command) {
133 wApplicationExtractDirPackIcon(scr, command, wm_instance, wm_class);
134 path = wDefaultGetIconFile(scr, wm_instance, wm_class, False);
137 if (path)
138 path = FindImage(wPreferences.icon_path, path);
140 dicon->icon = wIconCreateWithIconFile(scr, path, tile);
141 if (path)
142 wfree(path);
143 #ifdef XDND
144 wXDNDMakeAwareness(dicon->icon->core->window);
145 #endif
147 /* will be overriden by dock */
148 dicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
149 dicon->icon->core->descriptor.handle_expose = iconExpose;
150 dicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
151 dicon->icon->core->descriptor.parent = dicon;
152 AddToStackList(dicon->icon->core);
154 return dicon;
157 void makeAppIconFor(WApplication * wapp)
159 /* If app_icon, work is done, return */
160 if (wapp->app_icon)
161 return;
163 if (!WFLAGP(wapp->main_window_desc, no_appicon))
164 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
165 else
166 wapp->app_icon = NULL;
168 /* Now, paint the icon */
169 paint_app_icon(wapp);
172 void paint_app_icon(WApplication *wapp)
174 WIcon *icon;
175 WScreen *scr = wapp->main_window_desc->screen_ptr;
176 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
177 int x = 0, y = 0;
179 if (!wapp || !wapp->app_icon)
180 return;
182 icon = wapp->app_icon->icon;
183 wapp->app_icon->main_window = wapp->main_window;
185 /* If the icon is docked, don't continue */
186 if (wapp->app_icon->docked)
187 return;
189 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
190 wapp->app_icon->attracted = 1;
191 if (!icon->shadowed) {
192 icon->shadowed = 1;
193 icon->force_paint = 1;
195 wDockAttachIcon(clip, wapp->app_icon, x, y);
196 } else {
197 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wapp->main_window_desc));
198 wAppIconMove(wapp->app_icon, x, y);
199 wLowerFrame(icon->core);
202 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
203 XMapWindow(dpy, icon->core->window);
205 if (wPreferences.auto_arrange_icons && !wapp->app_icon->attracted)
206 wArrangeIcons(scr, True);
209 void removeAppIconFor(WApplication * wapp)
211 if (!wapp->app_icon)
212 return;
214 if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
215 wapp->app_icon->running = 0;
216 /* since we keep it, we don't care if it was attracted or not */
217 wapp->app_icon->attracted = 0;
218 wapp->app_icon->icon->shadowed = 0;
219 wapp->app_icon->main_window = None;
220 wapp->app_icon->pid = 0;
221 wapp->app_icon->icon->owner = NULL;
222 wapp->app_icon->icon->icon_win = None;
223 wapp->app_icon->icon->force_paint = 1;
224 wAppIconPaint(wapp->app_icon);
225 } else if (wapp->app_icon->docked) {
226 wapp->app_icon->running = 0;
227 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
228 } else {
229 wAppIconDestroy(wapp->app_icon);
232 wapp->app_icon = NULL;
234 if (wPreferences.auto_arrange_icons)
235 wArrangeIcons(wapp->main_window_desc->screen_ptr, True);
238 WAppIcon *wAppIconCreate(WWindow * leader_win)
240 WAppIcon *aicon;
241 WScreen *scr = leader_win->screen_ptr;
243 aicon = wmalloc(sizeof(WAppIcon));
244 wretain(aicon);
246 aicon->yindex = -1;
247 aicon->xindex = -1;
249 aicon->prev = NULL;
250 aicon->next = scr->app_icon_list;
251 if (scr->app_icon_list)
252 scr->app_icon_list->prev = aicon;
254 scr->app_icon_list = aicon;
256 if (leader_win->wm_class)
257 aicon->wm_class = wstrdup(leader_win->wm_class);
259 if (leader_win->wm_instance)
260 aicon->wm_instance = wstrdup(leader_win->wm_instance);
262 aicon->icon = wIconCreate(leader_win);
263 #ifdef XDND
264 wXDNDMakeAwareness(aicon->icon->core->window);
265 #endif
267 /* will be overriden if docked */
268 aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
269 aicon->icon->core->descriptor.handle_expose = iconExpose;
270 aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
271 aicon->icon->core->descriptor.parent = aicon;
272 AddToStackList(aicon->icon->core);
273 aicon->icon->show_title = 0;
274 wIconUpdate(aicon->icon);
276 return aicon;
279 void wAppIconDestroy(WAppIcon * aicon)
281 WScreen *scr = aicon->icon->core->screen_ptr;
283 RemoveFromStackList(aicon->icon->core);
284 wIconDestroy(aicon->icon);
285 if (aicon->command)
286 wfree(aicon->command);
287 #ifdef XDND
288 if (aicon->dnd_command)
289 wfree(aicon->dnd_command);
290 #endif
291 if (aicon->wm_instance)
292 wfree(aicon->wm_instance);
294 if (aicon->wm_class)
295 wfree(aicon->wm_class);
297 if (aicon == scr->app_icon_list) {
298 if (aicon->next)
299 aicon->next->prev = NULL;
300 scr->app_icon_list = aicon->next;
301 } else {
302 if (aicon->next)
303 aicon->next->prev = aicon->prev;
304 if (aicon->prev)
305 aicon->prev->next = aicon->next;
308 aicon->destroyed = 1;
309 wrelease(aicon);
312 static void drawCorner(WIcon * icon)
314 WScreen *scr = icon->core->screen_ptr;
315 XPoint points[3];
317 points[0].x = 1;
318 points[0].y = 1;
319 points[1].x = 12;
320 points[1].y = 1;
321 points[2].x = 1;
322 points[2].y = 12;
323 XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
324 points, 3, Convex, CoordModeOrigin);
325 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 0, 12);
326 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 12, 0);
329 void wAppIconMove(WAppIcon * aicon, int x, int y)
331 XMoveWindow(dpy, aicon->icon->core->window, x, y);
332 aicon->x_pos = x;
333 aicon->y_pos = y;
336 #ifdef WS_INDICATOR
337 static void updateDockNumbers(WScreen * scr)
339 int length;
340 char *ws_numbers;
341 WAppIcon *dicon = scr->dock->icon_array[0];
343 ws_numbers = wmalloc(20);
344 snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace + 1, ((scr->current_workspace / 10) + 1));
345 length = strlen(ws_numbers);
347 XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
349 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
350 scr->icon_title_font, 4, 3, ws_numbers, length);
352 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
353 scr->icon_title_font, 3, 2, ws_numbers, length);
355 wfree(ws_numbers);
357 #endif /* WS_INDICATOR */
359 void wAppIconPaint(WAppIcon * aicon)
361 WApplication *wapp;
362 WScreen *scr = aicon->icon->core->screen_ptr;
364 if (aicon->icon->owner)
365 wapp = wApplicationOf(aicon->icon->owner->main_window);
366 else
367 wapp = NULL;
369 wIconPaint(aicon->icon);
371 # ifdef WS_INDICATOR
372 if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
373 updateDockNumbers(scr);
374 # endif
375 if (scr->dock_dots && aicon->docked && !aicon->running && aicon->command != NULL) {
376 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
377 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
378 XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
379 scr->copy_gc, 0, 0, scr->dock_dots->width, scr->dock_dots->height, 0, 0);
381 #ifdef HIDDENDOT
382 if (wapp && wapp->flags.hidden) {
383 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
384 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
385 XCopyArea(dpy, scr->dock_dots->image,
386 aicon->icon->core->window, scr->copy_gc, 0, 0, 7, scr->dock_dots->height, 0, 0);
388 #endif /* HIDDENDOT */
390 if (aicon->omnipresent)
391 drawCorner(aicon->icon);
393 XSetClipMask(dpy, scr->copy_gc, None);
394 if (aicon->launching)
395 XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
396 0, 0, wPreferences.icon_size, wPreferences.icon_size);
399 /* Internal application to save the application icon */
400 static void save_app_icon_core(WAppIcon *aicon)
402 char *path;
404 path = wIconStore(aicon->icon);
405 if (!path)
406 return;
408 wApplicationSaveIconPathFor(path, aicon->wm_instance, aicon->wm_class);
410 wfree(path);
413 /* Save the application icon */
414 /* This function is used when the icon doesn't have window, like dock or clip */
415 void wAppIconSave(WAppIcon *aicon)
417 if (!aicon->docked || aicon->attracted)
418 return;
420 save_app_icon_core(aicon);
423 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
425 /* main_window may not have the full command line; try to find one which does */
426 static void relaunchApplication(WApplication *wapp)
428 WScreen *scr;
429 WWindow *wlist, *next;
431 scr = wapp->main_window_desc->screen_ptr;
432 wlist = scr->focused_window;
433 if (! wlist)
434 return;
436 while (wlist->prev)
437 wlist = wlist->prev;
439 while (wlist) {
440 next = wlist->next;
442 if (wlist->main_window == wapp->main_window) {
443 if (RelaunchWindow(wlist))
444 return;
447 wlist = next;
451 static void relaunchCallback(WMenu * menu, WMenuEntry * entry)
453 WApplication *wapp = (WApplication *) entry->clientdata;
455 relaunchApplication(wapp);
458 static void hideCallback(WMenu * menu, WMenuEntry * entry)
460 WApplication *wapp = (WApplication *) entry->clientdata;
462 if (wapp->flags.hidden) {
463 wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
464 wUnhideApplication(wapp, False, False);
465 } else {
466 wHideApplication(wapp);
470 static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
472 WApplication *wapp = (WApplication *) entry->clientdata;
474 wUnhideApplication(wapp, False, True);
477 static void setIconCallback(WMenu * menu, WMenuEntry * entry)
479 WAppIcon *icon = ((WApplication *) entry->clientdata)->app_icon;
480 char *file = NULL;
481 WScreen *scr;
482 int result;
484 assert(icon != NULL);
486 if (icon->editing)
487 return;
489 icon->editing = 1;
490 scr = icon->icon->core->screen_ptr;
492 wretain(icon);
494 result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
496 if (result && !icon->destroyed) {
497 if (file && *file == 0) {
498 wfree(file);
499 file = NULL;
501 if (!wIconChangeImageFile(icon->icon, file)) {
502 wMessageDialog(scr, _("Error"),
503 _("Could not open specified icon file"), _("OK"), NULL, NULL);
504 } else {
505 wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
506 wAppIconPaint(icon);
508 if (file)
509 wfree(file);
511 icon->editing = 0;
512 wrelease(icon);
515 static void killCallback(WMenu * menu, WMenuEntry * entry)
517 WApplication *wapp = (WApplication *) entry->clientdata;
518 WFakeGroupLeader *fPtr;
519 char *buffer;
520 char *shortname;
521 char *basename(const char *shortname);
523 if (!WCHECK_STATE(WSTATE_NORMAL))
524 return;
526 WCHANGE_STATE(WSTATE_MODAL);
528 assert(entry->clientdata != NULL);
530 shortname = basename(wapp->app_icon->wm_instance);
532 buffer = wstrconcat(wapp->app_icon ? shortname : NULL,
533 _(" will be forcibly closed.\n"
534 "Any unsaved changes will be lost.\n" "Please confirm."));
536 fPtr = wapp->main_window_desc->fake_group;
538 wretain(wapp->main_window_desc);
539 if (wPreferences.dont_confirm_kill
540 || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
541 buffer, _("Yes"), _("No"), NULL) == WAPRDefault) {
542 if (fPtr != NULL) {
543 WWindow *wwin, *twin;
545 wwin = wapp->main_window_desc->screen_ptr->focused_window;
546 while (wwin) {
547 twin = wwin->prev;
548 if (wwin->fake_group == fPtr)
549 wClientKill(wwin);
550 wwin = twin;
552 } else if (!wapp->main_window_desc->flags.destroyed) {
553 wClientKill(wapp->main_window_desc);
556 wrelease(wapp->main_window_desc);
557 wfree(buffer);
558 WCHANGE_STATE(WSTATE_NORMAL);
561 static WMenu *createApplicationMenu(WScreen * scr)
563 WMenu *menu;
565 menu = wMenuCreate(scr, NULL, False);
566 wMenuAddCallback(menu, _("Launch"), relaunchCallback, NULL);
567 wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
568 wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
569 wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
570 wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
572 return menu;
575 static void openApplicationMenu(WApplication * wapp, int x, int y)
577 WMenu *menu;
578 WScreen *scr = wapp->main_window_desc->screen_ptr;
579 int i;
581 if (!scr->icon_menu) {
582 scr->icon_menu = createApplicationMenu(scr);
583 wfree(scr->icon_menu->entries[1]->text);
586 menu = scr->icon_menu;
588 if (wapp->flags.hidden)
589 menu->entries[1]->text = _("Unhide");
590 else
591 menu->entries[1]->text = _("Hide");
593 menu->flags.realized = 0;
594 wMenuRealize(menu);
596 x -= menu->frame->core->width / 2;
597 if (x + menu->frame->core->width > scr->scr_width)
598 x = scr->scr_width - menu->frame->core->width;
600 if (x < 0)
601 x = 0;
603 /* set client data */
604 for (i = 0; i < menu->entry_no; i++)
605 menu->entries[i]->clientdata = wapp;
607 wMenuMapAt(menu, x, y, False);
610 /******************************************************************/
612 static void iconExpose(WObjDescriptor * desc, XEvent * event)
614 wAppIconPaint(desc->parent);
617 static void iconDblClick(WObjDescriptor * desc, XEvent * event)
619 WAppIcon *aicon = desc->parent;
620 WApplication *wapp;
621 WScreen *scr = aicon->icon->core->screen_ptr;
622 int unhideHere;
624 assert(aicon->icon->owner != NULL);
626 wapp = wApplicationOf(aicon->icon->owner->main_window);
628 if (event->xbutton.state & ControlMask) {
629 relaunchApplication(wapp);
630 return;
633 unhideHere = (event->xbutton.state & ShiftMask);
634 /* go to the last workspace that the user worked on the app */
635 if (!unhideHere && wapp->last_workspace != scr->current_workspace)
636 wWorkspaceChange(scr, wapp->last_workspace);
638 wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
640 if (event->xbutton.state & MOD_MASK)
641 wHideOtherApplications(aicon->icon->owner);
644 void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
646 WAppIcon *aicon = desc->parent;
647 WIcon *icon = aicon->icon;
648 XEvent ev;
649 int x = aicon->x_pos, y = aicon->y_pos;
650 int dx = event->xbutton.x, dy = event->xbutton.y;
651 int grabbed = 0;
652 int done = 0;
653 int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
654 WScreen *scr = icon->core->screen_ptr;
655 WWorkspace *workspace = scr->workspaces[scr->current_workspace];
656 int shad_x = 0, shad_y = 0, docking = 0, dockable, collapsed = 0;
657 int ix, iy;
658 int clickButton = event->xbutton.button;
659 Pixmap ghost = None;
660 Window wins[2];
661 Bool movingSingle = False;
662 int oldX = x;
663 int oldY = y;
664 Bool hasMoved = False;
666 if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
667 return;
669 if (IsDoubleClick(scr, event)) {
670 /* Middle or right mouse actions were handled on first click */
671 if (event->xbutton.button == Button1)
672 iconDblClick(desc, event);
673 return;
676 if (event->xbutton.button == Button2) {
677 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
679 if (wapp)
680 relaunchApplication(wapp);
682 return;
685 if (event->xbutton.button == Button3) {
686 WObjDescriptor *desc;
687 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
689 if (!wapp)
690 return;
692 if (event->xbutton.send_event &&
693 XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
694 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
695 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
696 wwarning("pointer grab failed for appicon menu");
697 return;
700 openApplicationMenu(wapp, event->xbutton.x_root, event->xbutton.y_root);
702 /* allow drag select of menu */
703 desc = &scr->icon_menu->menu->descriptor;
704 event->xbutton.send_event = True;
705 (*desc->handle_mousedown) (desc, event);
706 return;
709 if (event->xbutton.state & MOD_MASK)
710 wLowerFrame(icon->core);
711 else
712 wRaiseFrame(icon->core);
714 if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
715 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
716 GrabModeAsync, None, None, CurrentTime) != GrabSuccess)
717 wwarning("pointer grab failed for appicon move");
719 if (wPreferences.flags.nodock && wPreferences.flags.noclip)
720 dockable = 0;
721 else
722 dockable = canBeDocked(icon->owner);
724 wins[0] = icon->core->window;
725 wins[1] = scr->dock_shadow;
726 XRestackWindows(dpy, wins, 2);
727 if (superfluous) {
728 if (icon->pixmap != None)
729 ghost = MakeGhostIcon(scr, icon->pixmap);
730 else
731 ghost = MakeGhostIcon(scr, icon->core->window);
732 XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
733 XClearWindow(dpy, scr->dock_shadow);
736 while (!done) {
737 WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
738 | ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
739 switch (ev.type) {
740 case Expose:
741 WMHandleEvent(&ev);
742 break;
744 case EnterNotify:
745 /* It means the cursor moved so fast that it entered
746 * something else (if moving slowly, it would have
747 * stayed in the appIcon that is being moved. Ignore
748 * such "spurious" EnterNotifiy's */
749 break;
751 case MotionNotify:
752 hasMoved = True;
753 if (!grabbed) {
754 if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
755 || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
756 XChangeActivePointerGrab(dpy, ButtonMotionMask
757 | ButtonReleaseMask | ButtonPressMask,
758 wCursor[WCUR_MOVE], CurrentTime);
759 grabbed = 1;
760 } else {
761 break;
764 x = ev.xmotion.x_root - dx;
765 y = ev.xmotion.y_root - dy;
767 if (movingSingle)
768 XMoveWindow(dpy, icon->core->window, x, y);
769 else
770 wAppIconMove(aicon, x, y);
772 if (dockable) {
773 if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y, &ix, &iy, False)) {
774 shad_x = scr->dock->x_pos + ix * wPreferences.icon_size;
775 shad_y = scr->dock->y_pos + iy * wPreferences.icon_size;
777 if (scr->last_dock != scr->dock && collapsed) {
778 scr->last_dock->collapsed = 1;
779 wDockHideIcons(scr->last_dock);
780 collapsed = 0;
782 if (!collapsed && (collapsed = scr->dock->collapsed)) {
783 scr->dock->collapsed = 0;
784 wDockShowIcons(scr->dock);
787 if (scr->dock->auto_raise_lower)
788 wDockRaise(scr->dock);
790 scr->last_dock = scr->dock;
792 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
793 if (!docking)
794 XMapWindow(dpy, scr->dock_shadow);
796 docking = 1;
797 } else if (workspace->clip &&
798 wDockSnapIcon(workspace->clip, aicon, x, y, &ix, &iy, False)) {
799 shad_x = workspace->clip->x_pos + ix * wPreferences.icon_size;
800 shad_y = workspace->clip->y_pos + iy * wPreferences.icon_size;
802 if (scr->last_dock != workspace->clip && collapsed) {
803 scr->last_dock->collapsed = 1;
804 wDockHideIcons(scr->last_dock);
805 collapsed = 0;
807 if (!collapsed && (collapsed = workspace->clip->collapsed)) {
808 workspace->clip->collapsed = 0;
809 wDockShowIcons(workspace->clip);
812 if (workspace->clip->auto_raise_lower)
813 wDockRaise(workspace->clip);
815 scr->last_dock = workspace->clip;
817 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
818 if (!docking)
819 XMapWindow(dpy, scr->dock_shadow);
821 docking = 1;
822 } else if (docking) {
823 XUnmapWindow(dpy, scr->dock_shadow);
824 docking = 0;
827 break;
829 case ButtonPress:
830 break;
832 case ButtonRelease:
833 if (ev.xbutton.button != clickButton)
834 break;
835 XUngrabPointer(dpy, CurrentTime);
837 if (docking) {
838 Bool docked;
840 /* icon is trying to be docked */
841 SlideWindow(icon->core->window, x, y, shad_x, shad_y);
842 XUnmapWindow(dpy, scr->dock_shadow);
843 docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
844 if (scr->last_dock->auto_collapse)
845 collapsed = 0;
847 if (workspace->clip &&
848 workspace->clip != scr->last_dock && workspace->clip->auto_raise_lower)
849 wDockLower(workspace->clip);
851 if (!docked) {
852 /* If icon could not be docked, slide it back to the old
853 * position */
854 SlideWindow(icon->core->window, x, y, oldX, oldY);
856 } else {
857 if (movingSingle) {
858 /* move back to its place */
859 SlideWindow(icon->core->window, x, y, oldX, oldY);
860 wAppIconMove(aicon, oldX, oldY);
861 } else {
862 XMoveWindow(dpy, icon->core->window, x, y);
863 aicon->x_pos = x;
864 aicon->y_pos = y;
866 if (workspace->clip && workspace->clip->auto_raise_lower)
867 wDockLower(workspace->clip);
869 if (collapsed) {
870 scr->last_dock->collapsed = 1;
871 wDockHideIcons(scr->last_dock);
872 collapsed = 0;
874 if (superfluous) {
875 if (ghost != None)
876 XFreePixmap(dpy, ghost);
877 XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
880 if (wPreferences.auto_arrange_icons)
881 wArrangeIcons(scr, True);
883 if (wPreferences.single_click && !hasMoved)
884 iconDblClick(desc, event);
886 done = 1;
887 break;
892 /* This function save the application icon and store the path in the Dictionary */
893 void wApplicationSaveIconPathFor(char *iconPath, char *wm_instance, char *wm_class)
895 WMPropList *dict = WDWindowAttributes->dictionary;
896 WMPropList *adict, *key, *iconk;
897 WMPropList *val;
898 char *tmp;
900 tmp = get_name_for_instance_class(wm_instance, wm_class);
901 key = WMCreatePLString(tmp);
902 wfree(tmp);
904 adict = WMGetFromPLDictionary(dict, key);
905 iconk = WMCreatePLString("Icon");
907 if (adict) {
908 val = WMGetFromPLDictionary(adict, iconk);
909 } else {
910 /* no dictionary for app, so create one */
911 adict = WMCreatePLDictionary(NULL, NULL);
912 WMPutInPLDictionary(dict, key, adict);
913 WMReleasePropList(adict);
914 val = NULL;
917 if (!val) {
918 val = WMCreatePLString(iconPath);
919 WMPutInPLDictionary(adict, iconk, val);
920 WMReleasePropList(val);
921 } else {
922 val = NULL;
925 WMReleasePropList(key);
926 WMReleasePropList(iconk);
928 if (val && !wPreferences.flags.noupdates)
929 UpdateDomainFile(WDWindowAttributes);
932 /* Save the application icon */
933 /* This function is used by normal windows */
934 void save_app_icon(WApplication *wapp)
936 if (!wapp->app_icon)
937 return;
939 save_app_icon_core(wapp->app_icon);
942 static WAppIcon *findDockIconFor(WDock *dock, Window main_window)
944 WAppIcon *aicon = NULL;
946 aicon = wDockFindIconForWindow(dock, main_window);
947 if (!aicon) {
948 wDockTrackWindowLaunch(dock, main_window);
949 aicon = wDockFindIconForWindow(dock, main_window);
951 return aicon;
954 void app_icon_create_from_docks(WWindow *wwin, WApplication *wapp, Window main_window)
956 WScreen *scr = wwin->screen_ptr;
958 /* Create the application icon */
959 wapp->app_icon = NULL;
961 if (scr->last_dock)
962 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
964 /* check main dock if we did not find it in last dock */
965 if (!wapp->app_icon && scr->dock)
966 wapp->app_icon = findDockIconFor(scr->dock, main_window);
968 /* finally check clips */
969 if (!wapp->app_icon) {
970 int i;
971 for (i = 0; i < scr->workspace_count; i++) {
972 WDock *dock = scr->workspaces[i]->clip;
973 if (dock)
974 wapp->app_icon = findDockIconFor(dock, main_window);
975 if (wapp->app_icon)
976 break;
980 /* If created, then set some flags */
981 if (wapp->app_icon) {
982 WWindow *mainw = wapp->main_window_desc;
984 wapp->app_icon->running = 1;
985 wapp->app_icon->icon->force_paint = 1;
986 wapp->app_icon->icon->owner = mainw;
987 if (mainw->wm_hints && (mainw->wm_hints->flags & IconWindowHint))
988 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
990 wAppIconPaint(wapp->app_icon);
991 wAppIconSave(wapp->app_icon);
992 } else {
993 wapp->app_icon = wAppIconCreate(wapp->main_window_desc);