1 /* dock.c- built-in Dock module for WindowMaker
3 * Window Maker 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 #define CLIP_BUTTON_SIZE 23
75 /**** Global variables ****/
78 extern void DestroyDockAppSettingsPanel();
80 extern void ShowDockAppSettingsPanel(WAppIcon
*aicon
);
83 extern Cursor wCursor
[WCUR_LAST
];
85 extern WPreferences wPreferences
;
87 extern XContext wWinContext
;
90 extern Atom _XA_DND_PROTOCOL
;
94 #define MOD_MASK wPreferences.modifier_mask
96 extern void appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
98 #define ICON_SIZE wPreferences.icon_size
101 /***** Local variables ****/
103 static proplist_t dCommand
=NULL
;
105 static proplist_t dDropCommand
=NULL
;
107 static proplist_t dAutoLaunch
, dName
, dForced
, dBuggyApplication
, dYes
, dNo
;
108 static proplist_t dHost
, dDock
, dClip
;
109 static proplist_t dAutoAttractIcons
, dKeepAttracted
;
111 static proplist_t dPosition
, dApplications
, dLowered
, dCollapsed
, dAutoCollapse
;
113 static proplist_t dAutoRaiseLower
;
115 static void dockIconPaint(WAppIcon
*btn
);
117 static void iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
119 static pid_t
execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
);
121 static void trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
);
123 static int getClipButton(int px
, int py
);
125 static void toggleLowered(WDock
*dock
);
127 static void toggleCollapsed(WDock
*dock
);
129 static void clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
);
131 static void clipLeave(WDock
*dock
);
133 static void handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
);
135 Bool
moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
);
137 static void clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
);
138 static void clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
);
139 static void clipAutoCollapse(void *cdata
);
140 static void launchDockedApplication(WAppIcon
*btn
);
142 static void clipAutoLower(void *cdata
);
143 static void clipAutoRaise(void *cdata
);
145 static void showClipBalloon(WDock
*dock
, int workspace
);
161 #endif /* OFFIX_DND */
171 dCommand
= PLRetain(PLMakeString("Command"));
173 dDropCommand
= PLRetain(PLMakeString("DropCommand"));
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");
190 dKeepAttracted
= PLMakeString("KeepAttracted");
192 dDock
= PLMakeString("Dock");
193 dClip
= PLMakeString("Clip");
199 renameCallback(WMenu
*menu
, WMenuEntry
*entry
)
201 WDock
*dock
= entry
->clientdata
;
206 assert(entry
->clientdata
!=NULL
);
208 wspace
= dock
->screen_ptr
->current_workspace
;
210 name
= wstrdup(dock
->screen_ptr
->workspaces
[wspace
]->name
);
212 sprintf(buffer
, _("Type the name for workspace %i:"), wspace
+1);
213 if (wInputDialog(dock
->screen_ptr
, _("Rename Workspace"), buffer
,
215 wWorkspaceRename(dock
->screen_ptr
, wspace
, name
);
224 toggleLoweredCallback(WMenu
*menu
, WMenuEntry
*entry
)
226 assert(entry
->clientdata
!=NULL
);
228 toggleLowered(entry
->clientdata
);
230 entry
->flags
.indicator_on
= !((WDock
*)entry
->clientdata
)->lowered
;
238 killCallback(WMenu
*menu
, WMenuEntry
*entry
)
241 #ifdef REDUCE_APPICONS
242 WAppIconAppList
*tapplist
;
244 extern Atom _XA_WM_DELETE_WINDOW
;
249 if (!WCHECK_STATE(WSTATE_NORMAL
))
252 assert(entry
->clientdata
!=NULL
);
254 icon
= (WAppIcon
*)entry
->clientdata
;
258 WCHANGE_STATE(WSTATE_MODAL
);
260 #ifdef REDUCE_APPICONS
261 /* Send a delete message to the main window of each application
262 * bound to this docked appicon. - cls
264 tapplist
= icon
->applist
;
265 while (tapplist
!= NULL
) {
266 if (tapplist
->wapp
->main_window_desc
!= NULL
) {
267 if (tapplist
->wapp
->main_window_desc
->protocols
.DELETE_WINDOW
) {
268 wClientSendProtocol(tapplist
->wapp
->main_window_desc
,
269 _XA_WM_DELETE_WINDOW
, CurrentTime
);
271 wClientKill(tapplist
->wapp
->main_window_desc
);
274 tapplist
= tapplist
->next
;
277 buffer
= wstrappend(icon
->wm_class
,
278 _(" will be forcibly closed.\n"
279 "Any unsaved changes will be lost.\n"
282 if (wPreferences
.dont_confirm_kill
283 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
284 buffer
, _("Yes"), _("No"), NULL
)==WAPRDefault
) {
285 if (icon
->icon
&& icon
->icon
->owner
) {
286 wClientKill(icon
->icon
->owner
);
289 #endif /* !REDUCE_APPICONS */
293 WCHANGE_STATE(WSTATE_NORMAL
);}
297 getSelected(WDock
*dock
)
299 LinkedList
*ret
=NULL
;
303 for (i
=1; i
<dock
->max_icons
; i
++) {
304 btn
= dock
->icon_array
[i
];
305 if (btn
&& btn
->icon
->selected
) {
306 ret
= list_cons(btn
, ret
);
315 paintClipButtons(WAppIcon
*clipIcon
, Bool lpushed
, Bool rpushed
)
317 Window win
= clipIcon
->icon
->core
->window
;
318 WScreen
*scr
= clipIcon
->icon
->core
->screen_ptr
;
320 int pt
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
321 int tp
= ICON_SIZE
- pt
;
322 int as
= pt
- 15; /* 15 = 5+5+5 */
328 p
[1].x
= ICON_SIZE
-2;
330 p
[2].x
= ICON_SIZE
-2;
332 } else if (lpushed
) {
336 p
[1].y
= ICON_SIZE
-2;
338 p
[2].y
= ICON_SIZE
-2;
340 if (lpushed
|| rpushed
) {
341 XSetForeground(dpy
, scr
->draw_gc
, scr
->white_pixel
);
342 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
343 XSetForeground(dpy
, scr
->draw_gc
, scr
->black_pixel
);
346 p
[0].x
= p
[3].x
= ICON_SIZE
-6-as
;
348 p
[1].x
= ICON_SIZE
-6;
350 p
[2].x
= ICON_SIZE
-6;
353 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
354 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
356 XFillPolygon(dpy
, win
, scr
->clip_title_gc
, p
,3,Convex
,CoordModeOrigin
);
357 XDrawLines(dpy
, win
, scr
->clip_title_gc
, p
,4,CoordModeOrigin
);
361 p
[0].y
= p
[3].y
= ICON_SIZE
-6-as
;
363 p
[1].y
= ICON_SIZE
-6;
365 p
[2].y
= ICON_SIZE
-6;
367 XFillPolygon(dpy
, win
, scr
->draw_gc
, p
, 3, Convex
, CoordModeOrigin
);
368 XDrawLines(dpy
, win
, scr
->draw_gc
, p
, 4, CoordModeOrigin
);
370 XFillPolygon(dpy
, win
, scr
->clip_title_gc
, p
,3,Convex
,CoordModeOrigin
);
371 XDrawLines(dpy
, win
, scr
->clip_title_gc
, p
,4,CoordModeOrigin
);
377 wClipMakeTile(WScreen
*scr
, RImage
*normalTile
)
379 RImage
*tile
= RCloneImage(normalTile
);
385 pt
= CLIP_BUTTON_SIZE
*wPreferences
.icon_size
/64;
386 tp
= wPreferences
.icon_size
-1 - pt
;
389 black
.red
= black
.green
= black
.blue
= 0;
392 dark
.red
= dark
.green
= dark
.blue
= 80;
395 light
.red
= light
.green
= light
.blue
= 80;
399 ROperateLine(tile
, RSubtractOperation
, tp
, 0, wPreferences
.icon_size
-2,
401 RDrawLine(tile
, tp
-1, 0, wPreferences
.icon_size
-1, pt
+1, &black
);
402 ROperateLine(tile
, RAddOperation
, tp
, 2, wPreferences
.icon_size
-3,
407 ROperateLine(tile
, RAddOperation
, 2, tp
+2, pt
-2,
408 wPreferences
.icon_size
-3, &dark
);
409 RDrawLine(tile
, 0, tp
-1, pt
+1, wPreferences
.icon_size
-1, &black
);
410 ROperateLine(tile
, RSubtractOperation
, 0, tp
-2, pt
+1,
411 wPreferences
.icon_size
-2, &light
);
418 removeIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
420 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
423 LinkedList
*selectedIcons
;
426 assert(clickedIcon
!=NULL
);
428 dock
= clickedIcon
->dock
;
430 selectedIcons
= getSelected(dock
);
433 if (wMessageDialog(dock
->screen_ptr
, _("Workspace Clip"),
434 _("All selected icons will be removed!"),
435 _("OK"), _("Cancel"), NULL
)!=WAPRDefault
) {
439 if (clickedIcon
->xindex
==0 && clickedIcon
->yindex
==0)
441 selectedIcons
= list_cons(clickedIcon
, NULL
);
444 while (selectedIcons
) {
445 aicon
= selectedIcons
->head
;
446 keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
447 wDockDetach(dock
, aicon
);
449 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
450 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
451 aicon
->x_pos
, aicon
->y_pos
);
452 if (!dock
->mapped
|| dock
->collapsed
)
453 XMapWindow(dpy
, aicon
->icon
->core
->window
);
455 list_remove_head(&selectedIcons
);
458 if (wPreferences
.auto_arrange_icons
)
459 wArrangeIcons(dock
->screen_ptr
, True
);
464 keepIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
466 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
469 LinkedList
*selectedIcons
;
471 assert(clickedIcon
!=NULL
);
472 dock
= clickedIcon
->dock
;
474 selectedIcons
= getSelected(dock
);
476 if (!selectedIcons
&& clickedIcon
!=dock
->screen_ptr
->clip_icon
) {
477 char *command
= NULL
;
479 if (!clickedIcon
->command
&& !clickedIcon
->editing
) {
480 clickedIcon
->editing
= 1;
481 if (wInputDialog(dock
->screen_ptr
, _("Keep Icon"),
482 _("Type the command used to launch the application"),
484 if (command
&& (command
[0]==0 ||
485 (command
[0]=='-' && command
[1]==0))) {
489 clickedIcon
->command
= command
;
490 clickedIcon
->editing
= 0;
492 clickedIcon
->editing
= 0;
499 selectedIcons
= list_cons(clickedIcon
, NULL
);
502 while (selectedIcons
) {
503 aicon
= selectedIcons
->head
;
504 if (aicon
->icon
->selected
)
505 wIconSelect(aicon
->icon
);
506 if (aicon
&& aicon
->attracted
&& aicon
->command
) {
507 aicon
->attracted
= 0;
508 if (aicon
->icon
->shadowed
) {
509 aicon
->icon
->shadowed
= 0;
510 aicon
->icon
->force_paint
= 1;
511 wAppIconPaint(aicon
);
514 list_remove_head(&selectedIcons
);
522 toggleAutoAttractCallback(WMenu
*menu
, WMenuEntry
*entry
)
524 WDock
*dock
= (WDock
*)entry
->clientdata
;
526 assert(entry
->clientdata
!=NULL
);
528 dock
->attract_icons
= !dock
->attract_icons
;
529 /*if (!dock->attract_icons)
530 dock->keep_attracted = 0;*/
532 entry
->flags
.indicator_on
= dock
->attract_icons
;
539 toggleKeepCallback(WMenu
*menu
, WMenuEntry
*entry
)
541 WDock
*dock
= (WDock
*)entry
->clientdata
;
545 assert(entry
->clientdata
!=NULL
);
547 dock
->keep_attracted
= !dock
->keep_attracted
;
549 if (dock
->keep_attracted
) {
550 for (i
=0; i
< dock
->max_icons
; i
++) {
551 btn
= dock
->icon_array
[i
];
552 if (btn
&& btn
->attracted
&& btn
->command
) {
554 if (btn
->icon
->shadowed
) {
555 btn
->icon
->shadowed
= 0;
556 btn
->icon
->force_paint
= 1;
563 entry
->flags
.indicator_on
= dock
->keep_attracted
;
570 selectCallback(WMenu
*menu
, WMenuEntry
*entry
)
572 WAppIcon
*icon
= (WAppIcon
*)entry
->clientdata
;
576 wIconSelect(icon
->icon
);
583 colectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
585 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
588 int x
, y
, x_pos
, y_pos
;
590 assert(entry
->clientdata
!=NULL
);
591 clip
= clickedIcon
->dock
;
593 aicon
= clip
->screen_ptr
->app_icon_list
;
596 if (!aicon
->docked
&& wDockFindFreeSlot(clip
, &x
, &y
)) {
597 x_pos
= clip
->x_pos
+ x
*ICON_SIZE
;
598 y_pos
= clip
->y_pos
+ y
*ICON_SIZE
;
599 if (aicon
->x_pos
!= x_pos
|| aicon
->y_pos
!= y_pos
) {
601 if (wPreferences
.no_animations
) {
602 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
604 SlideWindow(aicon
->icon
->core
->window
,
605 aicon
->x_pos
, aicon
->y_pos
, x_pos
, y_pos
);
608 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x_pos
, y_pos
);
609 #endif /* ANIMATIONS */
611 aicon
->attracted
= 1;
612 if (!clip
->keep_attracted
&& !aicon
->icon
->shadowed
) {
613 aicon
->icon
->shadowed
= 1;
614 aicon
->icon
->force_paint
= 1;
615 /* We don't do an wAppIconPaint() here because it's in
616 * wDockAttachIcon(). -Dan
619 wDockAttachIcon(clip
, aicon
, x
, y
);
620 if (clip
->collapsed
|| !clip
->mapped
)
621 XUnmapWindow(dpy
, aicon
->icon
->core
->window
);
629 selectIconsCallback(WMenu
*menu
, WMenuEntry
*entry
)
631 WAppIcon
*clickedIcon
= (WAppIcon
*)entry
->clientdata
;
633 LinkedList
*selectedIcons
;
637 assert(clickedIcon
!=NULL
);
638 dock
= clickedIcon
->dock
;
640 selectedIcons
= getSelected(dock
);
642 if (!selectedIcons
) {
643 for (i
=1; i
<dock
->max_icons
; i
++) {
644 btn
= dock
->icon_array
[i
];
645 if (btn
&& !btn
->icon
->selected
) {
646 wIconSelect(btn
->icon
);
650 while(selectedIcons
) {
651 btn
= selectedIcons
->head
;
652 wIconSelect(btn
->icon
);
653 list_remove_head(&selectedIcons
);
662 toggleCollapsedCallback(WMenu
*menu
, WMenuEntry
*entry
)
664 assert(entry
->clientdata
!=NULL
);
666 toggleCollapsed(entry
->clientdata
);
668 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->collapsed
;
675 toggleAutoCollapseCallback(WMenu
*menu
, WMenuEntry
*entry
)
678 assert(entry
->clientdata
!=NULL
);
680 dock
= (WDock
*) entry
->clientdata
;
682 dock
->auto_collapse
= !dock
->auto_collapse
;
683 if (dock
->auto_collapse_magic
) {
684 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
685 dock
->auto_collapse_magic
= NULL
;
688 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->auto_collapse
;
695 toggleAutoRaiseLowerCallback(WMenu
*menu
, WMenuEntry
*entry
)
698 assert(entry
->clientdata
!=NULL
);
700 dock
= (WDock
*) entry
->clientdata
;
702 dock
->auto_raise_lower
= !dock
->auto_raise_lower
;
704 entry
->flags
.indicator_on
= ((WDock
*)entry
->clientdata
)->auto_raise_lower
;
711 launchCallback(WMenu
*menu
, WMenuEntry
*entry
)
713 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
715 launchDockedApplication(btn
);
720 settingsCallback(WMenu
*menu
, WMenuEntry
*entry
)
722 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
726 ShowDockAppSettingsPanel(btn
);
731 hideCallback(WMenu
*menu
, WMenuEntry
*entry
)
734 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
736 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
738 if (wapp
->flags
.hidden
) {
739 wWorkspaceChange(btn
->icon
->core
->screen_ptr
,wapp
->last_workspace
);
740 wUnhideApplication(wapp
, False
, False
);
742 wHideApplication(wapp
);
748 unhideHereCallback(WMenu
*menu
, WMenuEntry
*entry
)
751 WAppIcon
*btn
= (WAppIcon
*)entry
->clientdata
;
753 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
755 wUnhideApplication(wapp
, False
, True
);
760 mainIconCreate(WScreen
*scr
, int type
)
765 if (type
== WM_CLIP
) {
767 return scr
->clip_icon
;
768 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMClip", TILE_CLIP
);
769 btn
->icon
->core
->descriptor
.handle_expose
= clipIconExpose
;
770 btn
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
771 btn
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
772 /*x_pos = scr->scr_width - ICON_SIZE*2 - DOCK_EXTRA_SPACE;*/
775 btn
= wAppIconCreateForDock(scr
, NULL
, "Logo", "WMDock", TILE_NORMAL
);
776 x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
782 btn
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
783 btn
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
784 btn
->icon
->core
->descriptor
.parent
= btn
;
785 /*ChangeStackingLevel(btn->icon->core, WMDockLevel);*/
786 XMapWindow(dpy
, btn
->icon
->core
->window
);
791 scr
->clip_icon
= btn
;
798 switchWSCommand(WMenu
*menu
, WMenuEntry
*entry
)
800 WAppIcon
*btn
, *icon
= (WAppIcon
*) entry
->clientdata
;
801 WScreen
*scr
= icon
->icon
->core
->screen_ptr
;
803 LinkedList
*selectedIcons
;
806 if (entry
->order
== scr
->current_workspace
)
809 dest
= scr
->workspaces
[entry
->order
]->clip
;
811 selectedIcons
= getSelected(src
);
814 while(selectedIcons
) {
815 btn
= selectedIcons
->head
;
816 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
817 moveIconBetweenDocks(src
, dest
, btn
, x
, y
);
818 XUnmapWindow(dpy
, btn
->icon
->core
->window
);
820 list_remove_head(&selectedIcons
);
822 } else if (icon
!= scr
->clip_icon
) {
823 if (wDockFindFreeSlot(dest
, &x
, &y
)) {
824 moveIconBetweenDocks(src
, dest
, icon
, x
, y
);
825 XUnmapWindow(dpy
, icon
->icon
->core
->window
);
833 launchDockedApplication(WAppIcon
*btn
)
835 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
837 if (!btn
->launching
&& btn
->command
!=NULL
) {
838 if (!btn
->forced_dock
) {
839 btn
->relaunching
= btn
->running
;
842 if (btn
->wm_instance
|| btn
->wm_class
) {
843 WWindowAttributes attr
;
844 memset(&attr
, 0, sizeof(WWindowAttributes
));
845 wDefaultFillAttributes(scr
, btn
->wm_instance
, btn
->wm_class
,
848 if (!attr
.no_appicon
&& !btn
->buggy_app
)
853 btn
->drop_launch
= 0;
854 scr
->last_dock
= btn
->dock
;
855 btn
->pid
= execCommand(btn
, btn
->command
, NULL
);
857 if (btn
->buggy_app
) {
858 /* give feedback that the app was launched */
862 WMAddTimerHandler(200, (WMCallback
*)dockIconPaint
, btn
);
867 wwarning(_("could not launch application %s\n"), btn
->command
);
869 if (!btn
->relaunching
)
878 updateWorkspaceMenu(WMenu
*menu
, WAppIcon
*icon
)
880 WScreen
*scr
= menu
->frame
->screen_ptr
;
881 char title
[MAX_WORKSPACENAME_WIDTH
+1];
887 for (i
=0; i
<scr
->workspace_count
; i
++) {
888 if (i
< menu
->entry_no
) {
889 if (strcmp(menu
->entries
[i
]->text
,scr
->workspaces
[i
]->name
)!=0) {
890 free(menu
->entries
[i
]->text
);
891 strcpy(title
, scr
->workspaces
[i
]->name
);
892 menu
->entries
[i
]->text
= wstrdup(title
);
893 menu
->flags
.realized
= 0;
895 menu
->entries
[i
]->clientdata
= (void*)icon
;
897 strcpy(title
, scr
->workspaces
[i
]->name
);
899 wMenuAddCallback(menu
, title
, switchWSCommand
, (void*)icon
);
901 menu
->flags
.realized
= 0;
903 if (i
== scr
->current_workspace
) {
904 wMenuSetEnabled(menu
, i
, False
);
906 wMenuSetEnabled(menu
, i
, True
);
910 if (!menu
->flags
.realized
)
916 makeWorkspaceMenu(WScreen
*scr
)
920 menu
= wMenuCreate(scr
, NULL
, False
);
922 wwarning(_("could not create workspace submenu for Clip menu"));
924 wMenuAddCallback(menu
, "", switchWSCommand
, (void*)scr
->clip_icon
);
926 menu
->flags
.realized
= 0;
934 updateClipOptionsMenu(WMenu
*menu
, WDock
*dock
)
943 entry
= menu
->entries
[index
];
944 entry
->flags
.indicator_on
= !dock
->lowered
;
945 entry
->clientdata
= dock
;
948 entry
= menu
->entries
[++index
];
949 entry
->flags
.indicator_on
= dock
->collapsed
;
950 entry
->clientdata
= dock
;
953 entry
= menu
->entries
[++index
];
954 entry
->flags
.indicator_on
= dock
->auto_collapse
;
955 entry
->clientdata
= dock
;
957 /* auto-raise/lower */
958 entry
= menu
->entries
[++index
];
959 entry
->flags
.indicator_on
= dock
->auto_raise_lower
;
960 entry
->clientdata
= dock
;
963 entry
= menu
->entries
[++index
];
964 entry
->flags
.indicator_on
= dock
->attract_icons
;
965 entry
->clientdata
= dock
;
967 /* keep attracted icons */
968 entry
= menu
->entries
[++index
];
969 entry
->flags
.indicator_on
= dock
->keep_attracted
;
970 entry
->clientdata
= dock
;
972 menu
->flags
.realized
= 0;
978 makeClipOptionsMenu(WScreen
*scr
)
983 menu
= wMenuCreate(scr
, NULL
, False
);
985 wwarning(_("could not create options submenu for Clip menu"));
989 entry
= wMenuAddCallback(menu
, _("Keep on top"),
990 toggleLoweredCallback
, NULL
);
991 entry
->flags
.indicator
= 1;
992 entry
->flags
.indicator_on
= 1;
993 entry
->flags
.indicator_type
= MI_CHECK
;
995 entry
= wMenuAddCallback(menu
, _("Collapsed"),
996 toggleCollapsedCallback
, NULL
);
997 entry
->flags
.indicator
= 1;
998 entry
->flags
.indicator_on
= 1;
999 entry
->flags
.indicator_type
= MI_CHECK
;
1001 entry
= wMenuAddCallback(menu
, _("AutoCollapse"),
1002 toggleAutoCollapseCallback
, NULL
);
1003 entry
->flags
.indicator
= 1;
1004 entry
->flags
.indicator_on
= 1;
1005 entry
->flags
.indicator_type
= MI_CHECK
;
1007 entry
= wMenuAddCallback(menu
, _("AutoRaiseLower"),
1008 toggleAutoRaiseLowerCallback
, NULL
);
1009 entry
->flags
.indicator
= 1;
1010 entry
->flags
.indicator_on
= 1;
1011 entry
->flags
.indicator_type
= MI_CHECK
;
1013 entry
= wMenuAddCallback(menu
, _("AutoAttract Icons"),
1014 toggleAutoAttractCallback
, NULL
);
1015 entry
->flags
.indicator
= 1;
1016 entry
->flags
.indicator_on
= 1;
1017 entry
->flags
.indicator_type
= MI_CHECK
;
1019 entry
= wMenuAddCallback(menu
, _("Keep Attracted Icons"),
1020 toggleKeepCallback
, NULL
);
1021 entry
->flags
.indicator
= 1;
1022 entry
->flags
.indicator_on
= 1;
1023 entry
->flags
.indicator_type
= MI_CHECK
;
1025 menu
->flags
.realized
= 0;
1033 dockMenuCreate(WScreen
*scr
, int type
)
1038 if (type
== WM_CLIP
&& scr
->clip_menu
)
1039 return scr
->clip_menu
;
1041 menu
= wMenuCreate(scr
, NULL
, False
);
1042 if (type
!= WM_CLIP
) {
1043 entry
= wMenuAddCallback(menu
, _("Keep on top"),
1044 toggleLoweredCallback
, NULL
);
1045 entry
->flags
.indicator
= 1;
1046 entry
->flags
.indicator_on
= 1;
1047 entry
->flags
.indicator_type
= MI_CHECK
;
1049 entry
= wMenuAddCallback(menu
, _("Clip Options"), NULL
, NULL
);
1050 scr
->clip_options
= makeClipOptionsMenu(scr
);
1051 if (scr
->clip_options
)
1052 wMenuEntrySetCascade(menu
, entry
, scr
->clip_options
);
1054 wMenuAddCallback(menu
, _("Rename Workspace"), renameCallback
, NULL
);
1056 wMenuAddCallback(menu
, _("(Un)Select Icon"), selectCallback
, NULL
);
1058 wMenuAddCallback(menu
, _("(Un)Select All Icons"), selectIconsCallback
,
1061 wMenuAddCallback(menu
, _("Keep Icon(s)"), keepIconsCallback
, NULL
);
1063 entry
= wMenuAddCallback(menu
, _("Move Icon(s) To"), NULL
, NULL
);
1064 scr
->clip_submenu
= makeWorkspaceMenu(scr
);
1065 if (scr
->clip_submenu
)
1066 wMenuEntrySetCascade(menu
, entry
, scr
->clip_submenu
);
1068 wMenuAddCallback(menu
, _("Remove Icon(s)"), removeIconsCallback
, NULL
);
1070 wMenuAddCallback(menu
, _("Attract Icons"), colectIconsCallback
, NULL
);
1073 wMenuAddCallback(menu
, _("Launch"), launchCallback
, NULL
);
1075 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
1077 entry
= wMenuAddCallback(menu
, _("Hide"), hideCallback
, NULL
);
1079 entry
->text
= _("Hide");
1081 wMenuAddCallback(menu
, _("Settings..."), settingsCallback
, NULL
);
1083 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
1085 if (type
== WM_CLIP
)
1086 scr
->clip_menu
= menu
;
1093 wDockCreate(WScreen
*scr
, int type
)
1101 dock
= wmalloc(sizeof(WDock
));
1102 memset(dock
, 0, sizeof(WDock
));
1104 if (type
== WM_CLIP
)
1105 icon_count
= CLIP_MAX_ICONS
;
1107 icon_count
= scr
->scr_height
/wPreferences
.icon_size
;
1109 dock
->icon_array
= wmalloc(sizeof(WAppIcon
*)*icon_count
);
1110 memset(dock
->icon_array
, 0, sizeof(WAppIcon
*)*icon_count
);
1112 dock
->max_icons
= icon_count
;
1114 btn
= mainIconCreate(scr
, type
);
1118 dock
->x_pos
= btn
->x_pos
;
1119 dock
->y_pos
= btn
->y_pos
;
1120 dock
->screen_ptr
= scr
;
1122 dock
->icon_count
= 1;
1123 dock
->on_right_side
= 1;
1124 dock
->collapsed
= 0;
1125 dock
->auto_collapse
= 0;
1126 dock
->auto_collapse_magic
= NULL
;
1127 dock
->auto_raise_lower
= 0;
1128 dock
->auto_lower_magic
= NULL
;
1129 dock
->auto_raise_magic
= NULL
;
1130 dock
->attract_icons
= 0;
1131 dock
->keep_attracted
= 0;
1133 dock
->icon_array
[0] = btn
;
1134 wRaiseFrame(btn
->icon
->core
);
1135 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
1137 /* create dock menu */
1138 dock
->menu
= dockMenuCreate(scr
, type
);
1145 wDockDestroy(WDock
*dock
)
1150 for (i
=(dock
->type
== WM_CLIP
) ? 1 : 0; i
<dock
->max_icons
; i
++) {
1151 aicon
= dock
->icon_array
[i
];
1153 int keepit
= aicon
->running
&& wApplicationOf(aicon
->main_window
);
1154 wDockDetach(dock
, aicon
);
1156 PlaceIcon(dock
->screen_ptr
, &aicon
->x_pos
, &aicon
->y_pos
);
1157 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
1158 aicon
->x_pos
, aicon
->y_pos
);
1159 if (!dock
->mapped
|| dock
->collapsed
)
1160 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1164 if (wPreferences
.auto_arrange_icons
)
1165 wArrangeIcons(dock
->screen_ptr
, True
);
1166 free(dock
->icon_array
);
1167 if (dock
->menu
&& dock
->type
!=WM_CLIP
)
1168 wMenuDestroy(dock
->menu
, True
);
1174 wClipIconPaint(WAppIcon
*aicon
)
1176 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
1177 WWorkspace
*workspace
= scr
->workspaces
[scr
->current_workspace
];
1179 Window win
= aicon
->icon
->core
->window
;
1180 int length
, nlength
;
1181 char *ws_name
, ws_number
[10];
1184 wIconPaint(aicon
->icon
);
1186 length
= strlen(workspace
->name
);
1187 ws_name
= malloc(length
+ 1);
1188 sprintf(ws_name
, "%s", workspace
->name
);
1189 sprintf(ws_number
, "%i", scr
->current_workspace
+ 1);
1190 nlength
= strlen(ws_number
);
1192 gc
= scr
->clip_title_gc
;
1194 if (!workspace
->clip
->collapsed
)
1195 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_NORMAL
]);
1197 XSetForeground(dpy
, gc
, scr
->clip_title_pixel
[CLIP_COLLAPSED
]);
1199 ty
= ICON_SIZE
- scr
->clip_title_font
->height
- 3;
1201 tx
= CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
1203 wDrawString(win
, scr
->clip_title_font
, gc
, tx
,
1204 ty
+ scr
->clip_title_font
->y
, ws_name
, length
);
1206 tx
= (ICON_SIZE
/2 - wTextWidth(scr
->clip_title_font
->font
, ws_number
, nlength
))/2;
1208 wDrawString(win
, scr
->clip_title_font
, gc
, tx
,
1209 scr
->clip_title_font
->y
+ 2, ws_number
, nlength
);
1213 if (aicon
->launching
) {
1214 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
1215 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
1217 paintClipButtons(aicon
, aicon
->dock
->lclip_button_pushed
,
1218 aicon
->dock
->rclip_button_pushed
);
1223 clipIconExpose(WObjDescriptor
*desc
, XEvent
*event
)
1225 wClipIconPaint(desc
->parent
);
1230 dockIconPaint(WAppIcon
*btn
)
1232 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1233 wClipIconPaint(btn
);
1240 make_icon_state(WAppIcon
*btn
)
1242 proplist_t node
= NULL
;
1243 proplist_t command
, autolaunch
, name
, forced
, host
, position
, buggy
;
1249 command
= PLMakeString("-");
1251 command
= PLMakeString(btn
->command
);
1253 autolaunch
= btn
->auto_launch
? dYes
: dNo
;
1255 tmp
= EscapeWM_CLASS(btn
->wm_instance
, btn
->wm_class
);
1257 name
= PLMakeString(tmp
);
1261 forced
= btn
->forced_dock
? dYes
: dNo
;
1263 buggy
= btn
->buggy_app
? dYes
: dNo
;
1265 if (btn
== btn
->icon
->core
->screen_ptr
->clip_icon
)
1266 sprintf(buffer
, "%i,%i", btn
->x_pos
, btn
->y_pos
);
1268 sprintf(buffer
, "%hi,%hi", btn
->xindex
, btn
->yindex
);
1269 position
= PLMakeString(buffer
);
1271 node
= PLMakeDictionaryFromEntries(dCommand
, command
,
1273 dAutoLaunch
, autolaunch
,
1275 dBuggyApplication
, buggy
,
1276 dPosition
, position
,
1280 PLRelease(position
);
1282 if (btn
->dnd_command
) {
1283 command
= PLMakeString(btn
->dnd_command
);
1284 PLInsertDictionaryEntry(node
, dDropCommand
, command
);
1287 #endif /* OFFIX_DND */
1289 if (btn
->client_machine
&& btn
->remote_start
) {
1290 host
= PLMakeString(btn
->client_machine
);
1291 PLInsertDictionaryEntry(node
, dHost
, host
);
1301 dockSaveState(WDock
*dock
)
1304 proplist_t icon_info
;
1305 proplist_t list
=NULL
, dock_state
=NULL
;
1309 list
= PLMakeArrayFromElements(NULL
);
1311 for (i
=(dock
->type
==WM_DOCK
? 0 : 1); i
<dock
->max_icons
; i
++) {
1312 WAppIcon
*btn
= dock
->icon_array
[i
];
1314 if (!btn
|| (btn
->attracted
&& !dock
->keep_attracted
))
1317 if ((icon_info
= make_icon_state(dock
->icon_array
[i
]))) {
1318 list
= PLAppendArrayElement(list
, icon_info
);
1319 PLRelease(icon_info
);
1323 dock_state
= PLMakeDictionaryFromEntries(dApplications
, list
, NULL
);
1327 if (dock
->type
== WM_DOCK
) {
1328 sprintf(buffer
, "%i,%i", (dock
->on_right_side
? -ICON_SIZE
: 0),
1330 value
= PLMakeString(buffer
);
1331 PLInsertDictionaryEntry(dock_state
, dPosition
, value
);
1335 value
= (dock
->lowered
? dYes
: dNo
);
1336 PLInsertDictionaryEntry(dock_state
, dLowered
, value
);
1338 if (dock
->type
== WM_CLIP
) {
1339 value
= (dock
->collapsed
? dYes
: dNo
);
1340 PLInsertDictionaryEntry(dock_state
, dCollapsed
, value
);
1342 value
= (dock
->auto_collapse
? dYes
: dNo
);
1343 PLInsertDictionaryEntry(dock_state
, dAutoCollapse
, value
);
1345 value
= (dock
->auto_raise_lower
? dYes
: dNo
);
1346 PLInsertDictionaryEntry(dock_state
, dAutoRaiseLower
, value
);
1348 value
= (dock
->attract_icons
? dYes
: dNo
);
1349 PLInsertDictionaryEntry(dock_state
, dAutoAttractIcons
, value
);
1351 value
= (dock
->keep_attracted
? dYes
: dNo
);
1352 PLInsertDictionaryEntry(dock_state
, dKeepAttracted
, value
);
1360 wDockSaveState(WScreen
*scr
)
1362 proplist_t dock_state
;
1364 dock_state
= dockSaveState(scr
->dock
);
1366 PLInsertDictionaryEntry(scr
->session_state
, dDock
, dock_state
);
1368 PLRelease(dock_state
);
1373 wClipSaveState(WScreen
*scr
)
1375 proplist_t clip_state
;
1377 clip_state
= make_icon_state(scr
->clip_icon
);
1379 PLInsertDictionaryEntry(scr
->session_state
, dClip
, clip_state
);
1381 PLRelease(clip_state
);
1386 wClipSaveWorkspaceState(WScreen
*scr
, int workspace
)
1388 return dockSaveState(scr
->workspaces
[workspace
]->clip
);
1393 restore_icon_state(WScreen
*scr
, proplist_t info
, int type
, int index
)
1396 char *wclass
, *winstance
;
1397 proplist_t cmd
, value
;
1401 cmd
= PLGetDictionaryEntry(info
, dCommand
);
1402 if (!cmd
|| !PLIsString(cmd
)) {
1406 /* parse window name */
1407 value
= PLGetDictionaryEntry(info
, dName
);
1411 ParseWindowName(value
, &winstance
, &wclass
, "dock");
1413 if (!winstance
&& !wclass
) {
1420 command
= wstrdup(PLGetString(cmd
));
1424 if (!command
|| strcmp(command
, "-")==0) {
1435 aicon
= wAppIconCreateForDock(scr
, command
, winstance
, wclass
,
1442 aicon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
1443 if (type
== WM_CLIP
) {
1444 aicon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
1445 aicon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
1447 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
1448 aicon
->icon
->core
->descriptor
.parent
= aicon
;
1452 cmd
= PLGetDictionaryEntry(info
, dDropCommand
);
1454 aicon
->dnd_command
= wstrdup(PLGetString(cmd
));
1457 /* check auto launch */
1458 value
= PLGetDictionaryEntry(info
, dAutoLaunch
);
1460 aicon
->auto_launch
= 0;
1462 if (PLIsString(value
)) {
1463 if (strcasecmp(PLGetString(value
), "YES")==0)
1464 aicon
->auto_launch
= 1;
1466 wwarning(_("bad value in docked icon state info %s"),
1467 PLGetString(dAutoLaunch
));
1471 /* check if it wasn't normally docked */
1472 value
= PLGetDictionaryEntry(info
, dForced
);
1474 aicon
->forced_dock
= 0;
1476 if (PLIsString(value
)) {
1477 if (strcasecmp(PLGetString(value
), "YES")==0)
1478 aicon
->forced_dock
= 1;
1480 wwarning(_("bad value in docked icon state info %s"),
1481 PLGetString(dForced
));
1485 /* check if we can rely on the stuff in the app */
1486 value
= PLGetDictionaryEntry(info
, dBuggyApplication
);
1488 aicon
->buggy_app
= 0;
1490 if (PLIsString(value
)) {
1491 if (strcasecmp(PLGetString(value
), "YES")==0)
1492 aicon
->buggy_app
= 1;
1494 wwarning(_("bad value in docked icon state info %s"),
1495 PLGetString(dBuggyApplication
));
1499 /* get position in the dock */
1500 value
= PLGetDictionaryEntry(info
, dPosition
);
1501 if (value
&& PLIsString(value
)) {
1502 if (sscanf(PLGetString(value
), "%hi,%hi", &aicon
->xindex
,
1504 wwarning(_("bad value in docked icon state info %s"),
1505 PLGetString(dPosition
));
1507 /* check position sanity */
1508 /* incomplete section! */
1509 if (type
== WM_DOCK
) {
1511 if (aicon
->yindex
< 0)
1512 wwarning(_("bad value in docked icon position %i,%i"),
1513 aicon
->xindex
, aicon
->yindex
);
1516 aicon
->yindex
= index
;
1527 #define COMPLAIN(key) wwarning(_("bad value in dock state info:%s"), key)
1531 wClipRestoreState(WScreen
*scr
, proplist_t clip_state
)
1537 icon
= mainIconCreate(scr
, WM_CLIP
);
1542 PLRetain(clip_state
);
1544 /* restore position */
1546 value
= PLGetDictionaryEntry(clip_state
, dPosition
);
1549 if (!PLIsString(value
))
1550 COMPLAIN("Position");
1552 if (sscanf(PLGetString(value
), "%i,%i", &icon
->x_pos
,
1554 COMPLAIN("Position");
1556 /* check position sanity */
1557 if (icon
->y_pos
< 0)
1559 else if (icon
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1560 icon
->y_pos
= scr
->scr_height
-ICON_SIZE
;
1562 if (icon
->x_pos
< 0)
1564 else if (icon
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1565 icon
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1570 value
= PLGetDictionaryEntry(clip_state
, dDropCommand
);
1571 if (value
&& PLIsString(value
))
1572 icon
->dnd_command
= wstrdup(PLGetString(value
));
1575 PLRelease(clip_state
);
1582 wDockRestoreState(WScreen
*scr
, proplist_t dock_state
, int type
)
1587 WAppIcon
*aicon
, *old_top
;
1591 dock
= wDockCreate(scr
, type
);
1597 PLRetain(dock_state
);
1600 /* restore position */
1602 value
= PLGetDictionaryEntry(dock_state
, dPosition
);
1605 if (!PLIsString(value
))
1606 COMPLAIN("Position");
1608 if (sscanf(PLGetString(value
), "%i,%i", &dock
->x_pos
,
1610 COMPLAIN("Position");
1612 /* check position sanity */
1613 if (dock
->y_pos
< 0)
1615 else if (dock
->y_pos
> scr
->scr_height
-ICON_SIZE
)
1616 dock
->y_pos
= scr
->scr_height
- ICON_SIZE
;
1618 /* This is no more needed. ??? */
1619 if (type
== WM_CLIP
) {
1620 if (dock
->x_pos
< 0)
1622 else if (dock
->x_pos
> scr
->scr_width
-ICON_SIZE
)
1623 dock
->x_pos
= scr
->scr_width
-ICON_SIZE
;
1625 if (dock
->x_pos
>= 0) {
1626 dock
->x_pos
= DOCK_EXTRA_SPACE
;
1627 dock
->on_right_side
= 0;
1629 dock
->x_pos
= scr
->scr_width
- DOCK_EXTRA_SPACE
- ICON_SIZE
;
1630 dock
->on_right_side
= 1;
1636 /* restore lowered/raised state */
1640 value
= PLGetDictionaryEntry(dock_state
, dLowered
);
1643 if (!PLIsString(value
))
1644 COMPLAIN("Lowered");
1646 if (strcasecmp(PLGetString(value
), "YES")==0)
1652 /* restore collapsed state */
1654 dock
->collapsed
= 0;
1656 value
= PLGetDictionaryEntry(dock_state
, dCollapsed
);
1659 if (!PLIsString(value
))
1660 COMPLAIN("Collapsed");
1662 if (strcasecmp(PLGetString(value
), "YES")==0)
1663 dock
->collapsed
= 1;
1668 /* restore auto-collapsed state */
1670 value
= PLGetDictionaryEntry(dock_state
, dAutoCollapse
);
1673 if (!PLIsString(value
))
1674 COMPLAIN("AutoCollapse");
1676 if (strcasecmp(PLGetString(value
), "YES")==0) {
1677 dock
->auto_collapse
= 1;
1678 dock
->collapsed
= 1;
1684 /* restore auto-raise/lower state */
1686 value
= PLGetDictionaryEntry(dock_state
, dAutoRaiseLower
);
1689 if (!PLIsString(value
))
1690 COMPLAIN("AutoRaiseLower");
1692 if (strcasecmp(PLGetString(value
), "YES")==0) {
1693 dock
->auto_raise_lower
= 1;
1699 /* restore attract icons state */
1701 dock
->attract_icons
= 0;
1703 value
= PLGetDictionaryEntry(dock_state
, dAutoAttractIcons
);
1706 if (!PLIsString(value
))
1707 COMPLAIN("AutoAttractIcons");
1709 if (strcasecmp(PLGetString(value
), "YES")==0)
1710 dock
->attract_icons
= 1;
1715 /* restore keep attracted icons state */
1717 dock
->keep_attracted
= 0;
1719 value
= PLGetDictionaryEntry(dock_state
, dKeepAttracted
);
1722 if (!PLIsString(value
))
1723 COMPLAIN("KeepAttracted");
1725 if (strcasecmp(PLGetString(value
), "YES")==0)
1726 dock
->keep_attracted
= 1;
1731 /* application list */
1733 apps
= PLGetDictionaryEntry(dock_state
, dApplications
);
1739 count
= PLGetNumberOfElements(apps
);
1744 old_top
= dock
->icon_array
[0];
1746 /* dock->icon_count is set to 1 when dock is created.
1747 * Since Clip is already restored, we want to keep it so for clip,
1748 * but for dock we may change the default top tile, so we set it to 0.
1750 if (type
== WM_DOCK
)
1751 dock
->icon_count
= 0;
1753 for (i
=0; i
<count
; i
++) {
1754 if (dock
->icon_count
>= dock
->max_icons
) {
1755 wwarning(_("there are too many icons stored in dock. Ignoring what doesn't fit"));
1759 value
= PLGetArrayElement(apps
, i
);
1760 aicon
= restore_icon_state(scr
, value
, type
, dock
->icon_count
);
1762 dock
->icon_array
[dock
->icon_count
] = aicon
;
1766 aicon
->x_pos
= dock
->x_pos
+ (aicon
->xindex
*ICON_SIZE
);
1767 aicon
->y_pos
= dock
->y_pos
+ (aicon
->yindex
*ICON_SIZE
);
1770 ChangeStackingLevel(aicon
->icon
->core
, WMNormalLevel
);
1772 ChangeStackingLevel(aicon
->icon
->core
, WMDockLevel
);
1774 wCoreConfigure(aicon
->icon
->core
, aicon
->x_pos
, aicon
->y_pos
,
1777 if (!dock
->collapsed
)
1778 XMapWindow(dpy
, aicon
->icon
->core
->window
);
1779 wRaiseFrame(aicon
->icon
->core
);
1782 } else if (dock
->icon_count
==0 && type
==WM_DOCK
)
1786 /* if the first icon is not defined, use the default */
1787 if (dock
->icon_array
[0]==NULL
) {
1788 /* update default icon */
1789 old_top
->x_pos
= dock
->x_pos
;
1790 old_top
->y_pos
= dock
->y_pos
;
1792 ChangeStackingLevel(old_top
->icon
->core
, WMNormalLevel
);
1794 ChangeStackingLevel(old_top
->icon
->core
, WMDockLevel
);
1795 dock
->icon_array
[0] = old_top
;
1796 XMoveWindow(dpy
, old_top
->icon
->core
->window
, dock
->x_pos
, dock
->y_pos
);
1797 /* we don't need to increment dock->icon_count here because it was
1798 * incremented in the loop above.
1800 } else if (old_top
!=dock
->icon_array
[0]) {
1801 if (old_top
== scr
->clip_icon
)
1802 scr
->clip_icon
= dock
->icon_array
[0];
1803 wAppIconDestroy(old_top
);
1808 PLRelease(dock_state
);
1816 wDockLaunchWithState(WDock
*dock
, WAppIcon
*btn
, WSavedState
*state
)
1818 if (btn
&& btn
->command
&& !btn
->running
&& !btn
->launching
) {
1820 btn
->drop_launch
= 0;
1822 btn
->pid
= execCommand(btn
, btn
->command
, state
);
1825 if (!btn
->forced_dock
&& !btn
->buggy_app
) {
1837 wDockDoAutoLaunch(WDock
*dock
, int workspace
)
1843 for (i
= 0; i
< dock
->max_icons
; i
++) {
1844 btn
= dock
->icon_array
[i
];
1845 if (!btn
|| !btn
->auto_launch
)
1848 state
= wmalloc(sizeof(WSavedState
));
1849 memset(state
, 0, sizeof(WSavedState
));
1850 state
->workspace
= workspace
;
1851 /* TODO: this is klugy and is very difficult to understand
1852 * what's going on. Try to clean up */
1853 wDockLaunchWithState(dock
, btn
, state
);
1857 #ifdef REDUCE_APPICONS
1859 wDockSimulateLaunch(WDock
*dock
, WAppIcon
*btn
)
1861 if ((btn
== NULL
) || (dock
== NULL
))
1864 if (!btn
->running
) {
1865 if ((btn
->icon
->owner
== NULL
) && (btn
->applist
))
1866 btn
->icon
->owner
= btn
->applist
->wapp
->main_window_desc
;
1867 if (!btn
->forced_dock
)
1877 findDock(WScreen
*scr
, XEvent
*event
, int *icon_pos
)
1883 if ((dock
= scr
->dock
)!=NULL
) {
1884 for (i
=0; i
<dock
->max_icons
; i
++) {
1885 if (dock
->icon_array
[i
]
1886 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
1892 if (*icon_pos
<0 && (dock
= scr
->workspaces
[scr
->current_workspace
]->clip
)!=NULL
) {
1893 for (i
=0; i
<dock
->max_icons
; i
++) {
1894 if (dock
->icon_array
[i
]
1895 && dock
->icon_array
[i
]->icon
->core
->window
==event
->xclient
.window
) {
1908 wDockReceiveDNDDrop(WScreen
*scr
, XEvent
*event
)
1914 dock
= findDock(scr
, event
, &icon_pos
);
1919 * Return True if the drop was on an application icon window.
1920 * In this case, let the ClientMessage handler redirect the
1921 * message to the app.
1923 if (dock
->icon_array
[icon_pos
]->icon
->icon_win
!=None
)
1926 if (dock
->icon_array
[icon_pos
]->dnd_command
!=NULL
) {
1927 scr
->flags
.dnd_data_convertion_status
= 0;
1929 btn
= dock
->icon_array
[icon_pos
];
1931 if (!btn
->forced_dock
) {
1932 btn
->relaunching
= btn
->running
;
1935 if (btn
->wm_instance
|| btn
->wm_class
) {
1936 WWindowAttributes attr
;
1937 memset(&attr
, 0, sizeof(WWindowAttributes
));
1938 wDefaultFillAttributes(btn
->icon
->core
->screen_ptr
,
1940 btn
->wm_class
, &attr
, NULL
, True
);
1942 if (!attr
.no_appicon
)
1948 btn
->drop_launch
= 1;
1949 scr
->last_dock
= dock
;
1950 btn
->pid
= execCommand(btn
, btn
->dnd_command
, NULL
);
1955 if (!btn
->relaunching
) {
1962 #endif /* OFFIX_DND */
1967 wDockAttachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
1974 wwin
= icon
->icon
->owner
;
1975 if (icon
->command
==NULL
) {
1977 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
1979 icon
->command
= FlattenStringList(argv
, argc
);
1980 XFreeStringList(argv
);
1984 /* icon->forced_dock = 1;*/
1985 if (!icon
->attracted
|| dock
->type
!=WM_CLIP
|| dock
->keep_attracted
) {
1987 if (wInputDialog(dock
->screen_ptr
, _("Dock Icon"),
1988 _("Type the command used to launch the application"),
1990 if (command
&& (command
[0]==0 ||
1991 (command
[0]=='-' && command
[1]==0))) {
1995 icon
->command
= command
;
2001 /* If the target is the dock, reject the icon. If
2002 * the target is the clip, make it an attracted icon
2004 if (dock
->type
==WM_CLIP
) {
2005 icon
->attracted
= 1;
2006 if (!icon
->icon
->shadowed
) {
2007 icon
->icon
->shadowed
= 1;
2008 icon
->icon
->force_paint
= 1;
2020 for (index
=1; index
<dock
->max_icons
; index
++)
2021 if (dock
->icon_array
[index
] == NULL
)
2023 /* if (index == dock->max_icons)
2026 assert(index
< dock
->max_icons
);
2028 dock
->icon_array
[index
] = icon
;
2032 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
2033 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
2038 icon
->launching
= 0;
2041 icon
->icon
->core
->descriptor
.handle_mousedown
= iconMouseDown
;
2042 if (dock
->type
== WM_CLIP
) {
2043 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
2044 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
2046 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_DOCK_ICON
;
2047 icon
->icon
->core
->descriptor
.parent
= icon
;
2049 MoveInStackListUnder(dock
->icon_array
[index
-1]->icon
->core
,
2051 wAppIconMove(icon
, icon
->x_pos
, icon
->y_pos
);
2052 wAppIconPaint(icon
);
2054 if (wPreferences
.auto_arrange_icons
)
2055 wArrangeIcons(dock
->screen_ptr
, True
);
2058 if (icon
->command
&& !icon
->dnd_command
) {
2059 icon
->dnd_command
= wmalloc(strlen(icon
->command
)+8);
2060 sprintf(icon
->dnd_command
, "%s %%d", icon
->command
);
2069 reattachIcon(WDock
*dock
, WAppIcon
*icon
, int x
, int y
)
2073 for(index
=1; index
<dock
->max_icons
; index
++) {
2074 if(dock
->icon_array
[index
] == icon
)
2077 assert(index
< dock
->max_icons
);
2082 icon
->x_pos
= dock
->x_pos
+ x
*ICON_SIZE
;
2083 icon
->y_pos
= dock
->y_pos
+ y
*ICON_SIZE
;
2088 moveIconBetweenDocks(WDock
*src
, WDock
*dest
, WAppIcon
*icon
, int x
, int y
)
2098 wwin
= icon
->icon
->owner
;
2101 * For the moment we can't do this if we move icons in Clip from one
2102 * workspace to other, because if we move two or more icons without
2103 * command, the dialog box will not be able to tell us to which of the
2104 * moved icons it applies. -Dan
2106 if ((dest
->type
==WM_DOCK
/*|| dest->keep_attracted*/) && icon
->command
==NULL
) {
2107 if (XGetCommand(dpy
, wwin
->client_win
, &argv
, &argc
) && argc
>0) {
2109 icon
->command
= FlattenStringList(argv
, argc
);
2110 XFreeStringList(argv
);
2115 /* icon->forced_dock = 1;*/
2116 if (wInputDialog(src
->screen_ptr
, _("Dock Icon"),
2117 _("Type the command used to launch the application"),
2119 if (command
&& (command
[0]==0 ||
2120 (command
[0]=='-' && command
[1]==0))) {
2124 icon
->command
= command
;
2135 for(index
=1; index
<src
->max_icons
; index
++) {
2136 if(src
->icon_array
[index
] == icon
)
2139 assert(index
< src
->max_icons
);
2141 src
->icon_array
[index
] = NULL
;
2144 for(index
=1; index
<dest
->max_icons
; index
++) {
2145 if(dest
->icon_array
[index
] == NULL
)
2148 /* if (index == dest->max_icons)
2151 assert(index
< dest
->max_icons
);
2153 dest
->icon_array
[index
] = icon
;
2156 /* deselect the icon */
2157 if (icon
->icon
->selected
)
2158 wIconSelect(icon
->icon
);
2160 if (dest
->type
== WM_DOCK
) {
2161 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2162 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2164 icon
->icon
->core
->descriptor
.handle_enternotify
= clipEnterNotify
;
2165 icon
->icon
->core
->descriptor
.handle_leavenotify
= clipLeaveNotify
;
2168 /* set it to be kept when moving to dock, or to a clip that keep the
2170 * Unless the icon does not have a command set
2172 if (icon
->command
&& (dest
->type
==WM_DOCK
|| dest
->keep_attracted
)) {
2173 icon
->attracted
= 0;
2174 if (icon
->icon
->shadowed
) {
2175 icon
->icon
->shadowed
= 0;
2176 icon
->icon
->force_paint
= 1;
2180 if (src
->auto_collapse
|| src
->auto_raise_lower
)
2186 icon
->x_pos
= dest
->x_pos
+ x
*ICON_SIZE
;
2187 icon
->y_pos
= dest
->y_pos
+ y
*ICON_SIZE
;
2191 MoveInStackListUnder(dest
->icon_array
[index
-1]->icon
->core
,
2193 wAppIconPaint(icon
);
2200 wDockDetach(WDock
*dock
, WAppIcon
*icon
)
2204 /* make the settings panel be closed */
2206 DestroyDockAppSettingsPanel(icon
->panel
);
2211 icon
->attracted
= 0;
2212 if (icon
->icon
->shadowed
) {
2213 icon
->icon
->shadowed
= 0;
2214 icon
->icon
->force_paint
= 1;
2217 /* deselect the icon */
2218 if (icon
->icon
->selected
)
2219 wIconSelect(icon
->icon
);
2221 if (icon
->command
) {
2222 free(icon
->command
);
2223 icon
->command
= NULL
;
2226 if (icon
->dnd_command
) {
2227 free(icon
->dnd_command
);
2228 icon
->dnd_command
= NULL
;
2232 for (index
=1; index
<dock
->max_icons
; index
++)
2233 if (dock
->icon_array
[index
] == icon
)
2235 assert(index
< dock
->max_icons
);
2236 dock
->icon_array
[index
] = NULL
;
2241 /* if the dock is not attached to an application or
2242 * the the application did not set the approriate hints yet,
2243 * destroy the icon */
2244 #ifdef REDUCE_APPICONS
2245 if ((icon
->num_apps
== 0) && (!icon
->running
|| !wApplicationOf(icon
->main_window
)) )
2247 if (!icon
->running
|| !wApplicationOf(icon
->main_window
))
2249 wAppIconDestroy(icon
);
2251 icon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
2252 icon
->icon
->core
->descriptor
.handle_enternotify
= NULL
;
2253 icon
->icon
->core
->descriptor
.handle_leavenotify
= NULL
;
2254 icon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
2255 icon
->icon
->core
->descriptor
.parent
= icon
;
2257 ChangeStackingLevel(icon
->icon
->core
, NORMAL_ICON_LEVEL
);
2259 wAppIconPaint(icon
);
2260 if (wPreferences
.auto_arrange_icons
) {
2261 wArrangeIcons(dock
->screen_ptr
, True
);
2264 if (dock
->auto_collapse
|| dock
->auto_raise_lower
)
2270 * returns the closest Dock slot index for the passed
2273 * Returns False if icon can't be docked.
2276 wDockSnapIcon(WDock
*dock
, WAppIcon
*icon
, int req_x
, int req_y
,
2277 int *ret_x
, int *ret_y
, int redocking
)
2279 WScreen
*scr
= dock
->screen_ptr
;
2282 int i
, offset
= ICON_SIZE
/2;
2283 WAppIcon
*aicon
= NULL
;
2284 WAppIcon
*nicon
= NULL
;
2285 int max_y_icons
, max_x_icons
;
2287 max_x_icons
= scr
->scr_width
/ICON_SIZE
;
2288 max_y_icons
= scr
->scr_height
/ICON_SIZE
-1;
2290 if (wPreferences
.flags
.noupdates
)
2296 /* if the dock is full */
2298 (dock
->icon_count
>= dock
->max_icons
)) {
2302 /* exact position */
2304 ex_y
= (req_y
- offset
- dy
)/ICON_SIZE
;
2306 ex_y
= (req_y
+ offset
- dy
)/ICON_SIZE
;
2309 ex_x
= (req_x
- offset
- dx
)/ICON_SIZE
;
2311 ex_x
= (req_x
+ offset
- dx
)/ICON_SIZE
;
2313 /* check if the icon is outside the screen boundaries */
2314 if (dx
+ ex_x
*ICON_SIZE
< -ICON_SIZE
+2 ||
2315 dx
+ ex_x
*ICON_SIZE
>= scr
->scr_width
-1 ||
2316 dy
+ ex_y
*ICON_SIZE
< -ICON_SIZE
+2 ||
2317 dy
+ ex_y
*ICON_SIZE
>= scr
->scr_height
-1)
2320 if (dock
->type
== WM_DOCK
) {
2321 if (icon
->dock
!= dock
&& ex_x
!= 0)
2324 for (i
=0; i
<dock
->max_icons
; i
++) {
2325 nicon
= dock
->icon_array
[i
];
2326 if (nicon
&& nicon
->yindex
== ex_y
) {
2335 int sig
, done
, closest
;
2337 /* Possible cases when redocking:
2339 * icon dragged out of range of any slot -> false
2340 * icon dragged to range of free slot
2341 * icon dragged to range of same slot
2342 * icon dragged to range of different icon
2344 if (abs(ex_x
) > DOCK_DETTACH_THRESHOLD
)
2347 if (ex_y
>= 0 && ex_y
<= max_y_icons
&& (aicon
== icon
|| !aicon
)) {
2355 /* start looking at the upper slot or lower? */
2356 if (ex_y
*ICON_SIZE
< (req_y
+ offset
- dy
))
2363 /* look for closest free slot */
2364 for (i
=0; i
<(DOCK_DETTACH_THRESHOLD
+1)*2 && !done
; i
++) {
2368 closest
= sig
*(i
/2) + ex_y
;
2369 /* check if this slot is used */
2371 for (j
= 0; j
<dock
->max_icons
; j
++) {
2372 if (dock
->icon_array
[j
]
2373 && dock
->icon_array
[j
]->yindex
==closest
) {
2374 /* slot is used by someone else */
2375 if (dock
->icon_array
[j
]!=icon
)
2383 if (done
&& closest
>= 0 && closest
<= max_y_icons
&&
2384 ((ex_y
>= closest
&& ex_y
- closest
< DOCK_DETTACH_THRESHOLD
+1)
2386 (ex_y
< closest
&& closest
- ex_y
<= DOCK_DETTACH_THRESHOLD
+1))) {
2392 } else { /* !redocking */
2394 /* if slot is free and the icon is close enough, return it */
2395 if (!aicon
&& ex_x
== 0 && ex_y
>= 0 && ex_y
<= max_y_icons
) {
2403 for (i
=0; i
<dock
->max_icons
; i
++) {
2404 nicon
= dock
->icon_array
[i
];
2405 if (nicon
&& nicon
->xindex
== ex_x
&& nicon
->yindex
== ex_y
) {
2411 for (i
=0; i
<dock
->max_icons
; i
++) {
2412 nicon
= dock
->icon_array
[i
];
2413 if (nicon
&& nicon
!= icon
&& /* Icon can't be it's own neighbour */
2414 (abs(nicon
->xindex
- ex_x
) <= CLIP_ATTACH_VICINITY
&&
2415 abs(nicon
->yindex
- ex_y
) <= CLIP_ATTACH_VICINITY
)) {
2421 if (neighbours
&& (aicon
==NULL
|| (redocking
&& aicon
== icon
))) {
2430 #define MIN(x, y) ((x) > (y) ? (y) : (x))
2431 #define MAX(x, y) ((x) < (y) ? (y) : (x))
2433 #define ON_SCREEN(x, y, sx, ex, sy, ey) \
2434 ((((x)+ICON_SIZE/2) >= (sx)) && (((y)+ICON_SIZE/2) >= (sy)) && \
2435 (((x) + (ICON_SIZE/2)) <= (ex)) && (((y) + (ICON_SIZE/2)) <= ey))
2439 * returns true if it can find a free slot in the dock,
2440 * in which case it changes x_pos and y_pos accordingly.
2441 * Else returns false.
2444 wDockFindFreeSlot(WDock
*dock
, int *x_pos
, int *y_pos
)
2446 WScreen
*scr
= dock
->screen_ptr
;
2448 unsigned char *slot_map
;
2452 int i
, done
= False
;
2454 int sx
=0, sy
=0, ex
=scr
->scr_width
, ey
=scr
->scr_height
;
2457 /* if the dock is full */
2458 if (dock
->icon_count
>= dock
->max_icons
) {
2462 if (!wPreferences
.flags
.nodock
&& scr
->dock
) {
2463 if (scr
->dock
->on_right_side
)
2464 ex
-= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2466 sx
+= ICON_SIZE
+ DOCK_EXTRA_SPACE
;
2469 if (ex
< dock
->x_pos
)
2471 if (sx
> dock
->x_pos
+ICON_SIZE
)
2472 sx
= dock
->x_pos
+ICON_SIZE
;
2479 /* check if clip is in a corner */
2480 if (dock
->type
==WM_CLIP
) {
2481 if (dock
->x_pos
< 1 && dock
->y_pos
< 1)
2483 else if (dock
->x_pos
< 1 && dock
->y_pos
>= (ey
-ICON_SIZE
))
2485 else if (dock
->x_pos
>= (ex
-ICON_SIZE
)&& dock
->y_pos
>= (ey
-ICON_SIZE
))
2487 else if (dock
->x_pos
>= (ex
-ICON_SIZE
) && dock
->y_pos
< 1)
2494 /* If the clip is in the corner, use only slots that are in the border
2496 if (corner
!=C_NONE
) {
2500 hcount
= MIN(dock
->max_icons
, scr
->scr_width
/ICON_SIZE
);
2501 vcount
= MIN(dock
->max_icons
, scr
->scr_height
/ICON_SIZE
);
2502 hmap
= wmalloc(hcount
+1);
2503 memset(hmap
, 0, hcount
+1);
2504 vmap
= wmalloc(vcount
+1);
2505 memset(vmap
, 0, vcount
+1);
2507 /* mark used positions */
2510 for (i
=0; i
<dock
->max_icons
; i
++) {
2511 btn
= dock
->icon_array
[i
];
2515 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2516 vmap
[btn
->yindex
] = 1;
2517 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2518 hmap
[btn
->xindex
] = 1;
2521 for (i
=0; i
<dock
->max_icons
; i
++) {
2522 btn
= dock
->icon_array
[i
];
2526 if (btn
->xindex
==0 && btn
->yindex
> 0 && btn
->yindex
< vcount
)
2527 vmap
[btn
->yindex
] = 1;
2528 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2529 hmap
[-btn
->xindex
] = 1;
2532 for (i
=0; i
<dock
->max_icons
; i
++) {
2533 btn
= dock
->icon_array
[i
];
2537 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2538 vmap
[-btn
->yindex
] = 1;
2539 else if (btn
->yindex
==0 && btn
->xindex
>0 && btn
->xindex
<hcount
)
2540 hmap
[btn
->xindex
] = 1;
2544 for (i
=0; i
<dock
->max_icons
; i
++) {
2545 btn
= dock
->icon_array
[i
];
2549 if (btn
->xindex
==0 && btn
->yindex
< 0 && btn
->yindex
> -vcount
)
2550 vmap
[-btn
->yindex
] = 1;
2551 else if (btn
->yindex
==0 && btn
->xindex
<0 &&btn
->xindex
>-hcount
)
2552 hmap
[-btn
->xindex
] = 1;
2557 /* search a vacant slot */
2558 for (i
=1; i
<MAX(vcount
, hcount
); i
++) {
2559 if (i
< vcount
&& vmap
[i
]==0) {
2565 } else if (i
< hcount
&& hmap
[i
]==0) {
2575 /* If found a slot, translate and return */
2577 if (corner
==C_NW
|| corner
==C_NE
) {
2582 if (corner
==C_NE
|| corner
==C_SE
) {
2589 /* else, try to find a slot somewhere else */
2592 /* a map of mwidth x mwidth would be enough if we allowed icons to be
2593 * placed outside of screen */
2594 mwidth
= (int)ceil(sqrt(dock
->max_icons
));
2596 /* In the worst case (the clip is in the corner of the screen),
2597 * the amount of icons that fit in the clip is smaller.
2598 * Double the map to get a safe value.
2604 slot_map
= wmalloc(mwidth
*mwidth
);
2605 memset(slot_map
, 0, mwidth
*mwidth
);
2607 #define XY2OFS(x,y) (MAX(abs(x),abs(y)) > r) ? 0 : (((y)+r)*(mwidth)+(x)+r)
2609 /* mark used slots in the map. If the slot falls outside the map
2610 * (for example, when all icons are placed in line), ignore them. */
2611 for (i
=0; i
<dock
->max_icons
; i
++) {
2612 btn
= dock
->icon_array
[i
];
2614 slot_map
[XY2OFS(btn
->xindex
, btn
->yindex
)] = 1;
2616 /* Find closest slot from the center that is free by scanning the
2617 * map from the center to outward in circular passes.
2618 * This will not result in a neat layout, but will be optimal
2619 * in the sense that there will not be holes left.
2622 for (i
= 1; i
<= r
&& !done
; i
++) {
2625 /* top and bottom parts of the ring */
2626 for (x
= -i
; x
<= i
&& !done
; x
++) {
2627 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2629 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2630 if (slot_map
[XY2OFS(x
,y
)]==0
2631 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2638 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2639 if (slot_map
[XY2OFS(x
,y
)]==0
2640 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2647 /* left and right parts of the ring */
2648 for (y
= -i
+1; y
<= i
-1; y
++) {
2649 ty
= dock
->y_pos
+ y
*ICON_SIZE
;
2651 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2652 if (slot_map
[XY2OFS(x
,y
)]==0
2653 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2660 tx
= dock
->x_pos
+ x
*ICON_SIZE
;
2661 if (slot_map
[XY2OFS(x
,y
)]==0
2662 && ON_SCREEN(tx
, ty
, sx
, ex
, sy
, ey
)) {
2677 moveDock(WDock
*dock
, int new_x
, int new_y
)
2682 dock
->x_pos
= new_x
;
2683 dock
->y_pos
= new_y
;
2684 for (i
=0; i
<dock
->max_icons
; i
++) {
2685 btn
= dock
->icon_array
[i
];
2687 btn
->x_pos
= new_x
+ btn
->xindex
*ICON_SIZE
;
2688 btn
->y_pos
= new_y
+ btn
->yindex
*ICON_SIZE
;
2689 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2696 swapDock(WDock
*dock
)
2698 WScreen
*scr
= dock
->screen_ptr
;
2703 if (dock
->on_right_side
) {
2704 x
= dock
->x_pos
= scr
->scr_width
- ICON_SIZE
- DOCK_EXTRA_SPACE
;
2706 x
= dock
->x_pos
= DOCK_EXTRA_SPACE
;
2709 for (i
=0; i
<dock
->max_icons
; i
++) {
2710 btn
= dock
->icon_array
[i
];
2713 XMoveWindow(dpy
, btn
->icon
->core
->window
, btn
->x_pos
, btn
->y_pos
);
2717 wScreenUpdateUsableArea(scr
);
2722 execCommand(WAppIcon
*btn
, char *command
, WSavedState
*state
)
2724 WScreen
*scr
= btn
->icon
->core
->screen_ptr
;
2730 cmdline
= ExpandOptions(scr
, command
);
2732 if (scr
->flags
.dnd_data_convertion_status
|| !cmdline
) {
2740 ParseCommand(cmdline
, &argv
, &argc
);
2750 if ((pid
=fork())==0) {
2754 SetupEnvironment(scr
);
2760 args
= malloc(sizeof(char*)*(argc
+1));
2763 for (i
=0; i
<argc
; i
++) {
2767 execvp(argv
[0], args
);
2776 state
= wmalloc(sizeof(WSavedState
));
2777 memset(state
, 0, sizeof(WSavedState
));
2779 state
->miniaturized
= -1;
2781 if (btn
->dock
== scr
->dock
)
2782 state
->workspace
= -1;
2784 state
->workspace
= scr
->current_workspace
;
2786 wWindowAddSavedState(btn
->wm_instance
, btn
->wm_class
, cmdline
, pid
,
2788 wAddDeathHandler(pid
, (WDeathHandler
*)trackDeadProcess
,
2799 wDockHideIcons(WDock
*dock
)
2807 btn
= dock
->icon_array
[0];
2809 for (i
=1; i
<dock
->max_icons
; i
++) {
2810 if (dock
->icon_array
[i
])
2811 XUnmapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
2820 wDockShowIcons(WDock
*dock
)
2828 btn
= dock
->icon_array
[0];
2829 moveDock(dock
, btn
->x_pos
, btn
->y_pos
);
2831 newlevel
= dock
->lowered
? WMNormalLevel
: WMDockLevel
;
2832 ChangeStackingLevel(btn
->icon
->core
, newlevel
);
2834 for (i
=1; i
<dock
->max_icons
; i
++) {
2835 if (dock
->icon_array
[i
]) {
2836 MoveInStackListAbove(dock
->icon_array
[i
]->icon
->core
,
2842 if (!dock
->collapsed
) {
2843 for (i
=1; i
<dock
->max_icons
; i
++) {
2844 if (dock
->icon_array
[i
]) {
2845 XMapWindow(dpy
, dock
->icon_array
[i
]->icon
->core
->window
);
2856 wDockLower(WDock
*dock
)
2860 for (i
=0; i
<dock
->max_icons
; i
++) {
2861 if (dock
->icon_array
[i
])
2862 wLowerFrame(dock
->icon_array
[i
]->icon
->core
);
2868 wDockRaise(WDock
*dock
)
2872 for (i
=dock
->max_icons
-1; i
>=0; i
--) {
2873 if (dock
->icon_array
[i
])
2874 wRaiseFrame(dock
->icon_array
[i
]->icon
->core
);
2880 wDockRaiseLower(WDock
*dock
)
2882 if (!dock
->icon_array
[0]->icon
->core
->stacking
->above
2883 ||(dock
->icon_array
[0]->icon
->core
->stacking
->window_level
2884 !=dock
->icon_array
[0]->icon
->core
->stacking
->above
->stacking
->window_level
))
2892 wDockFinishLaunch(WDock
*dock
, WAppIcon
*icon
)
2894 icon
->launching
= 0;
2895 icon
->relaunching
= 0;
2896 dockIconPaint(icon
);
2901 wDockFindIconFor(WDock
*dock
, Window window
)
2906 for (i
=0; i
<dock
->max_icons
; i
++) {
2907 icon
= dock
->icon_array
[i
];
2908 if (icon
&& icon
->main_window
== window
)
2916 wDockTrackWindowLaunch(WDock
*dock
, Window window
)
2919 #ifdef REDUCE_APPICONS
2920 WAppIconAppList
*tapplist
;
2922 char *wm_class
, *wm_instance
;
2924 Bool firstPass
= True
;
2926 char *command
= NULL
;
2932 if (XGetCommand(dpy
, window
, &argv
, &argc
)) {
2933 if (argc
> 0 && argv
!= NULL
)
2934 command
= FlattenStringList(argv
,argc
);
2936 XFreeStringList(argv
);
2941 if (!PropGetWMClass(window
, &wm_class
, &wm_instance
) ||
2942 (!wm_class
&& !wm_instance
))
2946 for (i
=0; i
<dock
->max_icons
; i
++) {
2947 icon
= dock
->icon_array
[i
];
2951 /* app is already attached to icon */
2952 if (icon
->main_window
== window
) {
2957 if ((icon
->wm_instance
|| icon
->wm_class
)
2959 || (dock
->screen_ptr
->flags
.startup
&& !icon
->running
))) {
2961 if (icon
->wm_instance
&& wm_instance
&&
2962 strcmp(icon
->wm_instance
, wm_instance
)!=0) {
2965 if (icon
->wm_class
&& wm_class
&&
2966 strcmp(icon
->wm_class
, wm_class
)!=0) {
2969 if (firstPass
&& command
&& strcmp(icon
->command
, command
)!=0) {
2973 if (!icon
->relaunching
) {
2976 /* Possibly an application that was docked with dockit,
2977 * but the user did not update WMState to indicate that
2978 * it was docked by force */
2979 wapp
= wApplicationOf(window
);
2981 icon
->forced_dock
= 1;
2984 if (!icon
->forced_dock
)
2985 icon
->main_window
= window
;
2987 #ifdef REDUCE_APPICONS
2988 tapplist
= wmalloc(sizeof(WAppIconAppList
));
2989 memset(tapplist
, 0, sizeof(WAppIconAppList
));
2990 tapplist
->next
= icon
->applist
;
2992 icon
->applist
->prev
= tapplist
;
2993 icon
->applist
= tapplist
;
2994 tapplist
->wapp
= wApplicationOf(window
);
2999 wDockFinishLaunch(dock
, icon
);
3004 if (firstPass
&& !found
) {
3021 wClipUpdateForWorkspaceChange(WScreen
*scr
, int workspace
)
3023 if (!wPreferences
.flags
.noclip
) {
3024 scr
->clip_icon
->dock
= scr
->workspaces
[workspace
]->clip
;
3025 if (scr
->current_workspace
!= workspace
) {
3026 WDock
*old_clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
3028 wDockHideIcons(old_clip
);
3029 if (old_clip
->auto_raise_lower
)
3030 wDockLower(old_clip
);
3031 if (old_clip
->auto_collapse
&& !old_clip
->collapsed
)
3032 old_clip
->collapsed
= 1;
3033 wDockShowIcons(scr
->workspaces
[workspace
]->clip
);
3035 if (scr
->flags
.clip_balloon_mapped
)
3036 showClipBalloon(scr
->clip_icon
->dock
, workspace
);
3043 trackDeadProcess(pid_t pid
, unsigned char status
, WDock
*dock
)
3048 for (i
=0; i
<dock
->max_icons
; i
++) {
3049 icon
= dock
->icon_array
[i
];
3053 if (icon
->launching
&& icon
->pid
== pid
) {
3054 if (!icon
->relaunching
) {
3056 icon
->main_window
= None
;
3058 wDockFinishLaunch(dock
, icon
);
3063 sprintf(msg
, _("Could not execute command \"%s\""),
3064 icon
->drop_launch
&& icon
->dnd_command
3065 ? icon
->dnd_command
: icon
->command
);
3067 sprintf(msg
, _("Could not execute command \"%s\""),
3070 wMessageDialog(dock
->screen_ptr
, _("Error"), msg
,
3071 _("OK"), NULL
, NULL
);
3080 toggleLowered(WDock
*dock
)
3085 /* lower/raise Dock */
3086 if (!dock
->lowered
) {
3087 newlevel
= WMNormalLevel
;
3090 newlevel
= WMDockLevel
;
3094 for (i
=0; i
<dock
->max_icons
; i
++) {
3095 tmp
= dock
->icon_array
[i
];
3099 ChangeStackingLevel(tmp
->icon
->core
, newlevel
);
3101 wLowerFrame(tmp
->icon
->core
);
3104 if (dock
->type
== WM_DOCK
)
3105 wScreenUpdateUsableArea(dock
->screen_ptr
);
3110 toggleCollapsed(WDock
*dock
)
3112 if (dock
->collapsed
) {
3113 dock
->collapsed
= 0;
3114 wDockShowIcons(dock
);
3117 dock
->collapsed
= 1;
3118 wDockHideIcons(dock
);
3124 openDockMenu(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3126 WScreen
*scr
= dock
->screen_ptr
;
3127 WObjDescriptor
*desc
;
3129 WApplication
*wapp
= NULL
;
3132 int appIsRunning
= aicon
->running
&& aicon
->icon
&& aicon
->icon
->owner
;
3134 if (dock
->type
== WM_DOCK
) {
3136 entry
= dock
->menu
->entries
[index
];
3137 entry
->flags
.indicator_on
= !dock
->lowered
;
3138 entry
->clientdata
= dock
;
3141 if (scr
->clip_options
)
3142 updateClipOptionsMenu(scr
->clip_options
, dock
);
3144 /* Rename Workspace */
3145 entry
= dock
->menu
->entries
[++index
];
3146 entry
->clientdata
= dock
;
3149 entry
= dock
->menu
->entries
[++index
];
3150 entry
->clientdata
= aicon
;
3151 wMenuSetEnabled(dock
->menu
, index
, aicon
!=scr
->clip_icon
);
3153 /* (un)select all icons */
3154 entry
= dock
->menu
->entries
[++index
];
3155 entry
->clientdata
= aicon
;
3156 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3159 entry
= dock
->menu
->entries
[++index
];
3160 entry
->clientdata
= aicon
;
3161 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3163 /* this is the workspace submenu part */
3164 if (scr
->clip_submenu
)
3165 updateWorkspaceMenu(scr
->clip_submenu
, aicon
);
3168 /* remove icon(s) */
3169 entry
= dock
->menu
->entries
[++index
];
3170 entry
->clientdata
= aicon
;
3171 wMenuSetEnabled(dock
->menu
, index
, dock
->icon_count
> 1);
3173 /* attract icon(s) */
3174 entry
= dock
->menu
->entries
[++index
];
3175 entry
->clientdata
= aicon
;
3179 entry
= dock
->menu
->entries
[++index
];
3180 entry
->clientdata
= aicon
;
3181 wMenuSetEnabled(dock
->menu
, index
, aicon
->command
!=NULL
);
3184 entry
= dock
->menu
->entries
[++index
];
3185 entry
->clientdata
= aicon
;
3186 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3189 entry
= dock
->menu
->entries
[++index
];
3190 entry
->clientdata
= aicon
;
3191 if (aicon
->icon
->owner
) {
3192 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
3193 if (wapp
&& wapp
->flags
.hidden
)
3194 entry
->text
= _("Unhide");
3196 entry
->text
= _("Hide");
3198 entry
->text
= _("Hide");
3200 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3203 entry
= dock
->menu
->entries
[++index
];
3204 entry
->clientdata
= aicon
;
3205 wMenuSetEnabled(dock
->menu
, index
, !aicon
->editing
3206 && !wPreferences
.flags
.noupdates
);
3209 entry
= dock
->menu
->entries
[++index
];
3210 entry
->clientdata
= aicon
;
3211 wMenuSetEnabled(dock
->menu
, index
, appIsRunning
);
3213 if (!dock
->menu
->flags
.realized
)
3214 wMenuRealize(dock
->menu
);
3216 if (dock
->type
== WM_CLIP
) {
3217 x_pos
= event
->xbutton
.x_root
+2;
3219 x_pos
= dock
->on_right_side
?
3220 scr
->scr_width
- dock
->menu
->frame
->core
->width
- 2 : 0;
3223 wMenuMapAt(dock
->menu
, x_pos
, event
->xbutton
.y_root
+2, False
);
3225 /* allow drag select */
3226 event
->xany
.send_event
= True
;
3227 desc
= &dock
->menu
->menu
->descriptor
;
3228 (*desc
->handle_mousedown
)(desc
, event
);
3233 openClipWorkspaceMenu(WScreen
*scr
, int x
, int y
)
3235 if (!scr
->clip_ws_menu
) {
3236 scr
->clip_ws_menu
= wWorkspaceMenuMake(scr
, False
);
3238 wWorkspaceMenuUpdate(scr
, scr
->clip_ws_menu
);
3239 wMenuMapAt(scr
->clip_ws_menu
, x
, y
, False
);
3243 /******************************************************************/
3245 iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
3247 WAppIcon
*btn
= desc
->parent
;
3248 WDock
*dock
= btn
->dock
;
3249 WApplication
*wapp
= NULL
;
3252 #ifdef REDUCE_APPICONS
3253 if ((btn
->icon
->owner
&& !(event
->xbutton
.state
& ControlMask
)) ||
3254 ((btn
->icon
->owner
== NULL
) && (btn
->applist
!= NULL
))) {
3255 if (btn
->icon
->owner
== NULL
)
3256 btn
->icon
->owner
= btn
->applist
->wapp
->main_window_desc
;
3261 if (btn
->icon
->owner
&& !(event
->xbutton
.state
& ControlMask
)) {
3263 wapp
= wApplicationOf(btn
->icon
->owner
->main_window
);
3267 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
3269 /* go to the last workspace that the user worked on the app */
3271 wWorkspaceChange(dock
->screen_ptr
, wapp
->last_workspace
);
3274 wUnhideApplication(wapp
, event
->xbutton
.button
==Button2
,
3277 if (event
->xbutton
.state
& MOD_MASK
) {
3278 wHideOtherApplications(btn
->icon
->owner
);
3281 if (event
->xbutton
.button
==Button1
) {
3283 if (event
->xbutton
.state
& MOD_MASK
) {
3284 /* raise/lower dock */
3285 toggleLowered(dock
);
3286 } else if (btn
== dock
->screen_ptr
->clip_icon
) {
3287 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
)
3288 toggleCollapsed(dock
);
3290 handleClipChangeWorkspace(dock
->screen_ptr
, event
);
3291 } else if (btn
->command
) {
3292 if (!btn
->launching
&&
3293 (!btn
->running
|| (event
->xbutton
.state
& ControlMask
))) {
3294 launchDockedApplication(btn
);
3303 handleDockMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3305 WScreen
*scr
= dock
->screen_ptr
;
3306 int ofs_x
=event
->xbutton
.x
, ofs_y
=event
->xbutton
.y
;
3309 int grabbed
= 0, swapped
= 0, done
;
3310 Pixmap ghost
= None
;
3311 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3314 puts("moving dock");
3316 if (XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
3317 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3318 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3319 wwarning("pointer grab failed for dock move");
3322 for (x
=0; x
<dock
->max_icons
; x
++) {
3323 if (dock
->icon_array
[x
]!=NULL
&&
3324 dock
->icon_array
[x
]->yindex
> y
)
3325 y
= dock
->icon_array
[x
]->yindex
;
3328 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
*y
);
3332 WMMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3333 |ButtonMotionMask
|ExposureMask
, &ev
);
3341 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3342 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3343 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3344 |ButtonReleaseMask
|ButtonPressMask
,
3345 wCursor
[WCUR_MOVE
], CurrentTime
);
3350 if (dock
->type
== WM_CLIP
) {
3351 if (ev
.xmotion
.x_root
- ofs_x
< 0) {
3353 } else if (ev
.xmotion
.x_root
- ofs_x
+ ICON_SIZE
>
3355 x
= scr
->scr_width
- ICON_SIZE
;
3357 x
= ev
.xmotion
.x_root
- ofs_x
;
3359 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3361 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3363 y
= scr
->scr_height
- ICON_SIZE
;
3365 y
= ev
.xmotion
.y_root
- ofs_y
;
3367 moveDock(dock
, x
, y
);
3369 /* move vertically if pointer is inside the dock*/
3370 if ((dock
->on_right_side
&&
3371 ev
.xmotion
.x_root
>= dock
->x_pos
- ICON_SIZE
)
3372 || (!dock
->on_right_side
&&
3373 ev
.xmotion
.x_root
<= dock
->x_pos
+ ICON_SIZE
*2)) {
3375 if (ev
.xmotion
.y_root
- ofs_y
< 0) {
3377 } else if (ev
.xmotion
.y_root
- ofs_y
+ ICON_SIZE
>
3379 y
= scr
->scr_height
- ICON_SIZE
;
3381 y
= ev
.xmotion
.y_root
- ofs_y
;
3383 moveDock(dock
, dock
->x_pos
, y
);
3385 /* move horizontally to change sides */
3386 x
= ev
.xmotion
.x_root
- ofs_x
;
3387 if (!dock
->on_right_side
) {
3391 if (ev
.xmotion
.x_root
> dock
->x_pos
+ ICON_SIZE
*2) {
3392 XMoveWindow(dpy
, scr
->dock_shadow
, scr
->scr_width
-ICON_SIZE
3393 -DOCK_EXTRA_SPACE
-1, dock
->y_pos
);
3396 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3397 scr
->scr_width
-ICON_SIZE
3398 -DOCK_EXTRA_SPACE
-1,
3400 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3402 XClearWindow(dpy
, scr
->dock_shadow
);
3405 XMapRaised(dpy
, scr
->dock_shadow
);
3408 if (superfluous
&& ghost
!=None
) {
3409 XFreePixmap(dpy
, ghost
);
3412 XUnmapWindow(dpy
, scr
->dock_shadow
);
3417 if (ev
.xmotion
.x_root
< dock
->x_pos
- ICON_SIZE
) {
3418 XMoveWindow(dpy
, scr
->dock_shadow
,
3419 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3422 ghost
= MakeGhostDock(dock
, dock
->x_pos
,
3423 DOCK_EXTRA_SPACE
, dock
->y_pos
);
3424 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
3426 XClearWindow(dpy
, scr
->dock_shadow
);
3429 XMapRaised(dpy
, scr
->dock_shadow
);
3432 XUnmapWindow(dpy
, scr
->dock_shadow
);
3434 if (superfluous
&& ghost
!=None
) {
3435 XFreePixmap(dpy
, ghost
);
3447 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3449 XUngrabPointer(dpy
, CurrentTime
);
3450 XUnmapWindow(dpy
, scr
->dock_shadow
);
3451 XResizeWindow(dpy
, scr
->dock_shadow
, ICON_SIZE
, ICON_SIZE
);
3452 if (dock
->type
== WM_DOCK
) {
3455 dock
->on_right_side
= 1;
3457 dock
->on_right_side
= 0;
3459 wArrangeIcons(scr
, False
);
3468 XFreePixmap(dpy
, ghost
);
3469 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3472 puts("End dock move");
3479 handleIconMove(WDock
*dock
, WAppIcon
*aicon
, XEvent
*event
)
3481 WScreen
*scr
= dock
->screen_ptr
;
3483 WIcon
*icon
= aicon
->icon
;
3484 WDock
*dock2
= NULL
, *last_dock
= dock
, *clip
= NULL
;
3485 int ondock
, grabbed
= 0, change_dock
= 0, collapsed
= 0;
3487 int x
= aicon
->x_pos
, y
= aicon
->y_pos
;
3488 int ofs_x
= event
->xbutton
.x
, ofs_y
= event
->xbutton
.y
;
3489 int shad_x
= x
, shad_y
= y
;
3490 int ix
= aicon
->xindex
, iy
= aicon
->yindex
;
3492 Pixmap ghost
= None
;
3494 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
3496 if (wPreferences
.flags
.noupdates
)
3499 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
3500 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
3501 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
3503 wwarning("pointer grab failed for icon move");
3507 wRaiseFrame(icon
->core
);
3509 if (!wPreferences
.flags
.noclip
)
3510 clip
= scr
->workspaces
[scr
->current_workspace
]->clip
;
3512 if (dock
== scr
->dock
&& !wPreferences
.flags
.noclip
)
3514 else if (dock
!= scr
->dock
&& !wPreferences
.flags
.nodock
)
3517 wins
[0] = icon
->core
->window
;
3518 wins
[1] = scr
->dock_shadow
;
3519 XRestackWindows(dpy
, wins
, 2);
3520 XMoveResizeWindow(dpy
, scr
->dock_shadow
, aicon
->x_pos
, aicon
->y_pos
,
3521 ICON_SIZE
, ICON_SIZE
);
3523 if (icon
->pixmap
!=None
)
3524 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
3526 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
3528 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
, ghost
);
3529 XClearWindow(dpy
, scr
->dock_shadow
);
3531 XMapWindow(dpy
, scr
->dock_shadow
);
3537 XMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
3538 |ButtonMotionMask
|ExposureMask
, &ev
);
3546 if (abs(ofs_x
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
3547 || abs(ofs_y
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
3548 XChangeActivePointerGrab(dpy
, ButtonMotionMask
3549 |ButtonReleaseMask
|ButtonPressMask
,
3550 wCursor
[WCUR_MOVE
], CurrentTime
);
3557 x
= ev
.xmotion
.x_root
- ofs_x
;
3558 y
= ev
.xmotion
.y_root
- ofs_y
;
3559 tmp
= wDockSnapIcon(dock
, aicon
, x
, y
, &ix
, &iy
, True
);
3562 if (last_dock
!= dock
&& collapsed
) {
3563 last_dock
->collapsed
= 1;
3564 wDockHideIcons(last_dock
);
3567 if (!collapsed
&& (collapsed
= dock
->collapsed
)) {
3568 dock
->collapsed
= 0;
3569 wDockShowIcons(dock
);
3571 if (dock
->auto_raise_lower
)
3576 tmp
= wDockSnapIcon(dock2
, aicon
, x
, y
, &ix
, &iy
, False
);
3579 if (last_dock
!= dock2
&& collapsed
) {
3580 last_dock
->collapsed
= 1;
3581 wDockHideIcons(last_dock
);
3584 if (!collapsed
&& (collapsed
= dock2
->collapsed
)) {
3585 dock2
->collapsed
= 0;
3586 wDockShowIcons(dock2
);
3588 if (dock2
->auto_raise_lower
)
3593 if (aicon
->launching
3594 || (aicon
->running
&& !(ev
.xmotion
.state
& MOD_MASK
))
3595 || (!aicon
->running
&& tmp
)) {
3596 shad_x
= last_dock
->x_pos
+ ix
*wPreferences
.icon_size
;
3597 shad_y
= last_dock
->y_pos
+ iy
*wPreferences
.icon_size
;
3599 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
3602 XMapWindow(dpy
, scr
->dock_shadow
);
3604 if (!collapsed
&& (collapsed
= last_dock
->collapsed
)) {
3605 last_dock
->collapsed
= 0;
3606 wDockShowIcons(last_dock
);
3613 XUnmapWindow(dpy
, scr
->dock_shadow
);
3615 if (last_dock
&& collapsed
&&
3616 aicon
->running
&& (ev
.xmotion
.state
& MOD_MASK
)) {
3617 last_dock
->collapsed
= 1;
3618 wDockHideIcons(last_dock
);
3625 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
3632 if (ev
.xbutton
.button
!= event
->xbutton
.button
)
3634 XUngrabPointer(dpy
, CurrentTime
);
3636 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
3637 XUnmapWindow(dpy
, scr
->dock_shadow
);
3639 reattachIcon(dock
, aicon
, ix
, iy
);
3640 if (clip
&& dock
!=clip
&& clip
->auto_raise_lower
)
3643 docked
= moveIconBetweenDocks(dock
, dock2
, aicon
, ix
, iy
);
3645 /* Slide it back if dock rejected it */
3646 SlideWindow(icon
->core
->window
, x
, y
, aicon
->x_pos
,
3648 reattachIcon(dock
, aicon
, aicon
->xindex
,aicon
->yindex
);
3650 if (last_dock
->type
==WM_CLIP
&& last_dock
->auto_collapse
) {
3658 if (!aicon
->running
&& !wPreferences
.no_animations
) {
3659 /* We need to deselect it, even if is deselected in
3660 * wDockDetach(), because else DoKaboom() will fail.
3662 if (aicon
->icon
->selected
)
3663 wIconSelect(aicon
->icon
);
3664 DoKaboom(scr
,aicon
->icon
->core
->window
, x
, y
);
3667 if (clip
&& clip
->auto_raise_lower
)
3669 wDockDetach(dock
, aicon
);
3672 last_dock
->collapsed
= 1;
3673 wDockHideIcons(last_dock
);
3678 XFreePixmap(dpy
, ghost
);
3679 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
3682 puts("End icon move");
3691 getClipButton(int px
, int py
)
3693 int pt
= (CLIP_BUTTON_SIZE
+2)*ICON_SIZE
/64;
3695 if (px
< 0 || py
< 0 || px
>= ICON_SIZE
|| py
>= ICON_SIZE
)
3698 if (py
<= pt
-((int)ICON_SIZE
-1-px
))
3699 return CLIP_FORWARD
;
3700 else if (px
<= pt
-((int)ICON_SIZE
-1-py
))
3708 handleClipChangeWorkspace(WScreen
*scr
, XEvent
*event
)
3711 int done
, direction
, new_ws
;
3713 WDock
*clip
= scr
->clip_icon
->dock
;
3715 direction
= getClipButton(event
->xbutton
.x
, event
->xbutton
.y
);
3717 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3718 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3720 wClipIconPaint(scr
->clip_icon
);
3723 WMMaskEvent(dpy
, ExposureMask
|ButtonMotionMask
|ButtonReleaseMask
3724 |ButtonPressMask
, &ev
);
3731 new_dir
= getClipButton(ev
.xmotion
.x
, ev
.xmotion
.y
);
3732 if (new_dir
!= direction
) {
3733 direction
= new_dir
;
3734 clip
->lclip_button_pushed
= direction
==CLIP_REWIND
;
3735 clip
->rclip_button_pushed
= direction
==CLIP_FORWARD
;
3736 wClipIconPaint(scr
->clip_icon
);
3744 if (ev
.xbutton
.button
== event
->xbutton
.button
)
3749 clip
->lclip_button_pushed
= 0;
3750 clip
->rclip_button_pushed
= 0;
3752 new_ws
= wPreferences
.ws_advance
|| (event
->xbutton
.state
& ControlMask
);
3754 if (direction
== CLIP_FORWARD
) {
3755 if (scr
->current_workspace
< scr
->workspace_count
-1)
3756 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3757 else if (new_ws
&& scr
->current_workspace
< MAX_WORKSPACES
-1)
3758 wWorkspaceChange(scr
, scr
->current_workspace
+1);
3759 else if (wPreferences
.ws_cycle
)
3760 wWorkspaceChange(scr
, 0);
3762 else if (direction
== CLIP_REWIND
) {
3763 if (scr
->current_workspace
> 0)
3764 wWorkspaceChange(scr
, scr
->current_workspace
-1);
3765 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
3766 wWorkspaceChange(scr
, scr
->workspace_count
-1);
3769 wClipIconPaint(scr
->clip_icon
);
3774 iconMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
3776 WAppIcon
*aicon
= desc
->parent
;
3777 WDock
*dock
= aicon
->dock
;
3778 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
3780 if (aicon
->editing
|| WCHECK_STATE(WSTATE_MODAL
))
3783 scr
->last_dock
= dock
;
3785 if (dock
->menu
->flags
.mapped
)
3786 wMenuUnmap(dock
->menu
);
3788 if (IsDoubleClick(scr
, event
)) {
3789 /* double-click was not in the main clip icon */
3790 if (dock
->type
!= WM_CLIP
|| aicon
->xindex
!=0 || aicon
->yindex
!=0
3791 || getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)==CLIP_IDLE
) {
3792 iconDblClick(desc
, event
);
3797 if (dock
->type
== WM_CLIP
&& scr
->flags
.clip_balloon_mapped
) {
3798 XUnmapWindow(dpy
, scr
->clip_balloon
);
3799 scr
->flags
.clip_balloon_mapped
= 0;
3803 puts("handling dock");
3805 if (event
->xbutton
.button
== Button1
) {
3806 if (event
->xbutton
.state
& MOD_MASK
)
3811 if ((event
->xbutton
.state
& ShiftMask
) && aicon
!=scr
->clip_icon
&&
3812 dock
->type
!=WM_DOCK
) {
3813 wIconSelect(aicon
->icon
);
3817 if (aicon
->yindex
==0 && aicon
->xindex
==0) {
3818 if (getClipButton(event
->xbutton
.x
, event
->xbutton
.y
)!=CLIP_IDLE
3819 && dock
->type
==WM_CLIP
)
3820 handleClipChangeWorkspace(scr
, event
);
3822 handleDockMove(dock
, aicon
, event
);
3824 handleIconMove(dock
, aicon
, event
);
3826 } else if (event
->xbutton
.button
==Button2
&& dock
->type
==WM_CLIP
&&
3827 aicon
->xindex
==0 && aicon
->yindex
==0) {
3828 openClipWorkspaceMenu(scr
, event
->xbutton
.x_root
+2,
3829 event
->xbutton
.y_root
+2);
3830 if (scr
->clip_ws_menu
) {
3832 menu
= scr
->clip_ws_menu
;
3833 desc
= &menu
->menu
->descriptor
;
3835 event
->xany
.send_event
= True
;
3836 (*desc
->handle_mousedown
)(desc
, event
);
3838 } else if (event
->xbutton
.button
== Button3
) {
3839 openDockMenu(dock
, aicon
, event
);
3845 showClipBalloon(WDock
*dock
, int workspace
)
3849 WScreen
*scr
= dock
->screen_ptr
;
3853 scr
->flags
.clip_balloon_mapped
= 1;
3854 XMapWindow(dpy
, scr
->clip_balloon
);
3856 text
= scr
->workspaces
[workspace
]->name
;
3858 w
= wTextWidth(scr
->clip_title_font
->font
, text
, strlen(text
));
3860 h
= scr
->clip_title_font
->height
;
3861 XResizeWindow(dpy
, scr
->clip_balloon
, w
, h
);
3863 x
= dock
->x_pos
+ CLIP_BUTTON_SIZE
*ICON_SIZE
/64;
3864 y
= dock
->y_pos
+ ICON_SIZE
-scr
->clip_title_font
->height
- 3;
3866 if (x
+w
> scr
->scr_width
) {
3867 x
= scr
->scr_width
- w
;
3868 if (dock
->y_pos
+ ICON_SIZE
+ h
> scr
->scr_height
)
3869 y
= dock
->y_pos
- h
- 1;
3871 y
= dock
->y_pos
+ ICON_SIZE
;
3872 XRaiseWindow(dpy
, scr
->clip_balloon
);
3874 stack
[0] = scr
->clip_icon
->icon
->core
->window
;
3875 stack
[1] = scr
->clip_balloon
;
3876 XRestackWindows(dpy
, stack
, 2);
3878 XMoveWindow(dpy
, scr
->clip_balloon
, x
, y
);
3879 XSetForeground(dpy
, scr
->clip_title_gc
,
3880 scr
->clip_title_pixel
[CLIP_NORMAL
]);
3881 XClearWindow(dpy
, scr
->clip_balloon
);
3882 wDrawString(scr
->clip_balloon
, scr
->clip_title_font
, scr
->clip_title_gc
,
3883 0, scr
->clip_title_font
->y
, text
, strlen(text
));
3888 clipEnterNotify(WObjDescriptor
*desc
, XEvent
*event
)
3890 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
3893 assert(event
->type
==EnterNotify
);
3895 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
3899 if (!dock
|| dock
->type
!=WM_CLIP
)
3902 if (dock
->auto_lower_magic
) {
3903 WMDeleteTimerHandler(dock
->auto_lower_magic
);
3904 dock
->auto_lower_magic
= NULL
;
3906 if (dock
->auto_raise_lower
) {
3907 dock
->auto_raise_magic
= WMAddTimerHandler(AUTO_RAISE_DELAY
,
3912 if (btn
->xindex
== 0 && btn
->yindex
== 0)
3913 showClipBalloon(dock
, dock
->screen_ptr
->current_workspace
);
3915 if (dock
->screen_ptr
->flags
.clip_balloon_mapped
) {
3916 XUnmapWindow(dpy
, dock
->screen_ptr
->clip_balloon
);
3917 dock
->screen_ptr
->flags
.clip_balloon_mapped
= 0;
3920 if (dock
->auto_collapse
) {
3921 if (dock
->auto_collapse_magic
) {
3922 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
3923 dock
->auto_collapse_magic
= NULL
;
3926 if (dock
->collapsed
)
3927 toggleCollapsed(dock
);
3933 clipLeave(WDock
*dock
)
3935 if (!dock
|| dock
->type
!=WM_CLIP
)
3938 if (dock
->auto_raise_magic
) {
3939 WMDeleteTimerHandler(dock
->auto_raise_magic
);
3940 dock
->auto_raise_magic
= NULL
;
3942 if (dock
->auto_raise_lower
) {
3943 dock
->auto_lower_magic
= WMAddTimerHandler(AUTO_LOWER_DELAY
,
3948 if (dock
->auto_collapse
) {
3949 if (dock
->auto_collapse_magic
) {
3950 WMDeleteTimerHandler(dock
->auto_collapse_magic
);
3951 dock
->auto_collapse_magic
= NULL
;
3953 if (!dock
->collapsed
) {
3954 dock
->auto_collapse_magic
= WMAddTimerHandler(AUTO_COLLAPSE_DELAY
,
3963 clipLeaveNotify(WObjDescriptor
*desc
, XEvent
*event
)
3965 WAppIcon
*btn
= (WAppIcon
*)desc
->parent
;
3967 assert(event
->type
==LeaveNotify
);
3969 if(desc
->parent_type
!=WCLASS_DOCK_ICON
)
3972 clipLeave(btn
->dock
);
3977 clipAutoCollapse(void *cdata
)
3979 WDock
*dock
= (WDock
*)cdata
;
3981 if (dock
->type
!=WM_CLIP
|| !dock
->auto_collapse
)
3984 if (!dock
->collapsed
&& dock
->auto_collapse_magic
!=NULL
) {
3985 toggleCollapsed(dock
);
3987 dock
->auto_collapse_magic
= NULL
;
3992 clipAutoLower(void *cdata
)
3994 WDock
*dock
= (WDock
*)cdata
;
3996 if (dock
->type
!=WM_CLIP
)
3999 if (dock
->auto_raise_lower
)
4002 dock
->auto_lower_magic
= NULL
;
4007 clipAutoRaise(void *cdata
)
4009 WDock
*dock
= (WDock
*)cdata
;
4011 if (dock
->type
!=WM_CLIP
)
4014 if (dock
->auto_raise_lower
)
4017 if (dock
->screen_ptr
->flags
.clip_balloon_mapped
) {
4018 showClipBalloon(dock
, dock
->screen_ptr
->current_workspace
);
4021 dock
->auto_raise_magic
= NULL
;