1 /* appicon.c- icon for applications (not mini-window)
3 * WindowMaker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 #include <X11/Xutil.h>
30 #include "WindowMaker.h"
40 #include "workspace.h"
41 #include "superfluous.h"
48 * icon_file for the dock is got from the preferences file by
49 * using the classname/instancename
52 /**** Global variables ****/
53 extern Cursor wCursor
[WCUR_LAST
];
54 extern WPreferences wPreferences
;
56 #define MOD_MASK wPreferences.modifier_mask
58 void appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
59 static void iconDblClick(WObjDescriptor
*desc
, XEvent
*event
);
60 static void iconExpose(WObjDescriptor
*desc
, XEvent
*event
);
65 wAppIconCreateForDock(WScreen
*scr
, char *command
, char *wm_instance
,
66 char *wm_class
, int tile
)
71 dicon
= wmalloc(sizeof(WAppIcon
));
73 memset(dicon
, 0, sizeof(WAppIcon
));
78 dicon
->next
= scr
->app_icon_list
;
79 if (scr
->app_icon_list
) {
80 scr
->app_icon_list
->prev
= dicon
;
82 scr
->app_icon_list
= dicon
;
85 dicon
->command
= wstrdup(command
);
88 dicon
->wm_class
= wstrdup(wm_class
);
90 dicon
->wm_instance
= wstrdup(wm_instance
);
92 path
= wDefaultGetIconFile(scr
, wm_instance
, wm_class
, True
);
93 if (!path
&& command
) {
94 wApplicationExtractDirPackIcon(scr
, command
, wm_instance
, wm_class
);
96 path
= wDefaultGetIconFile(scr
, wm_instance
, wm_class
, False
);
100 path
= FindImage(wPreferences
.icon_path
, path
);
102 dicon
->icon
= wIconCreateWithIconFile(scr
, path
, tile
);
105 #ifdef REDUCE_APPICONS
109 /* will be overriden by dock */
110 dicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
111 dicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
112 dicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
113 dicon
->icon
->core
->descriptor
.parent
= dicon
;
114 AddToStackList(dicon
->icon
->core
);
122 wAppIconCreate(WWindow
*leader_win
)
125 #ifdef REDUCE_APPICONS
127 WAppIconAppList
*applist
;
128 char *tinstance
, *tclass
;
130 WScreen
*scr
= leader_win
->screen_ptr
;
132 aicon
= wmalloc(sizeof(WAppIcon
));
134 memset(aicon
, 0, sizeof(WAppIcon
));
135 #ifdef REDUCE_APPICONS
136 applist
= wmalloc(sizeof(WAppIconAppList
));
137 memset(applist
, 0, sizeof(WAppIconAppList
));
138 applist
->wapp
= wApplicationOf(leader_win
->main_window
);
139 aicon
->applist
= applist
;
140 if (applist
->wapp
== NULL
) {
141 /* Something's wrong. wApplicationOf() should always return a
142 * valid structure. Rather than violate assumptions, bail. -cls
154 aicon
->next
= scr
->app_icon_list
;
155 if (scr
->app_icon_list
) {
156 #ifdef REDUCE_APPICONS
157 /* If we aren't going to have a match, jump straight to new appicon */
158 if (leader_win
->wm_class
== NULL
|| leader_win
->wm_class
== NULL
)
161 atmp
= scr
->app_icon_list
;
163 while (atmp
!= NULL
) {
164 if ((tinstance
= atmp
->wm_instance
) == NULL
)
166 if ((tclass
= atmp
->wm_class
) == NULL
)
168 if ((strcmp(leader_win
->wm_class
, tclass
) == 0) &&
169 (strcmp(leader_win
->wm_instance
, tinstance
) == 0))
171 /* We have a winner */
174 applist
->next
= atmp
->applist
;
176 atmp
->applist
->prev
= applist
;
177 atmp
->applist
= applist
;
180 wDockSimulateLaunch(atmp
->dock
, atmp
);
189 scr
->app_icon_list
->prev
= aicon
;
190 #ifdef REDUCE_APPICONS
194 scr
->app_icon_list
= aicon
;
196 if (leader_win
->wm_class
)
197 aicon
->wm_class
= wstrdup(leader_win
->wm_class
);
198 if (leader_win
->wm_instance
)
199 aicon
->wm_instance
= wstrdup(leader_win
->wm_instance
);
200 #ifdef REDUCE_APPICONS
204 aicon
->icon
= wIconCreate(leader_win
);
206 /* will be overriden if docked */
207 aicon
->icon
->core
->descriptor
.handle_mousedown
= appIconMouseDown
;
208 aicon
->icon
->core
->descriptor
.handle_expose
= iconExpose
;
209 aicon
->icon
->core
->descriptor
.parent_type
= WCLASS_APPICON
;
210 aicon
->icon
->core
->descriptor
.parent
= aicon
;
211 AddToStackList(aicon
->icon
->core
);
212 aicon
->icon
->show_title
= 0;
213 wIconUpdate(aicon
->icon
);
220 wAppIconDestroy(WAppIcon
*aicon
)
222 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
223 #ifdef REDUCE_APPICONS
224 WAppIconAppList
*aptmp
;
227 RemoveFromStackList(aicon
->icon
->core
);
228 wIconDestroy(aicon
->icon
);
230 free(aicon
->command
);
232 if (aicon
->dnd_command
)
233 free(aicon
->dnd_command
);
235 if (aicon
->wm_instance
)
236 free(aicon
->wm_instance
);
238 free(aicon
->wm_class
);
239 #ifdef REDUCE_APPICONS
240 /* There should never be a list but just in case */
241 if (aicon
->applist
!= NULL
) {
242 aptmp
= aicon
->applist
;
243 while (aptmp
->next
) {
251 if (aicon
== scr
->app_icon_list
) {
253 aicon
->next
->prev
= NULL
;
254 scr
->app_icon_list
= aicon
->next
;
258 aicon
->next
->prev
= aicon
->prev
;
260 aicon
->prev
->next
= aicon
->next
;
263 aicon
->destroyed
= 1;
271 drawCorner(WIcon
*icon
, WWindow
*wwin
, int active
)
273 WScreen
*scr
= wwin
->screen_ptr
;
284 gc
=scr
->focused_texture
->any
.gc
;
286 gc
=scr
->unfocused_texture
->any
.gc
;
288 XFillPolygon(dpy
, icon
->core
->window
, gc
, points
, 3,
289 Convex
, CoordModeOrigin
);
291 #endif /* NEWAPPICON */
295 wAppIconMove(WAppIcon
*aicon
, int x
, int y
)
297 XMoveWindow(dpy
, aicon
->icon
->core
->window
, x
, y
);
305 updateDockNumbers(WScreen
*scr
)
310 XGCValues my_gc_values
;
311 unsigned long my_v_mask
= (GCForeground
);
312 WAppIcon
*dicon
= scr
->dock
->icon_array
[0];
314 my_gc_values
.foreground
= scr
->white_pixel
;
315 numbers_gc
= XCreateGC(dpy
, dicon
->icon
->core
->window
,
316 my_v_mask
, &my_gc_values
);
318 ws_numbers
= malloc(20);
319 sprintf(ws_numbers
, "%i [ %i ]", scr
->current_workspace
+1,
320 ((scr
->current_workspace
/10)+1));
321 length
= strlen(ws_numbers
);
323 XClearArea(dpy
, dicon
->icon
->core
->window
, 2, 2, 50,
324 scr
->icon_title_font
->y
+1, False
);
327 XSetFont(dpy
, numbers_gc
, scr
->icon_title_font
->font
->fid
);
328 XSetForeground(dpy
, numbers_gc
, scr
->black_pixel
);
329 XDrawString(dpy
, dicon
->icon
->core
->window
,
330 numbers_gc
, 4, scr
->icon_title_font
->y
+3, ws_numbers
, length
);
331 XSetForeground(dpy
, numbers_gc
, scr
->white_pixel
);
332 XDrawString(dpy
, dicon
->icon
->core
->window
,
333 numbers_gc
, 3, scr
->icon_title_font
->y
+2, ws_numbers
, length
);
335 XSetForeground(dpy
, numbers_gc
, scr
->black_pixel
);
336 XmbDrawString(dpy
, dicon
->icon
->core
->window
,
337 scr
->icon_title_font
->font
, numbers_gc
, 4,
338 scr
->icon_title_font
->y
+3, ws_numbers
, length
);
339 XSetForeground(dpy
, numbers_gc
, scr
->white_pixel
);
340 XmbDrawString(dpy
, dicon
->icon
->core
->window
,
341 scr
->icon_title_font
->font
, numbers_gc
, 3,
342 scr
->icon_title_font
->y
+2, ws_numbers
, length
);
345 XFreeGC(dpy
, numbers_gc
);
348 #endif /* WS_INDICATOR */
352 wAppIconPaint(WAppIcon
*aicon
)
354 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
356 wIconPaint(aicon
->icon
);
360 if (aicon
->docked
&& scr
->dock
&& aicon
->yindex
==0)
361 updateDockNumbers(scr
);
363 if (scr
->dock_dots
&& aicon
->docked
&& !aicon
->running
364 && aicon
->command
!=NULL
) {
365 XSetClipMask(dpy
, scr
->copy_gc
, scr
->dock_dots
->mask
);
366 XSetClipOrigin(dpy
, scr
->copy_gc
, 0, 0);
367 XCopyArea(dpy
, scr
->dock_dots
->image
, aicon
->icon
->core
->window
,
368 scr
->copy_gc
, 0, 0, scr
->dock_dots
->width
,
369 scr
->dock_dots
->height
, 0, 0);
373 if (!wPreferences
.strict_ns
&& aicon
->icon
->owner
!=NULL
) {
375 if (aicon
->main_window
==None
) {
376 active
= (aicon
->icon
->owner
->flags
.focused
? 1 : 0);
380 wapp
= wApplicationOf(aicon
->main_window
);
382 active
= aicon
->icon
->owner
->flags
.focused
;
383 wwarning("error in wAppIconPaint(). Please report it");
385 active
= wapp
->main_window_desc
->flags
.focused
;
386 if (wapp
->main_window_desc
->flags
.hidden
387 || !wapp
->main_window_desc
->flags
.mapped
)
392 drawCorner(aicon
->icon
, aicon
->icon
->owner
, active
);
394 #endif /* NEWAPPICON */
396 XSetClipMask(dpy
, scr
->copy_gc
, None
);
397 if (aicon
->launching
) {
398 XFillRectangle(dpy
, aicon
->icon
->core
->window
, scr
->stipple_gc
,
399 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
);
405 #define canBeDocked(wwin) ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
407 #ifdef REDUCE_APPICONS
409 wAppIconReduceAppCount(WApplication
*wapp
)
411 WAppIconAppList
*applist
;
416 if (wapp
->app_icon
== NULL
)
419 /* If given a main window, check the applist
420 * and remove the if it exists
422 applist
= wapp
->app_icon
->applist
;
423 while (applist
!= NULL
) {
424 if (applist
->wapp
== wapp
) {
425 /* If this app owns the appicon, change the appicon's
426 * owner to the next app in the list or NULL
428 if (wapp
->app_icon
->icon
->owner
== applist
->wapp
->main_window_desc
)
431 wapp
->app_icon
->icon
->owner
= applist
->next
->wapp
->main_window_desc
;
432 } else if (applist
->prev
) {
433 wapp
->app_icon
->icon
->owner
= applist
->prev
->wapp
->main_window_desc
;
435 wapp
->app_icon
->icon
->owner
= NULL
;
439 applist
->prev
->next
= applist
->next
;
442 applist
->next
->prev
= applist
->prev
;
444 if (applist
== wapp
->app_icon
->applist
)
445 wapp
->app_icon
->applist
= applist
->next
;
449 if (wapp
->app_icon
->applist
!= NULL
)
450 wapp
->app_icon
->main_window
= wapp
->app_icon
->applist
->wapp
->main_window
;
452 return (--wapp
->app_icon
->num_apps
);
454 applist
= applist
->next
;
456 return (--wapp
->app_icon
->num_apps
);
462 hideCallback(WMenu
*menu
, WMenuEntry
*entry
)
464 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
466 if (wapp
->flags
.hidden
) {
467 wWorkspaceChange(menu
->menu
->screen_ptr
, wapp
->last_workspace
);
468 wUnhideApplication(wapp
, False
, False
);
470 wHideApplication(wapp
);
476 unhideHereCallback(WMenu
*menu
, WMenuEntry
*entry
)
478 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
480 wUnhideApplication(wapp
, False
, True
);
485 setIconCallback(WMenu
*menu
, WMenuEntry
*entry
)
487 WAppIcon
*icon
= ((WApplication
*)entry
->clientdata
)->app_icon
;
497 scr
= icon
->icon
->core
->screen_ptr
;
501 result
= wIconChooserDialog(scr
, &file
);
503 if (result
&& !icon
->destroyed
) {
508 if (!wIconChangeImageFile(icon
->icon
, file
)) {
509 wMessageDialog(scr
, _("Error"),
510 _("Could not open specified icon file"),
511 _("OK"), NULL
, NULL
);
513 wDefaultChangeIcon(scr
, icon
->wm_instance
, icon
->wm_class
, file
);
525 killCallback(WMenu
*menu
, WMenuEntry
*entry
)
527 WApplication
*wapp
= (WApplication
*)entry
->clientdata
;
528 assert(entry
->clientdata
!=NULL
);
530 wretain(wapp
->main_window_desc
);
531 if (wPreferences
.dont_confirm_kill
532 || wMessageDialog(menu
->frame
->screen_ptr
, _("Kill Application"),
533 _("This will kill the application.\nAny unsaved changes will be lost.\nPlease confirm."),
534 _("Yes"), _("No"), NULL
)==WAPRDefault
) {
535 if (!wapp
->main_window_desc
->flags
.destroyed
)
536 wClientKill(wapp
->main_window_desc
);
538 wrelease(wapp
->main_window_desc
);
543 createApplicationMenu(WScreen
*scr
)
547 menu
= wMenuCreate(scr
, NULL
, False
);
548 wMenuAddCallback(menu
, _("Unhide Here"), unhideHereCallback
, NULL
);
549 wMenuAddCallback(menu
, _("(Un)Hide"), hideCallback
, NULL
);
550 wMenuAddCallback(menu
, _("Set Icon..."), setIconCallback
, NULL
);
551 wMenuAddCallback(menu
, _("Kill"), killCallback
, NULL
);
558 openApplicationMenu(WApplication
*wapp
, int x
, int y
)
561 WScreen
*scr
= wapp
->main_window_desc
->screen_ptr
;
564 if (!scr
->icon_menu
) {
565 scr
->icon_menu
= createApplicationMenu(scr
);
568 menu
= scr
->icon_menu
;
569 if (!menu
->flags
.realized
)
572 x
-= menu
->frame
->core
->width
/2;
573 if (x
+ menu
->frame
->core
->width
> scr
->scr_width
)
574 x
= scr
->scr_width
- menu
->frame
->core
->width
;
578 /* set client data */
579 for (i
= 0; i
< menu
->entry_no
; i
++) {
580 menu
->entries
[i
]->clientdata
= wapp
;
582 wMenuMapAt(menu
, x
, y
, False
);
586 /******************************************************************/
589 iconExpose(WObjDescriptor
*desc
, XEvent
*event
)
591 wAppIconPaint(desc
->parent
);
595 iconDblClick(WObjDescriptor
*desc
, XEvent
*event
)
597 WAppIcon
*aicon
= desc
->parent
;
599 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
602 #ifndef REDUCE_APPICONS
603 assert(aicon
->icon
->owner
!=NULL
);
605 if (aicon
->icon
->owner
== NULL
) {
606 fprintf(stderr
, "Double-click disabled: missing main window.\n");
611 wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
614 wwarning("could not find application descriptor for app icon!!");
618 #ifdef REDUCE_APPICONS
620 fprintf(stderr
, "Double-click disabled: missing wapp.\n");
623 #endif /* REDUCE_APPICONS */
625 /* aproveita que ta aqui pra atualizar */
626 wapp
->main_window
= aicon
->icon
->owner
->main_window
;
629 unhideHere
= (event
->xbutton
.state
& ShiftMask
);
631 /* go to the last workspace that the user worked on the app */
633 wWorkspaceChange(scr
, wapp
->last_workspace
);
635 wUnhideApplication(wapp
, event
->xbutton
.button
==Button2
, unhideHere
);
637 if (event
->xbutton
.state
& MOD_MASK
) {
638 wHideOtherApplications(aicon
->icon
->owner
);
644 appIconMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
646 WAppIcon
*aicon
= desc
->parent
;
647 WIcon
*icon
= aicon
->icon
;
649 int x
=aicon
->x_pos
, y
=aicon
->y_pos
;
650 int dx
=event
->xbutton
.x
, dy
=event
->xbutton
.y
;
653 int superfluous
= wPreferences
.superfluous
; /* we catch it to avoid problems */
654 WScreen
*scr
= icon
->core
->screen_ptr
;
655 WWorkspace
*workspace
= scr
->workspaces
[scr
->current_workspace
];
656 int shad_x
= 0, shad_y
= 0, docking
=0, dockable
, collapsed
= 0;
658 int clickButton
= event
->xbutton
.button
;
661 if (IsDoubleClick(scr
, event
)) {
662 iconDblClick(desc
, event
);
666 if (event
->xbutton
.button
== Button3
) {
667 WObjDescriptor
*desc
;
668 WApplication
*wapp
= wApplicationOf(aicon
->icon
->owner
->main_window
);
670 openApplicationMenu(wapp
, event
->xbutton
.x_root
,
671 event
->xbutton
.y_root
);
673 /* allow drag select of menu */
674 desc
= &scr
->icon_menu
->menu
->descriptor
;
675 event
->xbutton
.send_event
= True
;
676 (*desc
->handle_mousedown
)(desc
, event
);
683 if (event
->xbutton
.state
& MOD_MASK
)
684 wLowerFrame(icon
->core
);
686 wRaiseFrame(icon
->core
);
689 if (XGrabPointer(dpy
, icon
->core
->window
, True
, ButtonMotionMask
690 |ButtonReleaseMask
|ButtonPressMask
, GrabModeAsync
,
691 GrabModeAsync
, None
, None
, CurrentTime
) !=GrabSuccess
) {
692 wwarning("pointer grab failed for appicon move");
695 if (wPreferences
.flags
.nodock
&& wPreferences
.flags
.noclip
)
698 dockable
= canBeDocked(icon
->owner
);
702 WMMaskEvent(dpy
, PointerMotionMask
|ButtonReleaseMask
|ButtonPressMask
703 |ButtonMotionMask
|ExposureMask
, &ev
);
711 if (abs(dx
-ev
.xmotion
.x
)>=MOVE_THRESHOLD
712 || abs(dy
-ev
.xmotion
.y
)>=MOVE_THRESHOLD
) {
713 XChangeActivePointerGrab(dpy
, ButtonMotionMask
714 |ButtonReleaseMask
|ButtonPressMask
,
715 wCursor
[WCUR_MOVE
], CurrentTime
);
721 x
= ev
.xmotion
.x_root
- dx
;
722 y
= ev
.xmotion
.y_root
- dy
;
723 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
726 if (scr
->dock
&& wDockSnapIcon(scr
->dock
, aicon
, x
, y
,
728 shad_x
= scr
->dock
->x_pos
+ ix
*wPreferences
.icon_size
;
729 shad_y
= scr
->dock
->y_pos
+ iy
*wPreferences
.icon_size
;
731 if (scr
->last_dock
!= scr
->dock
&& collapsed
) {
732 scr
->last_dock
->collapsed
= 1;
733 wDockHideIcons(scr
->last_dock
);
736 if (!collapsed
&& (collapsed
= scr
->dock
->collapsed
)) {
737 scr
->dock
->collapsed
= 0;
738 wDockShowIcons(scr
->dock
);
741 scr
->last_dock
= scr
->dock
;
743 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
747 wins
[0] = icon
->core
->window
;
748 wins
[1] = scr
->dock_shadow
;
749 XRestackWindows(dpy
, wins
, 2);
751 if (icon
->pixmap
!=None
)
752 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
754 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
755 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
757 XClearWindow(dpy
, scr
->dock_shadow
);
759 XMapWindow(dpy
, scr
->dock_shadow
);
762 } else if (workspace
->clip
&&
763 wDockSnapIcon(workspace
->clip
, aicon
, x
, y
,
765 shad_x
= workspace
->clip
->x_pos
+ ix
*wPreferences
.icon_size
;
766 shad_y
= workspace
->clip
->y_pos
+ iy
*wPreferences
.icon_size
;
768 if (scr
->last_dock
!= workspace
->clip
&& collapsed
) {
769 scr
->last_dock
->collapsed
= 1;
770 wDockHideIcons(scr
->last_dock
);
773 if (!collapsed
&& (collapsed
= workspace
->clip
->collapsed
)) {
774 workspace
->clip
->collapsed
= 0;
775 wDockShowIcons(workspace
->clip
);
778 scr
->last_dock
= workspace
->clip
;
780 XMoveWindow(dpy
, scr
->dock_shadow
, shad_x
, shad_y
);
784 wins
[0] = icon
->core
->window
;
785 wins
[1] = scr
->dock_shadow
;
786 XRestackWindows(dpy
, wins
, 2);
788 if (icon
->pixmap
!=None
)
789 ghost
= MakeGhostIcon(scr
, icon
->pixmap
);
791 ghost
= MakeGhostIcon(scr
, icon
->core
->window
);
792 XSetWindowBackgroundPixmap(dpy
, scr
->dock_shadow
,
794 XClearWindow(dpy
, scr
->dock_shadow
);
796 XMapWindow(dpy
, scr
->dock_shadow
);
799 } else if (docking
) {
800 XUnmapWindow(dpy
, scr
->dock_shadow
);
811 if (ev
.xbutton
.button
!= clickButton
)
813 XUngrabPointer(dpy
, CurrentTime
);
818 /* icon is trying to be docked */
819 SlideWindow(icon
->core
->window
, x
, y
, shad_x
, shad_y
);
820 XUnmapWindow(dpy
, scr
->dock_shadow
);
821 docked
= wDockAttachIcon(scr
->last_dock
, aicon
, ix
, iy
);
822 if (scr
->last_dock
->auto_collapse
) {
827 /* If icon could not be docked, slide it back to the old
829 SlideWindow(icon
->core
->window
, x
, y
, aicon
->x_pos
,
833 XMoveWindow(dpy
, icon
->core
->window
, x
, y
);
838 scr
->last_dock
->collapsed
= 1;
839 wDockHideIcons(scr
->last_dock
);
844 XFreePixmap(dpy
, ghost
);
845 XSetWindowBackground(dpy
, scr
->dock_shadow
, scr
->white_pixel
);
852 puts("End icon move");