Icon: Make icon_create_for_* be more similar
[wmaker-crm.git] / src / appicon.c
bloba90e35b24c68f75c80bc637f3eb317c4ffe87d18
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 paint_app_icon(WApplication *wapp)
162 WIcon *icon;
163 WScreen *scr = wapp->main_window_desc->screen_ptr;
164 WDock *clip = scr->workspaces[scr->current_workspace]->clip;
165 int x = 0, y = 0;
167 if (!wapp || !wapp->app_icon)
168 return;
170 icon = wapp->app_icon->icon;
171 wapp->app_icon->main_window = wapp->main_window;
173 /* If the icon is docked, don't continue */
174 if (wapp->app_icon->docked)
175 return;
177 if (clip && clip->attract_icons && wDockFindFreeSlot(clip, &x, &y)) {
178 wapp->app_icon->attracted = 1;
179 if (!icon->shadowed) {
180 icon->shadowed = 1;
181 icon->force_paint = 1;
183 wDockAttachIcon(clip, wapp->app_icon, x, y);
184 } else {
185 PlaceIcon(scr, &x, &y, wGetHeadForWindow(wapp->main_window_desc));
186 wAppIconMove(wapp->app_icon, x, y);
187 wLowerFrame(icon->core);
190 if (!clip || !wapp->app_icon->attracted || !clip->collapsed)
191 XMapWindow(dpy, icon->core->window);
193 if (wPreferences.auto_arrange_icons && !wapp->app_icon->attracted)
194 wArrangeIcons(scr, True);
197 void removeAppIconFor(WApplication * wapp)
199 if (!wapp->app_icon)
200 return;
202 if (wapp->app_icon->docked && !wapp->app_icon->attracted) {
203 wapp->app_icon->running = 0;
204 /* since we keep it, we don't care if it was attracted or not */
205 wapp->app_icon->attracted = 0;
206 wapp->app_icon->icon->shadowed = 0;
207 wapp->app_icon->main_window = None;
208 wapp->app_icon->pid = 0;
209 wapp->app_icon->icon->owner = NULL;
210 wapp->app_icon->icon->icon_win = None;
211 wapp->app_icon->icon->force_paint = 1;
212 wAppIconPaint(wapp->app_icon);
213 } else if (wapp->app_icon->docked) {
214 wapp->app_icon->running = 0;
215 wDockDetach(wapp->app_icon->dock, wapp->app_icon);
216 } else {
217 wAppIconDestroy(wapp->app_icon);
220 wapp->app_icon = NULL;
222 if (wPreferences.auto_arrange_icons)
223 wArrangeIcons(wapp->main_window_desc->screen_ptr, True);
226 static WAppIcon *wAppIconCreate(WWindow *leader_win)
228 WAppIcon *aicon;
229 WScreen *scr = leader_win->screen_ptr;
231 aicon = wmalloc(sizeof(WAppIcon));
232 wretain(aicon);
233 aicon->yindex = -1;
234 aicon->xindex = -1;
236 /* When no_appicon is set we want to avoid having it on the list
237 * because otherwise there will be a hole when the icons are
238 * arranged with wArrangeIcons() */
239 if (!WFLAGP(leader_win, no_appicon))
240 add_to_appicon_list(scr, aicon);
242 if (leader_win->wm_class)
243 aicon->wm_class = wstrdup(leader_win->wm_class);
245 if (leader_win->wm_instance)
246 aicon->wm_instance = wstrdup(leader_win->wm_instance);
248 aicon->icon = icon_create_for_wwindow(leader_win);
249 #ifdef XDND
250 wXDNDMakeAwareness(aicon->icon->core->window);
251 #endif
253 /* will be overriden if docked */
254 aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
255 aicon->icon->core->descriptor.handle_expose = iconExpose;
256 aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
257 aicon->icon->core->descriptor.parent = aicon;
258 AddToStackList(aicon->icon->core);
259 aicon->icon->show_title = 0;
261 return aicon;
264 void wAppIconDestroy(WAppIcon * aicon)
266 WScreen *scr = aicon->icon->core->screen_ptr;
268 RemoveFromStackList(aicon->icon->core);
269 wIconDestroy(aicon->icon);
270 if (aicon->command)
271 wfree(aicon->command);
272 #ifdef XDND
273 if (aicon->dnd_command)
274 wfree(aicon->dnd_command);
275 #endif
276 if (aicon->wm_instance)
277 wfree(aicon->wm_instance);
279 if (aicon->wm_class)
280 wfree(aicon->wm_class);
282 remove_from_appicon_list(scr, aicon);
284 aicon->destroyed = 1;
285 wrelease(aicon);
288 static void drawCorner(WIcon * icon)
290 WScreen *scr = icon->core->screen_ptr;
291 XPoint points[3];
293 points[0].x = 1;
294 points[0].y = 1;
295 points[1].x = 12;
296 points[1].y = 1;
297 points[2].x = 1;
298 points[2].y = 12;
299 XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
300 points, 3, Convex, CoordModeOrigin);
301 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 0, 12);
302 XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc, 0, 0, 12, 0);
305 void wAppIconMove(WAppIcon * aicon, int x, int y)
307 XMoveWindow(dpy, aicon->icon->core->window, x, y);
308 aicon->x_pos = x;
309 aicon->y_pos = y;
312 #ifdef WS_INDICATOR
313 static void updateDockNumbers(WScreen * scr)
315 int length;
316 char *ws_numbers;
317 WAppIcon *dicon = scr->dock->icon_array[0];
319 ws_numbers = wmalloc(20);
320 snprintf(ws_numbers, 20, "%i [ %i ]", scr->current_workspace + 1, ((scr->current_workspace / 10) + 1));
321 length = strlen(ws_numbers);
323 XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, WMFontHeight(scr->icon_title_font) + 1, False);
325 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->black,
326 scr->icon_title_font, 4, 3, ws_numbers, length);
328 WMDrawString(scr->wmscreen, dicon->icon->core->window, scr->white,
329 scr->icon_title_font, 3, 2, ws_numbers, length);
331 wfree(ws_numbers);
333 #endif /* WS_INDICATOR */
335 void wAppIconPaint(WAppIcon * aicon)
337 WApplication *wapp;
338 WScreen *scr = aicon->icon->core->screen_ptr;
340 if (aicon->icon->owner)
341 wapp = wApplicationOf(aicon->icon->owner->main_window);
342 else
343 wapp = NULL;
345 wIconPaint(aicon->icon);
347 # ifdef WS_INDICATOR
348 if (aicon->docked && scr->dock && scr->dock == aicon->dock && aicon->yindex == 0)
349 updateDockNumbers(scr);
350 # endif
351 if (scr->dock_dots && aicon->docked && !aicon->running && aicon->command != NULL) {
352 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
353 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
354 XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
355 scr->copy_gc, 0, 0, scr->dock_dots->width, scr->dock_dots->height, 0, 0);
357 #ifdef HIDDENDOT
358 if (wapp && wapp->flags.hidden) {
359 XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
360 XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
361 XCopyArea(dpy, scr->dock_dots->image,
362 aicon->icon->core->window, scr->copy_gc, 0, 0, 7, scr->dock_dots->height, 0, 0);
364 #endif /* HIDDENDOT */
366 if (aicon->omnipresent)
367 drawCorner(aicon->icon);
369 XSetClipMask(dpy, scr->copy_gc, None);
370 if (aicon->launching)
371 XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
372 0, 0, wPreferences.icon_size, wPreferences.icon_size);
375 /* Save the application icon, if it's a dockapp then use it with dock = True */
376 void save_appicon(WAppIcon *aicon, Bool dock)
378 char *path;
380 if (!aicon)
381 return;
383 if (dock && (!aicon->docked || aicon->attracted))
384 return;
386 path = wIconStore(aicon->icon);
387 if (!path)
388 return;
390 wApplicationSaveIconPathFor(path, aicon->wm_instance, aicon->wm_class);
391 wfree(path);
394 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
396 /* main_window may not have the full command line; try to find one which does */
397 static void relaunchApplication(WApplication *wapp)
399 WScreen *scr;
400 WWindow *wlist, *next;
402 scr = wapp->main_window_desc->screen_ptr;
403 wlist = scr->focused_window;
404 if (! wlist)
405 return;
407 while (wlist->prev)
408 wlist = wlist->prev;
410 while (wlist) {
411 next = wlist->next;
413 if (wlist->main_window == wapp->main_window) {
414 if (RelaunchWindow(wlist))
415 return;
418 wlist = next;
422 static void relaunchCallback(WMenu * menu, WMenuEntry * entry)
424 WApplication *wapp = (WApplication *) entry->clientdata;
426 relaunchApplication(wapp);
429 static void hideCallback(WMenu * menu, WMenuEntry * entry)
431 WApplication *wapp = (WApplication *) entry->clientdata;
433 if (wapp->flags.hidden) {
434 wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
435 wUnhideApplication(wapp, False, False);
436 } else {
437 wHideApplication(wapp);
441 static void unhideHereCallback(WMenu * menu, WMenuEntry * entry)
443 WApplication *wapp = (WApplication *) entry->clientdata;
445 wUnhideApplication(wapp, False, True);
448 static void setIconCallback(WMenu * menu, WMenuEntry * entry)
450 WAppIcon *icon = ((WApplication *) entry->clientdata)->app_icon;
451 char *file = NULL;
452 WScreen *scr;
453 int result;
455 assert(icon != NULL);
457 if (icon->editing)
458 return;
460 icon->editing = 1;
461 scr = icon->icon->core->screen_ptr;
463 wretain(icon);
465 result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
467 if (result && !icon->destroyed) {
468 if (file && *file == 0) {
469 wfree(file);
470 file = NULL;
472 if (!wIconChangeImageFile(icon->icon, file)) {
473 wMessageDialog(scr, _("Error"),
474 _("Could not open specified icon file"), _("OK"), NULL, NULL);
475 } else {
476 wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
477 wAppIconPaint(icon);
479 if (file)
480 wfree(file);
482 icon->editing = 0;
483 wrelease(icon);
486 static void killCallback(WMenu * menu, WMenuEntry * entry)
488 WApplication *wapp = (WApplication *) entry->clientdata;
489 WFakeGroupLeader *fPtr;
490 char *buffer;
491 char *shortname;
492 char *basename(const char *shortname);
494 if (!WCHECK_STATE(WSTATE_NORMAL))
495 return;
497 WCHANGE_STATE(WSTATE_MODAL);
499 assert(entry->clientdata != NULL);
501 shortname = basename(wapp->app_icon->wm_instance);
503 buffer = wstrconcat(wapp->app_icon ? shortname : NULL,
504 _(" will be forcibly closed.\n"
505 "Any unsaved changes will be lost.\n" "Please confirm."));
507 fPtr = wapp->main_window_desc->fake_group;
509 wretain(wapp->main_window_desc);
510 if (wPreferences.dont_confirm_kill
511 || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
512 buffer, _("Yes"), _("No"), NULL) == WAPRDefault) {
513 if (fPtr != NULL) {
514 WWindow *wwin, *twin;
516 wwin = wapp->main_window_desc->screen_ptr->focused_window;
517 while (wwin) {
518 twin = wwin->prev;
519 if (wwin->fake_group == fPtr)
520 wClientKill(wwin);
521 wwin = twin;
523 } else if (!wapp->main_window_desc->flags.destroyed) {
524 wClientKill(wapp->main_window_desc);
527 wrelease(wapp->main_window_desc);
528 wfree(buffer);
529 WCHANGE_STATE(WSTATE_NORMAL);
532 static WMenu *createApplicationMenu(WScreen * scr)
534 WMenu *menu;
536 menu = wMenuCreate(scr, NULL, False);
537 wMenuAddCallback(menu, _("Launch"), relaunchCallback, NULL);
538 wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
539 wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
540 wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
541 wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
543 return menu;
546 static void openApplicationMenu(WApplication * wapp, int x, int y)
548 WMenu *menu;
549 WScreen *scr = wapp->main_window_desc->screen_ptr;
550 int i;
552 if (!scr->icon_menu) {
553 scr->icon_menu = createApplicationMenu(scr);
554 wfree(scr->icon_menu->entries[1]->text);
557 menu = scr->icon_menu;
559 if (wapp->flags.hidden)
560 menu->entries[1]->text = _("Unhide");
561 else
562 menu->entries[1]->text = _("Hide");
564 menu->flags.realized = 0;
565 wMenuRealize(menu);
567 x -= menu->frame->core->width / 2;
568 if (x + menu->frame->core->width > scr->scr_width)
569 x = scr->scr_width - menu->frame->core->width;
571 if (x < 0)
572 x = 0;
574 /* set client data */
575 for (i = 0; i < menu->entry_no; i++)
576 menu->entries[i]->clientdata = wapp;
578 wMenuMapAt(menu, x, y, False);
581 /******************************************************************/
583 static void iconExpose(WObjDescriptor * desc, XEvent * event)
585 wAppIconPaint(desc->parent);
588 static void iconDblClick(WObjDescriptor * desc, XEvent * event)
590 WAppIcon *aicon = desc->parent;
591 WApplication *wapp;
592 WScreen *scr = aicon->icon->core->screen_ptr;
593 int unhideHere;
595 assert(aicon->icon->owner != NULL);
597 wapp = wApplicationOf(aicon->icon->owner->main_window);
599 if (event->xbutton.state & ControlMask) {
600 relaunchApplication(wapp);
601 return;
604 unhideHere = (event->xbutton.state & ShiftMask);
605 /* go to the last workspace that the user worked on the app */
606 if (!unhideHere && wapp->last_workspace != scr->current_workspace)
607 wWorkspaceChange(scr, wapp->last_workspace);
609 wUnhideApplication(wapp, event->xbutton.button == Button2, unhideHere);
611 if (event->xbutton.state & MOD_MASK)
612 wHideOtherApplications(aicon->icon->owner);
615 void appIconMouseDown(WObjDescriptor * desc, XEvent * event)
617 WAppIcon *aicon = desc->parent;
618 WIcon *icon = aicon->icon;
619 XEvent ev;
620 int x = aicon->x_pos, y = aicon->y_pos;
621 int dx = event->xbutton.x, dy = event->xbutton.y;
622 int grabbed = 0;
623 int done = 0;
624 int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
625 WScreen *scr = icon->core->screen_ptr;
626 WWorkspace *workspace = scr->workspaces[scr->current_workspace];
627 int shad_x = 0, shad_y = 0, docking = 0, dockable, collapsed = 0;
628 int ix, iy;
629 int clickButton = event->xbutton.button;
630 Pixmap ghost = None;
631 Window wins[2];
632 Bool movingSingle = False;
633 int oldX = x;
634 int oldY = y;
635 Bool hasMoved = False;
637 if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
638 return;
640 if (IsDoubleClick(scr, event)) {
641 /* Middle or right mouse actions were handled on first click */
642 if (event->xbutton.button == Button1)
643 iconDblClick(desc, event);
644 return;
647 if (event->xbutton.button == Button2) {
648 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
650 if (wapp)
651 relaunchApplication(wapp);
653 return;
656 if (event->xbutton.button == Button3) {
657 WObjDescriptor *desc;
658 WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
660 if (!wapp)
661 return;
663 if (event->xbutton.send_event &&
664 XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
665 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
666 GrabModeAsync, None, None, CurrentTime) != GrabSuccess) {
667 wwarning("pointer grab failed for appicon menu");
668 return;
671 openApplicationMenu(wapp, event->xbutton.x_root, event->xbutton.y_root);
673 /* allow drag select of menu */
674 desc = &scr->icon_menu->menu->descriptor;
675 event->xbutton.send_event = True;
676 (*desc->handle_mousedown) (desc, event);
677 return;
680 if (event->xbutton.state & MOD_MASK)
681 wLowerFrame(icon->core);
682 else
683 wRaiseFrame(icon->core);
685 if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
686 | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
687 GrabModeAsync, None, None, CurrentTime) != GrabSuccess)
688 wwarning("pointer grab failed for appicon move");
690 if (wPreferences.flags.nodock && wPreferences.flags.noclip)
691 dockable = 0;
692 else
693 dockable = canBeDocked(icon->owner);
695 wins[0] = icon->core->window;
696 wins[1] = scr->dock_shadow;
697 XRestackWindows(dpy, wins, 2);
698 if (superfluous) {
699 if (icon->pixmap != None)
700 ghost = MakeGhostIcon(scr, icon->pixmap);
701 else
702 ghost = MakeGhostIcon(scr, icon->core->window);
703 XSetWindowBackgroundPixmap(dpy, scr->dock_shadow, ghost);
704 XClearWindow(dpy, scr->dock_shadow);
707 while (!done) {
708 WMMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
709 | ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
710 switch (ev.type) {
711 case Expose:
712 WMHandleEvent(&ev);
713 break;
715 case EnterNotify:
716 /* It means the cursor moved so fast that it entered
717 * something else (if moving slowly, it would have
718 * stayed in the appIcon that is being moved. Ignore
719 * such "spurious" EnterNotifiy's */
720 break;
722 case MotionNotify:
723 hasMoved = True;
724 if (!grabbed) {
725 if (abs(dx - ev.xmotion.x) >= MOVE_THRESHOLD
726 || abs(dy - ev.xmotion.y) >= MOVE_THRESHOLD) {
727 XChangeActivePointerGrab(dpy, ButtonMotionMask
728 | ButtonReleaseMask | ButtonPressMask,
729 wCursor[WCUR_MOVE], CurrentTime);
730 grabbed = 1;
731 } else {
732 break;
735 x = ev.xmotion.x_root - dx;
736 y = ev.xmotion.y_root - dy;
738 if (movingSingle)
739 XMoveWindow(dpy, icon->core->window, x, y);
740 else
741 wAppIconMove(aicon, x, y);
743 if (dockable) {
744 if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y, &ix, &iy, False)) {
745 shad_x = scr->dock->x_pos + ix * wPreferences.icon_size;
746 shad_y = scr->dock->y_pos + iy * wPreferences.icon_size;
748 if (scr->last_dock != scr->dock && collapsed) {
749 scr->last_dock->collapsed = 1;
750 wDockHideIcons(scr->last_dock);
751 collapsed = 0;
753 if (!collapsed && (collapsed = scr->dock->collapsed)) {
754 scr->dock->collapsed = 0;
755 wDockShowIcons(scr->dock);
758 if (scr->dock->auto_raise_lower)
759 wDockRaise(scr->dock);
761 scr->last_dock = scr->dock;
763 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
764 if (!docking)
765 XMapWindow(dpy, scr->dock_shadow);
767 docking = 1;
768 } else if (workspace->clip &&
769 wDockSnapIcon(workspace->clip, aicon, x, y, &ix, &iy, False)) {
770 shad_x = workspace->clip->x_pos + ix * wPreferences.icon_size;
771 shad_y = workspace->clip->y_pos + iy * wPreferences.icon_size;
773 if (scr->last_dock != workspace->clip && collapsed) {
774 scr->last_dock->collapsed = 1;
775 wDockHideIcons(scr->last_dock);
776 collapsed = 0;
778 if (!collapsed && (collapsed = workspace->clip->collapsed)) {
779 workspace->clip->collapsed = 0;
780 wDockShowIcons(workspace->clip);
783 if (workspace->clip->auto_raise_lower)
784 wDockRaise(workspace->clip);
786 scr->last_dock = workspace->clip;
788 XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
789 if (!docking)
790 XMapWindow(dpy, scr->dock_shadow);
792 docking = 1;
793 } else if (docking) {
794 XUnmapWindow(dpy, scr->dock_shadow);
795 docking = 0;
798 break;
800 case ButtonPress:
801 break;
803 case ButtonRelease:
804 if (ev.xbutton.button != clickButton)
805 break;
806 XUngrabPointer(dpy, CurrentTime);
808 if (docking) {
809 Bool docked;
811 /* icon is trying to be docked */
812 SlideWindow(icon->core->window, x, y, shad_x, shad_y);
813 XUnmapWindow(dpy, scr->dock_shadow);
814 docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
815 if (scr->last_dock->auto_collapse)
816 collapsed = 0;
818 if (workspace->clip &&
819 workspace->clip != scr->last_dock && workspace->clip->auto_raise_lower)
820 wDockLower(workspace->clip);
822 if (!docked) {
823 /* If icon could not be docked, slide it back to the old
824 * position */
825 SlideWindow(icon->core->window, x, y, oldX, oldY);
827 } else {
828 if (movingSingle) {
829 /* move back to its place */
830 SlideWindow(icon->core->window, x, y, oldX, oldY);
831 wAppIconMove(aicon, oldX, oldY);
832 } else {
833 XMoveWindow(dpy, icon->core->window, x, y);
834 aicon->x_pos = x;
835 aicon->y_pos = y;
837 if (workspace->clip && workspace->clip->auto_raise_lower)
838 wDockLower(workspace->clip);
840 if (collapsed) {
841 scr->last_dock->collapsed = 1;
842 wDockHideIcons(scr->last_dock);
843 collapsed = 0;
845 if (superfluous) {
846 if (ghost != None)
847 XFreePixmap(dpy, ghost);
848 XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
851 if (wPreferences.auto_arrange_icons)
852 wArrangeIcons(scr, True);
854 if (wPreferences.single_click && !hasMoved)
855 iconDblClick(desc, event);
857 done = 1;
858 break;
863 /* This function save the application icon and store the path in the Dictionary */
864 static void wApplicationSaveIconPathFor(char *iconPath, char *wm_instance, char *wm_class)
866 WMPropList *dict = WDWindowAttributes->dictionary;
867 WMPropList *adict, *key, *iconk;
868 WMPropList *val;
869 char *tmp;
871 tmp = get_name_for_instance_class(wm_instance, wm_class);
872 key = WMCreatePLString(tmp);
873 wfree(tmp);
875 adict = WMGetFromPLDictionary(dict, key);
876 iconk = WMCreatePLString("Icon");
878 if (adict) {
879 val = WMGetFromPLDictionary(adict, iconk);
880 } else {
881 /* no dictionary for app, so create one */
882 adict = WMCreatePLDictionary(NULL, NULL);
883 WMPutInPLDictionary(dict, key, adict);
884 WMReleasePropList(adict);
885 val = NULL;
888 if (!val) {
889 val = WMCreatePLString(iconPath);
890 WMPutInPLDictionary(adict, iconk, val);
891 WMReleasePropList(val);
892 } else {
893 val = NULL;
896 WMReleasePropList(key);
897 WMReleasePropList(iconk);
899 if (val && !wPreferences.flags.noupdates)
900 UpdateDomainFile(WDWindowAttributes);
903 static WAppIcon *findDockIconFor(WDock *dock, Window main_window)
905 WAppIcon *aicon = NULL;
907 aicon = wDockFindIconForWindow(dock, main_window);
908 if (!aicon) {
909 wDockTrackWindowLaunch(dock, main_window);
910 aicon = wDockFindIconForWindow(dock, main_window);
912 return aicon;
915 void create_appicon_from_dock(WWindow *wwin, WApplication *wapp, Window main_window)
917 WScreen *scr = wwin->screen_ptr;
918 wapp->app_icon = NULL;
920 if (scr->last_dock)
921 wapp->app_icon = findDockIconFor(scr->last_dock, main_window);
923 /* check main dock if we did not find it in last dock */
924 if (!wapp->app_icon && scr->dock)
925 wapp->app_icon = findDockIconFor(scr->dock, main_window);
927 /* finally check clips */
928 if (!wapp->app_icon) {
929 int i;
930 for (i = 0; i < scr->workspace_count; i++) {
931 WDock *dock = scr->workspaces[i]->clip;
932 if (dock)
933 wapp->app_icon = findDockIconFor(dock, main_window);
934 if (wapp->app_icon)
935 break;
939 /* If created, then set some flags */
940 if (wapp->app_icon) {
941 WWindow *mainw = wapp->main_window_desc;
943 wapp->app_icon->running = 1;
944 wapp->app_icon->icon->force_paint = 1;
945 wapp->app_icon->icon->owner = mainw;
946 if (mainw->wm_hints && (mainw->wm_hints->flags & IconWindowHint))
947 wapp->app_icon->icon->icon_win = mainw->wm_hints->icon_window;
949 wAppIconPaint(wapp->app_icon);
950 save_appicon(wapp->app_icon, True);
954 /* Add the appicon to the appiconlist */
955 static void add_to_appicon_list(WScreen *scr, WAppIcon *appicon)
957 appicon->prev = NULL;
958 appicon->next = scr->app_icon_list;
959 if (scr->app_icon_list)
960 scr->app_icon_list->prev = appicon;
962 scr->app_icon_list = appicon;
965 /* Remove the appicon from the appiconlist */
966 static void remove_from_appicon_list(WScreen *scr, WAppIcon *appicon)
968 if (appicon == scr->app_icon_list) {
969 if (appicon->next)
970 appicon->next->prev = NULL;
971 scr->app_icon_list = appicon->next;
972 } else {
973 if (appicon->next)
974 appicon->next->prev = appicon->prev;
975 if (appicon->prev)
976 appicon->prev->next = appicon->next;