1 /* dock.c- built-in Dock module for WindowMaker
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 * Copyright (c) 1998, 1999 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
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 #include <X11/Xutil.h>
36 #define PATH_MAX DEFAULT_PATH_MAX
39 #include "WindowMaker.h"
49 #include "properties.h"
53 #include "workspace.h"
55 #include "superfluous.h"
64 /**** Local variables ****/
67 #define CLIP_FORWARD 2
70 /**** Global variables ****/
73 extern void DestroyDockAppSettingsPanel();
75 extern void ShowDockAppSettingsPanel(WAppIcon
*aicon
);
78 extern XContext wWinContext
;
80 extern Cursor wCursor
[WCUR_LAST
];
82 extern WPreferences wPreferences
;
84 extern XContext wWinContext
;
87 extern Atom _XA_DND_PROTOCOL
;
91 #define MOD_MASK wPreferences.modifier_mask
93 extern void appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
95 #define ICON_SIZE wPreferences.icon_size
98 /***** Local variables ****/
100 static proplist_t dCommand
=NULL
;
102 static proplist_t dDropCommand
=NULL
;
104 static proplist_t dAutoLaunch
, dLock
;
105 static proplist_t dName
, dForced
, dBuggyApplication
, dYes
, dNo
;
106 static proplist_t dHost
, dDock
, dClip
;
107 static proplist_t dAutoAttractIcons
;
109 static proplist_t dPosition
, dApplications
, dLowered
, dCollapsed
, dAutoCollapse
;
111 static proplist_t dAutoRaiseLower
, dOmnipresent
;
113 static void dockIconPaint(WAppIcon
*btn
);
115 static void iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
117 static pid_t
execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
);
119 static void trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
);
121 static int getClipButton(int px
, int py
);
123 static void toggleLowered(WDock
*dock
);
125 static void toggleCollapsed(WDock
*dock
);
127 static void clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
);
129 static void clipLeave(WDock
*dock
);
131 static void handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
);
133 Bool
moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
);
135 static void clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
);
136 static void clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
);
137 static void clipAutoCollapse(void *cdata
);
138 static void clipAutoExpand(void *cdata
);
139 static void launchDockedApplication(WAppIcon
*btn
);
141 static void clipAutoLower(void *cdata
);
142 static void clipAutoRaise(void *cdata
);
144 static void showClipBalloon(WDock
*dock
, int workspace
);
160 #endif /* OFFIX_DND */
170 dCommand
= PLRetain(PLMakeString("Command"));
172 dDropCommand
= PLRetain(PLMakeString("DropCommand"));
174 dLock
= PLRetain(PLMakeString("Lock"));
175 dAutoLaunch
= PLRetain(PLMakeString("AutoLaunch"));
176 dName
= PLRetain(PLMakeString("Name"));
177 dForced
= PLRetain(PLMakeString("Forced"));
178 dBuggyApplication
= PLRetain(PLMakeString("BuggyApplication"));
179 dYes
= PLRetain(PLMakeString("Yes"));
180 dNo
= PLRetain(PLMakeString("No"));
181 dHost
= PLRetain(PLMakeString("Host"));
183 dPosition
= PLMakeString("Position");
184 dApplications
= PLMakeString("Applications");
185 dLowered
= PLMakeString("Lowered");
186 dCollapsed
= PLMakeString("Collapsed");
187 dAutoCollapse
= PLMakeString("AutoCollapse");
188 dAutoRaiseLower
= PLMakeString("AutoRaiseLower");
189 dAutoAttractIcons
= PLMakeString("AutoAttractIcons");
191 dOmnipresent
= PLMakeString("Omnipresent");
193 dDock
= PLMakeString("Dock");
194 dClip
= PLMakeString("Clip");
200 renameCallback(WMenu
*menu
, WMenuEntry
*entry
)
202 WDock
*dock
= entry
->clientdata
;
207 assert(entry
->clientdata
!=NULL
);
209 wspace
= dock
->screen_ptr
->current_workspace
;
211 name
= wstrdup(dock
->screen_ptr
->workspaces
[wspace
]->name
);
213 sprintf(buffer
, _("Type the name for workspace %i:"), wspace
+1);
214 if (wInputDialog(dock
->screen_ptr
, _("Rename Workspace"), buffer
,
216 wWorkspaceRename(dock
->screen_ptr
, wspace
, name
);
225 toggleLoweredCallback(WMenu
*menu
, WMenuEntry
*entry
)
227 assert(entry
->clientdata
!=NULL
);
229 toggleLowered(entry
->clientdata
);
231 entry
->flags
.indicator_on
= !(((WDock
*)entry
->clientdata
)->lowered
);
239 killCallback(WMenu
*menu
, WMenuEntry
*entry
)
244 if (!WCHECK_STATE(WSTATE_NORMAL
))
247 assert(entry
->clientdata
!=NULL
);
249 icon
= (WAppIcon
*)entry
->clientdata
;
253 WCHANGE_STATE(WSTATE_MODAL
);
255 buffer
= wstrconcat(icon
->wm_class
,
256 _(" will be forcibly closed.\n"
257 "Any unsaved changes will be lost.\n"
260 if (wPreferences
.dont_confirm_kill
261 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
262 buffer
, _("Yes"), _("No"), NULL
)==WAPRDefault
) {
263 if (icon
->icon
&& icon
->icon
->owner
) {
264 wClientKill(icon
->icon
->owner
);
272 WCHANGE_STATE(WSTATE_NORMAL
);
276 /* TODO: replace this function with a member of the dock struct */
278 numberOfSelectedIcons(WDock
*dock
)
284 for (i
=1; i
<dock
->max_icons
; i
++) {
285 aicon
= dock
->icon_array
[i
];
286 if (aicon
&& aicon
->icon
->selected
) {
296 getSelected(WDock
*dock
)
298 WMBag
*ret
= WMCreateBag(8);
302 for (i
=1; i
<dock
->max_icons
; i
++) {
303 btn
= dock
->icon_array
[i
];
304 if (btn
&& btn
->icon
->selected
) {
305 WMPutInBag(ret
, btn
);
314 paintClipButtons(WAppIcon
*clipIcon
, Bool lpushed
, Bool rpushed
)
316 Window win
= clipIcon
->icon
->core
->window
;
317 WScreen
*scr
= clipIcon
->icon
->core
->screen_ptr
;
319 int pt
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
320 int tp
= ICON_SIZE
- pt
;
321 int as
= pt
- 15; /* 15 = 5+5+5 */
322 GC gc
= scr
->clip_title_gc
;
323 #ifdef GRADIENT_CLIP_ARROW
324 Bool collapsed
= clipIcon
->dock
->collapsed
;
330 p
[1].x
= ICON_SIZE
-2;
332 p
[2].x
= ICON_SIZE
-2;
334 } else if (lpushed
) {
338 p
[1].y
= ICON_SIZE
-2;
340 p
[2].y
= ICON_SIZE
-2;
342 if (lpushed
|| rpushed
) {
343 XSetForeground(dpy
, scr
->draw_gc
, scr
->white_pixel
);
344 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
345 XSetForeground(dpy
, scr
->draw_gc
, scr
->black_pixel
);
347 #ifdef GRADIENT_CLIP_ARROW
349 XSetFillStyle(dpy
, scr
->copy_gc
, FillTiled
);
350 XSetTile(dpy
, scr
->copy_gc
, scr
->clip_arrow_gradient
);
351 XSetClipMask(dpy
, scr
->copy_gc
, None
);
354 #endif /* GRADIENT_CLIP_ARROW */
356 /* top right arrow */
357 p
[0].x
= p
[3].x
= ICON_SIZE
-5-as
;
359 p
[1].x
= ICON_SIZE
-6;
361 p
[2].x
= ICON_SIZE
-6;
364 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
365 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
367 #ifdef GRADIENT_CLIP_ARROW
369 XSetTSOrigin(dpy
, gc
, ICON_SIZE
-6-as
, 5);
371 XFillPolygon(dpy
, win
, gc
, p
,3,Convex
,CoordModeOrigin
);
372 XDrawLines(dpy
, win
, gc
, p
,4,CoordModeOrigin
);
375 /* bottom left arrow */
377 p
[0].y
= p
[3].y
= ICON_SIZE
-5-as
;
379 p
[1].y
= ICON_SIZE
-6;
381 p
[2].y
= ICON_SIZE
-6;
383 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
384 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
386 #ifdef GRADIENT_CLIP_ARROW
388 XSetTSOrigin(dpy
, gc
, 5, ICON_SIZE
-6-as
);
390 XFillPolygon(dpy
, win
, gc
, p
,3,Convex
,CoordModeOrigin
);
391 XDrawLines(dpy
, win
, gc
, p
,4,CoordModeOrigin
);
393 #ifdef GRADIENT_CLIP_ARROW
395 XSetFillStyle(dpy
, scr
->copy_gc
, FillSolid
);
401 wClipMakeTile(WScreen
*scr
, RImage
*normalTile
)
403 RImage
*tile
= RCloneImage(normalTile
);
410 pt
= CLIP_BUTTON_SIZE
*wPreferences
.icon_size
/64;
411 tp
= wPreferences
.icon_size
-1 - pt
;
415 black
.red
= black
.green
= black
.blue
= 0;
418 dark
.red
= dark
.green
= dark
.blue
= 60;
421 light
.red
= light
.green
= light
.blue
= 80;
425 ROperateLine(tile
, RSubtractOperation
, tp
, 0, wPreferences
.icon_size
-2,
427 RDrawLine(tile
, tp
-1, 0, wPreferences
.icon_size
-1, pt
+1, &black
);
428 ROperateLine(tile
, RAddOperation
, tp
, 2, wPreferences
.icon_size
-3,
432 ROperateLine(tile
, RSubtractOperation
, ICON_SIZE
- 7 - as
, 4,
433 ICON_SIZE
- 5, 4, &dark
);
434 ROperateLine(tile
, RSubtractOperation
, ICON_SIZE
- 6 - as
, 5,
435 ICON_SIZE
- 5, 6 + as
, &dark
);
436 ROperateLine(tile
, RAddOperation
, ICON_SIZE
- 5, 4, ICON_SIZE
- 5, 6 + as
,
440 ROperateLine(tile
, RAddOperation
, 2, tp
+2, pt
-2,
441 wPreferences
.icon_size
-3, &dark
);
442 RDrawLine(tile
, 0, tp
-1, pt
+1, wPreferences
.icon_size
-1, &black
);
443 ROperateLine(tile
, RSubtractOperation
, 0, tp
-2, pt
+1,
444 wPreferences
.icon_size
-2, &light
);
447 ROperateLine(tile
, RSubtractOperation
, 4, ICON_SIZE
- 7 - as
, 4,
448 ICON_SIZE
- 5, &dark
);
449 ROperateLine(tile
, RSubtractOperation
, 5, ICON_SIZE
- 6 - as
,
450 6 + as
, ICON_SIZE
- 5, &dark
);
451 ROperateLine(tile
, RAddOperation
, 4, ICON_SIZE
- 5, 6 + as
, ICON_SIZE
- 5,
459 omnipresentCallback(WMenu
*menu
, WMenuEntry
*entry
)
461 WAppIcon
*clickedIcon
= entry
->clientdata
;
464 WMBag
*selectedIcons
;
468 assert(entry
->clientdata
!=NULL
);
470 dock
= clickedIcon
->dock
;
472 selectedIcons
= getSelected(dock
);
474 if (!WMGetBagItemCount(selectedIcons
))
475 WMPutInBag(selectedIcons
, clickedIcon
);
478 for (i
= 0; i
< WMGetBagItemCount(selectedIcons
); i
++) {
479 aicon
= WMGetFromBag(selectedIcons
, i
);
481 if (wClipMakeIconOmnipresent(aicon
, !aicon
->omnipresent
) == WO_FAILED
)
483 else if (aicon
->icon
->selected
)
484 wIconSelect(aicon
->icon
);
486 WMFreeBag(selectedIcons
);
489 wMessageDialog(dock
->screen_ptr
, _("Warning"),
490 _("Some icons cannot be made omnipresent. "
491 "Please make sure that no other icon is "
492 "docked in the same positions on the other "
493 "workspaces and the Clip is not full in "
495 _("OK"), NULL
, NULL
);
496 } else if (failed
== 1) {
497 wMessageDialog(dock
->screen_ptr
, _("Warning"),
498 _("Icon cannot be made omnipresent. "
499 "Please make sure that no other icon is "
500 "docked in the same position on the other "
501 "workspaces and the Clip is not full in "
503 _("OK"), NULL
, NULL
);
509 removeIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
511 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
514 WMBag
*selectedIcons
;
518 assert(clickedIcon
!=NULL
);
520 dock
= clickedIcon
->dock
;
522 selectedIcons
= getSelected(dock
);
524 if (WMGetBagItemCount(selectedIcons
)) {
525 if (wMessageDialog(dock
->screen_ptr
, _("Workspace Clip"),
526 _("All selected icons will be removed!"),
527 _("OK"), _("Cancel"), NULL
)!=WAPRDefault
) {
528 WMFreeBag(selectedIcons
);
532 if (clickedIcon
->xindex
==0 && clickedIcon
->yindex
==0) {
533 WMFreeBag(selectedIcons
);
536 WMPutInBag(selectedIcons
, clickedIcon
);
539 WM_ITERATE_BAG(selectedIcons
, aicon
, it
) {
540 keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
541 wDockDetach(dock
, aicon
);
543 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
544 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
545 aicon
->x_pos
, aicon
->y_pos
);
546 if (!dock
->mapped
|| dock
->collapsed
)
547 XMapWindow(dpy
, aicon
->icon
->core
->window
);
550 WMFreeBag(selectedIcons
);
552 if (wPreferences
.auto_arrange_icons
)
553 wArrangeIcons(dock
->screen_ptr
, True
);
558 keepIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
560 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
563 WMBag
*selectedIcons
;
566 assert(clickedIcon
!=NULL
);
567 dock
= clickedIcon
->dock
;
569 selectedIcons
= getSelected(dock
);
571 if (!WMGetBagItemCount(selectedIcons
)
572 && clickedIcon
!=dock
->screen_ptr
->clip_icon
) {
573 char *command
= NULL
;
575 if (!clickedIcon
->command
&& !clickedIcon
->editing
) {
576 clickedIcon
->editing
= 1;
577 if (wInputDialog(dock
->screen_ptr
, _("Keep Icon"),
578 _("Type the command used to launch the application"),
580 if (command
&& (command
[0]==0 ||
581 (command
[0]=='-' && command
[1]==0))) {
585 clickedIcon
->command
= command
;
586 clickedIcon
->editing
= 0;
588 clickedIcon
->editing
= 0;
591 WMFreeBag(selectedIcons
);
596 WMPutInBag(selectedIcons
, clickedIcon
);
599 WM_ITERATE_BAG(selectedIcons
, aicon
, it
) {
600 if (aicon
->icon
->selected
)
601 wIconSelect(aicon
->icon
);
602 if (aicon
&& aicon
->attracted
&& aicon
->command
) {
603 aicon
->attracted
= 0;
604 if (aicon
->icon
->shadowed
) {
605 aicon
->icon
->shadowed
= 0;
606 aicon
->icon
->force_paint
= 1;
607 wAppIconPaint(aicon
);
611 WMFreeBag(selectedIcons
);
618 toggleAutoAttractCallback(WMenu
*menu
, WMenuEntry
*entry
)
620 WDock
*dock
= (WDock
*)entry
->clientdata
;
622 assert(entry
->clientdata
!=NULL
);
624 dock
->attract_icons
= !dock
->attract_icons
;
625 /*if (!dock->attract_icons)
626 dock->keep_attracted = 0;*/
628 entry
->flags
.indicator_on
= dock
->attract_icons
;
635 selectCallback(WMenu
*menu
, WMenuEntry
*entry
)
637 WAppIcon
*icon
= (WAppIcon
*)entry
->clientdata
;
641 wIconSelect(icon
->icon
);
648 colectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
650 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
653 int x
, y
, x_pos
, y_pos
;
655 assert(entry
->clientdata
!=NULL
);
656 clip
= clickedIcon
->dock
;
658 aicon
= clip
->screen_ptr
->app_icon_list
;
661 if (!aicon
->docked
&& wDockFindFreeSlot(clip
, &x
, &y
)) {
662 x_pos
= clip
->x_pos
+ x
*ICON_SIZE
;
663 y_pos
= clip
->y_pos
+ y
*ICON_SIZE
;
664 if (aicon
->x_pos
!= x_pos
|| aicon
->y_pos
!= y_pos
) {
666 if (wPreferences
.no_animations
) {
667 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
669 SlideWindow(aicon
->icon
->core
->window
,
670 aicon
->x_pos
, aicon
->y_pos
, x_pos
, y_pos
);
673 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
674 #endif /* ANIMATIONS */
676 aicon
->attracted
= 1;
677 if (!aicon
->icon
->shadowed
) {
678 aicon
->icon
->shadowed
= 1;
679 aicon
->icon
->force_paint
= 1;
680 /* We don't do an wAppIconPaint() here because it's in
681 * wDockAttachIcon(). -Dan
684 wDockAttachIcon(clip
, aicon
, x
, y
);
685 if (clip
->collapsed
|| !clip
->mapped
)
686 XUnmapWindow(dpy
, aicon
->icon
->core
->window
);
694 selectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
696 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
698 WMBag
*selectedIcons
;
702 assert(clickedIcon
!=NULL
);
703 dock
= clickedIcon
->dock
;
705 selectedIcons
= getSelected(dock
);
707 if (!WMGetBagItemCount(selectedIcons
)) {
708 for (i
=1; i
<dock
->max_icons
; i
++) {
709 btn
= dock
->icon_array
[i
];
710 if (btn
&& !btn
->icon
->selected
) {
711 wIconSelect(btn
->icon
);
715 for (i
= 0; i
< WMGetBagItemCount(selectedIcons
); i
++) {
716 btn
= WMGetFromBag(selectedIcons
, i
);
717 wIconSelect(btn
->icon
);
720 WMFreeBag(selectedIcons
);
727 toggleCollapsedCallback(WMenu
*menu
, WMenuEntry
*entry
)
729 assert(entry
->clientdata
!=NULL
);
731 toggleCollapsed(entry
->clientdata
);
733 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->collapsed
;
740 toggleAutoCollapseCallback(WMenu
*menu
, WMenuEntry
*entry
)
743 assert(entry
->clientdata
!=NULL
);
745 dock
= (WDock
*) entry
->clientdata
;
747 dock
->auto_collapse
= !dock
->auto_collapse
;
749 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->auto_collapse
;
756 toggleAutoRaiseLowerCallback(WMenu
*menu
, WMenuEntry
*entry
)
759 assert(entry
->clientdata
!=NULL
);
761 dock
= (WDock
*) entry
->clientdata
;
763 dock
->auto_raise_lower
= !dock
->auto_raise_lower
;
765 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->auto_raise_lower
;
772 launchCallback(WMenu
*menu
, WMenuEntry
*entry
)
774 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
776 launchDockedApplication(btn
);
781 settingsCallback(WMenu
*menu
, WMenuEntry
*entry
)
783 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
787 ShowDockAppSettingsPanel(btn
);
792 hideCallback(WMenu
*menu
, WMenuEntry
*entry
)
795 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
797 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
799 if (wapp
->flags
.hidden
) {
800 wWorkspaceChange(btn
->icon
->core
->screen_ptr
,wapp
->last_workspace
);
801 wUnhideApplication(wapp
, False
, False
);
803 wHideApplication(wapp
);
809 unhideHereCallback(WMenu
*menu
, WMenuEntry
*entry
)
812 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
814 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
816 wUnhideApplication(wapp
, False
, True
);
821 mainIconCreate(WScreen
*scr
, int type
)
826 if (type
== WM_CLIP
) {
828 return scr
->clip_icon
;
829 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMClip", TILE_CLIP
);
830 btn
->icon
->core
->descriptor
.handle_expose
= clipIconExpose
;
831 btn
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
832 btn
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
833 /*x_pos = scr->scr_width - ICON_SIZE*2 - DOCK_EXTRA_SPACE;*/
836 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMDock", TILE_NORMAL
);
837 x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
843 btn
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
844 btn
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
845 btn
->icon
->core
->descriptor
.parent
= btn
;
846 /*ChangeStackingLevel(btn->icon->core, WMDockLevel);*/
847 XMapWindow(dpy
, btn
->icon
->core
->window
);
852 scr
->clip_icon
= btn
;
859 switchWSCommand(WMenu
*menu
, WMenuEntry
*entry
)
861 WAppIcon
*btn
, *icon
= (WAppIcon
*) entry
->clientdata
;
862 WScreen
*scr
= icon
->icon
->core
->screen_ptr
;
864 WMBag
*selectedIcons
;
867 if (entry
->order
== scr
->current_workspace
)
870 dest
= scr
->workspaces
[entry
->order
]->clip
;
872 selectedIcons
= getSelected(src
);
874 if (WMGetBagItemCount(selectedIcons
)) {
876 for (i
= 0; i
< WMGetBagItemCount(selectedIcons
); i
++) {
877 btn
= WMGetFromBag(selectedIcons
, i
);
878 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
879 moveIconBetweenDocks(src
, dest
, btn
, x
, y
);
880 XUnmapWindow(dpy
, btn
->icon
->core
->window
);
883 } else if (icon
!= scr
->clip_icon
) {
884 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
885 moveIconBetweenDocks(src
, dest
, icon
, x
, y
);
886 XUnmapWindow(dpy
, icon
->icon
->core
->window
);
889 WMFreeBag(selectedIcons
);
895 launchDockedApplication(WAppIcon
*btn
)
897 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
899 if (!btn
->launching
&& btn
->command
!=NULL
) {
900 if (!btn
->forced_dock
) {
901 btn
->relaunching
= btn
->running
;
904 if (btn
->wm_instance
|| btn
->wm_class
) {
905 WWindowAttributes attr
;
906 memset(&attr
, 0, sizeof(WWindowAttributes
));
907 wDefaultFillAttributes(scr
, btn
->wm_instance
, btn
->wm_class
,
910 if (!attr
.no_appicon
&& !btn
->buggy_app
)
915 btn
->drop_launch
= 0;
916 scr
->last_dock
= btn
->dock
;
917 btn
->pid
= execCommand(btn
, btn
->command
, NULL
);
919 if (btn
->buggy_app
) {
920 /* give feedback that the app was launched */
924 WMAddTimerHandler(200, (WMCallback
*)dockIconPaint
, btn
);
929 wwarning(_("could not launch application %s\n"), btn
->command
);
931 if (!btn
->relaunching
)
940 updateWorkspaceMenu(WMenu
*menu
, WAppIcon
*icon
)
942 WScreen
*scr
= menu
->frame
->screen_ptr
;
943 char title
[MAX_WORKSPACENAME_WIDTH
+1];
949 for (i
=0; i
<scr
->workspace_count
; i
++) {
950 if (i
< menu
->entry_no
) {
951 if (strcmp(menu
->entries
[i
]->text
,scr
->workspaces
[i
]->name
)!=0) {
952 wfree(menu
->entries
[i
]->text
);
953 strcpy(title
, scr
->workspaces
[i
]->name
);
954 menu
->entries
[i
]->text
= wstrdup(title
);
955 menu
->flags
.realized
= 0;
957 menu
->entries
[i
]->clientdata
= (void*)icon
;
959 strcpy(title
, scr
->workspaces
[i
]->name
);
961 wMenuAddCallback(menu
, title
, switchWSCommand
, (void*)icon
);
963 menu
->flags
.realized
= 0;
965 if (i
== scr
->current_workspace
) {
966 wMenuSetEnabled(menu
, i
, False
);
968 wMenuSetEnabled(menu
, i
, True
);
972 if (!menu
->flags
.realized
)
978 makeWorkspaceMenu(WScreen
*scr
)
982 menu
= wMenuCreate(scr
, NULL
, False
);
984 wwarning(_("could not create workspace submenu for Clip menu"));
986 wMenuAddCallback(menu
, "", switchWSCommand
, (void*)scr
->clip_icon
);
988 menu
->flags
.realized
= 0;
996 updateClipOptionsMenu(WMenu
*menu
, WDock
*dock
)
1005 entry
= menu
->entries
[index
];
1006 entry
->flags
.indicator_on
= !dock
->lowered
;
1007 entry
->clientdata
= dock
;
1010 entry
= menu
->entries
[++index
];
1011 entry
->flags
.indicator_on
= dock
->collapsed
;
1012 entry
->clientdata
= dock
;
1015 entry
= menu
->entries
[++index
];
1016 entry
->flags
.indicator_on
= dock
->auto_collapse
;
1017 entry
->clientdata
= dock
;
1019 /* auto-raise/lower */
1020 entry
= menu
->entries
[++index
];
1021 entry
->flags
.indicator_on
= dock
->auto_raise_lower
;
1022 entry
->clientdata
= dock
;
1025 entry
= menu
->entries
[++index
];
1026 entry
->flags
.indicator_on
= dock
->attract_icons
;
1027 entry
->clientdata
= dock
;
1029 menu
->flags
.realized
= 0;
1035 makeClipOptionsMenu(WScreen
*scr
)
1040 menu
= wMenuCreate(scr
, NULL
, False
);
1042 wwarning(_("could not create options submenu for Clip menu"));
1046 entry
= wMenuAddCallback(menu
, _("Keep on Top"),
1047 toggleLoweredCallback
, NULL
);
1048 entry
->flags
.indicator
= 1;
1049 entry
->flags
.indicator_on
= 1;
1050 entry
->flags
.indicator_type
= MI_CHECK
;
1052 entry
= wMenuAddCallback(menu
, _("Collapsed"),
1053 toggleCollapsedCallback
, NULL
);
1054 entry
->flags
.indicator
= 1;
1055 entry
->flags
.indicator_on
= 1;
1056 entry
->flags
.indicator_type
= MI_CHECK
;
1058 entry
= wMenuAddCallback(menu
, _("Autocollapse"),
1059 toggleAutoCollapseCallback
, NULL
);
1060 entry
->flags
.indicator
= 1;
1061 entry
->flags
.indicator_on
= 1;
1062 entry
->flags
.indicator_type
= MI_CHECK
;
1064 entry
= wMenuAddCallback(menu
, _("Autoraise"),
1065 toggleAutoRaiseLowerCallback
, NULL
);
1066 entry
->flags
.indicator
= 1;
1067 entry
->flags
.indicator_on
= 1;
1068 entry
->flags
.indicator_type
= MI_CHECK
;
1070 entry
= wMenuAddCallback(menu
, _("Autoattract Icons"),
1071 toggleAutoAttractCallback
, NULL
);
1072 entry
->flags
.indicator
= 1;
1073 entry
->flags
.indicator_on
= 1;
1074 entry
->flags
.indicator_type
= MI_CHECK
;
1076 menu
->flags
.realized
= 0;
1084 dockMenuCreate(WScreen
*scr
, int type
)
1089 if (type
== WM_CLIP
&& scr
->clip_menu
)
1090 return scr
->clip_menu
;
1092 menu
= wMenuCreate(scr
, NULL
, False
);
1093 if (type
!= WM_CLIP
) {
1094 entry
= wMenuAddCallback(menu
, _("Keep on Top"),
1095 toggleLoweredCallback
, NULL
);
1096 entry
->flags
.indicator
= 1;
1097 entry
->flags
.indicator_on
= 1;
1098 entry
->flags
.indicator_type
= MI_CHECK
;
1100 entry
= wMenuAddCallback(menu
, _("Clip Options"), NULL
, NULL
);
1101 scr
->clip_options
= makeClipOptionsMenu(scr
);
1102 if (scr
->clip_options
)
1103 wMenuEntrySetCascade(menu
, entry
, scr
->clip_options
);
1105 entry
= wMenuAddCallback(menu
, _("Rename Workspace"), renameCallback
,
1108 entry
->text
= _("Rename Workspace");
1110 entry
= wMenuAddCallback(menu
, _("Selected"), selectCallback
, NULL
);
1111 entry
->flags
.indicator
= 1;
1112 entry
->flags
.indicator_on
= 1;
1113 entry
->flags
.indicator_type
= MI_CHECK
;
1115 entry
= wMenuAddCallback(menu
, _("Select All Icons"),
1116 selectIconsCallback
, NULL
);
1118 entry
->text
= _("Select All Icons");
1120 entry
= wMenuAddCallback(menu
, _("Keep Icon"), keepIconsCallback
, NULL
);
1122 entry
->text
= _("Keep Icon");
1124 entry
= wMenuAddCallback(menu
, _("Move Icon To"), NULL
, NULL
);
1126 entry
->text
= _("Move Icon To");
1127 scr
->clip_submenu
= makeWorkspaceMenu(scr
);
1128 if (scr
->clip_submenu
)
1129 wMenuEntrySetCascade(menu
, entry
, scr
->clip_submenu
);
1131 entry
= wMenuAddCallback(menu
, _("Remove Icon"), removeIconsCallback
,
1134 entry
->text
= _("Remove Icon");
1136 wMenuAddCallback(menu
, _("Attract Icons"), colectIconsCallback
, NULL
);
1139 wMenuAddCallback(menu
, _("Launch"), launchCallback
, NULL
);
1141 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
1143 entry
= wMenuAddCallback(menu
, _("Hide"), hideCallback
, NULL
);
1145 entry
->text
= _("Hide");
1147 wMenuAddCallback(menu
, _("Settings..."), settingsCallback
, NULL
);
1149 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
1151 if (type
== WM_CLIP
)
1152 scr
->clip_menu
= menu
;
1159 wDockCreate(WScreen
*scr
, int type
)
1167 dock
= wmalloc(sizeof(WDock
));
1168 memset(dock
, 0, sizeof(WDock
));
1170 if (type
== WM_CLIP
)
1171 icon_count
= CLIP_MAX_ICONS
;
1173 icon_count
= scr
->scr_height
/wPreferences
.icon_size
;
1175 dock
->icon_array
= wmalloc(sizeof(WAppIcon
*)*icon_count
);
1176 memset(dock
->icon_array
, 0, sizeof(WAppIcon
*)*icon_count
);
1178 dock
->max_icons
= icon_count
;
1180 btn
= mainIconCreate(scr
, type
);
1184 dock
->x_pos
= btn
->x_pos
;
1185 dock
->y_pos
= btn
->y_pos
;
1186 dock
->screen_ptr
= scr
;
1188 dock
->icon_count
= 1;
1189 dock
->on_right_side
= 1;
1190 dock
->collapsed
= 0;
1191 dock
->auto_collapse
= 0;
1192 dock
->auto_collapse_magic
= NULL
;
1193 dock
->auto_raise_lower
= 0;
1194 dock
->auto_lower_magic
= NULL
;
1195 dock
->auto_raise_magic
= NULL
;
1196 dock
->attract_icons
= 0;
1198 dock
->icon_array
[0] = btn
;
1199 wRaiseFrame(btn
->icon
->core
);
1200 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
1202 /* create dock menu */
1203 dock
->menu
= dockMenuCreate(scr
, type
);
1210 wDockDestroy(WDock
*dock
)
1215 for (i
=(dock
->type
== WM_CLIP
) ? 1 : 0; i
<dock
->max_icons
; i
++) {
1216 aicon
= dock
->icon_array
[i
];
1218 int keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
1219 wDockDetach(dock
, aicon
);
1221 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
1222 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
1223 aicon
->x_pos
, aicon
->y_pos
);
1224 if (!dock
->mapped
|| dock
->collapsed
)
1225 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1229 if (wPreferences
.auto_arrange_icons
)
1230 wArrangeIcons(dock
->screen_ptr
, True
);
1231 wfree(dock
->icon_array
);
1232 if (dock
->menu
&& dock
->type
!=WM_CLIP
)
1233 wMenuDestroy(dock
->menu
, True
);
1234 if (dock
->screen_ptr
->last_dock
== dock
)
1235 dock
->screen_ptr
->last_dock
= NULL
;
1241 wClipIconPaint(WAppIcon
*aicon
)
1243 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
1244 WWorkspace
*workspace
= scr
->workspaces
[scr
->current_workspace
];
1246 Window win
= aicon
->icon
->core
->window
;
1247 int length
, nlength
;
1248 char *ws_name
, ws_number
[10];
1251 wIconPaint(aicon
->icon
);
1253 length
= strlen(workspace
->name
);
1254 ws_name
= malloc(length
+ 1);
1255 sprintf(ws_name
, "%s", workspace
->name
);
1256 sprintf(ws_number
, "%i", scr
->current_workspace
+ 1);
1257 nlength
= strlen(ws_number
);
1259 gc
= scr
->clip_title_gc
;
1261 if (!workspace
->clip
->collapsed
)
1262 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_NORMAL
]);
1264 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_COLLAPSED
]);
1266 ty
= ICON_SIZE
- WMFontHeight(scr
->clip_title_font
) - 3;
1268 tx
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
1270 WMDrawString(scr
->wmscreen
, win
, gc
, scr
->clip_title_font
, tx
,
1271 ty
, ws_name
, length
);
1273 tx
= (ICON_SIZE
/2 - WMWidthOfString(scr
->clip_title_font
, ws_number
,
1276 WMDrawString(scr
->wmscreen
, win
, gc
, scr
->clip_title_font
, tx
,
1277 2, ws_number
, nlength
);
1281 if (aicon
->launching
) {
1282 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
1283 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
1285 paintClipButtons(aicon
, aicon
->dock
->lclip_button_pushed
,
1286 aicon
->dock
->rclip_button_pushed
);
1291 clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
)
1293 wClipIconPaint(desc
->parent
);
1298 dockIconPaint(WAppIcon
*btn
)
1300 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1301 wClipIconPaint(btn
);
1308 make_icon_state(WAppIcon
*btn
)
1310 proplist_t node
= NULL
;
1311 proplist_t command
, autolaunch
, lock
, name
, forced
, host
, position
, buggy
;
1312 proplist_t omnipresent
;
1318 command
= PLMakeString("-");
1320 command
= PLMakeString(btn
->command
);
1322 autolaunch
= btn
->auto_launch
? dYes
: dNo
;
1324 lock
= btn
->lock
? dYes
: dNo
;
1326 tmp
= EscapeWM_CLASS(btn
->wm_instance
, btn
->wm_class
);
1328 name
= PLMakeString(tmp
);
1332 forced
= btn
->forced_dock
? dYes
: dNo
;
1334 buggy
= btn
->buggy_app
? dYes
: dNo
;
1336 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1337 sprintf(buffer
, "%i,%i", btn
->x_pos
, btn
->y_pos
);
1339 sprintf(buffer
, "%hi,%hi", btn
->xindex
, btn
->yindex
);
1340 position
= PLMakeString(buffer
);
1342 node
= PLMakeDictionaryFromEntries(dCommand
, command
,
1344 dAutoLaunch
, autolaunch
,
1347 dBuggyApplication
, buggy
,
1348 dPosition
, position
,
1352 PLRelease(position
);
1354 omnipresent
= btn
->omnipresent
? dYes
: dNo
;
1355 if (btn
->dock
!= btn
->icon
->core
->screen_ptr
->dock
&&
1356 (btn
->xindex
!= 0 || btn
->yindex
!= 0))
1357 PLInsertDictionaryEntry(node
, dOmnipresent
, omnipresent
);
1360 if (btn
->dnd_command
) {
1361 command
= PLMakeString(btn
->dnd_command
);
1362 PLInsertDictionaryEntry(node
, dDropCommand
, command
);
1365 #endif /* OFFIX_DND */
1367 if (btn
->client_machine
&& btn
->remote_start
) {
1368 host
= PLMakeString(btn
->client_machine
);
1369 PLInsertDictionaryEntry(node
, dHost
, host
);
1379 dockSaveState(WDock
*dock
)
1382 proplist_t icon_info
;
1383 proplist_t list
=NULL
, dock_state
=NULL
;
1384 proplist_t value
, key
;
1387 list
= PLMakeArrayFromElements(NULL
);
1389 for (i
=(dock
->type
==WM_DOCK
? 0 : 1); i
<dock
->max_icons
; i
++) {
1390 WAppIcon
*btn
= dock
->icon_array
[i
];
1392 if (!btn
|| btn
->attracted
)
1395 if ((icon_info
= make_icon_state(dock
->icon_array
[i
]))) {
1396 list
= PLAppendArrayElement(list
, icon_info
);
1397 PLRelease(icon_info
);
1401 dock_state
= PLMakeDictionaryFromEntries(dApplications
, list
,
1404 if (dock
->type
== WM_DOCK
) {
1405 sprintf(buffer
, "Applications%i", dock
->screen_ptr
->scr_height
);
1406 key
= PLMakeString(buffer
);
1407 PLInsertDictionaryEntry(dock_state
, key
, list
);
1411 sprintf(buffer
, "%i,%i", (dock
->on_right_side
? -ICON_SIZE
: 0),
1413 value
= PLMakeString(buffer
);
1414 PLInsertDictionaryEntry(dock_state
, dPosition
, value
);
1420 value
= (dock
->lowered
? dYes
: dNo
);
1421 PLInsertDictionaryEntry(dock_state
, dLowered
, value
);
1423 if (dock
->type
== WM_CLIP
) {
1424 value
= (dock
->collapsed
? dYes
: dNo
);
1425 PLInsertDictionaryEntry(dock_state
, dCollapsed
, value
);
1427 value
= (dock
->auto_collapse
? dYes
: dNo
);
1428 PLInsertDictionaryEntry(dock_state
, dAutoCollapse
, value
);
1430 value
= (dock
->auto_raise_lower
? dYes
: dNo
);
1431 PLInsertDictionaryEntry(dock_state
, dAutoRaiseLower
, value
);
1433 value
= (dock
->attract_icons
? dYes
: dNo
);
1434 PLInsertDictionaryEntry(dock_state
, dAutoAttractIcons
, value
);
1442 wDockSaveState(WScreen
*scr
, proplist_t old_state
)
1444 proplist_t dock_state
;
1447 dock_state
= dockSaveState(scr
->dock
);
1450 * Copy saved states of docks with different sizes.
1456 keys
= PLGetAllDictionaryKeys(old_state
);
1457 for (i
= 0; i
< PLGetNumberOfElements(keys
); i
++) {
1458 tmp
= PLGetArrayElement(keys
, i
);
1460 if (strncasecmp(PLGetString(tmp
), "applications", 12) == 0
1461 && !PLGetDictionaryEntry(dock_state
, tmp
)) {
1463 PLInsertDictionaryEntry(dock_state
,
1465 PLGetDictionaryEntry(old_state
, tmp
));
1472 PLInsertDictionaryEntry(scr
->session_state
, dDock
, dock_state
);
1474 PLRelease(dock_state
);
1479 wClipSaveState(WScreen
*scr
)
1481 proplist_t clip_state
;
1483 clip_state
= make_icon_state(scr
->clip_icon
);
1485 PLInsertDictionaryEntry(scr
->session_state
, dClip
, clip_state
);
1487 PLRelease(clip_state
);
1492 wClipSaveWorkspaceState(WScreen
*scr
, int workspace
)
1494 return dockSaveState(scr
->workspaces
[workspace
]->clip
);
1499 getBooleanDockValue(proplist_t value
, proplist_t key
)
1502 if (PLIsString(value
)) {
1503 if (strcasecmp(PLGetString(value
), "YES")==0)
1506 wwarning(_("bad value in docked icon state info %s"),
1515 restore_icon_state(WScreen
*scr
, proplist_t info
, int type
, int index
)
1518 proplist_t cmd
, value
;
1521 cmd
= PLGetDictionaryEntry(info
, dCommand
);
1522 if (!cmd
|| !PLIsString(cmd
)) {
1526 /* parse window name */
1527 value
= PLGetDictionaryEntry(info
, dName
);
1532 char *wclass
, *winstance
;
1535 ParseWindowName(value
, &winstance
, &wclass
, "dock");
1537 if (!winstance
&& !wclass
) {
1544 command
= wstrdup(PLGetString(cmd
));
1548 if (!command
|| strcmp(command
, "-")==0) {
1559 aicon
= wAppIconCreateForDock(scr
, command
, winstance
, wclass
,
1569 aicon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
1570 if (type
== WM_CLIP
) {
1571 aicon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
1572 aicon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
1574 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
1575 aicon
->icon
->core
->descriptor
.parent
= aicon
;
1579 cmd
= PLGetDictionaryEntry(info
, dDropCommand
);
1581 aicon
->dnd_command
= wstrdup(PLGetString(cmd
));
1584 /* check auto launch */
1585 value
= PLGetDictionaryEntry(info
, dAutoLaunch
);
1587 aicon
->auto_launch
= getBooleanDockValue(value
, dAutoLaunch
);
1590 value
= PLGetDictionaryEntry(info
, dLock
);
1592 aicon
->lock
= getBooleanDockValue(value
, dLock
);
1594 /* check if it wasn't normally docked */
1595 value
= PLGetDictionaryEntry(info
, dForced
);
1597 aicon
->forced_dock
= getBooleanDockValue(value
, dForced
);
1599 /* check if we can rely on the stuff in the app */
1600 value
= PLGetDictionaryEntry(info
, dBuggyApplication
);
1602 aicon
->buggy_app
= getBooleanDockValue(value
, dBuggyApplication
);
1604 /* get position in the dock */
1605 value
= PLGetDictionaryEntry(info
, dPosition
);
1606 if (value
&& PLIsString(value
)) {
1607 if (sscanf(PLGetString(value
), "%hi,%hi", &aicon
->xindex
,
1609 wwarning(_("bad value in docked icon state info %s"),
1610 PLGetString(dPosition
));
1612 /* check position sanity */
1613 /* incomplete section! */
1614 if (type
== WM_DOCK
) {
1616 if (aicon
->yindex
< 0)
1617 wwarning(_("bad value in docked icon position %i,%i"),
1618 aicon
->xindex
, aicon
->yindex
);
1621 aicon
->yindex
= index
;
1625 /* check if icon is omnipresent */
1626 value
= PLGetDictionaryEntry(info
, dOmnipresent
);
1628 aicon
->omnipresent
= getBooleanDockValue(value
, dOmnipresent
);
1637 #define COMPLAIN(key) wwarning(_("bad value in dock state info:%s"), key)
1641 wClipRestoreState(WScreen
*scr
, proplist_t clip_state
)
1647 icon
= mainIconCreate(scr
, WM_CLIP
);
1652 PLRetain(clip_state
);
1654 /* restore position */
1656 value
= PLGetDictionaryEntry(clip_state
, dPosition
);
1659 if (!PLIsString(value
))
1660 COMPLAIN("Position");
1662 if (sscanf(PLGetString(value
), "%i,%i", &icon
->x_pos
,
1664 COMPLAIN("Position");
1666 /* check position sanity */
1667 if (icon
->y_pos
< 0)
1669 else if (icon
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1670 icon
->y_pos
= scr
->scr_height
-ICON_SIZE
;
1672 if (icon
->x_pos
< 0)
1674 else if (icon
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1675 icon
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1680 value
= PLGetDictionaryEntry(clip_state
, dDropCommand
);
1681 if (value
&& PLIsString(value
))
1682 icon
->dnd_command
= wstrdup(PLGetString(value
));
1685 PLRelease(clip_state
);
1692 wDockRestoreState(WScreen
*scr
, proplist_t dock_state
, int type
)
1697 WAppIcon
*aicon
, *old_top
;
1701 dock
= wDockCreate(scr
, type
);
1707 PLRetain(dock_state
);
1710 /* restore position */
1712 value
= PLGetDictionaryEntry(dock_state
, dPosition
);
1715 if (!PLIsString(value
))
1716 COMPLAIN("Position");
1718 if (sscanf(PLGetString(value
), "%i,%i", &dock
->x_pos
,
1720 COMPLAIN("Position");
1722 /* check position sanity */
1723 if (dock
->y_pos
< 0)
1725 else if (dock
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1726 dock
->y_pos
= scr
->scr_height
- ICON_SIZE
;
1728 /* This is no more needed. ??? */
1729 if (type
== WM_CLIP
) {
1730 if (dock
->x_pos
< 0)
1732 else if (dock
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1733 dock
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1735 if (dock
->x_pos
>= 0) {
1736 dock
->x_pos
= DOCK_EXTRA_SPACE
;
1737 dock
->on_right_side
= 0;
1739 dock
->x_pos
= scr
->scr_width
- DOCK_EXTRA_SPACE
- ICON_SIZE
;
1740 dock
->on_right_side
= 1;
1746 /* restore lowered/raised state */
1750 value
= PLGetDictionaryEntry(dock_state
, dLowered
);
1753 if (!PLIsString(value
))
1754 COMPLAIN("Lowered");
1756 if (strcasecmp(PLGetString(value
), "YES")==0)
1762 /* restore collapsed state */
1764 dock
->collapsed
= 0;
1766 value
= PLGetDictionaryEntry(dock_state
, dCollapsed
);
1769 if (!PLIsString(value
))
1770 COMPLAIN("Collapsed");
1772 if (strcasecmp(PLGetString(value
), "YES")==0)
1773 dock
->collapsed
= 1;
1778 /* restore auto-collapsed state */
1780 value
= PLGetDictionaryEntry(dock_state
, dAutoCollapse
);
1783 if (!PLIsString(value
))
1784 COMPLAIN("AutoCollapse");
1786 if (strcasecmp(PLGetString(value
), "YES")==0) {
1787 dock
->auto_collapse
= 1;
1788 dock
->collapsed
= 1;
1794 /* restore auto-raise/lower state */
1796 value
= PLGetDictionaryEntry(dock_state
, dAutoRaiseLower
);
1799 if (!PLIsString(value
))
1800 COMPLAIN("AutoRaiseLower");
1802 if (strcasecmp(PLGetString(value
), "YES")==0) {
1803 dock
->auto_raise_lower
= 1;
1808 /* restore attract icons state */
1810 dock
->attract_icons
= 0;
1812 value
= PLGetDictionaryEntry(dock_state
, dAutoAttractIcons
);
1815 if (!PLIsString(value
))
1816 COMPLAIN("AutoAttractIcons");
1818 if (strcasecmp(PLGetString(value
), "YES")==0)
1819 dock
->attract_icons
= 1;
1824 /* application list */
1831 * When saving, it saves the dock state in
1832 * Applications and Applicationsnnn
1834 * When loading, it will first try Applicationsnnn.
1835 * If it does not exist, use Applications as default.
1838 sprintf(buffer
, "Applications%i", scr
->scr_height
);
1840 tmp
= PLMakeString(buffer
);
1841 apps
= PLGetDictionaryEntry(dock_state
, tmp
);
1845 apps
= PLGetDictionaryEntry(dock_state
, dApplications
);
1853 count
= PLGetNumberOfElements(apps
);
1858 old_top
= dock
->icon_array
[0];
1860 /* dock->icon_count is set to 1 when dock is created.
1861 * Since Clip is already restored, we want to keep it so for clip,
1862 * but for dock we may change the default top tile, so we set it to 0.
1864 if (type
== WM_DOCK
)
1865 dock
->icon_count
= 0;
1867 for (i
=0; i
<count
; i
++) {
1868 if (dock
->icon_count
>= dock
->max_icons
) {
1869 wwarning(_("there are too many icons stored in dock. Ignoring what doesn't fit"));
1873 value
= PLGetArrayElement(apps
, i
);
1874 aicon
= restore_icon_state(scr
, value
, type
, dock
->icon_count
);
1876 dock
->icon_array
[dock
->icon_count
] = aicon
;
1880 aicon
->x_pos
= dock
->x_pos
+ (aicon
->xindex
*ICON_SIZE
);
1881 aicon
->y_pos
= dock
->y_pos
+ (aicon
->yindex
*ICON_SIZE
);
1884 ChangeStackingLevel(aicon
->icon
->core
, WMNormalLevel
);
1886 ChangeStackingLevel(aicon
->icon
->core
, WMDockLevel
);
1888 wCoreConfigure(aicon
->icon
->core
, aicon
->x_pos
, aicon
->y_pos
,
1891 if (!dock
->collapsed
)
1892 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1893 wRaiseFrame(aicon
->icon
->core
);
1896 } else if (dock
->icon_count
==0 && type
==WM_DOCK
)
1900 /* if the first icon is not defined, use the default */
1901 if (dock
->icon_array
[0]==NULL
) {
1902 /* update default icon */
1903 old_top
->x_pos
= dock
->x_pos
;
1904 old_top
->y_pos
= dock
->y_pos
;
1906 ChangeStackingLevel(old_top
->icon
->core
, WMNormalLevel
);
1908 ChangeStackingLevel(old_top
->icon
->core
, WMDockLevel
);
1909 dock
->icon_array
[0] = old_top
;
1910 XMoveWindow(dpy
, old_top
->icon
->core
->window
, dock
->x_pos
, dock
->y_pos
);
1911 /* we don't need to increment dock->icon_count here because it was
1912 * incremented in the loop above.
1914 } else if (old_top
!=dock
->icon_array
[0]) {
1915 if (old_top
== scr
->clip_icon
)
1916 scr
->clip_icon
= dock
->icon_array
[0];
1917 wAppIconDestroy(old_top
);
1922 PLRelease(dock_state
);
1930 wDockLaunchWithState(WDock
*dock
, WAppIcon
*btn
, WSavedState
*state
)
1932 if (btn
&& btn
->command
&& !btn
->running
&& !btn
->launching
) {
1934 btn
->drop_launch
= 0;
1936 btn
->pid
= execCommand(btn
, btn
->command
, state
);
1939 if (!btn
->forced_dock
&& !btn
->buggy_app
) {
1951 wDockDoAutoLaunch(WDock
*dock
, int workspace
)
1957 for (i
= 0; i
< dock
->max_icons
; i
++) {
1958 btn
= dock
->icon_array
[i
];
1959 if (!btn
|| !btn
->auto_launch
)
1962 state
= wmalloc(sizeof(WSavedState
));
1963 memset(state
, 0, sizeof(WSavedState
));
1964 state
->workspace
= workspace
;
1965 /* TODO: this is klugy and is very difficult to understand
1966 * what's going on. Try to clean up */
1967 wDockLaunchWithState(dock
, btn
, state
);
1974 findDock(WScreen
*scr
, XEvent
*event
, int *icon_pos
)
1980 if ((dock
= scr
->dock
)!=NULL
) {
1981 for (i
=0; i
<dock
->max_icons
; i
++) {
1982 if (dock
->icon_array
[i
]
1983 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
1989 if (*icon_pos
<0 && (dock
= scr
->workspaces
[scr
->current_workspace
]->clip
)!=NULL
) {
1990 for (i
=0; i
<dock
->max_icons
; i
++) {
1991 if (dock
->icon_array
[i
]
1992 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
2005 wDockReceiveDNDDrop(WScreen
*scr
, XEvent
*event
)
2011 dock
= findDock(scr
, event
, &icon_pos
);
2016 * Return True if the drop was on an application icon window.
2017 * In this case, let the ClientMessage handler redirect the
2018 * message to the app.
2020 if (dock
->icon_array
[icon_pos
]->icon
->icon_win
!=None
)
2023 if (dock
->icon_array
[icon_pos
]->dnd_command
!=NULL
) {
2024 scr
->flags
.dnd_data_convertion_status
= 0;
2026 btn
= dock
->icon_array
[icon_pos
];
2028 if (!btn
->forced_dock
) {
2029 btn
->relaunching
= btn
->running
;
2032 if (btn
->wm_instance
|| btn
->wm_class
) {
2033 WWindowAttributes attr
;
2034 memset(&attr
, 0, sizeof(WWindowAttributes
));
2035 wDefaultFillAttributes(btn
->icon
->core
->screen_ptr
,
2037 btn
->wm_class
, &attr
, NULL
, True
);
2039 if (!attr
.no_appicon
)
2045 btn
->drop_launch
= 1;
2046 scr
->last_dock
= dock
;
2047 btn
->pid
= execCommand(btn
, btn
->dnd_command
, NULL
);
2052 if (!btn
->relaunching
) {
2059 #endif /* OFFIX_DND */
2064 wDockAttachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
2071 wwin
= icon
->icon
->owner
;
2072 if (icon
->command
==NULL
) {
2074 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
2076 icon
->command
= wtokenjoin(argv
, argc
);
2077 XFreeStringList(argv
);
2081 /* icon->forced_dock = 1;*/
2082 if (dock
->type
!=WM_CLIP
|| !icon
->attracted
) {
2084 if (wInputDialog(dock
->screen_ptr
, _("Dock Icon"),
2085 _("Type the command used to launch the application"),
2087 if (command
&& (command
[0]==0 ||
2088 (command
[0]=='-' && command
[1]==0))) {
2092 icon
->command
= command
;
2098 /* If the target is the dock, reject the icon. If
2099 * the target is the clip, make it an attracted icon
2101 if (dock
->type
==WM_CLIP
) {
2102 icon
->attracted
= 1;
2103 if (!icon
->icon
->shadowed
) {
2104 icon
->icon
->shadowed
= 1;
2105 icon
->icon
->force_paint
= 1;
2117 for (index
=1; index
<dock
->max_icons
; index
++)
2118 if (dock
->icon_array
[index
] == NULL
)
2120 /* if (index == dock->max_icons)
2123 assert(index
< dock
->max_icons
);
2125 dock
->icon_array
[index
] = icon
;
2129 icon
->omnipresent
= 0;
2131 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
2132 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
2137 icon
->launching
= 0;
2140 icon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
2141 if (dock
->type
== WM_CLIP
) {
2142 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
2143 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
2145 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
2146 icon
->icon
->core
->descriptor
.parent
= icon
;
2148 MoveInStackListUnder(dock
->icon_array
[index
-1]->icon
->core
,
2150 wAppIconMove(icon
, icon
->x_pos
, icon
->y_pos
);
2151 wAppIconPaint(icon
);
2153 if (wPreferences
.auto_arrange_icons
)
2154 wArrangeIcons(dock
->screen_ptr
, True
);
2157 if (icon
->command
&& !icon
->dnd_command
) {
2158 icon
->dnd_command
= wmalloc(strlen(icon
->command
)+8);
2159 sprintf(icon
->dnd_command
, "%s %%d", icon
->command
);
2168 reattachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
2172 for(index
=1; index
<dock
->max_icons
; index
++) {
2173 if(dock
->icon_array
[index
] == icon
)
2176 assert(index
< dock
->max_icons
);
2181 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
2182 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
2187 moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
)
2195 return True
; /* No move needed, we're already there */
2200 wwin
= icon
->icon
->owner
;
2203 * For the moment we can't do this if we move icons in Clip from one
2204 * workspace to other, because if we move two or more icons without
2205 * command, the dialog box will not be able to tell us to which of the
2206 * moved icons it applies. -Dan
2208 if ((dest
->type
==WM_DOCK
/*|| dest->keep_attracted*/) && icon
->command
==NULL
) {
2209 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
2211 icon
->command
= wtokenjoin(argv
, argc
);
2212 XFreeStringList(argv
);
2217 /* icon->forced_dock = 1;*/
2218 if (wInputDialog(src
->screen_ptr
, _("Dock Icon"),
2219 _("Type the command used to launch the application"),
2221 if (command
&& (command
[0]==0 ||
2222 (command
[0]=='-' && command
[1]==0))) {
2226 icon
->command
= command
;
2237 if (dest
->type
== WM_DOCK
)
2238 wClipMakeIconOmnipresent(icon
, False
);
2240 for(index
=1; index
<src
->max_icons
; index
++) {
2241 if(src
->icon_array
[index
] == icon
)
2244 assert(index
< src
->max_icons
);
2246 src
->icon_array
[index
] = NULL
;
2249 for(index
=1; index
<dest
->max_icons
; index
++) {
2250 if(dest
->icon_array
[index
] == NULL
)
2253 /* if (index == dest->max_icons)
2256 assert(index
< dest
->max_icons
);
2258 dest
->icon_array
[index
] = icon
;
2261 /* deselect the icon */
2262 if (icon
->icon
->selected
)
2263 wIconSelect(icon
->icon
);
2265 if (dest
->type
== WM_DOCK
) {
2266 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2267 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2269 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
2270 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
2273 /* set it to be kept when moving to dock.
2274 * Unless the icon does not have a command set
2276 if (icon
->command
&& dest
->type
==WM_DOCK
) {
2277 icon
->attracted
= 0;
2278 if (icon
->icon
->shadowed
) {
2279 icon
->icon
->shadowed
= 0;
2280 icon
->icon
->force_paint
= 1;
2284 if (src
->auto_collapse
|| src
->auto_raise_lower
)
2290 icon
->x_pos
= dest
->x_pos
+ x
*ICON_SIZE
;
2291 icon
->y_pos
= dest
->y_pos
+ y
*ICON_SIZE
;
2295 MoveInStackListUnder(dest
->icon_array
[index
-1]->icon
->core
,
2297 wAppIconPaint(icon
);
2304 wDockDetach(WDock
*dock
, WAppIcon
*icon
)
2308 /* make the settings panel be closed */
2310 DestroyDockAppSettingsPanel(icon
->panel
);
2313 /* This must be called before icon->dock is set to NULL.
2314 * Don't move it. -Dan
2316 wClipMakeIconOmnipresent(icon
, False
);
2320 icon
->attracted
= 0;
2321 icon
->auto_launch
= 0;
2322 if (icon
->icon
->shadowed
) {
2323 icon
->icon
->shadowed
= 0;
2324 icon
->icon
->force_paint
= 1;
2327 /* deselect the icon */
2328 if (icon
->icon
->selected
)
2329 wIconSelect(icon
->icon
);
2331 if (icon
->command
) {
2332 wfree(icon
->command
);
2333 icon
->command
= NULL
;
2336 if (icon
->dnd_command
) {
2337 wfree(icon
->dnd_command
);
2338 icon
->dnd_command
= NULL
;
2342 for (index
=1; index
<dock
->max_icons
; index
++)
2343 if (dock
->icon_array
[index
] == icon
)
2345 assert(index
< dock
->max_icons
);
2346 dock
->icon_array
[index
] = NULL
;
2352 /* if the dock is not attached to an application or
2353 * the the application did not set the approriate hints yet,
2354 * destroy the icon */
2355 if (!icon
->running
|| !wApplicationOf(icon
->main_window
))
2356 wAppIconDestroy(icon
);
2358 icon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
2359 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2360 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2361 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
2362 icon
->icon
->core
->descriptor
.parent
= icon
;
2364 ChangeStackingLevel(icon
->icon
->core
, NORMAL_ICON_LEVEL
);
2366 wAppIconPaint(icon
);
2367 if (wPreferences
.auto_arrange_icons
) {
2368 wArrangeIcons(dock
->screen_ptr
, True
);
2370 WAppIcon
*bla
= wAppIconNextSibling(icon
);
2373 SlideWindow(icon
->icon
->core
->window
, icon
->x_pos
, icon
->y_pos
,
2374 bla
->x_pos
, bla
->y_pos
);
2375 wAppIconMove(icon
, bla
->x_pos
, bla
->y_pos
);
2379 if (dock
->auto_collapse
|| dock
->auto_raise_lower
)
2385 * returns the closest Dock slot index for the passed
2388 * Returns False if icon can't be docked.
2390 * Note: this function should NEVER alter ret_x or ret_y, unless it will
2394 wDockSnapIcon(WDock
*dock
, WAppIcon
*icon
, int req_x
, int req_y
,
2395 int *ret_x
, int *ret_y
, int redocking
)
2397 WScreen
*scr
= dock
->screen_ptr
;
2400 int i
, offset
= ICON_SIZE
/2;
2401 WAppIcon
*aicon
= NULL
;
2402 WAppIcon
*nicon
= NULL
;
2403 int max_y_icons
, max_x_icons
;
2405 max_x_icons
= scr
->scr_width
/ICON_SIZE
;
2406 max_y_icons
= scr
->scr_height
/ICON_SIZE
-1;
2408 if (wPreferences
.flags
.noupdates
)
2414 /* if the dock is full */
2416 (dock
->icon_count
>= dock
->max_icons
)) {
2420 /* exact position */
2422 ex_y
= (req_y
- offset
- dy
)/ICON_SIZE
;
2424 ex_y
= (req_y
+ offset
- dy
)/ICON_SIZE
;
2427 ex_x
= (req_x
- offset
- dx
)/ICON_SIZE
;
2429 ex_x
= (req_x
+ offset
- dx
)/ICON_SIZE
;
2431 /* check if the icon is outside the screen boundaries */
2432 if (dx
+ ex_x
*ICON_SIZE
< -ICON_SIZE
+2 ||
2433 dx
+ ex_x
*ICON_SIZE
>= scr
->scr_width
-1 ||
2434 dy
+ ex_y
*ICON_SIZE
< -ICON_SIZE
+2 ||
2435 dy
+ ex_y
*ICON_SIZE
>= scr
->scr_height
-1)
2438 if (dock
->type
== WM_DOCK
) {
2439 if (icon
->dock
!= dock
&& ex_x
!= 0)
2443 for (i
=0; i
<dock
->max_icons
; i
++) {
2444 nicon
= dock
->icon_array
[i
];
2445 if (nicon
&& nicon
->yindex
== ex_y
) {
2452 int sig
, done
, closest
;
2454 /* Possible cases when redocking:
2456 * icon dragged out of range of any slot -> false
2457 * icon dragged to range of free slot
2458 * icon dragged to range of same slot
2459 * icon dragged to range of different icon
2461 if (abs(ex_x
) > DOCK_DETTACH_THRESHOLD
)
2464 if (ex_y
>=0 && ex_y
<=max_y_icons
&& (aicon
==icon
|| !aicon
)) {
2470 /* start looking at the upper slot or lower? */
2471 if (ex_y
*ICON_SIZE
< (req_y
+ offset
- dy
))
2478 /* look for closest free slot */
2479 for (i
=0; i
<(DOCK_DETTACH_THRESHOLD
+1)*2 && !done
; i
++) {
2483 closest
= sig
*(i
/2) + ex_y
;
2484 /* check if this slot is used */
2486 for (j
= 0; j
<dock
->max_icons
; j
++) {
2487 if (dock
->icon_array
[j
]
2488 && dock
->icon_array
[j
]->yindex
==closest
) {
2489 /* slot is used by someone else */
2490 if (dock
->icon_array
[j
]!=icon
)
2498 if (done
&& closest
>= 0 && closest
<= max_y_icons
&&
2499 ((ex_y
>= closest
&& ex_y
- closest
< DOCK_DETTACH_THRESHOLD
+1)
2501 (ex_y
< closest
&& closest
- ex_y
<= DOCK_DETTACH_THRESHOLD
+1))) {
2506 } else { /* !redocking */
2508 /* if slot is free and the icon is close enough, return it */
2509 if (!aicon
&& ex_x
== 0 && ex_y
>= 0 && ex_y
<= max_y_icons
) {
2519 start
= icon
->omnipresent
? 0 : scr
->current_workspace
;
2520 stop
= icon
->omnipresent
? scr
->workspace_count
: start
+1;
2523 for (k
=start
; k
<stop
; k
++) {
2524 WDock
*tmp
= scr
->workspaces
[k
]->clip
;
2527 for (i
=0; i
<tmp
->max_icons
; i
++) {
2528 nicon
= tmp
->icon_array
[i
];
2529 if (nicon
&& nicon
->xindex
== ex_x
&& nicon
->yindex
== ex_y
) {
2537 for (k
=start
; k
<stop
; k
++) {
2538 WDock
*tmp
= scr
->workspaces
[k
]->clip
;
2541 for (i
=0; i
<tmp
->max_icons
; i
++) {
2542 nicon
= tmp
->icon_array
[i
];
2543 if (nicon
&& nicon
!= icon
&& /* Icon can't be it's own neighbour */
2544 (abs(nicon
->xindex
- ex_x
) <= CLIP_ATTACH_VICINITY
&&
2545 abs(nicon
->yindex
- ex_y
) <= CLIP_ATTACH_VICINITY
)) {
2554 if (neighbours
&& (aicon
==NULL
|| (redocking
&& aicon
== icon
))) {
2563 #define MIN(x, y) ((x) > (y) ? (y) : (x))
2564 #define MAX(x, y) ((x) < (y) ? (y) : (x))
2566 #define ON_SCREEN(x, y, sx, ex, sy, ey) \
2567 ((((x)+ICON_SIZE/2) >= (sx)) && (((y)+ICON_SIZE/2) >= (sy)) && \
2568 (((x) + (ICON_SIZE/2)) <= (ex)) && (((y) + (ICON_SIZE/2)) <= ey))
2572 * returns true if it can find a free slot in the dock,
2573 * in which case it changes x_pos and y_pos accordingly.
2574 * Else returns false.
2577 wDockFindFreeSlot(WDock
*dock
, int *x_pos
, int *y_pos
)
2579 WScreen
*scr
= dock
->screen_ptr
;
2581 WAppIconChain
*chain
;
2582 unsigned char *slot_map
;
2586 int i
, done
= False
;
2588 int sx
=0, sy
=0, ex
=scr
->scr_width
, ey
=scr
->scr_height
;
2591 if (dock
->type
== WM_CLIP
&&
2592 dock
!= scr
->workspaces
[scr
->current_workspace
]->clip
)
2593 extra_count
= scr
->global_icon_count
;
2595 /* if the dock is full */
2596 if (dock
->icon_count
+extra_count
>= dock
->max_icons
) {
2600 if (!wPreferences
.flags
.nodock
&& scr
->dock
) {
2601 if (scr
->dock
->on_right_side
)
2602 ex
-= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2604 sx
+= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2607 if (ex
< dock
->x_pos
)
2609 if (sx
> dock
->x_pos
+ICON_SIZE
)
2610 sx
= dock
->x_pos
+ICON_SIZE
;
2617 /* check if clip is in a corner */
2618 if (dock
->type
==WM_CLIP
) {
2619 if (dock
->x_pos
< 1 && dock
->y_pos
< 1)
2621 else if (dock
->x_pos
< 1 && dock
->y_pos
>= (ey
-ICON_SIZE
))
2623 else if (dock
->x_pos
>= (ex
-ICON_SIZE
)&& dock
->y_pos
>= (ey
-ICON_SIZE
))
2625 else if (dock
->x_pos
>= (ex
-ICON_SIZE
) && dock
->y_pos
< 1)
2632 /* If the clip is in the corner, use only slots that are in the border
2634 if (corner
!=C_NONE
) {
2638 hcount
= MIN(dock
->max_icons
, scr
->scr_width
/ICON_SIZE
);
2639 vcount
= MIN(dock
->max_icons
, scr
->scr_height
/ICON_SIZE
);
2640 hmap
= wmalloc(hcount
+1);
2641 memset(hmap
, 0, hcount
+1);
2642 vmap
= wmalloc(vcount
+1);
2643 memset(vmap
, 0, vcount
+1);
2645 /* mark used positions */
2648 for (i
=0; i
<dock
->max_icons
; i
++) {
2649 btn
= dock
->icon_array
[i
];
2653 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2654 vmap
[btn
->yindex
] = 1;
2655 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2656 hmap
[btn
->xindex
] = 1;
2658 for (chain
=scr
->global_icons
; chain
!=NULL
; chain
=chain
->next
) {
2660 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2661 vmap
[btn
->yindex
] = 1;
2662 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2663 hmap
[btn
->xindex
] = 1;
2667 for (i
=0; i
<dock
->max_icons
; i
++) {
2668 btn
= dock
->icon_array
[i
];
2672 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2673 vmap
[btn
->yindex
] = 1;
2674 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2675 hmap
[-btn
->xindex
] = 1;
2677 for (chain
=scr
->global_icons
; chain
!=NULL
; chain
=chain
->next
) {
2679 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2680 vmap
[btn
->yindex
] = 1;
2681 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2682 hmap
[-btn
->xindex
] = 1;
2686 for (i
=0; i
<dock
->max_icons
; i
++) {
2687 btn
= dock
->icon_array
[i
];
2691 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2692 vmap
[-btn
->yindex
] = 1;
2693 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2694 hmap
[btn
->xindex
] = 1;
2696 for (chain
=scr
->global_icons
; chain
!=NULL
; chain
=chain
->next
) {
2698 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2699 vmap
[-btn
->yindex
] = 1;
2700 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2701 hmap
[btn
->xindex
] = 1;
2706 for (i
=0; i
<dock
->max_icons
; i
++) {
2707 btn
= dock
->icon_array
[i
];
2711 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2712 vmap
[-btn
->yindex
] = 1;
2713 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2714 hmap
[-btn
->xindex
] = 1;
2716 for (chain
=scr
->global_icons
; chain
!=NULL
; chain
=chain
->next
) {
2718 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2719 vmap
[-btn
->yindex
] = 1;
2720 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2721 hmap
[-btn
->xindex
] = 1;
2726 /* search a vacant slot */
2727 for (i
=1; i
<MAX(vcount
, hcount
); i
++) {
2728 if (i
< vcount
&& vmap
[i
]==0) {
2734 } else if (i
< hcount
&& hmap
[i
]==0) {
2744 /* If found a slot, translate and return */
2746 if (corner
==C_NW
|| corner
==C_NE
) {
2751 if (corner
==C_NE
|| corner
==C_SE
) {
2758 /* else, try to find a slot somewhere else */
2761 /* a map of mwidth x mwidth would be enough if we allowed icons to be
2762 * placed outside of screen */
2763 mwidth
= (int)ceil(sqrt(dock
->max_icons
));
2765 /* In the worst case (the clip is in the corner of the screen),
2766 * the amount of icons that fit in the clip is smaller.
2767 * Double the map to get a safe value.
2773 slot_map
= wmalloc(mwidth
*mwidth
);
2774 memset(slot_map
, 0, mwidth
*mwidth
);
2776 #define XY2OFS(x,y) (MAX(abs(x),abs(y)) > r) ? 0 : (((y)+r)*(mwidth)+(x)+r)
2778 /* mark used slots in the map. If the slot falls outside the map
2779 * (for example, when all icons are placed in line), ignore them. */
2780 for (i
=0; i
<dock
->max_icons
; i
++) {
2781 btn
= dock
->icon_array
[i
];
2783 slot_map
[XY2OFS(btn
->xindex
, btn
->yindex
)] = 1;
2785 for (chain
=scr
->global_icons
; chain
!=NULL
; chain
=chain
->next
) {
2786 slot_map
[XY2OFS(chain
->aicon
->xindex
, chain
->aicon
->yindex
)] = 1;
2788 /* Find closest slot from the center that is free by scanning the
2789 * map from the center to outward in circular passes.
2790 * This will not result in a neat layout, but will be optimal
2791 * in the sense that there will not be holes left.
2794 for (i
= 1; i
<= r
&& !done
; i
++) {
2797 /* top and bottom parts of the ring */
2798 for (x
= -i
; x
<= i
&& !done
; x
++) {
2799 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2801 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2802 if (slot_map
[XY2OFS(x
,y
)]==0
2803 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2810 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2811 if (slot_map
[XY2OFS(x
,y
)]==0
2812 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2819 /* left and right parts of the ring */
2820 for (y
= -i
+1; y
<= i
-1; y
++) {
2821 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2823 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2824 if (slot_map
[XY2OFS(x
,y
)]==0
2825 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2832 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2833 if (slot_map
[XY2OFS(x
,y
)]==0
2834 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2849 moveDock(WDock
*dock
, int new_x
, int new_y
)
2854 dock
->x_pos
= new_x
;
2855 dock
->y_pos
= new_y
;
2856 for (i
=0; i
<dock
->max_icons
; i
++) {
2857 btn
= dock
->icon_array
[i
];
2859 btn
->x_pos
= new_x
+ btn
->xindex
*ICON_SIZE
;
2860 btn
->y_pos
= new_y
+ btn
->yindex
*ICON_SIZE
;
2861 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2868 swapDock(WDock
*dock
)
2870 WScreen
*scr
= dock
->screen_ptr
;
2875 if (dock
->on_right_side
) {
2876 x
= dock
->x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
2878 x
= dock
->x_pos
= DOCK_EXTRA_SPACE
;
2881 for (i
=0; i
<dock
->max_icons
; i
++) {
2882 btn
= dock
->icon_array
[i
];
2885 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2889 wScreenUpdateUsableArea(scr
);
2894 execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
)
2896 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
2902 cmdline
= ExpandOptions(scr
, command
);
2904 if (scr
->flags
.dnd_data_convertion_status
|| !cmdline
) {
2912 wtokensplit(cmdline
, &argv
, &argc
);
2922 if ((pid
=fork())==0) {
2926 SetupEnvironment(scr
);
2932 args
= malloc(sizeof(char*)*(argc
+1));
2935 for (i
=0; i
<argc
; i
++) {
2939 execvp(argv
[0], args
);
2943 wfree(argv
[--argc
]);
2948 state
= wmalloc(sizeof(WSavedState
));
2949 memset(state
, 0, sizeof(WSavedState
));
2951 state
->miniaturized
= -1;
2953 if (btn
->dock
==scr
->dock
|| btn
->omnipresent
)
2954 state
->workspace
= -1;
2956 state
->workspace
= scr
->current_workspace
;
2958 wWindowAddSavedState(btn
->wm_instance
, btn
->wm_class
, cmdline
, pid
,
2960 wAddDeathHandler(pid
, (WDeathHandler
*)trackDeadProcess
,
2971 wDockHideIcons(WDock
*dock
)
2978 for (i
=1; i
<dock
->max_icons
; i
++) {
2979 if (dock
->icon_array
[i
])
2980 XUnmapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
2984 dockIconPaint(dock
->icon_array
[0]);
2989 wDockShowIcons(WDock
*dock
)
2997 btn
= dock
->icon_array
[0];
2998 moveDock(dock
, btn
->x_pos
, btn
->y_pos
);
3000 newlevel
= dock
->lowered
? WMNormalLevel
: WMDockLevel
;
3001 ChangeStackingLevel(btn
->icon
->core
, newlevel
);
3003 for (i
=1; i
<dock
->max_icons
; i
++) {
3004 if (dock
->icon_array
[i
]) {
3005 MoveInStackListAbove(dock
->icon_array
[i
]->icon
->core
,
3011 if (!dock
->collapsed
) {
3012 for (i
=1; i
<dock
->max_icons
; i
++) {
3013 if (dock
->icon_array
[i
]) {
3014 XMapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
3025 wDockLower(WDock
*dock
)
3029 for (i
=0; i
<dock
->max_icons
; i
++) {
3030 if (dock
->icon_array
[i
])
3031 wLowerFrame(dock
->icon_array
[i
]->icon
->core
);
3037 wDockRaise(WDock
*dock
)
3041 for (i
=dock
->max_icons
-1; i
>=0; i
--) {
3042 if (dock
->icon_array
[i
])
3043 wRaiseFrame(dock
->icon_array
[i
]->icon
->core
);
3049 wDockRaiseLower(WDock
*dock
)
3051 if (!dock
->icon_array
[0]->icon
->core
->stacking
->above
3052 ||(dock
->icon_array
[0]->icon
->core
->stacking
->window_level
3053 !=dock
->icon_array
[0]->icon
->core
->stacking
->above
->stacking
->window_level
))
3061 wDockFinishLaunch(WDock
*dock
, WAppIcon
*icon
)
3063 icon
->launching
= 0;
3064 icon
->relaunching
= 0;
3065 dockIconPaint(icon
);
3070 wDockFindIconForWindow(WDock
*dock
, Window window
)
3075 for (i
=0; i
<dock
->max_icons
; i
++) {
3076 icon
= dock
->icon_array
[i
];
3077 if (icon
&& icon
->main_window
== window
)
3085 wDockTrackWindowLaunch(WDock
*dock
, Window window
)
3088 char *wm_class
, *wm_instance
;
3090 Bool firstPass
= True
;
3092 char *command
= NULL
;
3098 if (XGetCommand(dpy
, window
, &argv
, &argc
)) {
3099 if (argc
> 0 && argv
!= NULL
)
3100 command
= wtokenjoin(argv
,argc
);
3102 XFreeStringList(argv
);
3107 if (!PropGetWMClass(window
, &wm_class
, &wm_instance
) ||
3108 (!wm_class
&& !wm_instance
))
3112 for (i
=0; i
<dock
->max_icons
; i
++) {
3113 icon
= dock
->icon_array
[i
];
3117 /* app is already attached to icon */
3118 if (icon
->main_window
== window
) {
3123 if ((icon
->wm_instance
|| icon
->wm_class
)
3125 || (dock
->screen_ptr
->flags
.startup
&& !icon
->running
))) {
3127 if (icon
->wm_instance
&& wm_instance
&&
3128 strcmp(icon
->wm_instance
, wm_instance
)!=0) {
3131 if (icon
->wm_class
&& wm_class
&&
3132 strcmp(icon
->wm_class
, wm_class
)!=0) {
3135 if (firstPass
&& command
&& strcmp(icon
->command
, command
)!=0) {
3139 if (!icon
->relaunching
) {
3142 /* Possibly an application that was docked with dockit,
3143 * but the user did not update WMState to indicate that
3144 * it was docked by force */
3145 wapp
= wApplicationOf(window
);
3147 icon
->forced_dock
= 1;
3150 if (!icon
->forced_dock
)
3151 icon
->main_window
= window
;
3155 wDockFinishLaunch(dock
, icon
);
3160 if (firstPass
&& !found
) {
3177 wClipUpdateForWorkspaceChange(WScreen
*scr
, int workspace
)
3179 if (!wPreferences
.flags
.noclip
) {
3180 scr
->clip_icon
->dock
= scr
->workspaces
[workspace
]->clip
;
3181 if (scr
->current_workspace
!= workspace
) {
3182 WDock
*old_clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
3183 WAppIconChain
*chain
= scr
->global_icons
;
3186 moveIconBetweenDocks(chain
->aicon
->dock
,
3187 scr
->workspaces
[workspace
]->clip
,
3188 chain
->aicon
, chain
->aicon
->xindex
,
3189 chain
->aicon
->yindex
);
3190 if (scr
->workspaces
[workspace
]->clip
->collapsed
)
3191 XUnmapWindow(dpy
, chain
->aicon
->icon
->core
->window
);
3192 chain
= chain
->next
;
3195 wDockHideIcons(old_clip
);
3196 if (old_clip
->auto_raise_lower
) {
3197 if (old_clip
->auto_raise_magic
) {
3198 WMDeleteTimerHandler(old_clip
->auto_raise_magic
);
3199 old_clip
->auto_raise_magic
= NULL
;
3201 wDockLower(old_clip
);
3203 if (old_clip
->auto_collapse
) {
3204 if (old_clip
->auto_expand_magic
) {
3205 WMDeleteTimerHandler(old_clip
->auto_expand_magic
);
3206 old_clip
->auto_expand_magic
= NULL
;
3208 old_clip
->collapsed
= 1;
3210 wDockShowIcons(scr
->workspaces
[workspace
]->clip
);
3212 if (scr
->flags
.clip_balloon_mapped
)
3213 showClipBalloon(scr
->clip_icon
->dock
, workspace
);
3220 trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
)
3225 for (i
=0; i
<dock
->max_icons
; i
++) {
3226 icon
= dock
->icon_array
[i
];
3230 if (icon
->launching
&& icon
->pid
== pid
) {
3231 if (!icon
->relaunching
) {
3233 icon
->main_window
= None
;
3235 wDockFinishLaunch(dock
, icon
);
3240 sprintf(msg
, _("Could not execute command \"%s\""),
3241 icon
->drop_launch
&& icon
->dnd_command
3242 ? icon
->dnd_command
: icon
->command
);
3244 sprintf(msg
, _("Could not execute command \"%s\""),
3247 wMessageDialog(dock
->screen_ptr
, _("Error"), msg
,
3248 _("OK"), NULL
, NULL
);
3257 toggleLowered(WDock
*dock
)
3262 /* lower/raise Dock */
3263 if (!dock
->lowered
) {
3264 newlevel
= WMNormalLevel
;
3267 newlevel
= WMDockLevel
;
3271 for (i
=0; i
<dock
->max_icons
; i
++) {
3272 tmp
= dock
->icon_array
[i
];
3276 ChangeStackingLevel(tmp
->icon
->core
, newlevel
);
3278 wLowerFrame(tmp
->icon
->core
);
3281 if (dock
->type
== WM_DOCK
)
3282 wScreenUpdateUsableArea(dock
->screen_ptr
);
3287 toggleCollapsed(WDock
*dock
)
3289 if (dock
->collapsed
) {
3290 dock
->collapsed
= 0;
3291 wDockShowIcons(dock
);
3294 dock
->collapsed
= 1;
3295 wDockHideIcons(dock
);
3301 openDockMenu(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3303 WScreen
*scr
= dock
->screen_ptr
;
3304 WObjDescriptor
*desc
;
3306 WApplication
*wapp
= NULL
;
3310 int appIsRunning
= aicon
->running
&& aicon
->icon
&& aicon
->icon
->owner
;
3312 if (dock
->type
== WM_DOCK
) {
3314 entry
= dock
->menu
->entries
[index
];
3315 entry
->flags
.indicator_on
= !dock
->lowered
;
3316 entry
->clientdata
= dock
;
3317 dock
->menu
->flags
.realized
= 0;
3320 if (scr
->clip_options
)
3321 updateClipOptionsMenu(scr
->clip_options
, dock
);
3323 n_selected
= numberOfSelectedIcons(dock
);
3325 /* Rename Workspace */
3326 entry
= dock
->menu
->entries
[++index
];
3327 if (aicon
== scr
->clip_icon
) {
3328 entry
->callback
= renameCallback
;
3329 entry
->clientdata
= dock
;
3330 entry
->flags
.indicator
= 0;
3331 entry
->text
= _("Rename Workspace");
3333 entry
->callback
= omnipresentCallback
;
3334 entry
->clientdata
= aicon
;
3335 if (n_selected
> 0) {
3336 entry
->flags
.indicator
= 0;
3337 entry
->text
= _("Toggle Omnipresent");
3339 entry
->flags
.indicator
= 1;
3340 entry
->flags
.indicator_on
= aicon
->omnipresent
;
3341 entry
->flags
.indicator_type
= MI_CHECK
;
3342 entry
->text
= _("Omnipresent");
3346 /* select/unselect icon */
3347 entry
= dock
->menu
->entries
[++index
];
3348 entry
->clientdata
= aicon
;
3349 entry
->flags
.indicator_on
= aicon
->icon
->selected
;
3350 wMenuSetEnabled(dock
->menu
, index
, aicon
!=scr
->clip_icon
);
3352 /* select/unselect all icons */
3353 entry
= dock
->menu
->entries
[++index
];
3354 entry
->clientdata
= aicon
;
3356 entry
->text
= _("Unselect All Icons");
3358 entry
->text
= _("Select All Icons");
3359 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3362 entry
= dock
->menu
->entries
[++index
];
3363 entry
->clientdata
= aicon
;
3365 entry
->text
= _("Keep Icons");
3367 entry
->text
= _("Keep Icon");
3368 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3370 /* this is the workspace submenu part */
3371 entry
= dock
->menu
->entries
[++index
];
3373 entry
->text
= _("Move Icons To");
3375 entry
->text
= _("Move Icon To");
3376 if (scr
->clip_submenu
)
3377 updateWorkspaceMenu(scr
->clip_submenu
, aicon
);
3378 wMenuSetEnabled(dock
->menu
, index
, !aicon
->omnipresent
);
3380 /* remove icon(s) */
3381 entry
= dock
->menu
->entries
[++index
];
3382 entry
->clientdata
= aicon
;
3384 entry
->text
= _("Remove Icons");
3386 entry
->text
= _("Remove Icon");
3387 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3389 /* attract icon(s) */
3390 entry
= dock
->menu
->entries
[++index
];
3391 entry
->clientdata
= aicon
;
3393 dock
->menu
->flags
.realized
= 0;
3394 wMenuRealize(dock
->menu
);
3398 if (aicon
->icon
->owner
) {
3399 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
3405 entry
= dock
->menu
->entries
[++index
];
3406 entry
->clientdata
= aicon
;
3407 wMenuSetEnabled(dock
->menu
, index
, aicon
->command
!=NULL
);
3410 entry
= dock
->menu
->entries
[++index
];
3411 entry
->clientdata
= aicon
;
3412 if (wapp
&& wapp
->flags
.hidden
) {
3413 entry
->text
= _("Unhide Here");
3415 entry
->text
= _("Bring Here");
3417 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3420 entry
= dock
->menu
->entries
[++index
];
3421 entry
->clientdata
= aicon
;
3422 if (wapp
&& wapp
->flags
.hidden
) {
3423 entry
->text
= _("Unhide");
3425 entry
->text
= _("Hide");
3427 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3430 entry
= dock
->menu
->entries
[++index
];
3431 entry
->clientdata
= aicon
;
3432 wMenuSetEnabled(dock
->menu
, index
, !aicon
->editing
3433 && !wPreferences
.flags
.noupdates
);
3436 entry
= dock
->menu
->entries
[++index
];
3437 entry
->clientdata
= aicon
;
3438 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3440 if (!dock
->menu
->flags
.realized
)
3441 wMenuRealize(dock
->menu
);
3443 if (dock
->type
== WM_CLIP
) {
3444 x_pos
= event
->xbutton
.x_root
+2;
3446 x_pos
= dock
->on_right_side
?
3447 scr
->scr_width
- dock
->menu
->frame
->core
->width
- 2 : 0;
3450 wMenuMapAt(dock
->menu
, x_pos
, event
->xbutton
.y_root
+2, False
);
3452 /* allow drag select */
3453 event
->xany
.send_event
= True
;
3454 desc
= &dock
->menu
->menu
->descriptor
;
3455 (*desc
->handle_mousedown
)(desc
, event
);
3460 openClipWorkspaceMenu(WScreen
*scr
, int x
, int y
)
3462 if (!scr
->clip_ws_menu
) {
3463 scr
->clip_ws_menu
= wWorkspaceMenuMake(scr
, False
);
3465 wWorkspaceMenuUpdate(scr
, scr
->clip_ws_menu
);
3466 wMenuMapAt(scr
->clip_ws_menu
, x
, y
, False
);
3470 /******************************************************************/
3472 iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
3474 WAppIcon
*btn
= desc
->parent
;
3475 WDock
*dock
= btn
->dock
;
3476 WApplication
*wapp
= NULL
;
3479 if (btn
->icon
->owner
&& !(event
->xbutton
.state
& ControlMask
)) {
3480 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
3484 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
3486 /* go to the last workspace that the user worked on the app */
3487 if (wapp
->last_workspace
!= dock
->screen_ptr
->current_workspace
3489 wWorkspaceChange(dock
->screen_ptr
, wapp
->last_workspace
);
3492 wUnhideApplication(wapp
, event
->xbutton
.button
==Button2
,
3495 if (event
->xbutton
.state
& MOD_MASK
) {
3496 wHideOtherApplications(btn
->icon
->owner
);
3499 if (event
->xbutton
.button
==Button1
) {
3501 if (event
->xbutton
.state
& MOD_MASK
) {
3502 /* raise/lower dock */
3503 toggleLowered(dock
);
3504 } else if (btn
== dock
->screen_ptr
->clip_icon
) {
3505 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
)
3506 toggleCollapsed(dock
);
3508 handleClipChangeWorkspace(dock
->screen_ptr
, event
);
3509 } else if (btn
->command
) {
3510 if (!btn
->launching
&&
3511 (!btn
->running
|| (event
->xbutton
.state
& ControlMask
))) {
3512 launchDockedApplication(btn
);
3514 } else if (btn
->xindex
== 0 && btn
->yindex
== 0
3515 && btn
->dock
->type
== WM_DOCK
) {
3517 wShowGNUstepPanel(dock
->screen_ptr
);
3525 handleDockMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3527 WScreen
*scr
= dock
->screen_ptr
;
3528 int ofs_x
=event
->xbutton
.x
, ofs_y
=event
->xbutton
.y
;
3531 int grabbed
= 0, swapped
= 0, done
;
3532 Pixmap ghost
= None
;
3533 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3536 puts("moving dock");
3538 if (XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
3539 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3540 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3541 wwarning("pointer grab failed for dock move");
3544 for (x
=0; x
<dock
->max_icons
; x
++) {
3545 if (dock
->icon_array
[x
]!=NULL
&&
3546 dock
->icon_array
[x
]->yindex
> y
)
3547 y
= dock
->icon_array
[x
]->yindex
;
3550 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
*y
);
3554 WMMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3555 |ButtonMotionMask
|ExposureMask
, &ev
);
3563 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3564 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3565 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3566 |ButtonReleaseMask
|ButtonPressMask
,
3567 wCursor
[WCUR_MOVE
], CurrentTime
);
3572 if (dock
->type
== WM_CLIP
) {
3573 if (ev
.xmotion
.x_root
- ofs_x
< 0) {
3575 } else if (ev
.xmotion
.x_root
- ofs_x
+ ICON_SIZE
>
3577 x
= scr
->scr_width
- ICON_SIZE
;
3579 x
= ev
.xmotion
.x_root
- ofs_x
;
3581 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3583 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3585 y
= scr
->scr_height
- ICON_SIZE
;
3587 y
= ev
.xmotion
.y_root
- ofs_y
;
3589 moveDock(dock
, x
, y
);
3591 /* move vertically if pointer is inside the dock*/
3592 if ((dock
->on_right_side
&&
3593 ev
.xmotion
.x_root
>= dock
->x_pos
- ICON_SIZE
)
3594 || (!dock
->on_right_side
&&
3595 ev
.xmotion
.x_root
<= dock
->x_pos
+ ICON_SIZE
*2)) {
3597 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3599 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3601 y
= scr
->scr_height
- ICON_SIZE
;
3603 y
= ev
.xmotion
.y_root
- ofs_y
;
3605 moveDock(dock
, dock
->x_pos
, y
);
3607 /* move horizontally to change sides */
3608 x
= ev
.xmotion
.x_root
- ofs_x
;
3609 if (!dock
->on_right_side
) {
3613 if (ev
.xmotion
.x_root
> dock
->x_pos
+ ICON_SIZE
*2) {
3614 XMoveWindow(dpy
, scr
->dock_shadow
, scr
->scr_width
-ICON_SIZE
3615 -DOCK_EXTRA_SPACE
-1, dock
->y_pos
);
3616 if (superfluous
&& ghost
==None
) {
3617 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3618 scr
->scr_width
-ICON_SIZE
3619 -DOCK_EXTRA_SPACE
-1,
3621 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3623 XClearWindow(dpy
, scr
->dock_shadow
);
3625 XMapRaised(dpy
, scr
->dock_shadow
);
3628 if (superfluous
&& ghost
!=None
) {
3629 XFreePixmap(dpy
, ghost
);
3632 XUnmapWindow(dpy
, scr
->dock_shadow
);
3637 if (ev
.xmotion
.x_root
< dock
->x_pos
- ICON_SIZE
) {
3638 XMoveWindow(dpy
, scr
->dock_shadow
,
3639 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3640 if (superfluous
&& ghost
==None
) {
3641 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3642 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3643 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3645 XClearWindow(dpy
, scr
->dock_shadow
);
3647 XMapRaised(dpy
, scr
->dock_shadow
);
3650 XUnmapWindow(dpy
, scr
->dock_shadow
);
3652 if (superfluous
&& ghost
!=None
) {
3653 XFreePixmap(dpy
, ghost
);
3665 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3667 XUngrabPointer(dpy
, CurrentTime
);
3668 XUnmapWindow(dpy
, scr
->dock_shadow
);
3669 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
);
3670 if (dock
->type
== WM_DOCK
) {
3673 dock
->on_right_side
= 1;
3675 dock
->on_right_side
= 0;
3677 wArrangeIcons(scr
, False
);
3686 XFreePixmap(dpy
, ghost
);
3687 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3690 puts("End dock move");
3697 handleIconMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3699 WScreen
*scr
= dock
->screen_ptr
;
3701 WIcon
*icon
= aicon
->icon
;
3702 WDock
*dock2
= NULL
, *last_dock
= dock
, *clip
= NULL
;
3703 int ondock
, grabbed
= 0, change_dock
= 0, collapsed
= 0;
3705 int x
= aicon
->x_pos
, y
= aicon
->y_pos
;
3706 int ofs_x
= event
->xbutton
.x
, ofs_y
= event
->xbutton
.y
;
3707 int shad_x
= x
, shad_y
= y
;
3708 int ix
= aicon
->xindex
, iy
= aicon
->yindex
;
3710 Pixmap ghost
= None
;
3712 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3713 int omnipresent
= aicon
->omnipresent
; /* this must be cached!!! */
3716 if (wPreferences
.flags
.noupdates
)
3719 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
3720 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3721 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3723 wwarning("pointer grab failed for icon move");
3727 if (!(event
->xbutton
.state
& MOD_MASK
))
3728 wRaiseFrame(icon
->core
);
3730 if (!wPreferences
.flags
.noclip
)
3731 clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
3733 if (dock
== scr
->dock
&& !wPreferences
.flags
.noclip
)
3735 else if (dock
!= scr
->dock
&& !wPreferences
.flags
.nodock
)
3738 wins
[0] = icon
->core
->window
;
3739 wins
[1] = scr
->dock_shadow
;
3740 XRestackWindows(dpy
, wins
, 2);
3741 XMoveResizeWindow(dpy
, scr
->dock_shadow
, aicon
->x_pos
, aicon
->y_pos
,
3742 ICON_SIZE
, ICON_SIZE
);
3744 if (icon
->pixmap
!=None
)
3745 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
3747 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
3749 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
, ghost
);
3750 XClearWindow(dpy
, scr
->dock_shadow
);
3752 XMapWindow(dpy
, scr
->dock_shadow
);
3758 XMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3759 |ButtonMotionMask
|ExposureMask
, &ev
);
3767 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3768 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3769 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3770 |ButtonReleaseMask
|ButtonPressMask
,
3771 wCursor
[WCUR_MOVE
], CurrentTime
);
3780 for (i
=0; i
<scr
->workspace_count
; i
++) {
3781 if (i
== scr
->current_workspace
)
3783 wDockShowIcons(scr
->workspaces
[i
]->clip
);
3787 x
= ev
.xmotion
.x_root
- ofs_x
;
3788 y
= ev
.xmotion
.y_root
- ofs_y
;
3789 tmp
= wDockSnapIcon(dock
, aicon
, x
, y
, &ix
, &iy
, True
);
3792 if (last_dock
!= dock
&& collapsed
) {
3793 last_dock
->collapsed
= 1;
3794 wDockHideIcons(last_dock
);
3797 if (!collapsed
&& (collapsed
= dock
->collapsed
)) {
3798 dock
->collapsed
= 0;
3799 wDockShowIcons(dock
);
3801 if (dock
->auto_raise_lower
)
3805 tmp
= wDockSnapIcon(dock2
, aicon
, x
, y
, &ix
, &iy
, False
);
3808 if (last_dock
!= dock2
&& collapsed
) {
3809 last_dock
->collapsed
= 1;
3810 wDockHideIcons(last_dock
);
3813 if (!collapsed
&& (collapsed
= dock2
->collapsed
)) {
3814 dock2
->collapsed
= 0;
3815 wDockShowIcons(dock2
);
3817 if (dock2
->auto_raise_lower
)
3822 if (aicon
->launching
3824 || (aicon
->running
&& !(ev
.xmotion
.state
& MOD_MASK
))
3825 || (!aicon
->running
&& tmp
)) {
3826 shad_x
= last_dock
->x_pos
+ ix
*wPreferences
.icon_size
;
3827 shad_y
= last_dock
->y_pos
+ iy
*wPreferences
.icon_size
;
3829 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
3832 XMapWindow(dpy
, scr
->dock_shadow
);
3837 XUnmapWindow(dpy
, scr
->dock_shadow
);
3841 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
3848 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3850 XUngrabPointer(dpy
, CurrentTime
);
3852 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
3853 XUnmapWindow(dpy
, scr
->dock_shadow
);
3855 reattachIcon(dock
, aicon
, ix
, iy
);
3856 if (clip
&& dock
!=clip
&& clip
->auto_raise_lower
)
3859 docked
= moveIconBetweenDocks(dock
, dock2
, aicon
, ix
, iy
);
3861 /* Slide it back if dock rejected it */
3862 SlideWindow(icon
->core
->window
, x
, y
, aicon
->x_pos
,
3864 reattachIcon(dock
, aicon
, aicon
->xindex
,aicon
->yindex
);
3866 if (last_dock
->type
==WM_CLIP
&& last_dock
->auto_collapse
) {
3874 if (!aicon
->running
&& !wPreferences
.no_animations
) {
3875 /* We need to deselect it, even if is deselected in
3876 * wDockDetach(), because else DoKaboom() will fail.
3878 if (aicon
->icon
->selected
)
3879 wIconSelect(aicon
->icon
);
3882 wSoundPlay(WSOUND_KABOOM
);
3884 DoKaboom(scr
,aicon
->icon
->core
->window
, x
, y
);
3887 wSoundPlay(WSOUND_UNDOCK
);
3892 wSoundPlay(WSOUND_UNDOCK
);
3895 if (clip
&& clip
->auto_raise_lower
)
3897 wDockDetach(dock
, aicon
);
3900 last_dock
->collapsed
= 1;
3901 wDockHideIcons(last_dock
);
3906 XFreePixmap(dpy
, ghost
);
3907 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3911 for (i
=0; i
<scr
->workspace_count
; i
++) {
3912 if (i
== scr
->current_workspace
)
3914 wDockHideIcons(scr
->workspaces
[i
]->clip
);
3919 puts("End icon move");
3928 getClipButton(int px
, int py
)
3930 int pt
= (CLIP_BUTTON_SIZE
+2)*ICON_SIZE
/64;
3932 if (px
< 0 || py
< 0 || px
>= ICON_SIZE
|| py
>= ICON_SIZE
)
3935 if (py
<= pt
-((int)ICON_SIZE
-1-px
))
3936 return CLIP_FORWARD
;
3937 else if (px
<= pt
-((int)ICON_SIZE
-1-py
))
3945 handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
)
3948 int done
, direction
, new_ws
;
3950 WDock
*clip
= scr
->clip_icon
->dock
;
3952 direction
= getClipButton(event
->xbutton
.x
, event
->xbutton
.y
);
3954 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3955 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3957 wClipIconPaint(scr
->clip_icon
);
3960 WMMaskEvent(dpy
, ExposureMask
|ButtonMotionMask
|ButtonReleaseMask
3961 |ButtonPressMask
, &ev
);
3968 new_dir
= getClipButton(ev
.xmotion
.x
, ev
.xmotion
.y
);
3969 if (new_dir
!= direction
) {
3970 direction
= new_dir
;
3971 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3972 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3973 wClipIconPaint(scr
->clip_icon
);
3981 if (ev
.xbutton
.button
== event
->xbutton
.button
)
3986 clip
->lclip_button_pushed
= 0;
3987 clip
->rclip_button_pushed
= 0;
3989 new_ws
= wPreferences
.ws_advance
|| (event
->xbutton
.state
& ControlMask
);
3991 if (direction
== CLIP_FORWARD
) {
3992 if (scr
->current_workspace
< scr
->workspace_count
-1)
3993 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3994 else if (new_ws
&& scr
->current_workspace
< MAX_WORKSPACES
-1)
3995 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3996 else if (wPreferences
.ws_cycle
)
3997 wWorkspaceChange(scr
, 0);
3999 else if (direction
== CLIP_REWIND
) {
4000 if (scr
->current_workspace
> 0)
4001 wWorkspaceChange(scr
, scr
->current_workspace
-1);
4002 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
4003 wWorkspaceChange(scr
, scr
->workspace_count
-1);
4006 wClipIconPaint(scr
->clip_icon
);
4011 iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
4013 WAppIcon
*aicon
= desc
->parent
;
4014 WDock
*dock
= aicon
->dock
;
4015 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
4017 if (aicon
->editing
|| WCHECK_STATE(WSTATE_MODAL
))
4020 scr
->last_dock
= dock
;
4022 if (dock
->menu
->flags
.mapped
)
4023 wMenuUnmap(dock
->menu
);
4025 if (IsDoubleClick(scr
, event
)) {
4026 /* double-click was not in the main clip icon */
4027 if (dock
->type
!= WM_CLIP
|| aicon
->xindex
!=0 || aicon
->yindex
!=0
4028 || getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
) {
4029 iconDblClick(desc
, event
);
4034 if (dock
->type
== WM_CLIP
&& scr
->flags
.clip_balloon_mapped
) {
4035 XUnmapWindow(dpy
, scr
->clip_balloon
);
4036 scr
->flags
.clip_balloon_mapped
= 0;
4040 puts("handling dock");
4042 if (event
->xbutton
.button
== Button1
) {
4043 if (event
->xbutton
.state
& MOD_MASK
)
4048 if ((event
->xbutton
.state
& ShiftMask
) && aicon
!=scr
->clip_icon
&&
4049 dock
->type
!=WM_DOCK
) {
4050 wIconSelect(aicon
->icon
);
4054 if (aicon
->yindex
==0 && aicon
->xindex
==0) {
4055 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)!=CLIP_IDLE
4056 && dock
->type
==WM_CLIP
)
4057 handleClipChangeWorkspace(scr
, event
);
4059 handleDockMove(dock
, aicon
, event
);
4061 handleIconMove(dock
, aicon
, event
);
4063 } else if (event
->xbutton
.button
==Button2
&& dock
->type
==WM_CLIP
&&
4064 aicon
==scr
->clip_icon
) {
4065 openClipWorkspaceMenu(scr
, event
->xbutton
.x_root
+2,
4066 event
->xbutton
.y_root
+2);
4067 if (scr
->clip_ws_menu
) {
4069 menu
= scr
->clip_ws_menu
;
4070 desc
= &menu
->menu
->descriptor
;
4072 event
->xany
.send_event
= True
;
4073 (*desc
->handle_mousedown
)(desc
, event
);
4075 } else if (event
->xbutton
.button
==Button2
&& dock
->type
==WM_CLIP
&&
4076 (event
->xbutton
.state
& ShiftMask
) && aicon
!=scr
->clip_icon
) {
4077 wClipMakeIconOmnipresent(aicon
, !aicon
->omnipresent
);
4078 } else if (event
->xbutton
.button
== Button3
) {
4079 if (event
->xbutton
.send_event
&&
4080 XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
4081 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
4082 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
4083 wwarning("pointer grab failed for dockicon menu");
4087 openDockMenu(dock
, aicon
, event
);
4093 showClipBalloon(WDock
*dock
, int workspace
)
4097 WScreen
*scr
= dock
->screen_ptr
;
4101 scr
->flags
.clip_balloon_mapped
= 1;
4102 XMapWindow(dpy
, scr
->clip_balloon
);
4104 text
= scr
->workspaces
[workspace
]->name
;
4106 w
= WMWidthOfString(scr
->clip_title_font
, text
, strlen(text
));
4108 h
= WMFontHeight(scr
->clip_title_font
);
4109 XResizeWindow(dpy
, scr
->clip_balloon
, w
, h
);
4111 x
= dock
->x_pos
+ CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
4112 y
= dock
->y_pos
+ ICON_SIZE
- WMFontHeight(scr
->clip_title_font
) - 3;
4114 if (x
+w
> scr
->scr_width
) {
4115 x
= scr
->scr_width
- w
;
4116 if (dock
->y_pos
+ ICON_SIZE
+ h
> scr
->scr_height
)
4117 y
= dock
->y_pos
- h
- 1;
4119 y
= dock
->y_pos
+ ICON_SIZE
;
4120 XRaiseWindow(dpy
, scr
->clip_balloon
);
4122 stack
[0] = scr
->clip_icon
->icon
->core
->window
;
4123 stack
[1] = scr
->clip_balloon
;
4124 XRestackWindows(dpy
, stack
, 2);
4126 XMoveWindow(dpy
, scr
->clip_balloon
, x
, y
);
4127 XSetForeground(dpy
, scr
->clip_title_gc
,
4128 scr
->clip_title_pixel
[CLIP_NORMAL
]);
4129 XClearWindow(dpy
, scr
->clip_balloon
);
4130 WMDrawString(scr
->wmscreen
, scr
->clip_balloon
, scr
->clip_title_gc
,
4131 scr
->clip_title_font
, 0, 0, text
, strlen(text
));
4136 clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
)
4138 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
4142 assert(event
->type
==EnterNotify
);
4144 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
4147 scr
= btn
->icon
->core
->screen_ptr
;
4148 if (!btn
->omnipresent
)
4151 dock
= scr
->workspaces
[scr
->current_workspace
]->clip
;
4153 if (!dock
|| dock
->type
!=WM_CLIP
)
4156 /* The auto raise/lower code */
4157 if (dock
->auto_lower_magic
) {
4158 WMDeleteTimerHandler(dock
->auto_lower_magic
);
4159 dock
->auto_lower_magic
= NULL
;
4161 if (dock
->auto_raise_lower
&& !dock
->auto_raise_magic
) {
4162 dock
->auto_raise_magic
= WMAddTimerHandler(AUTO_RAISE_DELAY
,
4167 /* The auto expand/collapse code */
4168 if (dock
->auto_collapse_magic
) {
4169 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
4170 dock
->auto_collapse_magic
= NULL
;
4172 if (dock
->auto_collapse
&& !dock
->auto_expand_magic
) {
4173 dock
->auto_expand_magic
= WMAddTimerHandler(AUTO_EXPAND_DELAY
,
4178 if (btn
->xindex
== 0 && btn
->yindex
== 0)
4179 showClipBalloon(dock
, dock
->screen_ptr
->current_workspace
);
4181 if (dock
->screen_ptr
->flags
.clip_balloon_mapped
) {
4182 XUnmapWindow(dpy
, dock
->screen_ptr
->clip_balloon
);
4183 dock
->screen_ptr
->flags
.clip_balloon_mapped
= 0;
4190 clipLeave(WDock
*dock
)
4193 WObjDescriptor
*desc
= NULL
;
4195 if (!dock
|| dock
->type
!=WM_CLIP
)
4198 if (XCheckTypedEvent(dpy
, EnterNotify
, &event
)!=False
) {
4199 if (XFindContext(dpy
, event
.xcrossing
.window
, wWinContext
,
4200 (XPointer
*)&desc
)!=XCNOENT
4201 && desc
&& desc
->parent_type
==WCLASS_DOCK_ICON
4202 && ((WAppIcon
*)desc
->parent
)->dock
4203 && ((WAppIcon
*)desc
->parent
)->dock
->type
==WM_CLIP
) {
4204 /* We didn't left the Clip yet */
4205 XPutBackEvent(dpy
, &event
);
4209 XPutBackEvent(dpy
, &event
);
4211 /* We entered a withdrawn window, so we're still in Clip */
4215 if (dock
->auto_raise_magic
) {
4216 WMDeleteTimerHandler(dock
->auto_raise_magic
);
4217 dock
->auto_raise_magic
= NULL
;
4219 if (dock
->auto_raise_lower
&& !dock
->auto_lower_magic
) {
4220 dock
->auto_lower_magic
= WMAddTimerHandler(AUTO_LOWER_DELAY
,
4225 if (dock
->auto_expand_magic
) {
4226 WMDeleteTimerHandler(dock
->auto_expand_magic
);
4227 dock
->auto_expand_magic
= NULL
;
4229 if (dock
->auto_collapse
&& !dock
->auto_collapse_magic
) {
4230 dock
->auto_collapse_magic
= WMAddTimerHandler(AUTO_COLLAPSE_DELAY
,
4238 clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
)
4240 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
4242 assert(event
->type
==LeaveNotify
);
4244 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
4247 clipLeave(btn
->dock
);
4252 clipAutoCollapse(void *cdata
)
4254 WDock
*dock
= (WDock
*)cdata
;
4256 if (dock
->type
!=WM_CLIP
)
4259 if (dock
->auto_collapse
) {
4260 dock
->collapsed
= 1;
4261 wDockHideIcons(dock
);
4263 dock
->auto_collapse_magic
= NULL
;
4268 clipAutoExpand(void *cdata
)
4270 WDock
*dock
= (WDock
*)cdata
;
4272 if (dock
->type
!=WM_CLIP
)
4275 if (dock
->auto_collapse
) {
4276 dock
->collapsed
= 0;
4277 wDockShowIcons(dock
);
4279 dock
->auto_expand_magic
= NULL
;
4284 clipAutoLower(void *cdata
)
4286 WDock
*dock
= (WDock
*)cdata
;
4288 if (dock
->type
!=WM_CLIP
)
4291 if (dock
->auto_raise_lower
)
4294 dock
->auto_lower_magic
= NULL
;
4299 clipAutoRaise(void *cdata
)
4301 WDock
*dock
= (WDock
*)cdata
;
4303 if (dock
->type
!=WM_CLIP
)
4306 if (dock
->auto_raise_lower
)
4309 if (dock
->screen_ptr
->flags
.clip_balloon_mapped
) {
4310 showClipBalloon(dock
, dock
->screen_ptr
->current_workspace
);
4313 dock
->auto_raise_magic
= NULL
;
4318 iconCanBeOmnipresent(WAppIcon
*aicon
)
4320 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
4325 for (i
=0; i
<scr
->workspace_count
; i
++) {
4326 clip
= scr
->workspaces
[i
]->clip
;
4328 if (clip
== aicon
->dock
)
4331 if (clip
->icon_count
+ scr
->global_icon_count
>= clip
->max_icons
)
4332 return False
; /* Clip is full in some workspace */
4334 for (j
=0; j
<clip
->max_icons
; j
++) {
4335 btn
= clip
->icon_array
[j
];
4336 if(btn
&& btn
->xindex
==aicon
->xindex
&& btn
->yindex
==aicon
->yindex
)
4346 wClipMakeIconOmnipresent(WAppIcon
*aicon
, int omnipresent
)
4348 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
4349 WAppIconChain
*new_entry
, *tmp
, *tmp1
;
4350 int status
= WO_SUCCESS
;
4352 if ((scr
->dock
&& aicon
->dock
==scr
->dock
) || aicon
==scr
->clip_icon
) {
4353 return WO_NOT_APPLICABLE
;
4356 if (aicon
->omnipresent
== omnipresent
)
4360 if (iconCanBeOmnipresent(aicon
)) {
4361 aicon
->omnipresent
= 1;
4362 new_entry
= wmalloc(sizeof(WAppIconChain
));
4363 new_entry
->aicon
= aicon
;
4364 new_entry
->next
= scr
->global_icons
;
4365 scr
->global_icons
= new_entry
;
4366 scr
->global_icon_count
++;
4368 aicon
->omnipresent
= 0;
4372 aicon
->omnipresent
= 0;
4373 if (aicon
== scr
->global_icons
->aicon
) {
4374 tmp
= scr
->global_icons
->next
;
4375 wfree(scr
->global_icons
);
4376 scr
->global_icons
= tmp
;
4377 scr
->global_icon_count
--;
4379 tmp
= scr
->global_icons
;
4381 if (tmp
->next
->aicon
== aicon
) {
4382 tmp1
= tmp
->next
->next
;
4385 scr
->global_icon_count
--;
4393 wAppIconPaint(aicon
);