1 /* dock.c- built-in Dock module for WindowMaker
3 * WindowMaker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #include <X11/Xutil.h>
35 #define PATH_MAX DEFAULT_PATH_MAX
38 #include "WindowMaker.h"
48 #include "properties.h"
52 #include "workspace.h"
54 #include "superfluous.h"
67 /**** Local variables ****/
70 #define CLIP_FORWARD 2
72 /* This should be 24. It looks better.
73 * Proof: the golden ratio is ~1.6:
74 * 64/1.6 = 24, thus 24 will look better than 22 :)
77 * This is true, but... ;)
78 * CLIP_BUTTON_SIZE only means the button itself, without the black delimiting
79 * line. So because one sees the black line together with the button, it should
80 * be 23. There is no big difference between 23 and 24, but 23 gives also a
81 * better aspect ratio between the button and the arrow mark.
82 * Anyway if you feel stronger for 24 you can change it as it is not very
85 * BTW I think you meant 64-64/1.6=24 or 64/(1.6*1.6) ;)
88 #define CLIP_BUTTON_SIZE 23
91 /**** Global variables ****/
94 extern void DestroyDockAppSettingsPanel();
96 extern void ShowDockAppSettingsPanel(WAppIcon
*aicon
);
100 extern Cursor wCursor
[WCUR_LAST
];
102 extern WPreferences wPreferences
;
104 extern XContext wWinContext
;
107 extern Atom _XA_DND_PROTOCOL
;
111 #define MOD_MASK wPreferences.modifier_mask
113 extern void appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
115 #define ICON_SIZE wPreferences.icon_size
118 /***** Local variables ****/
120 static proplist_t dCommand
=NULL
;
122 static proplist_t dDropCommand
=NULL
;
124 static proplist_t dAutoLaunch
, dName
, dForced
, dBuggyApplication
, dYes
, dNo
;
125 static proplist_t dHost
, dDock
, dClip
;
126 static proplist_t dAutoAttractIcons
, dKeepAttracted
;
128 static proplist_t dPosition
, dApplications
, dLowered
, dCollapsed
, dAutoCollapse
;
130 static void dockIconPaint(WAppIcon
*btn
);
132 static void iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
134 static pid_t
execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
);
136 static void trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
);
138 static int getClipButton(int px
, int py
);
140 static void toggleLowered(WDock
*dock
);
142 static void toggleCollapsed(WDock
*dock
);
144 static void toggleAutoCollapse(WDock
*dock
);
146 static void clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
);
148 static void clipLeave(WDock
*dock
);
150 static void handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
);
152 Bool
moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
);
154 static void clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
);
155 static void clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
);
156 static void clipAutoCollapse(void *cdata
);
157 static void launchDockedApplication(WAppIcon
*btn
);
159 static void showClipBalloon(WDock
*dock
, int workspace
);
175 #endif /* OFFIX_DND */
185 dCommand
= PLRetain(PLMakeString("Command"));
187 dDropCommand
= PLRetain(PLMakeString("DropCommand"));
189 dAutoLaunch
= PLRetain(PLMakeString("AutoLaunch"));
190 dName
= PLRetain(PLMakeString("Name"));
191 dForced
= PLRetain(PLMakeString("Forced"));
192 dBuggyApplication
= PLRetain(PLMakeString("BuggyApplication"));
193 dYes
= PLRetain(PLMakeString("Yes"));
194 dNo
= PLRetain(PLMakeString("No"));
195 dHost
= PLRetain(PLMakeString("Host"));
197 dPosition
= PLMakeString("Position");
198 dApplications
= PLMakeString("Applications");
199 dLowered
= PLMakeString("Lowered");
200 dCollapsed
= PLMakeString("Collapsed");
201 dAutoCollapse
= PLMakeString("AutoCollapse");
202 dAutoAttractIcons
= PLMakeString("AutoAttractIcons");
203 dKeepAttracted
= PLMakeString("KeepAttracted");
205 dDock
= PLMakeString("Dock");
206 dClip
= PLMakeString("Clip");
212 renameCallback(WMenu
*menu
, WMenuEntry
*entry
)
214 WDock
*dock
= entry
->clientdata
;
219 assert(entry
->clientdata
!=NULL
);
221 wspace
= dock
->screen_ptr
->current_workspace
;
223 name
= wstrdup(dock
->screen_ptr
->workspaces
[wspace
]->name
);
225 sprintf(buffer
, _("Type the name for workspace %i:"), wspace
+1);
226 if (wInputDialog(dock
->screen_ptr
, _("Rename Workspace"), buffer
,
228 wWorkspaceRename(dock
->screen_ptr
, wspace
, name
);
237 toggleLoweredCallback(WMenu
*menu
, WMenuEntry
*entry
)
239 assert(entry
->clientdata
!=NULL
);
241 toggleLowered(entry
->clientdata
);
243 entry
->flags
.indicator_on
= !((WDock
*)entry
->clientdata
)->lowered
;
251 killCallback(WMenu
*menu
, WMenuEntry
*entry
)
254 #ifdef REDUCE_APPICONS
255 WAppIconAppList
*tapplist
;
257 extern Atom _XA_WM_DELETE_WINDOW
;
260 assert(entry
->clientdata
!=NULL
);
262 icon
= (WAppIcon
*)entry
->clientdata
;
263 #ifdef REDUCE_APPICONS
264 /* Send a delete message to the main window of each application
265 * bound to this docked appicon. - cls
267 tapplist
= icon
->applist
;
268 while (tapplist
!= NULL
) {
269 if (tapplist
->wapp
->main_window_desc
!= NULL
) {
270 if (tapplist
->wapp
->main_window_desc
->protocols
.DELETE_WINDOW
) {
271 wClientSendProtocol(tapplist
->wapp
->main_window_desc
,
272 _XA_WM_DELETE_WINDOW
, CurrentTime
);
274 wClientKill(tapplist
->wapp
->main_window_desc
);
277 tapplist
= tapplist
->next
;
280 if (wPreferences
.dont_confirm_kill
281 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
282 _("This will kill the application.\nAny unsaved changes will be lost.\nPlease confirm."),
283 _("Yes"), _("No"), NULL
)==WAPRDefault
) {
284 if (icon
->icon
&& icon
->icon
->owner
) {
285 wClientKill(icon
->icon
->owner
);
288 #endif /* !REDUCE_APPICONS */
293 getSelected(WDock
*dock
)
295 LinkedList
*ret
=NULL
;
299 for (i
=1; i
<dock
->max_icons
; i
++) {
300 btn
= dock
->icon_array
[i
];
301 if (btn
&& btn
->icon
->selected
) {
302 ret
= list_cons(btn
, ret
);
311 paintClipButtons(WAppIcon
*clipIcon
, Bool lpushed
, Bool rpushed
)
313 Window win
= clipIcon
->icon
->core
->window
;
314 WScreen
*scr
= clipIcon
->icon
->core
->screen_ptr
;
316 int pt
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
317 int tp
= ICON_SIZE
- pt
;
318 int as
= pt
- 15; /* 15 = 5+5+5 */
324 p
[1].x
= ICON_SIZE
-2;
326 p
[2].x
= ICON_SIZE
-2;
328 } else if (lpushed
) {
332 p
[1].y
= ICON_SIZE
-2;
334 p
[2].y
= ICON_SIZE
-2;
336 if (lpushed
|| rpushed
) {
337 XSetForeground(dpy
, scr
->draw_gc
, scr
->white_pixel
);
338 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
339 XSetForeground(dpy
, scr
->draw_gc
, scr
->black_pixel
);
342 p
[0].x
= p
[3].x
= ICON_SIZE
-6-as
;
344 p
[1].x
= ICON_SIZE
-6;
346 p
[2].x
= ICON_SIZE
-6;
349 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
350 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
352 XFillPolygon(dpy
, win
, scr
->clip_title_gc
, p
,3,Convex
,CoordModeOrigin
);
353 XDrawLines(dpy
, win
, scr
->clip_title_gc
, p
,4,CoordModeOrigin
);
357 p
[0].y
= p
[3].y
= ICON_SIZE
-6-as
;
359 p
[1].y
= ICON_SIZE
-6;
361 p
[2].y
= ICON_SIZE
-6;
363 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
364 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
366 XFillPolygon(dpy
, win
, scr
->clip_title_gc
, p
,3,Convex
,CoordModeOrigin
);
367 XDrawLines(dpy
, win
, scr
->clip_title_gc
, p
,4,CoordModeOrigin
);
373 wClipMakeTile(WScreen
*scr
, RImage
*normalTile
)
375 RImage
*tile
= RCloneImage(normalTile
);
381 pt
= CLIP_BUTTON_SIZE
*wPreferences
.icon_size
/64;
382 tp
= wPreferences
.icon_size
-1 - pt
;
385 black
.red
= black
.green
= black
.blue
= 0;
388 dark
.red
= dark
.green
= dark
.blue
= 80;
391 light
.red
= light
.green
= light
.blue
= 80;
395 ROperateLine(tile
, RSubtractOperation
, tp
, 0, wPreferences
.icon_size
-2,
397 RDrawLine(tile
, tp
-1, 0, wPreferences
.icon_size
-1, pt
+1, &black
);
398 ROperateLine(tile
, RAddOperation
, tp
, 2, wPreferences
.icon_size
-3,
403 ROperateLine(tile
, RAddOperation
, 2, tp
+2, pt
-2,
404 wPreferences
.icon_size
-3, &dark
);
405 RDrawLine(tile
, 0, tp
-1, pt
+1, wPreferences
.icon_size
-1, &black
);
406 ROperateLine(tile
, RSubtractOperation
, 0, tp
-2, pt
+1,
407 wPreferences
.icon_size
-2, &light
);
414 removeIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
416 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
419 LinkedList
*selectedIcons
;
422 assert(clickedIcon
!=NULL
);
424 dock
= clickedIcon
->dock
;
426 selectedIcons
= getSelected(dock
);
429 if (wMessageDialog(dock
->screen_ptr
, _("Workspace Clip"),
430 _("All selected icons will be removed!"),
431 _("OK"), _("Cancel"), NULL
)!=WAPRDefault
) {
435 if (clickedIcon
->xindex
==0 && clickedIcon
->yindex
==0)
437 selectedIcons
= list_cons(clickedIcon
, NULL
);
440 while(selectedIcons
) {
441 aicon
= selectedIcons
->head
;
442 keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
443 wDockDetach(dock
, aicon
);
445 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
447 wLowerFrame(aicon
->icon
->core
);
449 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
450 aicon
->x_pos
, aicon
->y_pos
);
451 if (!dock
->mapped
|| dock
->collapsed
)
452 XMapWindow(dpy
, aicon
->icon
->core
->window
);
454 list_remove_head(&selectedIcons
);
457 if (wPreferences
.auto_arrange_icons
)
458 wArrangeIcons(dock
->screen_ptr
, True
);
463 keepIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
465 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
468 LinkedList
*selectedIcons
;
470 assert(clickedIcon
!=NULL
);
471 dock
= clickedIcon
->dock
;
473 selectedIcons
= getSelected(dock
);
475 if (!selectedIcons
&& clickedIcon
!=dock
->screen_ptr
->clip_icon
) {
476 char *command
= NULL
;
478 if (!clickedIcon
->command
) {
479 if (wInputDialog(dock
->screen_ptr
, _("Keep Icon"),
480 _("Type the command used to launch the application"),
482 if (command
&& (command
[0]==0 ||
483 (command
[0]=='-' && command
[1]==0))) {
487 clickedIcon
->command
= command
;
495 selectedIcons
= list_cons(clickedIcon
, NULL
);
498 while (selectedIcons
) {
499 aicon
= selectedIcons
->head
;
500 if (aicon
->icon
->selected
)
501 wIconSelect(aicon
->icon
);
502 if (aicon
&& aicon
->attracted
&& aicon
->command
) {
503 aicon
->attracted
= 0;
504 if (aicon
->icon
->shadowed
) {
505 aicon
->icon
->shadowed
= 0;
506 aicon
->icon
->force_paint
= 1;
507 wAppIconPaint(aicon
);
510 list_remove_head(&selectedIcons
);
518 toggleAutoAttractCallback(WMenu
*menu
, WMenuEntry
*entry
)
520 WDock
*dock
= (WDock
*)entry
->clientdata
;
522 assert(entry
->clientdata
!=NULL
);
524 dock
->attract_icons
= !dock
->attract_icons
;
525 /*if (!dock->attract_icons)
526 dock->keep_attracted = 0;*/
528 entry
->flags
.indicator_on
= dock
->attract_icons
;
535 toggleKeepCallback(WMenu
*menu
, WMenuEntry
*entry
)
537 WDock
*dock
= (WDock
*)entry
->clientdata
;
541 assert(entry
->clientdata
!=NULL
);
543 dock
->keep_attracted
= !dock
->keep_attracted
;
545 if (dock
->keep_attracted
) {
546 for (i
=0; i
< dock
->max_icons
; i
++) {
547 btn
= dock
->icon_array
[i
];
548 if (btn
&& btn
->attracted
&& btn
->command
) {
550 if (btn
->icon
->shadowed
) {
551 btn
->icon
->shadowed
= 0;
552 btn
->icon
->force_paint
= 1;
559 entry
->flags
.indicator_on
= dock
->keep_attracted
;
566 selectCallback(WMenu
*menu
, WMenuEntry
*entry
)
568 WAppIcon
*icon
= (WAppIcon
*)entry
->clientdata
;
572 wIconSelect(icon
->icon
);
579 colectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
581 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
584 int x
, y
, x_pos
, y_pos
;
586 assert(entry
->clientdata
!=NULL
);
587 clip
= clickedIcon
->dock
;
589 aicon
= clip
->screen_ptr
->app_icon_list
;
592 if (!aicon
->docked
&& wDockFindFreeSlot(clip
, &x
, &y
)) {
593 x_pos
= clip
->x_pos
+ x
*ICON_SIZE
;
594 y_pos
= clip
->y_pos
+ y
*ICON_SIZE
;
595 if (aicon
->x_pos
!= x_pos
|| aicon
->y_pos
!= y_pos
) {
597 if (wPreferences
.no_animations
) {
598 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
600 SlideWindow(aicon
->icon
->core
->window
,
601 aicon
->x_pos
, aicon
->y_pos
, x_pos
, y_pos
);
604 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
605 #endif /* ANIMATIONS */
607 aicon
->attracted
= 1;
608 if (!clip
->keep_attracted
&& !aicon
->icon
->shadowed
) {
609 aicon
->icon
->shadowed
= 1;
610 aicon
->icon
->force_paint
= 1;
611 /* We don't do an wAppIconPaint() here because it's in
612 * wDockAttachIcon(). -Dan
615 wDockAttachIcon(clip
, aicon
, x
, y
);
616 if (clip
->collapsed
|| !clip
->mapped
)
617 XUnmapWindow(dpy
, aicon
->icon
->core
->window
);
625 selectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
627 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
629 LinkedList
*selectedIcons
;
633 assert(clickedIcon
!=NULL
);
634 dock
= clickedIcon
->dock
;
636 selectedIcons
= getSelected(dock
);
638 if (!selectedIcons
) {
639 for (i
=1; i
<dock
->max_icons
; i
++) {
640 btn
= dock
->icon_array
[i
];
641 if (btn
&& !btn
->icon
->selected
) {
642 wIconSelect(btn
->icon
);
646 while(selectedIcons
) {
647 btn
= selectedIcons
->head
;
648 wIconSelect(btn
->icon
);
649 list_remove_head(&selectedIcons
);
658 toggleCollapsedCallback(WMenu
*menu
, WMenuEntry
*entry
)
660 assert(entry
->clientdata
!=NULL
);
662 toggleCollapsed(entry
->clientdata
);
664 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->collapsed
;
671 toggleAutoCollapseCallback(WMenu
*menu
, WMenuEntry
*entry
)
673 assert(entry
->clientdata
!=NULL
);
675 toggleAutoCollapse(entry
->clientdata
);
677 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->auto_collapse
;
684 launchCallback(WMenu
*menu
, WMenuEntry
*entry
)
686 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
688 launchDockedApplication(btn
);
693 settingsCallback(WMenu
*menu
, WMenuEntry
*entry
)
695 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
699 ShowDockAppSettingsPanel(btn
);
704 hideCallback(WMenu
*menu
, WMenuEntry
*entry
)
707 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
709 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
711 if (wapp
->flags
.hidden
) {
712 wWorkspaceChange(btn
->icon
->core
->screen_ptr
,wapp
->last_workspace
);
713 wUnhideApplication(wapp
, False
, False
);
715 wHideApplication(wapp
);
721 unhideHereCallback(WMenu
*menu
, WMenuEntry
*entry
)
724 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
726 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
728 wUnhideApplication(wapp
, False
, True
);
733 mainIconCreate(WScreen
*scr
, int type
)
738 if (type
== WM_CLIP
) {
740 return scr
->clip_icon
;
741 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMClip", TILE_CLIP
);
742 btn
->icon
->core
->descriptor
.handle_expose
= clipIconExpose
;
743 btn
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
744 btn
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
745 /*x_pos = scr->scr_width - ICON_SIZE*2 - DOCK_EXTRA_SPACE;*/
749 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMDock", TILE_NORMAL
);
750 x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
756 btn
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
757 btn
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
758 btn
->icon
->core
->descriptor
.parent
= btn
;
759 /*ChangeStackingLevel(btn->icon->core, NSDockWindowLevel);*/
760 XMapWindow(dpy
, btn
->icon
->core
->window
);
765 scr
->clip_icon
= btn
;
772 switchWSCommand(WMenu
*menu
, WMenuEntry
*entry
)
774 WAppIcon
*btn
, *icon
= (WAppIcon
*) entry
->clientdata
;
775 WScreen
*scr
= icon
->icon
->core
->screen_ptr
;
777 LinkedList
*selectedIcons
;
780 if (entry
->order
== scr
->current_workspace
)
783 dest
= scr
->workspaces
[entry
->order
]->clip
;
785 selectedIcons
= getSelected(src
);
788 while(selectedIcons
) {
789 btn
= selectedIcons
->head
;
790 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
791 moveIconBetweenDocks(src
, dest
, btn
, x
, y
);
792 XUnmapWindow(dpy
, btn
->icon
->core
->window
);
794 list_remove_head(&selectedIcons
);
796 } else if (icon
!= scr
->clip_icon
) {
797 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
798 moveIconBetweenDocks(src
, dest
, icon
, x
, y
);
799 XUnmapWindow(dpy
, icon
->icon
->core
->window
);
807 launchDockedApplication(WAppIcon
*btn
)
809 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
811 if (!btn
->launching
&& btn
->command
!=NULL
) {
812 if (!btn
->forced_dock
) {
813 btn
->relaunching
= btn
->running
;
816 if (btn
->wm_instance
|| btn
->wm_class
) {
817 WWindowAttributes attr
;
818 memset(&attr
, 0, sizeof(WWindowAttributes
));
819 wDefaultFillAttributes(scr
, btn
->wm_instance
, btn
->wm_class
, &attr
,
822 if (!attr
.no_appicon
&& !btn
->buggy_app
)
827 btn
->drop_launch
= 0;
828 scr
->last_dock
= btn
->dock
;
829 btn
->pid
= execCommand(btn
, btn
->command
, NULL
);
831 if (btn
->buggy_app
) {
832 /* give feedback that the app was launched */
836 WMAddTimerHandler(200, (WMCallback
*)dockIconPaint
, btn
);
841 wwarning(_("could not launch application %s\n"), btn
->command
);
843 if (!btn
->relaunching
)
852 updateWorkspaceMenu(WMenu
*menu
, WAppIcon
*icon
)
854 WScreen
*scr
= menu
->frame
->screen_ptr
;
855 char title
[MAX_WORKSPACENAME_WIDTH
+1];
861 for (i
=0; i
<scr
->workspace_count
; i
++) {
862 if (i
< menu
->entry_no
) {
863 if (strcmp(menu
->entries
[i
]->text
,scr
->workspaces
[i
]->name
)!=0) {
864 free(menu
->entries
[i
]->text
);
865 strcpy(title
, scr
->workspaces
[i
]->name
);
866 menu
->entries
[i
]->text
= wstrdup(title
);
867 menu
->flags
.realized
= 0;
869 menu
->entries
[i
]->clientdata
= (void*)icon
;
871 strcpy(title
, scr
->workspaces
[i
]->name
);
873 wMenuAddCallback(menu
, title
, switchWSCommand
, (void*)icon
);
875 menu
->flags
.realized
= 0;
877 if (i
== scr
->current_workspace
) {
878 wMenuSetEnabled(menu
, i
, False
);
880 wMenuSetEnabled(menu
, i
, True
);
884 if (!menu
->flags
.realized
)
890 makeWorkspaceMenu(WScreen
*scr
)
894 menu
= wMenuCreate(scr
, NULL
, False
);
896 wwarning(_("could not create workspace submenu for Clip menu"));
898 wMenuAddCallback(menu
, "", switchWSCommand
, (void*)scr
->clip_icon
);
900 menu
->flags
.realized
= 0;
908 updateClipOptionsMenu(WMenu
*menu
, WDock
*dock
)
917 entry
= menu
->entries
[index
];
918 entry
->flags
.indicator_on
= !dock
->lowered
;
919 entry
->clientdata
= dock
;
922 entry
= menu
->entries
[++index
];
923 entry
->flags
.indicator_on
= dock
->collapsed
;
924 entry
->clientdata
= dock
;
927 entry
= menu
->entries
[++index
];
928 entry
->flags
.indicator_on
= dock
->auto_collapse
;
929 entry
->clientdata
= dock
;
932 entry
= menu
->entries
[++index
];
933 entry
->flags
.indicator_on
= dock
->attract_icons
;
934 entry
->clientdata
= dock
;
936 /* keep attracted icons */
937 entry
= menu
->entries
[++index
];
938 entry
->flags
.indicator_on
= dock
->keep_attracted
;
939 entry
->clientdata
= dock
;
941 menu
->flags
.realized
= 0;
947 makeClipOptionsMenu(WScreen
*scr
)
952 menu
= wMenuCreate(scr
, NULL
, False
);
954 wwarning(_("could not create options submenu for Clip menu"));
958 entry
= wMenuAddCallback(menu
, _("Floating Clip"),
959 toggleLoweredCallback
, NULL
);
960 entry
->flags
.indicator
= 1;
961 entry
->flags
.indicator_on
= 1;
962 entry
->flags
.indicator_type
= MI_CHECK
;
964 entry
= wMenuAddCallback(menu
, _("Collapsed"),
965 toggleCollapsedCallback
, NULL
);
966 entry
->flags
.indicator
= 1;
967 entry
->flags
.indicator_on
= 1;
968 entry
->flags
.indicator_type
= MI_CHECK
;
970 entry
= wMenuAddCallback(menu
, _("AutoCollapse"),
971 toggleAutoCollapseCallback
, NULL
);
972 entry
->flags
.indicator
= 1;
973 entry
->flags
.indicator_on
= 1;
974 entry
->flags
.indicator_type
= MI_CHECK
;
976 entry
= wMenuAddCallback(menu
, _("AutoAttract Icons"),
977 toggleAutoAttractCallback
, NULL
);
978 entry
->flags
.indicator
= 1;
979 entry
->flags
.indicator_on
= 1;
980 entry
->flags
.indicator_type
= MI_CHECK
;
982 entry
= wMenuAddCallback(menu
, _("Keep Attracted Icons"),
983 toggleKeepCallback
, NULL
);
984 entry
->flags
.indicator
= 1;
985 entry
->flags
.indicator_on
= 1;
986 entry
->flags
.indicator_type
= MI_CHECK
;
988 menu
->flags
.realized
= 0;
996 dockMenuCreate(WScreen
*scr
, int type
)
1001 if (type
== WM_CLIP
&& scr
->clip_menu
)
1002 return scr
->clip_menu
;
1004 menu
= wMenuCreate(scr
, NULL
, False
);
1005 if (type
!= WM_CLIP
) {
1006 entry
= wMenuAddCallback(menu
, _("Floating Dock"),
1007 toggleLoweredCallback
, NULL
);
1008 entry
->flags
.indicator
= 1;
1009 entry
->flags
.indicator_on
= 1;
1010 entry
->flags
.indicator_type
= MI_CHECK
;
1012 entry
= wMenuAddCallback(menu
, _("Clip Options"), NULL
, NULL
);
1013 scr
->clip_options
= makeClipOptionsMenu(scr
);
1014 if (scr
->clip_options
)
1015 wMenuEntrySetCascade(menu
, entry
, scr
->clip_options
);
1017 wMenuAddCallback(menu
, _("Rename Workspace"), renameCallback
, NULL
);
1019 wMenuAddCallback(menu
, _("(Un)Select Icon"), selectCallback
, NULL
);
1021 wMenuAddCallback(menu
, _("(Un)Select All Icons"), selectIconsCallback
,
1024 wMenuAddCallback(menu
, _("Keep Icon(s)"), keepIconsCallback
, NULL
);
1026 entry
= wMenuAddCallback(menu
, _("Move Icon(s) To"), NULL
, NULL
);
1027 scr
->clip_submenu
= makeWorkspaceMenu(scr
);
1028 if (scr
->clip_submenu
)
1029 wMenuEntrySetCascade(menu
, entry
, scr
->clip_submenu
);
1031 wMenuAddCallback(menu
, _("Remove Icon(s)"), removeIconsCallback
, NULL
);
1033 wMenuAddCallback(menu
, _("Attract Icons"), colectIconsCallback
, NULL
);
1036 wMenuAddCallback(menu
, _("Launch"), launchCallback
, NULL
);
1038 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
1040 wMenuAddCallback(menu
, _("(Un)Hide"), hideCallback
, NULL
);
1042 wMenuAddCallback(menu
, _("Settings..."), settingsCallback
, NULL
);
1044 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
1046 if (type
== WM_CLIP
)
1047 scr
->clip_menu
= menu
;
1054 wDockCreate(WScreen
*scr
, int type
)
1062 dock
= wmalloc(sizeof(WDock
));
1063 memset(dock
, 0, sizeof(WDock
));
1065 if (type
== WM_CLIP
)
1066 icon_count
= CLIP_MAX_ICONS
;
1068 icon_count
= scr
->scr_height
/wPreferences
.icon_size
;
1070 dock
->icon_array
= wmalloc(sizeof(WAppIcon
*)*icon_count
);
1071 memset(dock
->icon_array
, 0, sizeof(WAppIcon
*)*icon_count
);
1073 dock
->max_icons
= icon_count
;
1075 btn
= mainIconCreate(scr
, type
);
1079 dock
->x_pos
= btn
->x_pos
;
1080 dock
->y_pos
= btn
->y_pos
;
1081 dock
->screen_ptr
= scr
;
1083 dock
->icon_count
= 1;
1084 dock
->on_right_side
= 1;
1085 dock
->collapsed
= 0;
1086 dock
->auto_collapse
= 0;
1087 dock
->auto_collapse_magic
= NULL
;
1088 dock
->attract_icons
= 0;
1089 dock
->keep_attracted
= 0;
1091 dock
->icon_array
[0] = btn
;
1092 wRaiseFrame(btn
->icon
->core
);
1093 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
1095 /* create dock menu */
1096 dock
->menu
= dockMenuCreate(scr
, type
);
1103 wDockDestroy(WDock
*dock
)
1108 for (i
=(dock
->type
== WM_CLIP
) ? 1 : 0; i
<dock
->max_icons
; i
++) {
1109 aicon
= dock
->icon_array
[i
];
1111 int keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
1112 wDockDetach(dock
, aicon
);
1114 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
1116 wLowerFrame(aicon
->icon
->core
);
1118 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
1119 aicon
->x_pos
, aicon
->y_pos
);
1120 if (!dock
->mapped
|| dock
->collapsed
)
1121 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1125 if (wPreferences
.auto_arrange_icons
)
1126 wArrangeIcons(dock
->screen_ptr
, True
);
1127 free(dock
->icon_array
);
1128 if (dock
->menu
&& dock
->type
!=WM_CLIP
)
1129 wMenuDestroy(dock
->menu
, True
);
1135 wClipIconPaint(WAppIcon
*aicon
)
1137 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
1138 WWorkspace
*workspace
= scr
->workspaces
[scr
->current_workspace
];
1140 Window win
= aicon
->icon
->core
->window
;
1141 int length
, nlength
;
1142 char *ws_name
, ws_number
[10];
1145 wIconPaint(aicon
->icon
);
1147 length
= strlen(workspace
->name
);
1148 ws_name
= malloc(length
+ 1);
1149 sprintf(ws_name
, "%s", workspace
->name
);
1150 sprintf(ws_number
, "%i", scr
->current_workspace
+ 1);
1151 nlength
= strlen(ws_number
);
1153 gc
= scr
->clip_title_gc
;
1155 if (!workspace
->clip
->collapsed
)
1156 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_NORMAL
]);
1158 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_COLLAPSED
]);
1160 ty
= ICON_SIZE
- scr
->clip_title_font
->height
- 3;
1162 tx
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
1164 wDrawString(win
, scr
->clip_title_font
, gc
, tx
,
1165 ty
+ scr
->clip_title_font
->y
, ws_name
, length
);
1167 tx
= (ICON_SIZE
/2 - wTextWidth(scr
->clip_title_font
->font
, ws_number
, nlength
))/2;
1169 wDrawString(win
, scr
->clip_title_font
, gc
, tx
,
1170 scr
->clip_title_font
->y
+ 2, ws_number
, nlength
);
1174 if (aicon
->launching
) {
1175 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
1176 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
1178 paintClipButtons(aicon
, aicon
->dock
->lclip_button_pushed
,
1179 aicon
->dock
->rclip_button_pushed
);
1184 clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
)
1186 wClipIconPaint(desc
->parent
);
1191 dockIconPaint(WAppIcon
*btn
)
1193 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1194 wClipIconPaint(btn
);
1201 make_icon_state(WAppIcon
*btn
)
1203 proplist_t node
= NULL
;
1204 proplist_t command
, autolaunch
, name
, forced
, host
, position
, buggy
;
1210 command
= PLMakeString("-");
1212 command
= PLMakeString(btn
->command
);
1214 autolaunch
= btn
->auto_launch
? dYes
: dNo
;
1216 if (btn
->wm_class
&& btn
->wm_instance
)
1217 sprintf(buffer
, "%s.%s", btn
->wm_instance
, btn
->wm_class
);
1218 else if (btn
->wm_instance
)
1219 sprintf(buffer
, "%s", btn
->wm_instance
);
1220 else if (btn
->wm_class
)
1221 sprintf(buffer
, ".%s", btn
->wm_class
);
1223 sprintf(buffer
, ".");
1225 name
= PLMakeString(buffer
);
1227 forced
= btn
->forced_dock
? dYes
: dNo
;
1229 buggy
= btn
->buggy_app
? dYes
: dNo
;
1231 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1232 sprintf(buffer
, "%i,%i", btn
->x_pos
, btn
->y_pos
);
1234 sprintf(buffer
, "%hi,%hi", btn
->xindex
, btn
->yindex
);
1235 position
= PLMakeString(buffer
);
1237 node
= PLMakeDictionaryFromEntries(dCommand
, command
,
1239 dAutoLaunch
, autolaunch
,
1241 dBuggyApplication
, buggy
,
1242 dPosition
, position
,
1246 PLRelease(position
);
1248 if (btn
->dnd_command
) {
1249 command
= PLMakeString(btn
->dnd_command
);
1250 PLInsertDictionaryEntry(node
, dDropCommand
, command
);
1253 #endif /* OFFIX_DND */
1255 if (btn
->client_machine
&& btn
->remote_start
) {
1256 host
= PLMakeString(btn
->client_machine
);
1257 PLInsertDictionaryEntry(node
, dHost
, host
);
1267 dockSaveState(WDock
*dock
)
1270 proplist_t icon_info
;
1271 proplist_t list
=NULL
, dock_state
=NULL
;
1275 list
= PLMakeArrayFromElements(NULL
);
1277 for (i
=(dock
->type
==WM_DOCK
? 0 : 1); i
<dock
->max_icons
; i
++) {
1278 WAppIcon
*btn
= dock
->icon_array
[i
];
1280 if (!btn
|| (btn
->attracted
&& !dock
->keep_attracted
))
1283 if ((icon_info
= make_icon_state(dock
->icon_array
[i
]))) {
1284 list
= PLAppendArrayElement(list
, icon_info
);
1285 PLRelease(icon_info
);
1289 dock_state
= PLMakeDictionaryFromEntries(dApplications
, list
, NULL
);
1293 if (dock
->type
== WM_DOCK
) {
1294 sprintf(buffer
, "%i,%i", (dock
->on_right_side
? -ICON_SIZE
: 0),
1296 value
= PLMakeString(buffer
);
1297 PLInsertDictionaryEntry(dock_state
, dPosition
, value
);
1301 value
= (dock
->lowered
? dYes
: dNo
);
1302 PLInsertDictionaryEntry(dock_state
, dLowered
, value
);
1304 if (dock
->type
== WM_CLIP
) {
1305 value
= (dock
->collapsed
? dYes
: dNo
);
1306 PLInsertDictionaryEntry(dock_state
, dCollapsed
, value
);
1308 value
= (dock
->auto_collapse
? dYes
: dNo
);
1309 PLInsertDictionaryEntry(dock_state
, dAutoCollapse
, value
);
1311 value
= (dock
->attract_icons
? dYes
: dNo
);
1312 PLInsertDictionaryEntry(dock_state
, dAutoAttractIcons
, value
);
1314 value
= (dock
->keep_attracted
? dYes
: dNo
);
1315 PLInsertDictionaryEntry(dock_state
, dKeepAttracted
, value
);
1323 wDockSaveState(WScreen
*scr
)
1325 proplist_t dock_state
;
1327 dock_state
= dockSaveState(scr
->dock
);
1329 PLInsertDictionaryEntry(scr
->session_state
, dDock
, dock_state
);
1331 PLRelease(dock_state
);
1336 wClipSaveState(WScreen
*scr
)
1338 proplist_t clip_state
;
1340 clip_state
= make_icon_state(scr
->clip_icon
);
1342 PLInsertDictionaryEntry(scr
->session_state
, dClip
, clip_state
);
1344 PLRelease(clip_state
);
1349 wClipSaveWorkspaceState(WScreen
*scr
, int workspace
)
1351 return dockSaveState(scr
->workspaces
[workspace
]->clip
);
1356 restore_icon_state(WScreen
*scr
, proplist_t info
, int type
, int index
)
1359 char *wclass
, *winstance
;
1360 proplist_t cmd
, value
;
1364 cmd
= PLGetDictionaryEntry(info
, dCommand
);
1365 if (!cmd
|| !PLIsString(cmd
)) {
1369 /* parse window name */
1370 value
= PLGetDictionaryEntry(info
, dName
);
1374 ParseWindowName(value
, &winstance
, &wclass
, "dock");
1376 if (!winstance
&& !wclass
) {
1382 command
= wstrdup(PLGetString(cmd
));
1384 if (!command
|| strcmp(command
, "-")==0) {
1395 aicon
= wAppIconCreateForDock(scr
, command
, winstance
, wclass
,
1402 aicon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
1403 if (type
== WM_CLIP
) {
1404 aicon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
1405 aicon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
1407 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
1408 aicon
->icon
->core
->descriptor
.parent
= aicon
;
1412 cmd
= PLGetDictionaryEntry(info
, dDropCommand
);
1414 aicon
->dnd_command
= wstrdup(PLGetString(cmd
));
1417 /* check auto launch */
1418 value
= PLGetDictionaryEntry(info
, dAutoLaunch
);
1420 aicon
->auto_launch
= 0;
1422 if (PLIsString(value
)) {
1423 if (strcasecmp(PLGetString(value
), "YES")==0)
1424 aicon
->auto_launch
= 1;
1426 wwarning(_("bad value in docked icon state info %s"),
1427 PLGetString(dAutoLaunch
));
1431 /* check if it wasn't normally docked */
1432 value
= PLGetDictionaryEntry(info
, dForced
);
1434 aicon
->forced_dock
= 0;
1436 if (PLIsString(value
)) {
1437 if (strcasecmp(PLGetString(value
), "YES")==0)
1438 aicon
->forced_dock
= 1;
1440 wwarning(_("bad value in docked icon state info %s"),
1441 PLGetString(dForced
));
1445 /* check if we can rely on the stuff in the app */
1446 value
= PLGetDictionaryEntry(info
, dBuggyApplication
);
1448 aicon
->buggy_app
= 0;
1450 if (PLIsString(value
)) {
1451 if (strcasecmp(PLGetString(value
), "YES")==0)
1452 aicon
->buggy_app
= 1;
1454 wwarning(_("bad value in docked icon state info %s"),
1455 PLGetString(dBuggyApplication
));
1459 /* get position in the dock */
1460 value
= PLGetDictionaryEntry(info
, dPosition
);
1461 if (value
&& PLIsString(value
)) {
1462 if (sscanf(PLGetString(value
), "%hi,%hi", &aicon
->xindex
,
1464 wwarning(_("bad value in docked icon state info %s"),
1465 PLGetString(dPosition
));
1467 /* check position sanity */
1468 /* incomplete section! */
1469 if (type
== WM_DOCK
) {
1471 if (aicon
->yindex
< 0)
1472 wwarning(_("bad value in docked icon position %i,%i"),
1473 aicon
->xindex
, aicon
->yindex
);
1476 aicon
->yindex
= index
;
1487 #define COMPLAIN(key) wwarning(_("bad value in dock state info:%s"), key)
1491 wClipRestoreState(WScreen
*scr
, proplist_t clip_state
)
1497 icon
= mainIconCreate(scr
, WM_CLIP
);
1502 PLRetain(clip_state
);
1504 /* restore position */
1506 value
= PLGetDictionaryEntry(clip_state
, dPosition
);
1509 if (!PLIsString(value
))
1510 COMPLAIN("Position");
1512 if (sscanf(PLGetString(value
), "%i,%i", &icon
->x_pos
,
1514 COMPLAIN("Position");
1516 /* check position sanity */
1517 if (icon
->y_pos
< 0)
1519 else if (icon
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1520 icon
->y_pos
= scr
->scr_height
-ICON_SIZE
;
1522 if (icon
->x_pos
< 0)
1524 else if (icon
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1525 icon
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1530 value
= PLGetDictionaryEntry(clip_state
, dDropCommand
);
1531 if (value
&& PLIsString(value
))
1532 icon
->dnd_command
= wstrdup(PLGetString(value
));
1535 PLRelease(clip_state
);
1542 wDockRestoreState(WScreen
*scr
, proplist_t dock_state
, int type
)
1547 WAppIcon
*aicon
, *old_top
;
1551 dock
= wDockCreate(scr
, type
);
1557 PLRetain(dock_state
);
1560 /* restore position */
1562 value
= PLGetDictionaryEntry(dock_state
, dPosition
);
1565 if (!PLIsString(value
))
1566 COMPLAIN("Position");
1568 if (sscanf(PLGetString(value
), "%i,%i", &dock
->x_pos
,
1570 COMPLAIN("Position");
1572 /* check position sanity */
1573 if (dock
->y_pos
< 0)
1575 else if (dock
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1576 dock
->y_pos
= scr
->scr_height
-ICON_SIZE
;
1578 /* This is no more needed. ??? */
1579 if (type
== WM_CLIP
) {
1580 if (dock
->x_pos
< 0)
1582 else if (dock
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1583 dock
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1586 if (dock
->x_pos
>= 0) {
1587 dock
->x_pos
= DOCK_EXTRA_SPACE
;
1588 dock
->on_right_side
= 0;
1590 dock
->x_pos
= scr
->scr_width
- DOCK_EXTRA_SPACE
- ICON_SIZE
;
1591 dock
->on_right_side
= 1;
1597 /* restore lowered/raised state */
1601 value
= PLGetDictionaryEntry(dock_state
, dLowered
);
1604 if (!PLIsString(value
))
1605 COMPLAIN("Lowered");
1607 if (strcasecmp(PLGetString(value
), "YES")==0)
1613 /* restore collapsed state */
1615 dock
->collapsed
= 0;
1617 value
= PLGetDictionaryEntry(dock_state
, dCollapsed
);
1620 if (!PLIsString(value
))
1621 COMPLAIN("Collapsed");
1623 if (strcasecmp(PLGetString(value
), "YES")==0)
1624 dock
->collapsed
= 1;
1629 /* restore auto-collapsed state */
1631 value
= PLGetDictionaryEntry(dock_state
, dAutoCollapse
);
1634 if (!PLIsString(value
))
1635 COMPLAIN("AutoCollapse");
1637 if (strcasecmp(PLGetString(value
), "YES")==0) {
1638 dock
->auto_collapse
= 1;
1639 dock
->collapsed
= 1;
1645 /* restore attract icons state */
1647 dock
->attract_icons
= 0;
1649 value
= PLGetDictionaryEntry(dock_state
, dAutoAttractIcons
);
1652 if (!PLIsString(value
))
1653 COMPLAIN("AutoAttractIcons");
1655 if (strcasecmp(PLGetString(value
), "YES")==0)
1656 dock
->attract_icons
= 1;
1661 /* restore keep attracted icons state */
1663 dock
->keep_attracted
= 0;
1665 value
= PLGetDictionaryEntry(dock_state
, dKeepAttracted
);
1668 if (!PLIsString(value
))
1669 COMPLAIN("KeepAttracted");
1671 if (strcasecmp(PLGetString(value
), "YES")==0)
1672 dock
->keep_attracted
= 1;
1677 /* application list */
1679 apps
= PLGetDictionaryEntry(dock_state
, dApplications
);
1685 count
= PLGetNumberOfElements(apps
);
1690 old_top
= dock
->icon_array
[0];
1692 /* dock->icon_count is set to 1 when dock is created.
1693 * Since Clip is already restored, we want to keep it so for clip,
1694 * but for dock we may change the default top tile, so we set it to 0.
1696 if (type
== WM_DOCK
)
1697 dock
->icon_count
= 0;
1699 for (i
=0; i
<count
; i
++) {
1700 if (dock
->icon_count
>= dock
->max_icons
) {
1701 wwarning(_("there are too many icons stored in dock. Ignoring what doesn't fit"));
1705 value
= PLGetArrayElement(apps
, i
);
1706 aicon
= restore_icon_state(scr
, value
, type
, dock
->icon_count
);
1708 dock
->icon_array
[dock
->icon_count
] = aicon
;
1712 aicon
->x_pos
= dock
->x_pos
+ (aicon
->xindex
*ICON_SIZE
);
1713 aicon
->y_pos
= dock
->y_pos
+ (aicon
->yindex
*ICON_SIZE
);
1716 ChangeStackingLevel(aicon
->icon
->core
, WMNormalWindowLevel
);
1718 ChangeStackingLevel(aicon
->icon
->core
, WMDockWindowLevel
);
1720 wCoreConfigure(aicon
->icon
->core
, aicon
->x_pos
, aicon
->y_pos
,
1723 if (!dock
->collapsed
)
1724 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1725 wRaiseFrame(aicon
->icon
->core
);
1728 } else if (dock
->icon_count
==0 && type
==WM_DOCK
)
1732 /* if the first icon is not defined, use the default */
1733 if (dock
->icon_array
[0]==NULL
) {
1734 /* update default icon */
1735 old_top
->x_pos
= dock
->x_pos
;
1736 old_top
->y_pos
= dock
->y_pos
;
1738 ChangeStackingLevel(old_top
->icon
->core
, WMNormalWindowLevel
);
1740 ChangeStackingLevel(old_top
->icon
->core
, WMDockWindowLevel
);
1741 dock
->icon_array
[0] = old_top
;
1742 XMoveWindow(dpy
, old_top
->icon
->core
->window
, dock
->x_pos
, dock
->y_pos
);
1743 /* we don't need to increment dock->icon_count here because it was
1744 * incremented in the loop above.
1746 } else if (old_top
!=dock
->icon_array
[0]) {
1747 if (old_top
== scr
->clip_icon
)
1748 scr
->clip_icon
= dock
->icon_array
[0];
1749 wAppIconDestroy(old_top
);
1754 PLRelease(dock_state
);
1762 wDockLaunchWithState(WDock
*dock
, WAppIcon
*btn
, WSavedState
*state
)
1764 if (btn
&& btn
->command
&& !btn
->running
&& !btn
->launching
) {
1766 btn
->drop_launch
= 0;
1768 btn
->pid
= execCommand(btn
, btn
->command
, state
);
1771 if (!btn
->forced_dock
&& !btn
->buggy_app
) {
1783 wDockDoAutoLaunch(WDock
*dock
, int workspace
)
1789 for (i
=0; i
< dock
->max_icons
; i
++) {
1790 btn
= dock
->icon_array
[i
];
1791 if (!btn
|| !btn
->auto_launch
)
1794 state
= wmalloc(sizeof(WSavedState
));
1795 memset(state
, 0, sizeof(WSavedState
));
1796 state
->workspace
= workspace
;
1797 /* TODO: this is klugy and is very difficult to understand
1798 * what's going on. Try to clean up */
1799 wDockLaunchWithState(dock
, btn
, state
);
1803 #ifdef REDUCE_APPICONS
1805 wDockSimulateLaunch(WDock
*dock
, WAppIcon
*btn
)
1807 if ((btn
== NULL
) || (dock
== NULL
))
1810 if (!btn
->running
) {
1811 if ((btn
->icon
->owner
== NULL
) && (btn
->applist
))
1812 btn
->icon
->owner
= btn
->applist
->wapp
->main_window_desc
;
1813 if (!btn
->forced_dock
)
1823 findDock(WScreen
*scr
, XEvent
*event
, int *icon_pos
)
1829 if ((dock
= scr
->dock
)!=NULL
) {
1830 for (i
=0; i
<dock
->max_icons
; i
++) {
1831 if (dock
->icon_array
[i
]
1832 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
1838 if (*icon_pos
<0 && (dock
= scr
->workspaces
[scr
->current_workspace
]->clip
)!=NULL
) {
1839 for (i
=0; i
<dock
->max_icons
; i
++) {
1840 if (dock
->icon_array
[i
]
1841 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
1854 wDockReceiveDNDDrop(WScreen
*scr
, XEvent
*event
)
1860 dock
= findDock(scr
, event
, &icon_pos
);
1865 * Return True if the drop was on an application icon window.
1866 * In this case, let the ClientMessage handler redirect the
1867 * message to the app.
1869 if (dock
->icon_array
[icon_pos
]->icon
->icon_win
!=None
)
1872 if (dock
->icon_array
[icon_pos
]->dnd_command
!=NULL
) {
1873 scr
->flags
.dnd_data_convertion_status
= 0;
1875 btn
= dock
->icon_array
[icon_pos
];
1877 if (!btn
->forced_dock
) {
1878 btn
->relaunching
= btn
->running
;
1881 if (btn
->wm_instance
|| btn
->wm_class
) {
1882 WWindowAttributes attr
;
1883 memset(&attr
, 0, sizeof(WWindowAttributes
));
1884 wDefaultFillAttributes(btn
->icon
->core
->screen_ptr
,
1886 btn
->wm_class
, &attr
, True
);
1888 if (!attr
.no_appicon
)
1894 btn
->drop_launch
= 1;
1895 scr
->last_dock
= dock
;
1896 btn
->pid
= execCommand(btn
, btn
->dnd_command
, NULL
);
1901 if (!btn
->relaunching
) {
1908 #endif /* OFFIX_DND */
1913 wDockAttachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
1920 wwin
= icon
->icon
->owner
;
1921 if (icon
->command
==NULL
) {
1922 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
1924 icon
->command
= FlattenStringList(argv
, argc
);
1925 XFreeStringList(argv
);
1929 /* icon->forced_dock = 1;*/
1930 if (!icon
->attracted
|| dock
->type
!=WM_CLIP
|| dock
->keep_attracted
) {
1931 if (wInputDialog(dock
->screen_ptr
, _("Dock Icon"),
1932 _("Type the command used to launch the application"),
1933 &command
)==WDB_OK
) {
1934 if (command
&& (command
[0]==0 ||
1935 (command
[0]=='-' && command
[1]==0))) {
1939 icon
->command
= command
;
1943 /* If the target is the dock, reject the icon. If
1944 * the target is the clip, make it an attracted icon
1946 if (dock
->type
==WM_CLIP
) {
1947 icon
->attracted
= 1;
1948 if (!icon
->icon
->shadowed
) {
1949 icon
->icon
->shadowed
= 1;
1950 icon
->icon
->force_paint
= 1;
1960 for (index
=1; index
<dock
->max_icons
; index
++)
1961 if (dock
->icon_array
[index
] == NULL
)
1963 /* if (index == dock->max_icons)
1966 assert(index
< dock
->max_icons
);
1968 dock
->icon_array
[index
] = icon
;
1972 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
1973 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
1978 icon
->launching
= 0;
1981 icon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
1982 if (dock
->type
== WM_CLIP
) {
1983 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
1984 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
1986 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
1987 icon
->icon
->core
->descriptor
.parent
= icon
;
1989 MoveInStackListUnder(dock
->icon_array
[index
-1]->icon
->core
,
1991 wAppIconMove(icon
, icon
->x_pos
, icon
->y_pos
);
1992 wAppIconPaint(icon
);
1994 if (wPreferences
.auto_arrange_icons
)
1995 wArrangeIcons(dock
->screen_ptr
, True
);
2002 reattachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
2006 for(index
=1; index
<dock
->max_icons
; index
++) {
2007 if(dock
->icon_array
[index
] == icon
)
2010 assert(index
< dock
->max_icons
);
2015 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
2016 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
2021 moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
)
2031 wwin
= icon
->icon
->owner
;
2034 * For the moment we can't do this if we move icons in Clip from one
2035 * workspace to other, because if we move two or more icons without
2036 * command, the dialog box will not be able to tell us to which of the
2037 * moved icons it applies. -Dan
2039 if ((dest
->type
==WM_DOCK
/*|| dest->keep_attracted*/) && icon
->command
==NULL
) {
2040 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
2042 icon
->command
= FlattenStringList(argv
, argc
);
2043 XFreeStringList(argv
);
2047 /* icon->forced_dock = 1;*/
2048 if (wInputDialog(src
->screen_ptr
, _("Dock Icon"),
2049 _("Type the command used to launch the application"),
2050 &command
)==WDB_OK
) {
2051 if (command
&& (command
[0]==0 ||
2052 (command
[0]=='-' && command
[1]==0))) {
2056 icon
->command
= command
;
2065 for(index
=1; index
<src
->max_icons
; index
++) {
2066 if(src
->icon_array
[index
] == icon
)
2069 assert(index
< src
->max_icons
);
2071 src
->icon_array
[index
] = NULL
;
2074 for(index
=1; index
<dest
->max_icons
; index
++) {
2075 if(dest
->icon_array
[index
] == NULL
)
2078 /* if (index == dest->max_icons)
2081 assert(index
< dest
->max_icons
);
2083 dest
->icon_array
[index
] = icon
;
2086 /* deselect the icon */
2087 if (icon
->icon
->selected
)
2088 wIconSelect(icon
->icon
);
2090 if (dest
->type
== WM_DOCK
) {
2091 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2092 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2094 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
2095 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
2098 /* set it to be kept when moving to dock, or to a clip that keep the
2100 * Unless the icon does not have a command set
2102 if (icon
->command
&& (dest
->type
==WM_DOCK
|| dest
->keep_attracted
)) {
2103 icon
->attracted
= 0;
2104 if (icon
->icon
->shadowed
) {
2105 icon
->icon
->shadowed
= 0;
2106 icon
->icon
->force_paint
= 1;
2110 if (src
->auto_collapse
)
2116 icon
->x_pos
= dest
->x_pos
+ x
*ICON_SIZE
;
2117 icon
->y_pos
= dest
->y_pos
+ y
*ICON_SIZE
;
2121 MoveInStackListUnder(dest
->icon_array
[index
-1]->icon
->core
,
2123 wAppIconPaint(icon
);
2129 wDockDetach(WDock
*dock
, WAppIcon
*icon
)
2133 /* make the settings panel be closed */
2135 DestroyDockAppSettingsPanel(icon
->panel
);
2140 icon
->attracted
= 0;
2141 if (icon
->icon
->shadowed
) {
2142 icon
->icon
->shadowed
= 0;
2143 icon
->icon
->force_paint
= 1;
2146 /* deselect the icon */
2147 if (icon
->icon
->selected
)
2148 wIconSelect(icon
->icon
);
2150 if (icon
->command
) {
2151 free(icon
->command
);
2152 icon
->command
= NULL
;
2155 if (icon
->dnd_command
) {
2156 free(icon
->dnd_command
);
2157 icon
->dnd_command
= NULL
;
2161 for (index
=1; index
<dock
->max_icons
; index
++)
2162 if (dock
->icon_array
[index
] == icon
)
2164 assert(index
< dock
->max_icons
);
2165 dock
->icon_array
[index
] = NULL
;
2170 /* if the dock is not attached to an application or
2171 * the the application did not set the approriate hints yet,
2172 * destroy the icon */
2173 #ifdef REDUCE_APPICONS
2174 if ((icon
->num_apps
== 0) && (!icon
->running
|| !wApplicationOf(icon
->main_window
)) )
2176 if (!icon
->running
|| !wApplicationOf(icon
->main_window
))
2178 wAppIconDestroy(icon
);
2180 icon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
2181 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2182 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2183 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
2184 icon
->icon
->core
->descriptor
.parent
= icon
;
2185 ChangeStackingLevel(icon
->icon
->core
, WMNormalWindowLevel
);
2186 wAppIconPaint(icon
);
2187 if (wPreferences
.auto_arrange_icons
) {
2188 wArrangeIcons(dock
->screen_ptr
, True
);
2191 if (dock
->auto_collapse
)
2197 * returns the closest Dock slot index for the passed
2200 * Returns False if icon can't be docked.
2203 wDockSnapIcon(WDock
*dock
, WAppIcon
*icon
, int req_x
, int req_y
,
2204 int *ret_x
, int *ret_y
, int redocking
)
2206 WScreen
*scr
= dock
->screen_ptr
;
2209 int i
, offset
= ICON_SIZE
/2;
2210 int only_down
= (dock
->type
== WM_DOCK
);
2211 WAppIcon
*aicon
= NULL
;
2212 WAppIcon
*nicon
= NULL
;
2217 /* if the dock is full */
2219 (dock
->icon_count
>= dock
->max_icons
)) {
2223 /* exact position */
2225 ex_y
= (req_y
- offset
- dy
)/ICON_SIZE
;
2227 ex_y
= (req_y
+ offset
- dy
)/ICON_SIZE
;
2230 ex_x
= (req_x
- offset
- dx
)/ICON_SIZE
;
2232 ex_x
= (req_x
+ offset
- dx
)/ICON_SIZE
;
2234 if ((ex_y
< 1 || ex_x
!= 0) && only_down
)
2237 if (dock
->x_pos
+ ex_x
*ICON_SIZE
< -ICON_SIZE
+2 ||
2238 dock
->x_pos
+ ex_x
*ICON_SIZE
> scr
->scr_width
-1 ||
2239 dock
->y_pos
+ ex_y
*ICON_SIZE
< -ICON_SIZE
+2 ||
2240 dock
->y_pos
+ ex_y
*ICON_SIZE
> scr
->scr_height
-1)
2243 for (i
=0; i
<dock
->max_icons
; i
++) {
2244 nicon
= dock
->icon_array
[i
];
2245 if (nicon
&& nicon
->xindex
== ex_x
&& nicon
->yindex
== ex_y
) {
2253 for (i
=0; i
<dock
->max_icons
; i
++) {
2254 nicon
= dock
->icon_array
[i
];
2255 if (nicon
&& nicon
!= icon
&& /* Icon can't be it's own neighbour */
2256 (abs(nicon
->xindex
- ex_x
) <= CLIP_ATTACH_VICINITY
&&
2257 abs(nicon
->yindex
- ex_y
) <= CLIP_ATTACH_VICINITY
)) {
2262 if ((!redocking
&& neighbours
&& !aicon
) ||
2263 (redocking
&& neighbours
&& (aicon
== icon
|| !aicon
))) {
2270 if ((!redocking
&& !aicon
) ||
2271 (redocking
&& (aicon
==icon
|| !aicon
))) {
2281 #define MIN(x, y) ((x) > (y) ? (y) : (x))
2282 #define MAX(x, y) ((x) < (y) ? (y) : (x))
2284 #define ON_SCREEN(x, y, sx, ex, sy, ey) \
2285 ((((x)+ICON_SIZE/2) >= (sx)) && (((y)+ICON_SIZE/2) >= (sy)) && \
2286 (((x) + (ICON_SIZE/2)) <= (ex)) && (((y) + (ICON_SIZE/2)) <= ey))
2290 * returns true if it can find a free slot in the dock,
2291 * in which case it changes x_pos and y_pos accordingly.
2292 * Else returns false.
2295 wDockFindFreeSlot(WDock
*dock
, int *x_pos
, int *y_pos
)
2297 WScreen
*scr
= dock
->screen_ptr
;
2300 unsigned char *slot_map
;
2304 int i
, done
= False
;
2307 int n
= MAX(dock
->max_icons
, MAX(scr
->scr_width
, scr
->scr_height
)/ICON_SIZE
+ 1);
2308 unsigned char *north
, *south
, *east
, *west
;
2309 int i
, j
, done
=False
;
2311 int sx
=0, sy
=0, ex
=scr
->scr_width
, ey
=scr
->scr_height
;
2313 /* if the dock is full */
2314 if (dock
->icon_count
>= dock
->max_icons
) {
2318 if (!wPreferences
.flags
.nodock
&& scr
->dock
) {
2319 if (scr
->dock
->on_right_side
)
2320 ex
-= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2322 sx
+= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2325 if (ex
< dock
->x_pos
)
2327 if (sx
> dock
->x_pos
+ICON_SIZE
)
2328 sx
= dock
->x_pos
+ICON_SIZE
;
2336 /* check if clip is in a corner */
2337 if (dock
->type
==WM_CLIP
) {
2338 if (dock
->x_pos
< 1 && dock
->y_pos
< 1)
2340 else if (dock
->x_pos
< 1 && dock
->y_pos
>= (ey
-ICON_SIZE
))
2342 else if (dock
->x_pos
>= (ex
-ICON_SIZE
)&& dock
->y_pos
>= (ey
-ICON_SIZE
))
2344 else if (dock
->x_pos
>= (ex
-ICON_SIZE
) && dock
->y_pos
< 1)
2351 /* This one checks for diagonal positions, uses less memory
2352 * and CPU. -Alfredo */
2354 /* If the clip is in the corner, use only slots that are in the border
2356 if (corner
!=C_NONE
) {
2360 hcount
= MIN(dock
->max_icons
, scr
->scr_width
/ICON_SIZE
);
2361 vcount
= MIN(dock
->max_icons
, scr
->scr_height
/ICON_SIZE
);
2362 hmap
= wmalloc(hcount
+1);
2363 memset(hmap
, 0, hcount
+1);
2364 vmap
= wmalloc(vcount
+1);
2365 memset(vmap
, 0, vcount
+1);
2367 /* mark used positions */
2370 for (i
=0; i
<dock
->max_icons
; i
++) {
2371 btn
= dock
->icon_array
[i
];
2375 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2376 vmap
[btn
->yindex
] = 1;
2377 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2378 hmap
[btn
->xindex
] = 1;
2381 for (i
=0; i
<dock
->max_icons
; i
++) {
2382 btn
= dock
->icon_array
[i
];
2386 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2387 vmap
[btn
->yindex
] = 1;
2388 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2389 hmap
[-btn
->xindex
] = 1;
2392 for (i
=0; i
<dock
->max_icons
; i
++) {
2393 btn
= dock
->icon_array
[i
];
2397 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2398 vmap
[-btn
->yindex
] = 1;
2399 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2400 hmap
[btn
->xindex
] = 1;
2404 for (i
=0; i
<dock
->max_icons
; i
++) {
2405 btn
= dock
->icon_array
[i
];
2409 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2410 vmap
[-btn
->yindex
] = 1;
2411 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2412 hmap
[-btn
->xindex
] = 1;
2417 /* search a vacant slot */
2418 for (i
=1; i
<MAX(vcount
, hcount
); i
++) {
2419 if (i
< vcount
&& vmap
[i
]==0) {
2425 } else if (i
< hcount
&& hmap
[i
]==0) {
2435 /* If found a slot, translate and return */
2437 if (corner
==C_NW
|| corner
==C_NE
) {
2442 if (corner
==C_NE
|| corner
==C_SE
) {
2449 /* else, try to find a slot somewhere else */
2452 /* a map of mwidth x mwidth would be enough if we allowed icons to be
2453 * placed outside of screen */
2454 mwidth
= (int)ceil(sqrt(dock
->max_icons
));
2456 /* In the worst case (the clip is in the corner of the screen),
2457 * the amount of icons that fit in the clip is smaller.
2458 * Double the map to get a safe value.
2464 slot_map
= wmalloc(mwidth
*mwidth
);
2465 memset(slot_map
, 0, mwidth
*mwidth
);
2467 #define XY2OFS(x,y) (MAX(abs(x),abs(y)) > r) ? 0 : (((y)+r)*(mwidth)+(x)+r)
2469 /* mark used slots in the map. If the slot falls outside the map
2470 * (for example, when all icons are placed in line), ignore them. */
2471 for (i
=0; i
<dock
->max_icons
; i
++) {
2472 btn
= dock
->icon_array
[i
];
2474 slot_map
[XY2OFS(btn
->xindex
, btn
->yindex
)] = 1;
2476 /* Find closest slot from the center that is free by scanning the
2477 * map from the center to outward in circular passes.
2478 * This will not result in a neat layout, but will be optimal
2479 * in the sense that there will not be holes left.
2482 for (i
= 1; i
<= r
&& !done
; i
++) {
2485 /* top and bottom parts of the ring */
2486 for (x
= -i
; x
<= i
&& !done
; x
++) {
2487 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2489 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2490 if (slot_map
[XY2OFS(x
,y
)]==0
2491 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2498 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2499 if (slot_map
[XY2OFS(x
,y
)]==0
2500 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2507 /* left and right parts of the ring */
2508 for (y
= -i
+1; y
<= i
-1; y
++) {
2509 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2511 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2512 if (slot_map
[XY2OFS(x
,y
)]==0
2513 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2520 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2521 if (slot_map
[XY2OFS(x
,y
)]==0
2522 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2534 north
= (unsigned char*) wmalloc(sizeof(unsigned char) * n
);
2535 south
= (unsigned char*) wmalloc(sizeof(unsigned char) * n
);
2536 east
= (unsigned char*) wmalloc(sizeof(unsigned char) * n
);
2537 west
= (unsigned char*) wmalloc(sizeof(unsigned char) * n
);
2539 /* We allow 3 passes to find a free position. This can be increased,
2540 * but usually is more than enough for a normal (<25 icons/clip)
2541 * environment. 25 free slots are found in the first pass for a
2542 * 1024x768 screen size.
2545 for (i
=0; i
<3 && !done
; i
++) {
2546 memset(north
, 0, sizeof(unsigned char) * n
);
2547 memset(south
, 0, sizeof(unsigned char) * n
);
2548 memset(east
, 0, sizeof(unsigned char) * n
);
2549 memset(west
, 0, sizeof(unsigned char) * n
);
2550 for (j
=0; j
<dock
->max_icons
; j
++) {
2551 btn
= dock
->icon_array
[j
];
2555 if (btn
->yindex
== i
&& btn
->xindex
>= 0)
2556 east
[btn
->xindex
] = 1;
2557 else if (btn
->yindex
== -i
&& btn
->xindex
< 0)
2558 west
[-(btn
->xindex
)] = 1;
2559 else if (btn
->xindex
== -i
&& btn
->yindex
>= 0)
2560 south
[btn
->yindex
] = 1;
2561 else if (btn
->xindex
== i
&& btn
->yindex
< 0)
2562 north
[-(btn
->yindex
)] = 1;
2564 for (j
=1; j
<n
; j
++) {
2568 x
= dock
->x_pos
+ j
*ICON_SIZE
;
2569 y
= dock
->y_pos
+ i
*ICON_SIZE
;
2570 if (ON_SCREEN(x
, y
, sx
, ex
, sy
, ey
)) {
2578 x
= dock
->x_pos
+ (-j
)*ICON_SIZE
;
2579 y
= dock
->y_pos
+ (-i
)*ICON_SIZE
;
2580 if (ON_SCREEN(x
, y
, sx
, ex
, sy
, ey
)) {
2588 x
= dock
->x_pos
+ (-i
)*ICON_SIZE
;
2589 y
= dock
->y_pos
+ (j
)*ICON_SIZE
;
2590 if (ON_SCREEN(x
, y
, sx
, ex
, sy
, ey
)) {
2598 x
= dock
->x_pos
+ (i
)*ICON_SIZE
;
2599 y
= dock
->y_pos
+ (-j
)*ICON_SIZE
;
2600 if (ON_SCREEN(x
, y
, sx
, ex
, sy
, ey
)) {
2615 return done
; /* If done is True this means that we found a free slot */
2621 moveDock(WDock
*dock
, int new_x
, int new_y
)
2626 dock
->x_pos
= new_x
;
2627 dock
->y_pos
= new_y
;
2628 for (i
=0; i
<dock
->max_icons
; i
++) {
2629 btn
= dock
->icon_array
[i
];
2631 btn
->x_pos
= new_x
+ btn
->xindex
*ICON_SIZE
;
2632 btn
->y_pos
= new_y
+ btn
->yindex
*ICON_SIZE
;
2633 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2640 swapDock(WDock
*dock
)
2642 WScreen
*scr
= dock
->screen_ptr
;
2647 if (dock
->on_right_side
) {
2648 x
= dock
->x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
2650 x
= dock
->x_pos
= DOCK_EXTRA_SPACE
;
2653 for (i
=0; i
<dock
->max_icons
; i
++) {
2654 btn
= dock
->icon_array
[i
];
2657 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2664 execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
)
2666 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
2672 cmdline
= ExpandOptions(scr
, command
);
2674 if (scr
->flags
.dnd_data_convertion_status
|| !cmdline
) {
2682 ParseCommand(cmdline
, &argv
, &argc
);
2692 if ((pid
=fork())==0) {
2696 SetupEnvironment(scr
);
2698 close(ConnectionNumber(dpy
));
2704 args
= malloc(sizeof(char*)*(argc
+1));
2707 for (i
=0; i
<argc
; i
++) {
2711 execvp(argv
[0], args
);
2720 state
= wmalloc(sizeof(WSavedState
));
2721 memset(state
, 0, sizeof(WSavedState
));
2723 state
->miniaturized
= -1;
2725 if (btn
->dock
== scr
->dock
)
2726 state
->workspace
= -1;
2728 state
->workspace
= scr
->current_workspace
;
2730 wAddWindowSavedState(btn
->wm_instance
, btn
->wm_class
,
2731 cmdline
, pid
, state
);
2732 wAddDeathHandler(pid
, (WDeathHandler
*)trackDeadProcess
,
2743 wDockHideIcons(WDock
*dock
)
2751 btn
= dock
->icon_array
[0];
2753 for (i
=1; i
<dock
->max_icons
; i
++) {
2754 if (dock
->icon_array
[i
])
2755 XUnmapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
2764 wDockShowIcons(WDock
*dock
)
2772 btn
= dock
->icon_array
[0];
2773 moveDock(dock
, btn
->x_pos
, btn
->y_pos
);
2775 newlevel
= dock
->lowered
? WMNormalWindowLevel
: WMDockWindowLevel
;
2776 ChangeStackingLevel(btn
->icon
->core
, newlevel
);
2778 for (i
=1; i
<dock
->max_icons
; i
++) {
2779 if (dock
->icon_array
[i
]) {
2780 MoveInStackListAbove(dock
->icon_array
[i
]->icon
->core
,
2786 if (!dock
->collapsed
) {
2787 for (i
=1; i
<dock
->max_icons
; i
++) {
2788 if (dock
->icon_array
[i
]) {
2789 XMapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
2800 wDockLower(WDock
*dock
)
2804 for (i
=0; i
<dock
->max_icons
; i
++) {
2805 if (dock
->icon_array
[i
])
2806 wLowerFrame(dock
->icon_array
[i
]->icon
->core
);
2812 wDockRaise(WDock
*dock
)
2816 for (i
=dock
->max_icons
-1; i
>=0; i
--) {
2817 if (dock
->icon_array
[i
])
2818 wRaiseFrame(dock
->icon_array
[i
]->icon
->core
);
2824 wDockRaiseLower(WDock
*dock
)
2826 if (!dock
->icon_array
[0]->icon
->core
->stacking
->above
2827 ||(dock
->icon_array
[0]->icon
->core
->stacking
->window_level
2828 !=dock
->icon_array
[0]->icon
->core
->stacking
->above
->stacking
->window_level
))
2836 wDockFinishLaunch(WDock
*dock
, WAppIcon
*icon
)
2838 icon
->launching
= 0;
2839 icon
->relaunching
= 0;
2840 dockIconPaint(icon
);
2845 wDockFindIconFor(WDock
*dock
, Window window
)
2850 for (i
=0; i
<dock
->max_icons
; i
++) {
2851 icon
= dock
->icon_array
[i
];
2852 if (icon
&& icon
->main_window
== window
)
2860 wDockTrackWindowLaunch(WDock
*dock
, Window window
)
2863 #ifdef REDUCE_APPICONS
2864 WAppIconAppList
*tapplist
;
2866 char *wm_class
, *wm_instance
;
2870 if (!PropGetWMClass(window
, &wm_class
, &wm_instance
) ||
2871 (!wm_class
&& !wm_instance
))
2874 for (i
=0; i
<dock
->max_icons
; i
++) {
2875 icon
= dock
->icon_array
[i
];
2879 /* kluge. If this does not exist, some windows attach themselves
2880 * to more than one icon. Find out why */
2881 if (icon
->main_window
== window
) {
2884 if ((icon
->wm_instance
|| icon
->wm_class
)
2886 || (dock
->screen_ptr
->flags
.startup
&& !icon
->running
))) {
2888 if (icon
->wm_instance
&& wm_instance
&&
2889 strcmp(icon
->wm_instance
, wm_instance
)!=0) {
2892 if (icon
->wm_class
&& wm_class
&&
2893 strcmp(icon
->wm_class
, wm_class
)!=0) {
2897 if (!icon
->relaunching
) {
2900 /* Possibly an application that was docked with dockit,
2901 * but the user did not update WMState to indicate that
2902 * it was docked by force */
2903 wapp
= wApplicationOf(window
);
2905 icon
->forced_dock
= 1;
2908 if (!icon
->forced_dock
)
2909 icon
->main_window
= window
;
2910 #ifdef REDUCE_APPICONS
2911 tapplist
= wmalloc(sizeof(WAppIconAppList
));
2912 memset(tapplist
, 0, sizeof(WAppIconAppList
));
2913 tapplist
->next
= icon
->applist
;
2915 icon
->applist
->prev
= tapplist
;
2916 icon
->applist
= tapplist
;
2917 tapplist
->wapp
= wApplicationOf(window
);
2921 wDockFinishLaunch(dock
, icon
);
2935 wClipUpdateForWorkspaceChange(WScreen
*scr
, int workspace
)
2937 if (!wPreferences
.flags
.noclip
) {
2938 scr
->clip_icon
->dock
= scr
->workspaces
[workspace
]->clip
;
2939 if (scr
->current_workspace
!= workspace
) {
2940 WDock
*old_clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
2942 wDockHideIcons(old_clip
);
2943 if (old_clip
->auto_collapse
&& !old_clip
->collapsed
)
2944 old_clip
->collapsed
= 1;
2945 wDockShowIcons(scr
->workspaces
[workspace
]->clip
);
2947 if (scr
->flags
.clip_balloon_mapped
)
2948 showClipBalloon(scr
->clip_icon
->dock
, workspace
);
2955 trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
)
2960 for (i
=0; i
<dock
->max_icons
; i
++) {
2961 icon
= dock
->icon_array
[i
];
2965 if (icon
->launching
&& icon
->pid
== pid
) {
2966 if (!icon
->relaunching
) {
2968 icon
->main_window
= None
;
2970 wDockFinishLaunch(dock
, icon
);
2975 sprintf(msg
, _("Could not execute command \"%s\""),
2976 icon
->drop_launch
&& icon
->dnd_command
2977 ? icon
->dnd_command
: icon
->command
);
2979 sprintf(msg
, _("Could not execute command \"%s\""),
2982 wMessageDialog(dock
->screen_ptr
, _("Error"), msg
,
2983 _("OK"), NULL
, NULL
);
2992 toggleLowered(WDock
*dock
)
2997 /* lower/raise Dock */
2998 if (!dock
->lowered
) {
2999 newlevel
= WMNormalWindowLevel
;
3002 newlevel
= WMDockWindowLevel
;
3006 for (i
=0; i
<dock
->max_icons
; i
++) {
3007 tmp
= dock
->icon_array
[i
];
3011 ChangeStackingLevel(tmp
->icon
->core
, newlevel
);
3013 wLowerFrame(tmp
->icon
->core
);
3019 toggleCollapsed(WDock
*dock
)
3021 if (dock
->collapsed
) {
3022 dock
->collapsed
= 0;
3023 wDockShowIcons(dock
);
3026 dock
->collapsed
= 1;
3027 wDockHideIcons(dock
);
3033 toggleAutoCollapse(WDock
*dock
)
3035 dock
->auto_collapse
= !dock
->auto_collapse
;
3036 if (dock
->auto_collapse_magic
) {
3037 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
3038 dock
->auto_collapse_magic
= NULL
;
3044 openDockMenu(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3046 WScreen
*scr
= dock
->screen_ptr
;
3047 WObjDescriptor
*desc
;
3051 int appIsRunning
= aicon
->running
&& aicon
->icon
&& aicon
->icon
->owner
;
3053 if (dock
->type
== WM_DOCK
) {
3055 entry
= dock
->menu
->entries
[index
];
3056 entry
->flags
.indicator_on
= !dock
->lowered
;
3057 entry
->clientdata
= dock
;
3060 if (scr
->clip_options
)
3061 updateClipOptionsMenu(scr
->clip_options
, dock
);
3063 /* Rename Workspace */
3064 entry
= dock
->menu
->entries
[++index
];
3065 entry
->clientdata
= dock
;
3068 entry
= dock
->menu
->entries
[++index
];
3069 entry
->clientdata
= aicon
;
3070 wMenuSetEnabled(dock
->menu
, index
, aicon
!=scr
->clip_icon
);
3072 /* (un)select all icons */
3073 entry
= dock
->menu
->entries
[++index
];
3074 entry
->clientdata
= aicon
;
3075 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3078 entry
= dock
->menu
->entries
[++index
];
3079 entry
->clientdata
= aicon
;
3080 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3082 /* this is the workspace submenu part */
3083 if (scr
->clip_submenu
)
3084 updateWorkspaceMenu(scr
->clip_submenu
, aicon
);
3087 /* remove icon(s) */
3088 entry
= dock
->menu
->entries
[++index
];
3089 entry
->clientdata
= aicon
;
3090 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3092 /* attract icon(s) */
3093 entry
= dock
->menu
->entries
[++index
];
3094 entry
->clientdata
= aicon
;
3098 entry
= dock
->menu
->entries
[++index
];
3099 entry
->clientdata
= aicon
;
3100 wMenuSetEnabled(dock
->menu
, index
, aicon
->command
!=NULL
);
3103 entry
= dock
->menu
->entries
[++index
];
3104 entry
->clientdata
= aicon
;
3105 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3108 entry
= dock
->menu
->entries
[++index
];
3109 entry
->clientdata
= aicon
;
3110 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3113 entry
= dock
->menu
->entries
[++index
];
3114 entry
->clientdata
= aicon
;
3115 wMenuSetEnabled(dock
->menu
, index
, !aicon
->editing
);
3118 entry
= dock
->menu
->entries
[++index
];
3119 entry
->clientdata
= aicon
;
3120 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3122 if (!dock
->menu
->flags
.realized
)
3123 wMenuRealize(dock
->menu
);
3125 if (dock
->type
== WM_CLIP
) {
3126 x_pos
= event
->xbutton
.x_root
+2;
3129 x_pos
= dock
->on_right_side
?
3130 scr
->scr_width
- dock
->menu
->frame
->core
->width
- 2 : 0;
3133 wMenuMapAt(dock
->menu
, x_pos
, event
->xbutton
.y_root
+2, False
);
3135 /* allow drag select */
3136 event
->xany
.send_event
= True
;
3137 desc
= &dock
->menu
->menu
->descriptor
;
3138 (*desc
->handle_mousedown
)(desc
, event
);
3143 openClipWorkspaceMenu(WScreen
*scr
, int x
, int y
)
3145 if (!scr
->clip_ws_menu
) {
3146 scr
->clip_ws_menu
= wWorkspaceMenuMake(scr
, False
);
3148 wWorkspaceMenuUpdate(scr
, scr
->clip_ws_menu
);
3149 wMenuMapAt(scr
->clip_ws_menu
, x
, y
, False
);
3153 /******************************************************************/
3155 iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
3157 WAppIcon
*btn
= desc
->parent
;
3158 WDock
*dock
= btn
->dock
;
3159 WApplication
*wapp
= NULL
;
3162 #ifdef REDUCE_APPICONS
3163 if ((btn
->icon
->owner
&& !(event
->xbutton
.state
& ControlMask
)) ||
3164 ((btn
->icon
->owner
== NULL
) && (btn
->applist
!= NULL
))) {
3165 if (btn
->icon
->owner
== NULL
)
3166 btn
->icon
->owner
= btn
->applist
->wapp
->main_window_desc
;
3171 if (btn
->icon
->owner
&& !(event
->xbutton
.state
& ControlMask
)) {
3173 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
3177 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
3179 /* go to the last workspace that the user worked on the app */
3181 wWorkspaceChange(dock
->screen_ptr
, wapp
->last_workspace
);
3184 wUnhideApplication(wapp
, event
->xbutton
.button
==Button2
,
3187 if (event
->xbutton
.state
& MOD_MASK
) {
3188 wHideOtherApplications(btn
->icon
->owner
);
3191 if (event
->xbutton
.button
==Button1
) {
3193 if (event
->xbutton
.state
& MOD_MASK
) {
3194 /* raise/lower dock */
3195 toggleLowered(dock
);
3196 } else if (btn
== dock
->screen_ptr
->clip_icon
) {
3197 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
)
3198 toggleCollapsed(dock
);
3200 handleClipChangeWorkspace(dock
->screen_ptr
, event
);
3201 } else if (btn
->command
) {
3202 if (!btn
->launching
&&
3203 (!btn
->running
|| (event
->xbutton
.state
& ControlMask
))) {
3204 launchDockedApplication(btn
);
3213 handleDockMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3215 WScreen
*scr
= dock
->screen_ptr
;
3216 int ofs_x
=event
->xbutton
.x
, ofs_y
=event
->xbutton
.y
;
3219 int grabbed
= 0, swapped
= 0, done
;
3220 Pixmap ghost
= None
;
3221 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3224 puts("moving dock");
3226 if (XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
3227 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3228 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3229 wwarning("pointer grab failed for dock move");
3232 for (x
=0; x
<dock
->max_icons
; x
++) {
3233 if (dock
->icon_array
[x
]!=NULL
&&
3234 dock
->icon_array
[x
]->yindex
> y
)
3235 y
= dock
->icon_array
[x
]->yindex
;
3238 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
*y
);
3242 WMMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3243 |ButtonMotionMask
|ExposureMask
, &ev
);
3251 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3252 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3253 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3254 |ButtonReleaseMask
|ButtonPressMask
,
3255 wCursor
[WCUR_MOVE
], CurrentTime
);
3260 if (dock
->type
== WM_CLIP
) {
3261 if (ev
.xmotion
.x_root
- ofs_x
< 0) {
3263 } else if (ev
.xmotion
.x_root
- ofs_x
+ ICON_SIZE
>
3265 x
= scr
->scr_width
- ICON_SIZE
;
3267 x
= ev
.xmotion
.x_root
- ofs_x
;
3269 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3271 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3273 y
= scr
->scr_height
- ICON_SIZE
;
3275 y
= ev
.xmotion
.y_root
- ofs_y
;
3277 moveDock(dock
, x
, y
);
3280 /* move vertically if pointer is inside the dock*/
3281 if ((dock
->on_right_side
&&
3282 ev
.xmotion
.x_root
>= dock
->x_pos
- ICON_SIZE
)
3283 || (!dock
->on_right_side
&&
3284 ev
.xmotion
.x_root
<= dock
->x_pos
+ ICON_SIZE
*2)) {
3286 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3288 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3290 y
= scr
->scr_height
- ICON_SIZE
;
3292 y
= ev
.xmotion
.y_root
- ofs_y
;
3294 moveDock(dock
, dock
->x_pos
, y
);
3296 /* move horizontally to change sides */
3297 x
= ev
.xmotion
.x_root
- ofs_x
;
3298 if (!dock
->on_right_side
) {
3302 if (ev
.xmotion
.x_root
> dock
->x_pos
+ ICON_SIZE
*2) {
3303 XMoveWindow(dpy
, scr
->dock_shadow
, scr
->scr_width
-ICON_SIZE
3304 -DOCK_EXTRA_SPACE
, dock
->y_pos
);
3307 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3308 scr
->scr_width
-ICON_SIZE
3311 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3313 XClearWindow(dpy
, scr
->dock_shadow
);
3316 XMapRaised(dpy
, scr
->dock_shadow
);
3319 if (superfluous
&& ghost
!=None
) {
3320 XFreePixmap(dpy
, ghost
);
3323 XUnmapWindow(dpy
, scr
->dock_shadow
);
3328 if (ev
.xmotion
.x_root
< dock
->x_pos
- ICON_SIZE
) {
3329 XMoveWindow(dpy
, scr
->dock_shadow
,
3330 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3333 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3334 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3335 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3337 XClearWindow(dpy
, scr
->dock_shadow
);
3340 XMapRaised(dpy
, scr
->dock_shadow
);
3343 XUnmapWindow(dpy
, scr
->dock_shadow
);
3345 if (superfluous
&& ghost
!=None
) {
3346 XFreePixmap(dpy
, ghost
);
3358 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3360 XUngrabPointer(dpy
, CurrentTime
);
3361 XUnmapWindow(dpy
, scr
->dock_shadow
);
3362 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
);
3363 if (dock
->type
== WM_DOCK
) {
3366 dock
->on_right_side
= 1;
3368 dock
->on_right_side
= 0;
3370 wArrangeIcons(scr
, False
);
3379 XFreePixmap(dpy
, ghost
);
3380 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3383 puts("End dock move");
3390 handleIconMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3392 WScreen
*scr
= dock
->screen_ptr
;
3394 WIcon
*icon
= aicon
->icon
;
3395 WDock
*dock2
= NULL
, *last_dock
= dock
;
3396 int ondock
, grabbed
= 0, change_dock
= 0, collapsed
= 0;
3398 int x
= aicon
->x_pos
, y
= aicon
->y_pos
;
3399 int ofs_x
= event
->xbutton
.x
, ofs_y
= event
->xbutton
.y
;
3400 int shad_x
= x
, shad_y
= y
;
3401 int ix
= aicon
->xindex
, iy
= aicon
->yindex
;
3403 Pixmap ghost
= None
;
3405 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3407 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
3408 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3409 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3411 wwarning("pointer grab failed for icon move");
3415 wRaiseFrame(icon
->core
);
3417 if (dock
== scr
->dock
&& !wPreferences
.flags
.noclip
)
3418 dock2
= scr
->workspaces
[scr
->current_workspace
]->clip
;
3419 else if (dock
!= scr
->dock
&& !wPreferences
.flags
.nodock
)
3422 wins
[0] = icon
->core
->window
;
3423 wins
[1] = scr
->dock_shadow
;
3424 XRestackWindows(dpy
, wins
, 2);
3425 XMoveResizeWindow(dpy
, scr
->dock_shadow
, aicon
->x_pos
, aicon
->y_pos
,
3426 ICON_SIZE
, ICON_SIZE
);
3428 if (icon
->pixmap
!=None
)
3429 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
3431 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
3433 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
, ghost
);
3434 XClearWindow(dpy
, scr
->dock_shadow
);
3436 XMapWindow(dpy
, scr
->dock_shadow
);
3442 XMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3443 |ButtonMotionMask
|ExposureMask
, &ev
);
3451 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3452 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3453 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3454 |ButtonReleaseMask
|ButtonPressMask
,
3455 wCursor
[WCUR_MOVE
], CurrentTime
);
3462 x
= ev
.xmotion
.x_root
- ofs_x
;
3463 y
= ev
.xmotion
.y_root
- ofs_y
;
3464 tmp
= wDockSnapIcon(dock
, aicon
, x
, y
, &ix
, &iy
, True
);
3467 if (last_dock
!= dock
&& collapsed
) {
3468 last_dock
->collapsed
= 1;
3469 wDockHideIcons(last_dock
);
3472 if (!collapsed
&& (collapsed
= dock
->collapsed
)) {
3473 dock
->collapsed
= 0;
3474 wDockShowIcons(dock
);
3479 tmp
= wDockSnapIcon(dock2
, aicon
, x
, y
, &ix
, &iy
, False
);
3482 if (last_dock
!= dock2
&& collapsed
) {
3483 last_dock
->collapsed
= 1;
3484 wDockHideIcons(last_dock
);
3487 if (!collapsed
&& (collapsed
= dock2
->collapsed
)) {
3488 dock2
->collapsed
= 0;
3489 wDockShowIcons(dock2
);
3494 if (aicon
->launching
3495 || (aicon
->running
&& !(ev
.xmotion
.state
& MOD_MASK
))
3496 || (!aicon
->running
&& tmp
)) {
3497 shad_x
= last_dock
->x_pos
+ ix
*wPreferences
.icon_size
;
3498 shad_y
= last_dock
->y_pos
+ iy
*wPreferences
.icon_size
;
3500 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
3503 XMapWindow(dpy
, scr
->dock_shadow
);
3505 if (!collapsed
&& (collapsed
= last_dock
->collapsed
)) {
3506 last_dock
->collapsed
= 0;
3507 wDockShowIcons(last_dock
);
3514 XUnmapWindow(dpy
, scr
->dock_shadow
);
3516 if (last_dock
&& collapsed
&&
3517 aicon
->running
&& (ev
.xmotion
.state
& MOD_MASK
)) {
3518 last_dock
->collapsed
= 1;
3519 wDockHideIcons(last_dock
);
3526 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
3533 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3535 XUngrabPointer(dpy
, CurrentTime
);
3537 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
3538 XUnmapWindow(dpy
, scr
->dock_shadow
);
3540 reattachIcon(dock
, aicon
, ix
, iy
);
3542 docked
= moveIconBetweenDocks(dock
, dock2
, aicon
, ix
, iy
);
3544 /* Slide it back if dock rejected it */
3545 SlideWindow(icon
->core
->window
, x
, y
, aicon
->x_pos
,
3547 reattachIcon(dock
, aicon
, aicon
->xindex
,aicon
->yindex
);
3549 if (last_dock
->type
==WM_CLIP
&& last_dock
->auto_collapse
) {
3557 if (!aicon
->running
&& !wPreferences
.no_animations
) {
3558 /* We need to deselect it, even if is deselected in
3559 * wDockDetach(), because else DoKaboom() will fail.
3561 if (aicon
->icon
->selected
)
3562 wIconSelect(aicon
->icon
);
3563 DoKaboom(scr
,aicon
->icon
->core
->window
, x
, y
);
3566 wDockDetach(dock
, aicon
);
3569 last_dock
->collapsed
= 1;
3570 wDockHideIcons(last_dock
);
3575 XFreePixmap(dpy
, ghost
);
3576 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3579 puts("End icon move");
3588 getClipButton(int px
, int py
)
3590 int pt
= (CLIP_BUTTON_SIZE
+2)*ICON_SIZE
/64;
3592 if (px
< 0 || py
< 0 || px
>= ICON_SIZE
|| py
>= ICON_SIZE
)
3595 if (py
<= pt
-((int)ICON_SIZE
-1-px
))
3596 return CLIP_FORWARD
;
3597 else if (px
<= pt
-((int)ICON_SIZE
-1-py
))
3605 handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
)
3608 int done
, direction
, new_ws
;
3610 WDock
*clip
= scr
->clip_icon
->dock
;
3612 /* if this is reached during startup (before the 1st wWorkspaceForceChange)
3613 * we will get undesired effects, like having all windows unmapped and
3614 * don't having them back if the clip buttons are clicked.
3616 if (scr
->flags
.startup2
|| scr
->flags
.startup
)
3619 direction
= getClipButton(event
->xbutton
.x
, event
->xbutton
.y
);
3621 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3622 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3624 wClipIconPaint(scr
->clip_icon
);
3627 WMMaskEvent(dpy
, ExposureMask
|ButtonMotionMask
|ButtonReleaseMask
3628 |ButtonPressMask
, &ev
);
3635 new_dir
= getClipButton(ev
.xmotion
.x
, ev
.xmotion
.y
);
3636 if (new_dir
!= direction
) {
3637 direction
= new_dir
;
3638 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3639 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3640 wClipIconPaint(scr
->clip_icon
);
3648 if (ev
.xbutton
.button
== event
->xbutton
.button
)
3653 clip
->lclip_button_pushed
= 0;
3654 clip
->rclip_button_pushed
= 0;
3656 new_ws
= wPreferences
.ws_advance
|| (event
->xbutton
.state
& ControlMask
);
3658 if (direction
== CLIP_FORWARD
) {
3659 if (scr
->current_workspace
< scr
->workspace_count
-1)
3660 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3661 else if (new_ws
&& scr
->current_workspace
< MAX_WORKSPACES
-1)
3662 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3663 else if (wPreferences
.ws_cycle
)
3664 wWorkspaceChange(scr
, 0);
3666 else if (direction
== CLIP_REWIND
) {
3667 if (scr
->current_workspace
> 0)
3668 wWorkspaceChange(scr
, scr
->current_workspace
-1);
3669 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
3670 wWorkspaceChange(scr
, scr
->workspace_count
-1);
3673 wClipIconPaint(scr
->clip_icon
);
3678 iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
3680 WAppIcon
*aicon
= desc
->parent
;
3681 WDock
*dock
= aicon
->dock
;
3682 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
3684 scr
->last_dock
= dock
;
3686 if (dock
->menu
->flags
.mapped
)
3687 wMenuUnmap(dock
->menu
);
3689 if (IsDoubleClick(scr
, event
)) {
3690 /* double-click was not in the main clip icon */
3691 if (dock
->type
!= WM_CLIP
|| aicon
->xindex
!=0 || aicon
->yindex
!=0
3692 || getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
) {
3693 iconDblClick(desc
, event
);
3698 if (dock
->type
== WM_CLIP
&& scr
->flags
.clip_balloon_mapped
) {
3699 XUnmapWindow(dpy
, scr
->clip_balloon
);
3700 scr
->flags
.clip_balloon_mapped
= 0;
3704 puts("handling dock");
3706 if (event
->xbutton
.button
== Button1
) {
3707 if (event
->xbutton
.state
& MOD_MASK
)
3712 if ((event
->xbutton
.state
& ShiftMask
) && aicon
!=scr
->clip_icon
&&
3713 dock
->type
!=WM_DOCK
) {
3714 wIconSelect(aicon
->icon
);
3718 if (aicon
->yindex
==0 && aicon
->xindex
==0) {
3719 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)!=CLIP_IDLE
3720 && dock
->type
==WM_CLIP
)
3721 handleClipChangeWorkspace(scr
, event
);
3723 handleDockMove(dock
, aicon
, event
);
3725 handleIconMove(dock
, aicon
, event
);
3727 } else if (event
->xbutton
.button
==Button2
&& dock
->type
==WM_CLIP
&&
3728 aicon
->xindex
==0 && aicon
->yindex
==0) {
3729 openClipWorkspaceMenu(scr
, event
->xbutton
.x_root
+2,
3730 event
->xbutton
.y_root
+2);
3731 if (scr
->clip_ws_menu
) {
3733 menu
= scr
->clip_ws_menu
;
3734 desc
= &menu
->menu
->descriptor
;
3736 event
->xany
.send_event
= True
;
3737 (*desc
->handle_mousedown
)(desc
, event
);
3739 } else if (event
->xbutton
.button
== Button3
) {
3740 openDockMenu(dock
, aicon
, event
);
3746 showClipBalloon(WDock
*dock
, int workspace
)
3750 WScreen
*scr
= dock
->screen_ptr
;
3754 scr
->flags
.clip_balloon_mapped
= 1;
3755 XMapWindow(dpy
, scr
->clip_balloon
);
3757 text
= scr
->workspaces
[workspace
]->name
;
3759 w
= wTextWidth(scr
->clip_title_font
->font
, text
, strlen(text
)) + 4;
3761 h
= scr
->clip_title_font
->height
;
3762 XResizeWindow(dpy
, scr
->clip_balloon
, w
, h
);
3764 x
= dock
->x_pos
+ CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
3765 y
= dock
->y_pos
+ ICON_SIZE
-scr
->clip_title_font
->height
- 3;
3767 if (x
+w
> scr
->scr_width
) {
3768 x
= scr
->scr_width
- w
;
3769 if (dock
->y_pos
+ ICON_SIZE
+ h
> scr
->scr_height
)
3770 y
= dock
->y_pos
- h
- 1;
3772 y
= dock
->y_pos
+ ICON_SIZE
;
3773 XRaiseWindow(dpy
, scr
->clip_balloon
);
3775 stack
[0] = scr
->clip_icon
->icon
->core
->window
;
3776 stack
[1] = scr
->clip_balloon
;
3777 XRestackWindows(dpy
, stack
, 2);
3779 XMoveWindow(dpy
, scr
->clip_balloon
, x
, y
);
3780 XSetForeground(dpy
, scr
->clip_title_gc
,
3781 scr
->clip_title_pixel
[CLIP_NORMAL
]);
3782 XClearWindow(dpy
, scr
->clip_balloon
);
3783 wDrawString(scr
->clip_balloon
, scr
->clip_title_font
, scr
->clip_title_gc
,
3784 0, scr
->clip_title_font
->y
, text
, strlen(text
));
3789 clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
)
3791 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
3794 assert(event
->type
==EnterNotify
);
3796 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
3800 if (!dock
|| dock
->type
!=WM_CLIP
)
3803 if (btn
->xindex
== 0 && btn
->yindex
== 0)
3804 showClipBalloon(dock
, dock
->screen_ptr
->current_workspace
);
3806 if (dock
->screen_ptr
->flags
.clip_balloon_mapped
) {
3807 XUnmapWindow(dpy
, dock
->screen_ptr
->clip_balloon
);
3808 dock
->screen_ptr
->flags
.clip_balloon_mapped
= 0;
3811 if (!dock
->auto_collapse
)
3814 if (dock
->auto_collapse_magic
) {
3815 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
3816 dock
->auto_collapse_magic
= NULL
;
3819 if (dock
->collapsed
)
3820 toggleCollapsed(dock
);
3825 clipLeave(WDock
*dock
)
3827 if (!dock
|| dock
->type
!=WM_CLIP
|| !dock
->auto_collapse
)
3830 if (dock
->auto_collapse_magic
) {
3831 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
3832 dock
->auto_collapse_magic
= NULL
;
3834 if (!dock
->collapsed
) {
3835 dock
->auto_collapse_magic
= WMAddTimerHandler(AUTO_COLLAPSE_DELAY
,
3843 clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
)
3845 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
3847 assert(event
->type
==LeaveNotify
);
3849 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
3852 clipLeave(btn
->dock
);
3857 clipAutoCollapse(void *cdata
)
3859 WDock
*dock
= (WDock
*)cdata
;
3861 if (dock
->type
!=WM_CLIP
|| !dock
->auto_collapse
)
3864 if (!dock
->collapsed
&& dock
->auto_collapse_magic
!=NULL
) {
3865 toggleCollapsed(dock
);
3867 dock
->auto_collapse_magic
= NULL
;