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.
26 #include <X11/Xutil.h>
33 #include "WindowMaker.h"
36 #include "application.h"
43 #include "workspace.h"
44 #include "superfluous.h"
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
;
63 extern XContext wWinContext
;
65 #define MOD_MASK wPreferences.modifier_mask
66 #define ICON_SIZE wPreferences.icon_size
68 void appIconMouseDown(WObjDescriptor
* desc
, XEvent
* event
);
69 static void iconDblClick(WObjDescriptor
* desc
, XEvent
* event
);
70 static void iconExpose(WObjDescriptor
* desc
, XEvent
* event
);
71 static void wApplicationSaveIconPathFor(char *iconPath
, char *wm_instance
, char *wm_class
);
72 static WAppIcon
*wAppIconCreate(WWindow
* leader_win
);
73 static void add_to_appicon_list(WScreen
*scr
, WAppIcon
*appicon
);
74 static void remove_from_appicon_list(WScreen
*scr
, WAppIcon
*appicon
);
75 static void create_appicon_from_dock(WWindow
*wwin
, WApplication
*wapp
, Window main_window
);
77 /* This function is used if the application is a .app. It checks if it has an icon in it
78 * like for example /usr/local/GNUstep/Applications/WPrefs.app/WPrefs.tiff
80 void wApplicationExtractDirPackIcon(WScreen
* scr
, char *path
, char *wm_instance
, char *wm_class
)
82 char *iconPath
= NULL
;
85 if (strstr(path
, ".app")) {
86 tmp
= wmalloc(strlen(path
) + 16);
88 if (scr
->flags
.supports_tiff
) {
91 if (access(tmp
, R_OK
) == 0)
98 if (access(tmp
, R_OK
) == 0)
106 wApplicationSaveIconPathFor(iconPath
, wm_instance
, wm_class
);
112 WAppIcon
*wAppIconCreateForDock(WScreen
*scr
, char *command
, char *wm_instance
, char *wm_class
, int tile
)
116 aicon
= wmalloc(sizeof(WAppIcon
));
121 add_to_appicon_list(scr
, aicon
);
124 aicon
->command
= wstrdup(command
);
127 aicon
->wm_class
= wstrdup(wm_class
);
130 aicon
->wm_instance
= wstrdup(wm_instance
);
132 if (strcmp(wm_class
, "WMDock") == 0 && wPreferences
.flags
.clip_merged_in_dock
)
134 aicon
->icon
= icon_create_for_dock(scr
, command
, wm_instance
, wm_class
, tile
);
137 wXDNDMakeAwareness(aicon
->icon
->core
->window
);
140 /* will be overriden by dock */
141 aicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
142 aicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
143 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
144 aicon
->icon
->core
->descriptor
.parent
= aicon
;
145 AddToStackList(aicon
->icon
->core
);
150 void create_appicon_for_application(WApplication
*wapp
, WWindow
*wwin
)
152 /* Try to create an icon from the dock or clip */
153 create_appicon_from_dock(wwin
, wapp
, wapp
->main_window
);
155 /* If app_icon was not found, create it */
156 if (!wapp
->app_icon
) {
157 /* Create the icon */
158 wapp
->app_icon
= wAppIconCreate(wapp
->main_window_desc
);
159 wIconUpdate(wapp
->app_icon
->icon
, NULL
);
161 /* Now, paint the icon */
162 if (!WFLAGP(wapp
->main_window_desc
, no_appicon
))
163 paint_app_icon(wapp
);
166 /* Save the app_icon in a file */
167 save_appicon(wapp
->app_icon
, False
);
170 void unpaint_app_icon(WApplication
*wapp
)
176 if (!wapp
|| !wapp
->app_icon
)
179 aicon
= wapp
->app_icon
;
181 /* If the icon is docked, don't continue */
185 scr
= wapp
->main_window_desc
->screen_ptr
;
186 clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
188 if (!clip
|| !aicon
->attracted
|| !clip
->collapsed
)
189 XUnmapWindow(dpy
, aicon
->icon
->core
->window
);
191 /* We want to avoid having it on the list because otherwise
192 * there will be a hole when the icons are arranged with
194 remove_from_appicon_list(scr
, aicon
);
196 if (wPreferences
.auto_arrange_icons
&& !aicon
->attracted
)
197 wArrangeIcons(scr
, True
);
200 void paint_app_icon(WApplication
*wapp
)
203 WScreen
*scr
= wapp
->main_window_desc
->screen_ptr
;
204 WDock
*attracting_dock
;
206 Bool update_icon
= False
;
208 if (!wapp
|| !wapp
->app_icon
)
211 icon
= wapp
->app_icon
->icon
;
212 wapp
->app_icon
->main_window
= wapp
->main_window
;
214 /* If the icon is docked, don't continue */
215 if (wapp
->app_icon
->docked
)
218 attracting_dock
= scr
->attracting_drawer
!= NULL
?
219 scr
->attracting_drawer
:
220 scr
->workspaces
[scr
->current_workspace
]->clip
;
221 if (attracting_dock
&& attracting_dock
->attract_icons
&&
222 wDockFindFreeSlot(attracting_dock
, &x
, &y
)) {
223 wapp
->app_icon
->attracted
= 1;
224 if (!icon
->shadowed
) {
228 wDockAttachIcon(attracting_dock
, wapp
->app_icon
, x
, y
, update_icon
);
230 /* We must know if the icon is painted in the screen,
231 * because if painted, then PlaceIcon will return the next
232 * space on the screen, and the icon will move */
233 if (wapp
->app_icon
->next
== NULL
&& wapp
->app_icon
->prev
== NULL
) {
234 PlaceIcon(scr
, &x
, &y
, wGetHeadForWindow(wapp
->main_window_desc
));
235 wAppIconMove(wapp
->app_icon
, x
, y
);
236 wLowerFrame(icon
->core
);
240 /* If we want appicon (no_appicon is not set) and the icon is not
241 * in the appicon_list, we must add it. Else, we want to avoid
242 * having it on the list */
243 if (!WFLAGP(wapp
->main_window_desc
, no_appicon
) &&
244 wapp
->app_icon
->next
== NULL
&& wapp
->app_icon
->prev
== NULL
)
245 add_to_appicon_list(scr
, wapp
->app_icon
);
247 if (!attracting_dock
|| !wapp
->app_icon
->attracted
|| !attracting_dock
->collapsed
)
248 XMapWindow(dpy
, icon
->core
->window
);
250 if (wPreferences
.auto_arrange_icons
&& !wapp
->app_icon
->attracted
)
251 wArrangeIcons(scr
, True
);
254 void removeAppIconFor(WApplication
*wapp
)
259 if (wPreferences
.highlight_active_app
)
260 wIconSetHighlited(wapp
->app_icon
->icon
, False
);
261 if (wapp
->app_icon
->docked
&& !wapp
->app_icon
->attracted
) {
262 wapp
->app_icon
->running
= 0;
263 /* since we keep it, we don't care if it was attracted or not */
264 wapp
->app_icon
->attracted
= 0;
265 wapp
->app_icon
->icon
->shadowed
= 0;
266 wapp
->app_icon
->main_window
= None
;
267 wapp
->app_icon
->pid
= 0;
268 wapp
->app_icon
->icon
->owner
= NULL
;
269 wapp
->app_icon
->icon
->icon_win
= None
;
271 /* Set the icon image */
272 set_icon_image_from_database(wapp
->app_icon
->icon
, wapp
->app_icon
->wm_instance
,
273 wapp
->app_icon
->wm_class
, wapp
->app_icon
->command
);
276 wAppIconPaint(wapp
->app_icon
);
277 } else if (wapp
->app_icon
->docked
) {
278 wapp
->app_icon
->running
= 0;
279 if (wapp
->app_icon
->dock
->type
== WM_DRAWER
) {
280 wDrawerFillTheGap(wapp
->app_icon
->dock
, wapp
->app_icon
, True
);
282 wDockDetach(wapp
->app_icon
->dock
, wapp
->app_icon
);
284 wAppIconDestroy(wapp
->app_icon
);
287 wapp
->app_icon
= NULL
;
289 if (wPreferences
.auto_arrange_icons
)
290 wArrangeIcons(wapp
->main_window_desc
->screen_ptr
, True
);
293 static WAppIcon
*wAppIconCreate(WWindow
*leader_win
)
297 aicon
= wmalloc(sizeof(WAppIcon
));
304 if (leader_win
->wm_class
)
305 aicon
->wm_class
= wstrdup(leader_win
->wm_class
);
307 if (leader_win
->wm_instance
)
308 aicon
->wm_instance
= wstrdup(leader_win
->wm_instance
);
310 aicon
->icon
= icon_create_for_wwindow(leader_win
);
312 wXDNDMakeAwareness(aicon
->icon
->core
->window
);
315 /* will be overriden if docked */
316 aicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
317 aicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
318 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
319 aicon
->icon
->core
->descriptor
.parent
= aicon
;
320 AddToStackList(aicon
->icon
->core
);
321 aicon
->icon
->show_title
= 0;
326 void wAppIconDestroy(WAppIcon
* aicon
)
328 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
330 RemoveFromStackList(aicon
->icon
->core
);
331 wIconDestroy(aicon
->icon
);
333 wfree(aicon
->command
);
335 if (aicon
->dnd_command
)
336 wfree(aicon
->dnd_command
);
338 if (aicon
->wm_instance
)
339 wfree(aicon
->wm_instance
);
342 wfree(aicon
->wm_class
);
344 remove_from_appicon_list(scr
, aicon
);
346 aicon
->destroyed
= 1;
350 static void drawCorner(WIcon
* icon
)
352 WScreen
*scr
= icon
->core
->screen_ptr
;
361 XFillPolygon(dpy
, icon
->core
->window
, scr
->icon_title_texture
->normal_gc
,
362 points
, 3, Convex
, CoordModeOrigin
);
363 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
, 0, 0, 0, 12);
364 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
, 0, 0, 12, 0);
367 void wAppIconMove(WAppIcon
* aicon
, int x
, int y
)
369 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x
, y
);
375 static void updateDockNumbers(WScreen
* scr
)
379 WAppIcon
*dicon
= scr
->dock
->icon_array
[0];
381 ws_numbers
= wmalloc(20);
382 snprintf(ws_numbers
, 20, "%i [ %i ]", scr
->current_workspace
+ 1, ((scr
->current_workspace
/ 10) + 1));
383 length
= strlen(ws_numbers
);
385 XClearArea(dpy
, dicon
->icon
->core
->window
, 2, 2, 50, WMFontHeight(scr
->icon_title_font
) + 1, False
);
387 WMDrawString(scr
->wmscreen
, dicon
->icon
->core
->window
, scr
->black
,
388 scr
->icon_title_font
, 4, 3, ws_numbers
, length
);
390 WMDrawString(scr
->wmscreen
, dicon
->icon
->core
->window
, scr
->white
,
391 scr
->icon_title_font
, 3, 2, ws_numbers
, length
);
395 #endif /* WS_INDICATOR */
397 void wAppIconPaint(WAppIcon
*aicon
)
400 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
402 if (aicon
->icon
->owner
)
403 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
407 wIconPaint(aicon
->icon
);
410 if (aicon
->docked
&& scr
->dock
&& scr
->dock
== aicon
->dock
&& aicon
->yindex
== 0)
411 updateDockNumbers(scr
);
413 if (scr
->dock_dots
&& aicon
->docked
&& !aicon
->running
&& aicon
->command
!= NULL
) {
414 XSetClipMask(dpy
, scr
->copy_gc
, scr
->dock_dots
->mask
);
415 XSetClipOrigin(dpy
, scr
->copy_gc
, 0, 0);
416 XCopyArea(dpy
, scr
->dock_dots
->image
, aicon
->icon
->core
->window
,
417 scr
->copy_gc
, 0, 0, scr
->dock_dots
->width
, scr
->dock_dots
->height
, 0, 0);
420 if (wapp
&& wapp
->flags
.hidden
) {
421 XSetClipMask(dpy
, scr
->copy_gc
, scr
->dock_dots
->mask
);
422 XSetClipOrigin(dpy
, scr
->copy_gc
, 0, 0);
423 XCopyArea(dpy
, scr
->dock_dots
->image
,
424 aicon
->icon
->core
->window
, scr
->copy_gc
, 0, 0, 7, scr
->dock_dots
->height
, 0, 0);
426 #endif /* HIDDENDOT */
428 if (aicon
->omnipresent
)
429 drawCorner(aicon
->icon
);
431 XSetClipMask(dpy
, scr
->copy_gc
, None
);
432 if (aicon
->launching
)
433 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
434 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
437 /* Save the application icon, if it's a dockapp then use it with dock = True */
438 void save_appicon(WAppIcon
*aicon
, Bool dock
)
445 if (dock
&& (!aicon
->docked
|| aicon
->attracted
))
448 path
= wIconStore(aicon
->icon
);
452 wApplicationSaveIconPathFor(path
, aicon
->wm_instance
, aicon
->wm_class
);
456 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
458 /* main_window may not have the full command line; try to find one which does */
459 static void relaunchApplication(WApplication
*wapp
)
462 WWindow
*wlist
, *next
;
464 scr
= wapp
->main_window_desc
->screen_ptr
;
465 wlist
= scr
->focused_window
;
475 if (wlist
->main_window
== wapp
->main_window
) {
476 if (RelaunchWindow(wlist
))
484 static void relaunchCallback(WMenu
* menu
, WMenuEntry
* entry
)
486 WApplication
*wapp
= (WApplication
*) entry
->clientdata
;
488 relaunchApplication(wapp
);
491 static void hideCallback(WMenu
* menu
, WMenuEntry
* entry
)
493 WApplication
*wapp
= (WApplication
*) entry
->clientdata
;
495 if (wapp
->flags
.hidden
) {
496 wWorkspaceChange(menu
->menu
->screen_ptr
, wapp
->last_workspace
);
497 wUnhideApplication(wapp
, False
, False
);
499 wHideApplication(wapp
);
503 static void unhideHereCallback(WMenu
* menu
, WMenuEntry
* entry
)
505 WApplication
*wapp
= (WApplication
*) entry
->clientdata
;
507 wUnhideApplication(wapp
, False
, True
);
510 static void setIconCallback(WMenu
*menu
, WMenuEntry
*entry
)
512 WAppIcon
*icon
= ((WApplication
*) entry
->clientdata
)->app_icon
;
517 assert(icon
!= NULL
);
523 scr
= icon
->icon
->core
->screen_ptr
;
527 result
= wIconChooserDialog(scr
, &file
, icon
->wm_instance
, icon
->wm_class
);
529 if (result
&& !icon
->destroyed
) {
530 if (file
&& *file
== 0) {
534 if (!wIconChangeImageFile(icon
->icon
, file
)) {
535 wMessageDialog(scr
, _("Error"),
536 _("Could not open specified icon file"), _("OK"), NULL
, NULL
);
538 wDefaultChangeIcon(scr
, icon
->wm_instance
, icon
->wm_class
, file
);
548 static void killCallback(WMenu
* menu
, WMenuEntry
* entry
)
550 WApplication
*wapp
= (WApplication
*) entry
->clientdata
;
551 WFakeGroupLeader
*fPtr
;
554 char *basename(const char *shortname
);
556 if (!WCHECK_STATE(WSTATE_NORMAL
))
559 WCHANGE_STATE(WSTATE_MODAL
);
561 assert(entry
->clientdata
!= NULL
);
563 shortname
= basename(wapp
->app_icon
->wm_instance
);
565 buffer
= wstrconcat(wapp
->app_icon
? shortname
: NULL
,
566 _(" will be forcibly closed.\n"
567 "Any unsaved changes will be lost.\n" "Please confirm."));
569 fPtr
= wapp
->main_window_desc
->fake_group
;
571 wretain(wapp
->main_window_desc
);
572 if (wPreferences
.dont_confirm_kill
573 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
574 buffer
, _("Yes"), _("No"), NULL
) == WAPRDefault
) {
576 WWindow
*wwin
, *twin
;
578 wwin
= wapp
->main_window_desc
->screen_ptr
->focused_window
;
581 if (wwin
->fake_group
== fPtr
)
585 } else if (!wapp
->main_window_desc
->flags
.destroyed
) {
586 wClientKill(wapp
->main_window_desc
);
589 wrelease(wapp
->main_window_desc
);
591 WCHANGE_STATE(WSTATE_NORMAL
);
594 static WMenu
*createApplicationMenu(WScreen
*scr
)
598 menu
= wMenuCreate(scr
, NULL
, False
);
599 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
600 wMenuAddCallback(menu
, _("Hide"), hideCallback
, NULL
);
601 wMenuAddCallback(menu
, _("Launch"), relaunchCallback
, NULL
);
602 wMenuAddCallback(menu
, _("Set Icon..."), setIconCallback
, NULL
);
603 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
608 static void openApplicationMenu(WApplication
* wapp
, int x
, int y
)
611 WScreen
*scr
= wapp
->main_window_desc
->screen_ptr
;
614 if (!scr
->icon_menu
) {
615 scr
->icon_menu
= createApplicationMenu(scr
);
616 wfree(scr
->icon_menu
->entries
[1]->text
);
619 menu
= scr
->icon_menu
;
621 if (wapp
->flags
.hidden
)
622 menu
->entries
[1]->text
= _("Unhide");
624 menu
->entries
[1]->text
= _("Hide");
626 menu
->flags
.realized
= 0;
629 x
-= menu
->frame
->core
->width
/ 2;
630 if (x
+ menu
->frame
->core
->width
> scr
->scr_width
)
631 x
= scr
->scr_width
- menu
->frame
->core
->width
;
636 /* set client data */
637 for (i
= 0; i
< menu
->entry_no
; i
++)
638 menu
->entries
[i
]->clientdata
= wapp
;
640 wMenuMapAt(menu
, x
, y
, False
);
643 /******************************************************************/
645 static void iconExpose(WObjDescriptor
*desc
, XEvent
*event
)
647 wAppIconPaint(desc
->parent
);
650 static void iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
652 WAppIcon
*aicon
= desc
->parent
;
654 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
657 assert(aicon
->icon
->owner
!= NULL
);
659 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
661 if (event
->xbutton
.state
& ControlMask
) {
662 relaunchApplication(wapp
);
666 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
667 /* go to the last workspace that the user worked on the app */
668 if (!unhideHere
&& wapp
->last_workspace
!= scr
->current_workspace
)
669 wWorkspaceChange(scr
, wapp
->last_workspace
);
671 wUnhideApplication(wapp
, event
->xbutton
.button
== Button2
, unhideHere
);
673 if (event
->xbutton
.state
& MOD_MASK
)
674 wHideOtherApplications(aicon
->icon
->owner
);
677 void appIconMouseDown(WObjDescriptor
* desc
, XEvent
* event
)
679 WAppIcon
*aicon
= desc
->parent
;
680 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
683 if (aicon
->editing
|| WCHECK_STATE(WSTATE_MODAL
))
686 if (IsDoubleClick(scr
, event
)) {
687 /* Middle or right mouse actions were handled on first click */
688 if (event
->xbutton
.button
== Button1
)
689 iconDblClick(desc
, event
);
693 if (event
->xbutton
.button
== Button2
) {
694 WApplication
*wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
697 relaunchApplication(wapp
);
702 if (event
->xbutton
.button
== Button3
) {
703 WObjDescriptor
*desc
;
704 WApplication
*wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
709 if (event
->xbutton
.send_event
&&
710 XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
711 | ButtonReleaseMask
| ButtonPressMask
, GrabModeAsync
,
712 GrabModeAsync
, None
, None
, CurrentTime
) != GrabSuccess
) {
713 wwarning("pointer grab failed for appicon menu");
717 openApplicationMenu(wapp
, event
->xbutton
.x_root
, event
->xbutton
.y_root
);
719 /* allow drag select of menu */
720 desc
= &scr
->icon_menu
->menu
->descriptor
;
721 event
->xbutton
.send_event
= True
;
722 (*desc
->handle_mousedown
) (desc
, event
);
726 hasMoved
= wHandleAppIconMove(aicon
, event
);
727 if (wPreferences
.single_click
&& !hasMoved
&& aicon
->dock
!= NULL
)
729 iconDblClick(desc
, event
);
733 Bool
wHandleAppIconMove(WAppIcon
*aicon
, XEvent
*event
)
735 WIcon
*icon
= aicon
->icon
;
736 WScreen
*scr
= icon
->core
->screen_ptr
;
737 WDock
*originalDock
= aicon
->dock
; /* can be NULL */
738 WDock
*lastDock
= originalDock
;
739 WDock
*allDocks
[scr
->drawer_count
+ 2]; /* clip, dock and drawers (order determined at runtime) */
741 Bool done
= False
, dockable
, ondock
;
742 Bool grabbed
= False
;
743 Bool collapsed
= False
; /* Stores the collapsed state of lastDock, before the moving appicon entered it */
744 int superfluous
= wPreferences
.superfluous
; /* we cache it to avoid problems */
745 int omnipresent
= aicon
->omnipresent
; /* this must be cached */
746 Bool showed_all_clips
= False
;
748 int clickButton
= event
->xbutton
.button
;
750 Window wins
[2]; /* Managing shadow window */
753 int x
= aicon
->x_pos
, y
= aicon
->y_pos
;
754 int ofs_x
= event
->xbutton
.x
, ofs_y
= event
->xbutton
.y
;
755 int shad_x
= x
, shad_y
= y
;
756 int ix
= aicon
->xindex
, iy
= aicon
->yindex
;
760 Bool hasMoved
= False
;
762 if (wPreferences
.flags
.noupdates
&& originalDock
!= NULL
)
765 if (!(event
->xbutton
.state
& MOD_MASK
))
766 wRaiseFrame(icon
->core
);
768 /* If Mod is pressed for an docked appicon, assume it is to undock it,
769 * so don't lower it */
770 if (originalDock
== NULL
)
771 wLowerFrame(icon
->core
);
774 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
775 | ButtonReleaseMask
| ButtonPressMask
, GrabModeAsync
,
776 GrabModeAsync
, None
, None
, CurrentTime
) != GrabSuccess
) {
777 wwarning("Pointer grab failed in wHandleAppIconMove");
780 if (originalDock
!= NULL
) {
786 if (wPreferences
.flags
.nodock
&& wPreferences
.flags
.noclip
&& wPreferences
.flags
.nodrawer
)
789 dockable
= canBeDocked(icon
->owner
);
792 /* We try the various docks in that order:
793 * - First, the dock the appicon comes from, if any
794 * - Then, the drawers
795 * - Then, the "dock" (WM_DOCK)
796 * - Finally, the clip
799 if (originalDock
!= NULL
)
800 allDocks
[ i
++ ] = originalDock
;
801 /* Testing scr->drawers is enough, no need to test wPreferences.flags.nodrawer */
802 for (dc
= scr
->drawers
; dc
!= NULL
; dc
= dc
->next
) {
803 if (dc
->adrawer
!= originalDock
)
804 allDocks
[ i
++ ] = dc
->adrawer
;
806 if (!wPreferences
.flags
.nodock
&& scr
->dock
!= originalDock
)
807 allDocks
[ i
++ ] = scr
->dock
;
808 if (!wPreferences
.flags
.noclip
&&
809 originalDock
!= scr
->workspaces
[scr
->current_workspace
]->clip
)
810 allDocks
[ i
++ ] = scr
->workspaces
[scr
->current_workspace
]->clip
;
811 for ( ; i
< scr
->drawer_count
+ 2; i
++) /* In case the clip, the dock, or both, are disabled */
812 allDocks
[ i
] = NULL
;
814 wins
[0] = icon
->core
->window
;
815 wins
[1] = scr
->dock_shadow
;
816 XRestackWindows(dpy
, wins
, 2);
817 XMoveResizeWindow(dpy
, scr
->dock_shadow
, aicon
->x_pos
, aicon
->y_pos
, ICON_SIZE
, ICON_SIZE
);
819 if (icon
->pixmap
!= None
)
820 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
822 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
823 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
, ghost
);
824 XClearWindow(dpy
, scr
->dock_shadow
);
827 XMapWindow(dpy
, scr
->dock_shadow
);
830 WMMaskEvent(dpy
, PointerMotionMask
| ButtonReleaseMask
| ButtonPressMask
831 | ButtonMotionMask
| ExposureMask
| EnterWindowMask
, &ev
);
838 /* It means the cursor moved so fast that it entered
839 * something else (if moving slowly, it would have
840 * stayed in the appIcon that is being moved. Ignore
841 * such "spurious" EnterNotifiy's */
847 if (abs(ofs_x
- ev
.xmotion
.x
) >= MOVE_THRESHOLD
848 || abs(ofs_y
- ev
.xmotion
.y
) >= MOVE_THRESHOLD
) {
849 XChangeActivePointerGrab(dpy
, ButtonMotionMask
850 | ButtonReleaseMask
| ButtonPressMask
,
851 wCursor
[WCUR_MOVE
], CurrentTime
);
858 if (omnipresent
&& !showed_all_clips
) {
860 for (i
= 0; i
< scr
->workspace_count
; i
++) {
861 if (i
== scr
->current_workspace
)
863 wDockShowIcons(scr
->workspaces
[i
]->clip
);
864 /* Note: if dock is collapsed (for instance, because it
865 auto-collapses), its icons still won't show up */
867 showed_all_clips
= True
; /* To prevent flickering */
870 x
= ev
.xmotion
.x_root
- ofs_x
;
871 y
= ev
.xmotion
.y_root
- ofs_y
;
872 wAppIconMove(aicon
, x
, y
);
874 WDock
*theNewDock
= NULL
;
875 if (!(ev
.xmotion
.state
& MOD_MASK
) || aicon
->launching
|| aicon
->lock
) {
876 for (i
= 0; dockable
&& i
< scr
->drawer_count
+ 2; i
++) {
877 WDock
*theDock
= allDocks
[i
];
880 if (wDockSnapIcon(theDock
, aicon
, x
, y
, &ix
, &iy
, (theDock
== originalDock
))) {
881 theNewDock
= theDock
;
885 if (originalDock
!= NULL
&& theNewDock
== NULL
&&
886 (aicon
->launching
|| aicon
->lock
|| aicon
->running
)) {
887 /* In those cases, stay in lastDock if no dock really wants us */
888 theNewDock
= lastDock
;
891 if (lastDock
!= NULL
&& lastDock
!= theNewDock
) {
892 /* Leave lastDock in the state we found it */
893 if (lastDock
->type
== WM_DRAWER
) {
894 wDrawerFillTheGap(lastDock
, aicon
, (lastDock
== originalDock
));
897 lastDock
->collapsed
= 1;
898 wDockHideIcons(lastDock
);
901 if (lastDock
->auto_raise_lower
) {
902 wDockLower(lastDock
);
905 if (theNewDock
!= NULL
) {
906 if (lastDock
!= theNewDock
) {
907 collapsed
= theNewDock
->collapsed
;
909 theNewDock
->collapsed
= 0;
910 wDockShowIcons(theNewDock
);
912 if (theNewDock
->auto_raise_lower
) {
913 wDockRaise(theNewDock
);
914 /* And raise the moving tile above it */
915 wRaiseFrame(aicon
->icon
->core
);
917 lastDock
= theNewDock
;
920 shad_x
= lastDock
->x_pos
+ ix
*wPreferences
.icon_size
;
921 shad_y
= lastDock
->y_pos
+ iy
*wPreferences
.icon_size
;
923 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
926 XMapWindow(dpy
, scr
->dock_shadow
);
930 lastDock
= theNewDock
; // i.e., NULL
932 XUnmapWindow(dpy
, scr
->dock_shadow
);
934 * Leaving that weird comment for now.
935 * But if we see no gap, there is no need to fill one!
936 * We could test ondock first and the lastDock to NULL afterwards
937 if (lastDock_before_it_was_null->type == WM_DRAWER) {
938 wDrawerFillTheGap(lastDock, aicon, (lastDock == originalDock));
950 if (ev
.xbutton
.button
!= clickButton
)
952 XUngrabPointer(dpy
, CurrentTime
);
956 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
957 XUnmapWindow(dpy
, scr
->dock_shadow
);
958 if (originalDock
== NULL
) { // docking an undocked appicon
959 docked
= wDockAttachIcon(lastDock
, aicon
, ix
, iy
, False
);
961 /* AppIcon got rejected (happens only when we can't get the
962 command for that appicon, and the user cancels the
963 wInputDialog asking for one). Make the rejection obvious by
964 sliding the icon to its old position */
965 if (lastDock
->type
== WM_DRAWER
) {
966 // Also fill the gap left in the drawer
967 wDrawerFillTheGap(lastDock
, aicon
, False
);
969 SlideWindow(icon
->core
->window
, x
, y
, oldX
, oldY
);
972 else { // moving a docked appicon to a dock
973 if (originalDock
== lastDock
) {
975 wDockReattachIcon(originalDock
, aicon
, ix
, iy
);
978 docked
= wDockMoveIconBetweenDocks(originalDock
, lastDock
, aicon
, ix
, iy
);
980 /* Possible scenario: user moved an auto-attracted appicon
981 from the clip to the dock, and cancelled the wInputDialog
982 asking for a command */
983 if (lastDock
->type
== WM_DRAWER
) {
984 wDrawerFillTheGap(lastDock
, aicon
, False
);
986 /* If aicon comes from a drawer, make some room to reattach it */
987 if (originalDock
->type
== WM_DRAWER
) {
988 WAppIcon
*aiconsToShift
[ originalDock
->icon_count
];
991 for (i
= 0; i
< originalDock
->max_icons
; i
++) {
992 WAppIcon
*ai
= originalDock
->icon_array
[ i
];
993 if (ai
&& ai
!= aicon
&&
994 abs(ai
->xindex
) >= abs(aicon
->xindex
))
995 aiconsToShift
[j
++] = ai
;
997 if (j
!= originalDock
->icon_count
- abs(aicon
->xindex
) - 1)
998 // Trust this never happens?
999 wwarning("Shifting j=%d appicons (instead of %d!) to reinsert aicon at index %d.",
1000 j
, originalDock
->icon_count
- abs(aicon
->xindex
) - 1, aicon
->xindex
);
1001 wSlideAppicons(aiconsToShift
, j
, originalDock
->on_right_side
);
1002 // Trust the appicon is inserted at exactly the same place, so its oldX/oldY are consistent with its "new" location?
1005 SlideWindow(icon
->core
->window
, x
, y
, oldX
, oldY
);
1006 wDockReattachIcon(originalDock
, aicon
, aicon
->xindex
, aicon
->yindex
);
1009 if (originalDock
->auto_collapse
&& !originalDock
->collapsed
) {
1010 originalDock
->collapsed
= 1;
1011 wDockHideIcons(originalDock
);
1013 if (originalDock
->auto_raise_lower
)
1014 wDockLower(originalDock
);
1018 // No matter what happened above, check to lower lastDock
1019 // Don't see why I commented out the following 2 lines
1020 /* if (lastDock->auto_raise_lower)
1021 wDockLower(lastDock); */
1022 /* If docked (or tried to dock) to a auto_collapsing dock, unset
1023 * collapsed, so that wHandleAppIconMove doesn't collapse it
1024 * right away (the timer will take care of it) */
1025 if (lastDock
->auto_collapse
)
1029 if (originalDock
!= NULL
) { /* Detaching a docked appicon */
1031 if (!aicon
->running
&& !wPreferences
.no_animations
) {
1032 /* We need to deselect it, even if is deselected in
1033 * wDockDetach(), because else DoKaboom() will fail.
1035 if (aicon
->icon
->selected
)
1036 wIconSelect(aicon
->icon
);
1037 DoKaboom(scr
, aicon
->icon
->core
->window
, x
, y
);
1040 wDockDetach(originalDock
, aicon
);
1041 if (originalDock
->auto_collapse
&& !originalDock
->collapsed
) {
1042 originalDock
->collapsed
= 1;
1043 wDockHideIcons(originalDock
);
1045 if (originalDock
->auto_raise_lower
)
1046 wDockLower(originalDock
);
1049 // Can't remember why the icon hiding is better done above than below (commented out)
1050 // Also, lastDock is quite different from originalDock
1053 lastDock->collapsed = 1;
1054 wDockHideIcons(lastDock);
1060 XFreePixmap(dpy
, ghost
);
1061 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
1063 if (showed_all_clips
) {
1065 for (i
= 0; i
< scr
->workspace_count
; i
++) {
1066 if (i
== scr
->current_workspace
)
1068 wDockHideIcons(scr
->workspaces
[i
]->clip
);
1071 if (wPreferences
.auto_arrange_icons
&& !(originalDock
!= NULL
&& docked
))
1072 /* Need to rearrange unless moving from dock to dock */
1073 wArrangeIcons(scr
, True
);
1077 return False
; /* Never reached */
1080 /* This function save the application icon and store the path in the Dictionary */
1081 static void wApplicationSaveIconPathFor(char *iconPath
, char *wm_instance
, char *wm_class
)
1083 WMPropList
*dict
= WDWindowAttributes
->dictionary
;
1084 WMPropList
*adict
, *key
, *iconk
;
1088 tmp
= get_name_for_instance_class(wm_instance
, wm_class
);
1089 key
= WMCreatePLString(tmp
);
1092 adict
= WMGetFromPLDictionary(dict
, key
);
1093 iconk
= WMCreatePLString("Icon");
1096 val
= WMGetFromPLDictionary(adict
, iconk
);
1098 /* no dictionary for app, so create one */
1099 adict
= WMCreatePLDictionary(NULL
, NULL
);
1100 WMPutInPLDictionary(dict
, key
, adict
);
1101 WMReleasePropList(adict
);
1106 val
= WMCreatePLString(iconPath
);
1107 WMPutInPLDictionary(adict
, iconk
, val
);
1108 WMReleasePropList(val
);
1113 WMReleasePropList(key
);
1114 WMReleasePropList(iconk
);
1116 if (val
&& !wPreferences
.flags
.noupdates
)
1117 UpdateDomainFile(WDWindowAttributes
);
1120 static WAppIcon
*findDockIconFor(WDock
*dock
, Window main_window
)
1122 WAppIcon
*aicon
= NULL
;
1124 aicon
= wDockFindIconForWindow(dock
, main_window
);
1126 wDockTrackWindowLaunch(dock
, main_window
);
1127 aicon
= wDockFindIconForWindow(dock
, main_window
);
1132 static void create_appicon_from_dock(WWindow
*wwin
, WApplication
*wapp
, Window main_window
)
1134 WScreen
*scr
= wwin
->screen_ptr
;
1135 wapp
->app_icon
= NULL
;
1138 wapp
->app_icon
= findDockIconFor(scr
->last_dock
, main_window
);
1140 /* check main dock if we did not find it in last dock */
1141 if (!wapp
->app_icon
&& scr
->dock
)
1142 wapp
->app_icon
= findDockIconFor(scr
->dock
, main_window
);
1145 if (!wapp
->app_icon
) {
1147 for (i
= 0; i
< scr
->workspace_count
; i
++) {
1148 WDock
*dock
= scr
->workspaces
[i
]->clip
;
1150 wapp
->app_icon
= findDockIconFor(dock
, main_window
);
1156 /* Finally check drawers */
1157 if (!wapp
->app_icon
) {
1159 for (dc
= scr
->drawers
; dc
!= NULL
; dc
= dc
->next
) {
1160 wapp
->app_icon
= findDockIconFor(dc
->adrawer
, main_window
);
1166 /* If created, then set some flags */
1167 if (wapp
->app_icon
) {
1168 WWindow
*mainw
= wapp
->main_window_desc
;
1170 wapp
->app_icon
->running
= 1;
1171 wapp
->app_icon
->icon
->owner
= mainw
;
1172 if (mainw
->wm_hints
&& (mainw
->wm_hints
->flags
& IconWindowHint
))
1173 wapp
->app_icon
->icon
->icon_win
= mainw
->wm_hints
->icon_window
;
1175 /* Update the icon images */
1176 wIconUpdate(wapp
->app_icon
->icon
, NULL
);
1179 wAppIconPaint(wapp
->app_icon
);
1180 save_appicon(wapp
->app_icon
, True
);
1184 /* Add the appicon to the appiconlist */
1185 static void add_to_appicon_list(WScreen
*scr
, WAppIcon
*appicon
)
1187 appicon
->prev
= NULL
;
1188 appicon
->next
= scr
->app_icon_list
;
1189 if (scr
->app_icon_list
)
1190 scr
->app_icon_list
->prev
= appicon
;
1192 scr
->app_icon_list
= appicon
;
1195 /* Remove the appicon from the appiconlist */
1196 static void remove_from_appicon_list(WScreen
*scr
, WAppIcon
*appicon
)
1198 if (appicon
== scr
->app_icon_list
) {
1200 appicon
->next
->prev
= NULL
;
1201 scr
->app_icon_list
= appicon
->next
;
1204 appicon
->next
->prev
= appicon
->prev
;
1206 appicon
->prev
->next
= appicon
->next
;
1209 appicon
->prev
= NULL
;
1210 appicon
->next
= NULL
;
1213 /* Return the AppIcon associated with a given (Xlib) Window. */
1214 WAppIcon
*wAppIconFor(Window window
)
1216 WObjDescriptor
*desc
;
1221 if (XFindContext(dpy
, window
, wWinContext
, (XPointer
*) & desc
) == XCNOENT
)
1224 if (desc
->parent_type
== WCLASS_APPICON
|| desc
->parent_type
== WCLASS_DOCK_ICON
)
1225 return desc
->parent
;