1 /* appicon.c- icon for applications (not mini-window)
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #include <X11/Xutil.h>
31 #include "WindowMaker.h"
41 #include "workspace.h"
42 #include "superfluous.h"
54 * icon_file for the dock is got from the preferences file by
55 * using the classname/instancename
58 /**** Global variables ****/
59 extern Cursor wCursor
[WCUR_LAST
];
60 extern WPreferences wPreferences
;
62 #define MOD_MASK wPreferences.modifier_mask
64 void appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
65 static void iconDblClick(WObjDescriptor
*desc
, XEvent
*event
);
66 static void iconExpose(WObjDescriptor
*desc
, XEvent
*event
);
71 wAppIconCreateForDock(WScreen
*scr
, char *command
, char *wm_instance
,
72 char *wm_class
, int tile
)
77 dicon
= wmalloc(sizeof(WAppIcon
));
79 memset(dicon
, 0, sizeof(WAppIcon
));
84 dicon
->next
= scr
->app_icon_list
;
85 if (scr
->app_icon_list
) {
86 scr
->app_icon_list
->prev
= dicon
;
88 scr
->app_icon_list
= dicon
;
91 dicon
->command
= wstrdup(command
);
94 dicon
->wm_class
= wstrdup(wm_class
);
96 dicon
->wm_instance
= wstrdup(wm_instance
);
98 path
= wDefaultGetIconFile(scr
, wm_instance
, wm_class
, True
);
99 if (!path
&& command
) {
100 wApplicationExtractDirPackIcon(scr
, command
, wm_instance
, wm_class
);
102 path
= wDefaultGetIconFile(scr
, wm_instance
, wm_class
, False
);
106 path
= FindImage(wPreferences
.icon_path
, path
);
108 dicon
->icon
= wIconCreateWithIconFile(scr
, path
, tile
);
112 wXDNDMakeAwareness(dicon
->icon
->core
->window
);
115 #ifdef DEMATERIALIZE_ICON
117 XSetWindowAttributes attribs
;
118 attribs
.save_under
= True
;
119 XChangeWindowAttributes(dpy
, dicon
->icon
->core
->window
,
120 CWSaveUnder
, &attribs
);
124 /* will be overriden by dock */
125 dicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
126 dicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
127 dicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
128 dicon
->icon
->core
->descriptor
.parent
= dicon
;
129 AddToStackList(dicon
->icon
->core
);
137 wAppIconCreate(WWindow
*leader_win
)
140 WScreen
*scr
= leader_win
->screen_ptr
;
142 aicon
= wmalloc(sizeof(WAppIcon
));
144 memset(aicon
, 0, sizeof(WAppIcon
));
150 aicon
->next
= scr
->app_icon_list
;
151 if (scr
->app_icon_list
) {
152 scr
->app_icon_list
->prev
= aicon
;
154 scr
->app_icon_list
= aicon
;
156 if (leader_win
->wm_class
)
157 aicon
->wm_class
= wstrdup(leader_win
->wm_class
);
158 if (leader_win
->wm_instance
)
159 aicon
->wm_instance
= wstrdup(leader_win
->wm_instance
);
161 aicon
->icon
= wIconCreate(leader_win
);
162 #ifdef DEMATERIALIZE_ICON
164 XSetWindowAttributes attribs
;
165 attribs
.save_under
= True
;
166 XChangeWindowAttributes(dpy
, aicon
->icon
->core
->window
,
167 CWSaveUnder
, &attribs
);
171 wXDNDMakeAwareness(aicon
->icon
->core
->window
);
174 /* will be overriden if docked */
175 aicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
176 aicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
177 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
178 aicon
->icon
->core
->descriptor
.parent
= aicon
;
179 AddToStackList(aicon
->icon
->core
);
180 aicon
->icon
->show_title
= 0;
181 wIconUpdate(aicon
->icon
);
188 wAppIconDestroy(WAppIcon
*aicon
)
190 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
192 RemoveFromStackList(aicon
->icon
->core
);
193 wIconDestroy(aicon
->icon
);
195 wfree(aicon
->command
);
197 if (aicon
->dnd_command
)
198 wfree(aicon
->dnd_command
);
200 if (aicon
->wm_instance
)
201 wfree(aicon
->wm_instance
);
203 wfree(aicon
->wm_class
);
205 if (aicon
== scr
->app_icon_list
) {
207 aicon
->next
->prev
= NULL
;
208 scr
->app_icon_list
= aicon
->next
;
212 aicon
->next
->prev
= aicon
->prev
;
214 aicon
->prev
->next
= aicon
->next
;
217 aicon
->destroyed
= 1;
225 drawCorner(WIcon
*icon
, WWindow
*wwin
, int active
)
227 WScreen
*scr
= wwin
->screen_ptr
;
238 gc
=scr
->focused_texture
->any
.gc
;
240 gc
=scr
->unfocused_texture
->any
.gc
;
242 XFillPolygon(dpy
, icon
->core
->window
, gc
, points
, 3,
243 Convex
, CoordModeOrigin
);
245 #endif /* NEWAPPICON */
249 drawCorner(WIcon
*icon
)
251 WScreen
*scr
= icon
->core
->screen_ptr
;
260 XFillPolygon(dpy
, icon
->core
->window
, scr
->icon_title_texture
->normal_gc
,
261 points
, 3, Convex
, CoordModeOrigin
);
262 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
,
264 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
,
266 /* drawing the second line gives a weird concave look. -Dan */
268 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
,
270 XDrawLine(dpy
, icon
->core
->window
, scr
->icon_title_texture
->light_gc
,
277 wAppIconMove(WAppIcon
*aicon
, int x
, int y
)
279 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x
, y
);
287 updateDockNumbers(WScreen
*scr
)
291 WAppIcon
*dicon
= scr
->dock
->icon_array
[0];
293 ws_numbers
= wmalloc(20);
294 snprintf(ws_numbers
, 20, "%i [ %i ]", scr
->current_workspace
+1,
295 ((scr
->current_workspace
/10)+1));
296 length
= strlen(ws_numbers
);
298 XClearArea(dpy
, dicon
->icon
->core
->window
, 2, 2, 50,
299 WMFontHeight(scr
->icon_title_font
)+1, False
);
301 WMDrawString(scr
->wmscreen
, dicon
->icon
->core
->window
, scr
->black
,
302 scr
->icon_title_font
, 4, 3, ws_numbers
, length
);
304 WMDrawString(scr
->wmscreen
, dicon
->icon
->core
->window
, scr
->white
,
305 scr
->icon_title_font
, 3, 2, ws_numbers
, length
);
309 #endif /* WS_INDICATOR */
313 wAppIconPaint(WAppIcon
*aicon
)
316 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
318 if (aicon
->icon
->owner
)
319 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
323 wIconPaint(aicon
->icon
);
327 if (aicon
->docked
&& scr
->dock
&& scr
->dock
==aicon
->dock
&&
329 updateDockNumbers(scr
);
331 if (scr
->dock_dots
&& aicon
->docked
&& !aicon
->running
332 && aicon
->command
!=NULL
) {
333 XSetClipMask(dpy
, scr
->copy_gc
, scr
->dock_dots
->mask
);
334 XSetClipOrigin(dpy
, scr
->copy_gc
, 0, 0);
335 XCopyArea(dpy
, scr
->dock_dots
->image
, aicon
->icon
->core
->window
,
336 scr
->copy_gc
, 0, 0, scr
->dock_dots
->width
,
337 scr
->dock_dots
->height
, 0, 0);
341 if (wapp
&& wapp
->flags
.hidden
) {
342 XSetClipMask(dpy
, scr
->copy_gc
, scr
->dock_dots
->mask
);
343 XSetClipOrigin(dpy
, scr
->copy_gc
, 0, 0);
344 XCopyArea(dpy
, scr
->dock_dots
->image
,
345 aicon
->icon
->core
->window
,
346 scr
->copy_gc
, 0, 0, 7,
347 scr
->dock_dots
->height
, 0, 0);
349 #endif /* HIDDENDOT */
351 if (aicon
->omnipresent
)
352 drawCorner(aicon
->icon
);
354 XSetClipMask(dpy
, scr
->copy_gc
, None
);
355 if (aicon
->launching
) {
356 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
357 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
363 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
368 hideCallback(WMenu
*menu
, WMenuEntry
*entry
)
370 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
372 if (wapp
->flags
.hidden
) {
373 wWorkspaceChange(menu
->menu
->screen_ptr
, wapp
->last_workspace
);
374 wUnhideApplication(wapp
, False
, False
);
376 wHideApplication(wapp
);
382 unhideHereCallback(WMenu
*menu
, WMenuEntry
*entry
)
384 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
386 wUnhideApplication(wapp
, False
, True
);
391 setIconCallback(WMenu
*menu
, WMenuEntry
*entry
)
393 WAppIcon
*icon
= ((WApplication
*)entry
->clientdata
)->app_icon
;
403 scr
= icon
->icon
->core
->screen_ptr
;
407 result
= wIconChooserDialog(scr
, &file
, icon
->wm_instance
, icon
->wm_class
);
409 if (result
&& !icon
->destroyed
) {
410 if (file
&& *file
==0) {
414 if (!wIconChangeImageFile(icon
->icon
, file
)) {
415 wMessageDialog(scr
, _("Error"),
416 _("Could not open specified icon file"),
417 _("OK"), NULL
, NULL
);
419 wDefaultChangeIcon(scr
, icon
->wm_instance
, icon
->wm_class
, file
);
431 killCallback(WMenu
*menu
, WMenuEntry
*entry
)
433 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
434 WFakeGroupLeader
*fPtr
;
437 if (!WCHECK_STATE(WSTATE_NORMAL
))
440 WCHANGE_STATE(WSTATE_MODAL
);
442 assert(entry
->clientdata
!=NULL
);
444 buffer
= wstrconcat(wapp
->app_icon
? wapp
->app_icon
->wm_class
: NULL
,
445 _(" will be forcibly closed.\n"
446 "Any unsaved changes will be lost.\n"
449 fPtr
= wapp
->main_window_desc
->fake_group
;
451 wretain(wapp
->main_window_desc
);
452 if (wPreferences
.dont_confirm_kill
453 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
454 buffer
, _("Yes"), _("No"), NULL
)==WAPRDefault
) {
456 WWindow
*wwin
, *twin
;
458 wwin
= wapp
->main_window_desc
->screen_ptr
->focused_window
;
461 if (wwin
->fake_group
== fPtr
) {
466 } else if (!wapp
->main_window_desc
->flags
.destroyed
) {
467 wClientKill(wapp
->main_window_desc
);
470 wrelease(wapp
->main_window_desc
);
474 WCHANGE_STATE(WSTATE_NORMAL
);
479 createApplicationMenu(WScreen
*scr
)
483 menu
= wMenuCreate(scr
, NULL
, False
);
484 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
485 wMenuAddCallback(menu
, _("Hide"), hideCallback
, NULL
);
486 wMenuAddCallback(menu
, _("Set Icon..."), setIconCallback
, NULL
);
487 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
494 openApplicationMenu(WApplication
*wapp
, int x
, int y
)
497 WScreen
*scr
= wapp
->main_window_desc
->screen_ptr
;
500 if (!scr
->icon_menu
) {
501 scr
->icon_menu
= createApplicationMenu(scr
);
502 wfree(scr
->icon_menu
->entries
[1]->text
);
505 menu
= scr
->icon_menu
;
507 if (wapp
->flags
.hidden
) {
508 menu
->entries
[1]->text
= _("Unhide");
510 menu
->entries
[1]->text
= _("Hide");
513 menu
->flags
.realized
= 0;
516 x
-= menu
->frame
->core
->width
/2;
517 if (x
+ menu
->frame
->core
->width
> scr
->scr_width
)
518 x
= scr
->scr_width
- menu
->frame
->core
->width
;
522 /* set client data */
523 for (i
= 0; i
< menu
->entry_no
; i
++) {
524 menu
->entries
[i
]->clientdata
= wapp
;
526 wMenuMapAt(menu
, x
, y
, False
);
530 /******************************************************************/
533 iconExpose(WObjDescriptor
*desc
, XEvent
*event
)
535 wAppIconPaint(desc
->parent
);
540 iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
542 WAppIcon
*aicon
= desc
->parent
;
544 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
547 assert(aicon
->icon
->owner
!=NULL
);
549 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
552 wwarning("could not find application descriptor for app icon!!");
557 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
559 /* go to the last workspace that the user worked on the app */
560 if (!unhideHere
&& wapp
->last_workspace
!= scr
->current_workspace
)
561 wWorkspaceChange(scr
, wapp
->last_workspace
);
563 wUnhideApplication(wapp
, event
->xbutton
.button
==Button2
, unhideHere
);
565 if (event
->xbutton
.state
& MOD_MASK
) {
566 wHideOtherApplications(aicon
->icon
->owner
);
573 appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
575 WAppIcon
*aicon
= desc
->parent
;
576 WIcon
*icon
= aicon
->icon
;
578 int x
=aicon
->x_pos
, y
=aicon
->y_pos
;
579 int dx
=event
->xbutton
.x
, dy
=event
->xbutton
.y
;
582 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
583 WScreen
*scr
= icon
->core
->screen_ptr
;
584 WWorkspace
*workspace
= scr
->workspaces
[scr
->current_workspace
];
585 int shad_x
= 0, shad_y
= 0, docking
=0, dockable
, collapsed
= 0;
587 int clickButton
= event
->xbutton
.button
;
590 Bool movingSingle
= False
;
594 if (aicon
->editing
|| WCHECK_STATE(WSTATE_MODAL
))
597 if (IsDoubleClick(scr
, event
)) {
598 iconDblClick(desc
, event
);
602 if (event
->xbutton
.button
== Button3
) {
603 WObjDescriptor
*desc
;
604 WApplication
*wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
609 if (event
->xbutton
.send_event
&&
610 XGrabPointer(dpy
, aicon
->icon
->core
->window
, True
, ButtonMotionMask
611 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
612 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
613 wwarning("pointer grab failed for appicon menu");
617 openApplicationMenu(wapp
, event
->xbutton
.x_root
,
618 event
->xbutton
.y_root
);
620 /* allow drag select of menu */
621 desc
= &scr
->icon_menu
->menu
->descriptor
;
622 event
->xbutton
.send_event
= True
;
623 (*desc
->handle_mousedown
)(desc
, event
);
630 if (event
->xbutton
.state
& MOD_MASK
)
631 wLowerFrame(icon
->core
);
633 wRaiseFrame(icon
->core
);
635 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
636 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
637 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
638 wwarning("pointer grab failed for appicon move");
641 if (wPreferences
.flags
.nodock
&& wPreferences
.flags
.noclip
)
644 dockable
= canBeDocked(icon
->owner
);
646 wins
[0] = icon
->core
->window
;
647 wins
[1] = scr
->dock_shadow
;
648 XRestackWindows(dpy
, wins
, 2);
650 if (icon
->pixmap
!=None
)
651 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
653 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
654 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
656 XClearWindow(dpy
, scr
->dock_shadow
);
660 WMMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
661 |ButtonMotionMask
|ExposureMask
, &ev
);
669 if (abs(dx
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
670 || abs(dy
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
671 XChangeActivePointerGrab(dpy
, ButtonMotionMask
672 |ButtonReleaseMask
|ButtonPressMask
,
673 wCursor
[WCUR_MOVE
], CurrentTime
);
679 x
= ev
.xmotion
.x_root
- dx
;
680 y
= ev
.xmotion
.y_root
- dy
;
683 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
685 wAppIconMove(aicon
, x
, y
);
689 if (scr
->dock
&& wDockSnapIcon(scr
->dock
, aicon
, x
, y
,
691 shad_x
= scr
->dock
->x_pos
+ ix
*wPreferences
.icon_size
;
692 shad_y
= scr
->dock
->y_pos
+ iy
*wPreferences
.icon_size
;
694 if (scr
->last_dock
!= scr
->dock
&& collapsed
) {
695 scr
->last_dock
->collapsed
= 1;
696 wDockHideIcons(scr
->last_dock
);
699 if (!collapsed
&& (collapsed
= scr
->dock
->collapsed
)) {
700 scr
->dock
->collapsed
= 0;
701 wDockShowIcons(scr
->dock
);
704 if (scr
->dock
->auto_raise_lower
)
705 wDockRaise(scr
->dock
);
707 scr
->last_dock
= scr
->dock
;
709 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
711 XMapWindow(dpy
, scr
->dock_shadow
);
714 } else if (workspace
->clip
&&
715 wDockSnapIcon(workspace
->clip
, aicon
, x
, y
,
717 shad_x
= workspace
->clip
->x_pos
+ ix
*wPreferences
.icon_size
;
718 shad_y
= workspace
->clip
->y_pos
+ iy
*wPreferences
.icon_size
;
720 if (scr
->last_dock
!= workspace
->clip
&& collapsed
) {
721 scr
->last_dock
->collapsed
= 1;
722 wDockHideIcons(scr
->last_dock
);
725 if (!collapsed
&& (collapsed
= workspace
->clip
->collapsed
)) {
726 workspace
->clip
->collapsed
= 0;
727 wDockShowIcons(workspace
->clip
);
730 if (workspace
->clip
->auto_raise_lower
)
731 wDockRaise(workspace
->clip
);
733 scr
->last_dock
= workspace
->clip
;
735 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
737 XMapWindow(dpy
, scr
->dock_shadow
);
740 } else if (docking
) {
741 XUnmapWindow(dpy
, scr
->dock_shadow
);
752 if (ev
.xbutton
.button
!= clickButton
)
754 XUngrabPointer(dpy
, CurrentTime
);
759 /* icon is trying to be docked */
760 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
761 XUnmapWindow(dpy
, scr
->dock_shadow
);
762 docked
= wDockAttachIcon(scr
->last_dock
, aicon
, ix
, iy
);
763 if (scr
->last_dock
->auto_collapse
) {
766 if (workspace
->clip
&&
767 workspace
->clip
!= scr
->last_dock
&&
768 workspace
->clip
->auto_raise_lower
)
769 wDockLower(workspace
->clip
);
772 /* If icon could not be docked, slide it back to the old
774 SlideWindow(icon
->core
->window
, x
, y
, oldX
, oldY
);
777 wSoundPlay(WSOUND_DOCK
);
780 /* move back to its place */
781 SlideWindow(icon
->core
->window
, x
, y
, oldX
, oldY
);
782 wAppIconMove(aicon
, oldX
, oldY
);
784 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
788 if (workspace
->clip
&& workspace
->clip
->auto_raise_lower
)
789 wDockLower(workspace
->clip
);
792 scr
->last_dock
->collapsed
= 1;
793 wDockHideIcons(scr
->last_dock
);
798 XFreePixmap(dpy
, ghost
);
799 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
802 if (wPreferences
.auto_arrange_icons
)
803 wArrangeIcons(scr
, True
);
810 puts("End icon move");