1 /* window.c - client window managing stuffs
3 * Window Maker window manager
5 * Copyright (c) 1997-2002 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>
28 #include <X11/extensions/shape.h>
30 #ifdef KEEP_XKB_LOCK_STATUS
31 #include <X11/XKBlib.h>
32 #endif /* KEEP_XKB_LOCK_STATUS */
37 /* For getting mouse wheel mappings from WINGs */
38 #include <WINGs/WINGsP.h>
40 #include "WindowMaker.h"
46 #include "winspector.h"
48 #include "properties.h"
55 #include "workspace.h"
68 # include "openlook.h"
71 /****** Global Variables ******/
73 extern WShortKey wKeyBindings
[WKBD_LAST
];
76 extern Bool wShapeSupported
;
80 extern XContext wWinContext
;
83 extern Cursor wCursor
[WCUR_LAST
];
86 extern Atom _XA_WM_DELETE_WINDOW
;
87 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
89 extern Atom _XA_WINDOWMAKER_STATE
;
91 extern WPreferences wPreferences
;
93 #define MOD_MASK wPreferences.modifier_mask
95 extern Time LastTimestamp
;
98 extern void DoWindowBirth(WWindow
*);
102 /***** Local Stuff *****/
105 static WWindowState
*windowState
=NULL
;
109 /* local functions */
110 static FocusMode
getFocusMode(WWindow
*wwin
);
112 static int getSavedState(Window window
, WSavedState
**state
);
114 static void setupGNUstepHints(WWindow
*wwin
, GNUstepWMAttributes
*gs_hints
);
119 /* frame window (during window grabs) */
120 static void frameMouseDown(WObjDescriptor
*desc
, XEvent
*event
);
123 static void windowCloseClick(WCoreWindow
*sender
, void *data
, XEvent
*event
);
124 static void windowCloseDblClick(WCoreWindow
*sender
, void *data
, XEvent
*event
);
127 static void windowIconifyClick(WCoreWindow
*sender
, void *data
, XEvent
*event
);
129 #ifdef XKB_BUTTON_HINT
130 static void windowLanguageClick(WCoreWindow
*sender
, void *data
, XEvent
*event
);
133 static void titlebarMouseDown(WCoreWindow
*sender
, void *data
, XEvent
*event
);
134 static void titlebarDblClick(WCoreWindow
*sender
, void *data
, XEvent
*event
);
136 static void resizebarMouseDown(WCoreWindow
*sender
, void *data
, XEvent
*event
);
139 /****** Notification Observers ******/
142 appearanceObserver(void *self
, WMNotification
*notif
)
144 WWindow
*wwin
= (WWindow
*)self
;
145 int flags
= (int)WMGetNotificationClientData(notif
);
147 if (!wwin
->frame
|| (!wwin
->frame
->titlebar
&& !wwin
->frame
->resizebar
))
150 if (flags
& WFontSettings
) {
151 wWindowConfigureBorders(wwin
);
152 if(wwin
->flags
.shaded
) {
153 wFrameWindowResize(wwin
->frame
, wwin
->frame
->core
->width
,
154 wwin
->frame
->top_width
- 1);
156 wwin
->client
.y
= wwin
->frame_y
- wwin
->client
.height
157 + wwin
->frame
->top_width
;
158 wWindowSynthConfigureNotify(wwin
);
161 if (flags
& WTextureSettings
) {
162 wwin
->frame
->flags
.need_texture_remake
= 1;
164 if (flags
& (WTextureSettings
| WColorSettings
)) {
165 if (wwin
->frame
->titlebar
)
166 XClearWindow(dpy
, wwin
->frame
->titlebar
->window
);
168 wFrameWindowPaint(wwin
->frame
);
172 /************************************/
175 wWindowFor(Window window
)
177 WObjDescriptor
*desc
;
182 if (XFindContext(dpy
, window
, wWinContext
, (XPointer
*)&desc
)==XCNOENT
)
185 if (desc
->parent_type
==WCLASS_WINDOW
)
187 else if (desc
->parent_type
==WCLASS_FRAME
) {
188 WFrameWindow
*frame
= (WFrameWindow
*)desc
->parent
;
189 if (frame
->flags
.is_client_window_frame
)
202 wwin
= wmalloc(sizeof(WWindow
));
205 memset(wwin
, 0, sizeof(WWindow
));
207 wwin
->client_descriptor
.handle_mousedown
= frameMouseDown
;
208 wwin
->client_descriptor
.parent
= wwin
;
209 wwin
->client_descriptor
.self
= wwin
;
210 wwin
->client_descriptor
.parent_type
= WCLASS_WINDOW
;
217 wWindowDestroy(WWindow
*wwin
)
221 if (wwin
->screen_ptr
->cmap_window
== wwin
) {
222 wwin
->screen_ptr
->cmap_window
= NULL
;
225 WMRemoveNotificationObserver(wwin
);
227 wwin
->flags
.destroyed
= 1;
229 for (i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
230 if (!wwin
->screen_ptr
->shortcutWindows
[i
])
233 WMRemoveFromArray(wwin
->screen_ptr
->shortcutWindows
[i
], wwin
);
235 if (!WMGetArrayItemCount(wwin
->screen_ptr
->shortcutWindows
[i
])) {
236 WMFreeArray(wwin
->screen_ptr
->shortcutWindows
[i
]);
237 wwin
->screen_ptr
->shortcutWindows
[i
] = NULL
;
241 if (wwin
->fake_group
&& wwin
->fake_group
->retainCount
>0) {
242 wwin
->fake_group
->retainCount
--;
243 if (wwin
->fake_group
->retainCount
==0 && wwin
->fake_group
->leader
!=None
) {
244 XDestroyWindow(dpy
, wwin
->fake_group
->leader
);
245 wwin
->fake_group
->leader
= None
;
246 wwin
->fake_group
->origLeader
= None
;
251 if (wwin
->normal_hints
)
252 XFree(wwin
->normal_hints
);
255 XFree(wwin
->wm_hints
);
257 if (wwin
->wm_instance
)
258 XFree(wwin
->wm_instance
);
261 XFree(wwin
->wm_class
);
263 if (wwin
->wm_gnustep_attr
)
264 wfree(wwin
->wm_gnustep_attr
);
266 if (wwin
->cmap_windows
)
267 XFree(wwin
->cmap_windows
);
269 XDeleteContext(dpy
, wwin
->client_win
, wWinContext
);
272 wFrameWindowDestroy(wwin
->frame
);
275 RemoveFromStackList(wwin
->icon
->core
);
276 wIconDestroy(wwin
->icon
);
277 if (wPreferences
.auto_arrange_icons
)
278 wArrangeIcons(wwin
->screen_ptr
, True
);
287 setupGNUstepHints(WWindow
*wwin
, GNUstepWMAttributes
*gs_hints
)
289 if (gs_hints
->flags
& GSWindowStyleAttr
) {
290 if (gs_hints
->window_style
== WMBorderlessWindowMask
) {
291 wwin
->client_flags
.no_border
= 1;
292 wwin
->client_flags
.no_titlebar
= 1;
293 wwin
->client_flags
.no_closable
= 1;
294 wwin
->client_flags
.no_miniaturizable
= 1;
295 wwin
->client_flags
.no_resizable
= 1;
296 wwin
->client_flags
.no_close_button
= 1;
297 wwin
->client_flags
.no_miniaturize_button
= 1;
298 wwin
->client_flags
.no_resizebar
= 1;
300 wwin
->client_flags
.no_close_button
=
301 ((gs_hints
->window_style
& WMClosableWindowMask
)?0:1);
303 wwin
->client_flags
.no_closable
=
304 ((gs_hints
->window_style
& WMClosableWindowMask
)?0:1);
306 wwin
->client_flags
.no_miniaturize_button
=
307 ((gs_hints
->window_style
& WMMiniaturizableWindowMask
)?0:1);
309 wwin
->client_flags
.no_miniaturizable
=
310 wwin
->client_flags
.no_miniaturize_button
;
312 wwin
->client_flags
.no_resizebar
=
313 ((gs_hints
->window_style
& WMResizableWindowMask
)?0:1);
315 wwin
->client_flags
.no_resizable
= wwin
->client_flags
.no_resizebar
;
317 /* these attributes supposedly imply in the existence
319 if (gs_hints
->window_style
& (WMResizableWindowMask
|
320 WMClosableWindowMask
|
321 WMMiniaturizableWindowMask
)) {
322 wwin
->client_flags
.no_titlebar
= 0;
324 wwin
->client_flags
.no_titlebar
=
325 ((gs_hints
->window_style
& WMTitledWindowMask
)?0:1);
330 /* setup the defaults */
331 wwin
->client_flags
.no_border
= 0;
332 wwin
->client_flags
.no_titlebar
= 0;
333 wwin
->client_flags
.no_closable
= 0;
334 wwin
->client_flags
.no_miniaturizable
= 0;
335 wwin
->client_flags
.no_resizable
= 0;
336 wwin
->client_flags
.no_close_button
= 0;
337 wwin
->client_flags
.no_miniaturize_button
= 0;
338 wwin
->client_flags
.no_resizebar
= 0;
340 if (gs_hints
->extra_flags
& GSNoApplicationIconFlag
) {
341 wwin
->client_flags
.no_appicon
= 1;
347 wWindowCheckAttributeSanity(WWindow
*wwin
, WWindowAttributes
*wflags
,
348 WWindowAttributes
*mask
)
350 if (wflags
->no_appicon
&& mask
->no_appicon
)
351 wflags
->emulate_appicon
= 0;
353 if (wwin
->main_window
!=None
) {
354 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
355 if (wapp
&& !wapp
->flags
.emulated
)
356 wflags
->emulate_appicon
= 0;
359 if (wwin
->transient_for
!=None
360 && wwin
->transient_for
!=wwin
->screen_ptr
->root_win
)
361 wflags
->emulate_appicon
= 0;
363 if (wflags
->sunken
&& mask
->sunken
&& wflags
->floating
&& mask
->floating
)
370 wWindowSetupInitialAttributes(WWindow
*wwin
, int *level
, int *workspace
)
372 WScreen
*scr
= wwin
->screen_ptr
;
374 /* sets global default stuff */
375 wDefaultFillAttributes(scr
, wwin
->wm_instance
, wwin
->wm_class
,
376 &wwin
->client_flags
, NULL
, True
);
378 * Decoration setting is done in this precedence (lower to higher)
379 * - use global default in the resource database
380 * - guess some settings
381 * - use GNUstep/external window attributes
382 * - set hints specified for the app in the resource DB
385 WSETUFLAG(wwin
, broken_close
, 0);
387 if (wwin
->protocols
.DELETE_WINDOW
)
388 WSETUFLAG(wwin
, kill_close
, 0);
390 WSETUFLAG(wwin
, kill_close
, 1);
392 /* transients can't be iconified or maximized */
393 if (wwin
->transient_for
!=None
&& wwin
->transient_for
!=scr
->root_win
) {
394 WSETUFLAG(wwin
, no_miniaturizable
, 1);
395 WSETUFLAG(wwin
, no_miniaturize_button
, 1);
398 /* if the window can't be resized, remove the resizebar */
399 if (wwin
->normal_hints
->flags
& (PMinSize
|PMaxSize
)
400 && (wwin
->normal_hints
->min_width
==wwin
->normal_hints
->max_width
)
401 && (wwin
->normal_hints
->min_height
==wwin
->normal_hints
->max_height
)) {
402 WSETUFLAG(wwin
, no_resizable
, 1);
403 WSETUFLAG(wwin
, no_resizebar
, 1);
406 /* set GNUstep window attributes */
407 if (wwin
->wm_gnustep_attr
) {
408 setupGNUstepHints(wwin
, wwin
->wm_gnustep_attr
);
410 if (wwin
->wm_gnustep_attr
->flags
& GSWindowLevelAttr
) {
412 *level
= wwin
->wm_gnustep_attr
->window_level
;
414 * INT_MIN is the only illegal window level.
416 if (*level
== INT_MIN
)
417 *level
= INT_MIN
+ 1;
420 *level
= WMNormalLevel
;
423 int tmp_workspace
= -1;
424 int tmp_level
= INT_MIN
; /* INT_MIN is never used by the window levels */
430 wMWMCheckClientHints(wwin
);
431 #endif /* MWM_HINTS */
434 check
= wGNOMECheckClientHints(wwin
, &tmp_level
, &tmp_workspace
);
435 #endif /* GNOME_STUFF */
439 wKWMCheckClientHints(wwin
, &tmp_level
, &tmp_workspace
);
440 #endif /* KWM_HINTS */
443 wOLWMCheckClientHints(wwin
);
444 #endif /* OLWM_HINTS */
446 /* window levels are between INT_MIN+1 and INT_MAX, so if we still
447 * have INT_MIN that means that no window level was requested. -Dan
449 if (tmp_level
== INT_MIN
) {
450 if (WFLAGP(wwin
, floating
))
451 *level
= WMFloatingLevel
;
452 else if (WFLAGP(wwin
, sunken
))
453 *level
= WMSunkenLevel
;
455 *level
= WMNormalLevel
;
460 if (tmp_workspace
>= 0) {
461 *workspace
= tmp_workspace
% scr
->workspace_count
;
466 * Set attributes specified only for that window/class.
467 * This might do duplicate work with the 1st wDefaultFillAttributes().
469 wDefaultFillAttributes(scr
, wwin
->wm_instance
, wwin
->wm_class
,
470 &wwin
->user_flags
, &wwin
->defined_user_flags
,
473 * Sanity checks for attributes that depend on other attributes
475 if (wwin
->user_flags
.no_appicon
&& wwin
->defined_user_flags
.no_appicon
)
476 wwin
->user_flags
.emulate_appicon
= 0;
478 if (wwin
->main_window
!=None
) {
479 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
480 if (wapp
&& !wapp
->flags
.emulated
)
481 wwin
->user_flags
.emulate_appicon
= 0;
484 if (wwin
->transient_for
!=None
485 && wwin
->transient_for
!=wwin
->screen_ptr
->root_win
)
486 wwin
->user_flags
.emulate_appicon
= 0;
488 if (wwin
->user_flags
.sunken
&& wwin
->defined_user_flags
.sunken
489 && wwin
->user_flags
.floating
&& wwin
->defined_user_flags
.floating
)
490 wwin
->user_flags
.sunken
= 0;
492 WSETUFLAG(wwin
, no_shadeable
, WFLAGP(wwin
, no_titlebar
));
495 /* windows that have takefocus=False shouldn't take focus at all */
496 if (wwin
->focus_mode
== WFM_NO_INPUT
) {
497 /* dont use WSETUFLAG, since this was not an attribute change
498 * made by the user */
499 wwin
->user_flags
.no_focusable
= 1;
507 wWindowCanReceiveFocus(WWindow
*wwin
)
509 if (!wwin
->flags
.mapped
&& (!wwin
->flags
.shaded
|| wwin
->flags
.hidden
))
511 if (WFLAGP(wwin
, no_focusable
) || wwin
->flags
.miniaturized
)
513 if (wwin
->frame
->workspace
!= wwin
->screen_ptr
->current_workspace
)
521 wWindowObscuresWindow(WWindow
*wwin
, WWindow
*obscured
)
525 w1
= wwin
->frame
->core
->width
;
526 h1
= wwin
->frame
->core
->height
;
527 w2
= obscured
->frame
->core
->width
;
528 h2
= obscured
->frame
->core
->height
;
530 if (!IS_OMNIPRESENT(wwin
) && !IS_OMNIPRESENT(obscured
)
531 && wwin
->frame
->workspace
!= obscured
->frame
->workspace
)
534 if (wwin
->frame_x
+ w1
< obscured
->frame_x
535 || wwin
->frame_y
+ h1
< obscured
->frame_y
536 || wwin
->frame_x
> obscured
->frame_x
+ w2
537 || wwin
->frame_y
> obscured
->frame_y
+ h2
) {
546 createFakeWindowGroupLeader(WScreen
*scr
, Window win
, char *instance
, char *class)
548 XClassHint
*classHint
;
554 leader
= XCreateSimpleWindow(dpy
, scr
->root_win
, 10, 10, 10, 10, 0, 0, 0);
556 classHint
= XAllocClassHint();
557 classHint
->res_name
= instance
;
558 classHint
->res_class
= class;
559 XSetClassHint(dpy
, leader
, classHint
);
562 /* inherit these from the original leader if available */
563 hints
= XGetWMHints(dpy
, win
);
565 hints
= XAllocWMHints();
568 /* set window group leader to self */
569 hints
->window_group
= leader
;
570 hints
->flags
|= WindowGroupHint
;
571 XSetWMHints(dpy
, leader
, hints
);
574 if (XGetCommand(dpy
, win
, &argv
, &argc
)!=0 && argc
> 0) {
575 XSetCommand(dpy
, leader
, argv
, argc
);
576 XFreeStringList(argv
);
584 matchIdentifier(void *item
, void *cdata
)
586 return (strcmp(((WFakeGroupLeader
*)item
)->identifier
, (char*)cdata
)==0);
591 *----------------------------------------------------------------
593 * reparents the window and allocates a descriptor for it.
594 * Window manager hints and other hints are fetched to configure
595 * the window decoration attributes and others. User preferences
596 * for the window are used if available, to configure window
597 * decorations and some behaviour.
598 * If in startup, windows that are override redirect,
599 * unmapped and never were managed and are Withdrawn are not
603 * the new window descriptor
606 * The window is reparented and appropriate notification
607 * is done to the client. Input mask for the window is setup.
608 * The window descriptor is also associated with various window
609 * contexts and inserted in the head of the window list.
610 * Event handler contexts are associated for some objects
611 * (buttons, titlebar and resizebar)
613 *----------------------------------------------------------------
616 wManageWindow(WScreen
*scr
, Window window
)
620 unsigned width
, height
;
621 XWindowAttributes wattribs
;
622 XSetWindowAttributes attribs
;
623 WWindowState
*win_state
;
624 WWindow
*transientOwner
= NULL
;
630 Bool withdraw
= False
;
634 /* XGrabServer(dpy); */
636 /* make sure the window is still there */
637 if (!XGetWindowAttributes(dpy
, window
, &wattribs
)) {
642 /* if it's an override-redirect, ignore it */
643 if (wattribs
.override_redirect
) {
648 wm_state
= PropGetWindowState(window
);
650 /* if it's startup and the window is unmapped, don't manage it */
651 if (scr
->flags
.startup
&& wm_state
< 0 && wattribs
.map_state
==IsUnmapped
) {
656 if (!wFetchName(dpy
, window
, &title
)) {
661 if (title
&& !wKWMManageableClient(scr
, window
, title
)) {
666 #endif /* KWM_HINTS */
669 wwin
= wWindowCreate();
671 XSaveContext(dpy
, window
, wWinContext
, (XPointer
)&wwin
->client_descriptor
);
674 printf("managing window %x\n", (unsigned)window
);
678 if (wShapeSupported
) {
683 XShapeSelectInput(dpy
, window
, ShapeNotifyMask
);
684 XShapeQueryExtents(dpy
, window
, &b_shaped
, &junk
, &junk
, &ujunk
,
685 &ujunk
, &junk
, &junk
, &junk
, &ujunk
, &ujunk
);
686 wwin
->flags
.shaped
= b_shaped
;
691 *--------------------------------------------------
693 * Get hints and other information in properties
695 *--------------------------------------------------
697 PropGetWMClass(window
, &wwin
->wm_class
, &wwin
->wm_instance
);
699 /* setup descriptor */
700 wwin
->client_win
= window
;
701 wwin
->screen_ptr
= scr
;
703 wwin
->old_border_width
= wattribs
.border_width
;
705 wwin
->event_mask
= CLIENT_EVENTS
;
706 attribs
.event_mask
= CLIENT_EVENTS
;
707 attribs
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
;
708 attribs
.save_under
= False
;
709 XChangeWindowAttributes(dpy
, window
, CWEventMask
|CWDontPropagate
710 |CWSaveUnder
, &attribs
);
711 XSetWindowBorderWidth(dpy
, window
, 0);
713 /* get hints from GNUstep app */
714 if (wwin
->wm_class
!= 0 && strcmp(wwin
->wm_class
, "GNUstep") == 0) {
715 wwin
->flags
.is_gnustep
= 1;
717 if (!PropGetGNUstepWMAttr(window
, &wwin
->wm_gnustep_attr
)) {
718 wwin
->wm_gnustep_attr
= NULL
;
721 wwin
->client_leader
= PropGetClientLeader(window
);
722 if (wwin
->client_leader
!=None
)
723 wwin
->main_window
= wwin
->client_leader
;
725 wwin
->wm_hints
= XGetWMHints(dpy
, window
);
727 if (wwin
->wm_hints
) {
728 if (wwin
->wm_hints
->flags
& StateHint
) {
730 if (wwin
->wm_hints
->initial_state
== IconicState
) {
732 wwin
->flags
.miniaturized
= 1;
734 } else if (wwin
->wm_hints
->initial_state
== WithdrawnState
) {
740 if (wwin
->wm_hints
->flags
& WindowGroupHint
) {
741 wwin
->group_id
= wwin
->wm_hints
->window_group
;
742 /* window_group has priority over CLIENT_LEADER */
743 wwin
->main_window
= wwin
->group_id
;
745 wwin
->group_id
= None
;
748 if (wwin
->wm_hints
->flags
& UrgencyHint
)
749 wwin
->flags
.urgent
= 1;
751 wwin
->group_id
= None
;
754 PropGetProtocols(window
, &wwin
->protocols
);
756 if (!XGetTransientForHint(dpy
, window
, &wwin
->transient_for
)) {
757 wwin
->transient_for
= None
;
759 if (wwin
->transient_for
==None
|| wwin
->transient_for
==window
) {
760 wwin
->transient_for
= scr
->root_win
;
762 transientOwner
= wWindowFor(wwin
->transient_for
);
763 if (transientOwner
&& transientOwner
->main_window
!=None
) {
764 wwin
->main_window
= transientOwner
->main_window
;
766 wwin->main_window = None;
771 /* guess the focus mode */
772 wwin
->focus_mode
= getFocusMode(wwin
);
774 /* get geometry stuff */
775 wClientGetNormalHints(wwin
, &wattribs
, True
, &x
, &y
, &width
, &height
);
777 /* get colormap windows */
778 GetColormapWindows(wwin
);
781 *--------------------------------------------------
783 * Setup the decoration/window attributes and
786 *--------------------------------------------------
789 wWindowSetupInitialAttributes(wwin
, &window_level
, &workspace
);
792 if (wwin
->client_flags
.olwm_transient
&& wwin
->transient_for
==None
793 && wwin
->group_id
!= None
&& wwin
->group_id
!= window
) {
795 transientOwner
= wWindowFor(wwin
->group_id
);
797 if (transientOwner
) {
798 wwin
->transient_for
= wwin
->group_id
;
800 /* transients can't be iconified or maximized */
801 if (wwin
->transient_for
) {
802 WSETUFLAG(wwin
, no_miniaturizable
, 1);
803 WSETUFLAG(wwin
, no_miniaturize_button
, 1);
807 #endif /* OLWM_HINTS */
809 /* Make broken apps behave as a nice app. */
810 if (WFLAGP(wwin
, emulate_appicon
)) {
811 wwin
->main_window
= wwin
->client_win
;
814 wwin
->orig_main_window
= wwin
->main_window
;
816 if (wwin
->flags
.is_gnustep
) {
817 WSETUFLAG(wwin
, shared_appicon
, 0);
820 if (wwin
->main_window
) {
821 extern Atom _XA_WINDOWMAKER_MENU
;
822 XTextProperty text_prop
;
824 if (XGetTextProperty(dpy
, wwin
->main_window
, &text_prop
,
825 _XA_WINDOWMAKER_MENU
)) {
826 WSETUFLAG(wwin
, shared_appicon
, 0);
830 if (!withdraw
&& wwin
->main_window
&& WFLAGP(wwin
, shared_appicon
)) {
831 char *buffer
, *instance
, *class;
832 WFakeGroupLeader
*fPtr
;
835 #define ADEQUATE(x) ((x)!=None && (x)!=wwin->client_win && (x)!=fPtr->leader)
838 PropGetWMClass(wwin
->main_window
, &class, &instance
);
839 buffer
= StrConcatDot(instance
, class);
841 index
= WMFindInArray(scr
->fakeGroupLeaders
, matchIdentifier
, (void*)buffer
);
842 if (index
!= WANotFound
) {
843 fPtr
= WMGetFromArray(scr
->fakeGroupLeaders
, index
);
844 if (fPtr
->retainCount
== 0) {
845 fPtr
->leader
= createFakeWindowGroupLeader(scr
, wwin
->main_window
,
850 if (fPtr
->origLeader
==None
) {
852 if (ADEQUATE(wwin
->group_id
)) {
854 fPtr
->origLeader
= wwin
->group_id
;
855 } else if (ADEQUATE(wwin
->client_leader
)) {
857 fPtr
->origLeader
= wwin
->client_leader
;
858 } else if (ADEQUATE(wwin
->main_window
)) {
860 fPtr
->origLeader
= wwin
->main_window
;
863 if (ADEQUATE(wwin
->main_window
)) {
865 fPtr
->origLeader
= wwin
->main_window
;
869 wwin
->fake_group
= fPtr
;
870 /*wwin->group_id = fPtr->leader;*/
871 wwin
->main_window
= fPtr
->leader
;
874 fPtr
= (WFakeGroupLeader
*)wmalloc(sizeof(WFakeGroupLeader
));
876 fPtr
->identifier
= buffer
;
877 fPtr
->leader
= createFakeWindowGroupLeader(scr
, wwin
->main_window
,
879 fPtr
->origLeader
= None
;
880 fPtr
->retainCount
= 1;
882 WMAddToArray(scr
->fakeGroupLeaders
, fPtr
);
885 if (ADEQUATE(wwin
->group_id
)) {
887 fPtr
->origLeader
= wwin
->group_id
;
888 } else if (ADEQUATE(wwin
->client_leader
)) {
890 fPtr
->origLeader
= wwin
->client_leader
;
891 } else if (ADEQUATE(wwin
->main_window
)) {
893 fPtr
->origLeader
= wwin
->main_window
;
896 if (ADEQUATE(wwin
->main_window
)) {
898 fPtr
->origLeader
= wwin
->main_window
;
901 wwin
->fake_group
= fPtr
;
902 /*wwin->group_id = fPtr->leader;*/
903 wwin
->main_window
= fPtr
->leader
;
915 *------------------------------------------------------------
917 * Setup the initial state of the window
919 *------------------------------------------------------------
922 if (WFLAGP(wwin
, start_miniaturized
) && !WFLAGP(wwin
, no_miniaturizable
)) {
923 wwin
->flags
.miniaturized
= 1;
926 if (WFLAGP(wwin
, start_maximized
) && !WFLAGP(wwin
, no_resizable
)) {
927 wwin
->flags
.maximized
= MAX_VERTICAL
|MAX_HORIZONTAL
;
935 bla
= wGNOMECheckInitialClientState(wwin
);
939 wKWMCheckClientInitialState(wwin
);
943 /* apply previous state if it exists and we're in startup */
944 if (scr
->flags
.startup
&& wm_state
>= 0) {
946 if (wm_state
== IconicState
) {
948 wwin
->flags
.miniaturized
= 1;
950 } else if (wm_state
== WithdrawnState
) {
956 /* if there is a saved state (from file), restore it */
958 if (wwin
->main_window
!=None
/* && wwin->main_window!=window*/) {
959 win_state
= (WWindowState
*)wWindowGetSavedState(wwin
->main_window
);
961 win_state
= (WWindowState
*)wWindowGetSavedState(window
);
963 if (win_state
&& !withdraw
) {
965 if (win_state
->state
->hidden
>0)
966 wwin
->flags
.hidden
= win_state
->state
->hidden
;
968 if (win_state
->state
->shaded
>0 && !WFLAGP(wwin
, no_shadeable
))
969 wwin
->flags
.shaded
= win_state
->state
->shaded
;
971 if (win_state
->state
->miniaturized
>0 &&
972 !WFLAGP(wwin
, no_miniaturizable
)) {
973 wwin
->flags
.miniaturized
= win_state
->state
->miniaturized
;
976 if (!IS_OMNIPRESENT(wwin
)) {
977 int w
= wDefaultGetStartWorkspace(scr
, wwin
->wm_instance
,
979 if (w
< 0 || w
>= scr
->workspace_count
) {
980 workspace
= win_state
->state
->workspace
;
981 if (workspace
>= scr
->workspace_count
)
982 workspace
= scr
->current_workspace
;
987 workspace
= scr
->current_workspace
;
991 /* if we're restarting, restore saved state (from hints).
992 * This will overwrite previous */
996 if (getSavedState(window
, &wstate
)) {
997 wwin
->flags
.shaded
= wstate
->shaded
;
998 wwin
->flags
.hidden
= wstate
->hidden
;
999 wwin
->flags
.miniaturized
= wstate
->miniaturized
;
1000 wwin
->flags
.maximized
= wstate
->maximized
;
1001 if (wwin
->flags
.maximized
) {
1002 wwin
->old_geometry
.x
= wstate
->x
;
1003 wwin
->old_geometry
.y
= wstate
->y
;
1004 wwin
->old_geometry
.width
= wstate
->w
;
1005 wwin
->old_geometry
.height
= wstate
->h
;
1008 workspace
= wstate
->workspace
;
1013 /* restore window shortcut */
1014 if (wstate
!= NULL
|| win_state
!= NULL
) {
1017 if (win_state
!= NULL
)
1018 mask
= win_state
->state
->window_shortcuts
;
1020 if (wstate
!= NULL
&& mask
== 0)
1021 mask
= wstate
->window_shortcuts
;
1026 for (i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
1027 if (mask
& (1<<i
)) {
1028 if (!scr
->shortcutWindows
[i
])
1029 scr
->shortcutWindows
[i
] = WMCreateArray(4);
1031 WMAddToArray(scr
->shortcutWindows
[i
], wwin
);
1036 if (wstate
!= NULL
) {
1041 /* don't let transients start miniaturized if their owners are not */
1042 if (transientOwner
&& !transientOwner
->flags
.miniaturized
1043 && wwin
->flags
.miniaturized
&& !withdraw
) {
1044 wwin
->flags
.miniaturized
= 0;
1046 wwin
->wm_hints
->initial_state
= NormalState
;
1049 /* set workspace on which the window starts */
1050 if (workspace
>= 0) {
1051 if (workspace
> scr
->workspace_count
-1) {
1052 workspace
= workspace
% scr
->workspace_count
;
1057 w
= wDefaultGetStartWorkspace(scr
, wwin
->wm_instance
, wwin
->wm_class
);
1059 if (w
>= 0 && w
< scr
->workspace_count
&& !(IS_OMNIPRESENT(wwin
))) {
1064 if (wPreferences
.open_transients_with_parent
&& transientOwner
) {
1066 workspace
= transientOwner
->frame
->workspace
;
1070 workspace
= scr
->current_workspace
;
1075 /* setup window geometry */
1076 if (win_state
&& win_state
->state
->w
> 0) {
1077 width
= win_state
->state
->w
;
1078 height
= win_state
->state
->h
;
1080 wWindowConstrainSize(wwin
, &width
, &height
);
1082 /* do not ask for window placement if the window is
1083 * transient, during startup, if the initial workspace is another one
1084 * or if the window wants to start iconic.
1085 * If geometry was saved, restore it. */
1087 Bool dontBring
= False
;
1089 if (win_state
&& win_state
->state
->w
> 0) {
1090 x
= win_state
->state
->x
;
1091 y
= win_state
->state
->y
;
1092 } else if ((wwin
->transient_for
==None
1093 || wPreferences
.window_placement
!=WPM_MANUAL
)
1094 && !scr
->flags
.startup
1095 && workspace
== scr
->current_workspace
1096 && !wwin
->flags
.miniaturized
1097 && !wwin
->flags
.maximized
1098 && !(wwin
->normal_hints
->flags
& (USPosition
|PPosition
))) {
1100 if (transientOwner
&& transientOwner
->flags
.mapped
) {
1101 int offs
= WMAX(20, 2*transientOwner
->frame
->top_width
);
1103 x
= transientOwner
->frame_x
+
1104 abs((transientOwner
->frame
->core
->width
- width
)/2) + offs
;
1105 y
= transientOwner
->frame_y
+
1106 abs((transientOwner
->frame
->core
->height
- height
)/3) + offs
;
1110 else if (x
+ width
> scr
->scr_width
)
1111 x
= scr
->scr_width
- width
;
1115 else if (y
+ height
> scr
->scr_height
)
1116 y
= scr
->scr_height
- height
;
1118 PlaceWindow(wwin
, &x
, &y
, width
, height
);
1120 if (wPreferences
.window_placement
== WPM_MANUAL
)
1124 if (WFLAGP(wwin
, dont_move_off
) && dontBring
)
1125 wScreenBringInside(scr
, &x
, &y
, width
, height
);
1128 if (wwin
->flags
.urgent
) {
1129 if (!IS_OMNIPRESENT(wwin
))
1130 wwin
->flags
.omnipresent
^= 1;
1134 *--------------------------------------------------
1136 * Create frame, borders and do reparenting
1138 *--------------------------------------------------
1140 foo
= WFF_LEFT_BUTTON
| WFF_RIGHT_BUTTON
;
1141 #ifdef XKB_BUTTON_HINT
1142 if (wPreferences
.modelock
)
1143 foo
|= WFF_LANGUAGE_BUTTON
;
1145 if (!WFLAGP(wwin
, no_titlebar
))
1146 foo
|= WFF_TITLEBAR
;
1147 if (!WFLAGP(wwin
, no_resizebar
))
1148 foo
|= WFF_RESIZEBAR
;
1149 if (!WFLAGP(wwin
, no_border
))
1152 wwin
->frame
= wFrameWindowCreate(scr
, window_level
,
1153 x
, y
, width
, height
,
1154 &wPreferences
.window_title_clearance
, foo
,
1155 scr
->window_title_texture
,
1156 scr
->resizebar_texture
,
1157 scr
->window_title_pixel
,
1160 wwin
->frame
->flags
.is_client_window_frame
= 1;
1161 wwin
->frame
->flags
.justification
= wPreferences
.title_justification
;
1163 /* setup button images */
1164 wWindowUpdateButtonImages(wwin
);
1166 /* hide unused buttons */
1168 if (WFLAGP(wwin
, no_close_button
))
1169 foo
|= WFF_RIGHT_BUTTON
;
1170 if (WFLAGP(wwin
, no_miniaturize_button
))
1171 foo
|= WFF_LEFT_BUTTON
;
1172 #ifdef XKB_BUTTON_HINT
1173 if (WFLAGP(wwin
, no_language_button
) || WFLAGP(wwin
, no_focusable
))
1174 foo
|= WFF_LANGUAGE_BUTTON
;
1177 wFrameWindowHideButton(wwin
->frame
, foo
);
1179 wwin
->frame
->child
= wwin
;
1182 /* emulate olwm push pin. Make the button look as pushed-in for
1183 * the pinned-out state. When the button is clicked, it will
1184 * revert to the normal position, which means the pin is pinned-in.
1186 if (wwin
->flags
.olwm_push_pin_out
)
1187 wFrameWindowUpdatePushButton(wwin
->frame
, True
);
1188 #endif /* OLWM_HINTS */
1191 wwin
->frame
->workspace
= workspace
;
1193 wwin
->frame
->on_click_left
= windowIconifyClick
;
1194 #ifdef XKB_BUTTON_HINT
1195 if (wPreferences
.modelock
)
1196 wwin
->frame
->on_click_language
= windowLanguageClick
;
1199 wwin
->frame
->on_click_right
= windowCloseClick
;
1200 wwin
->frame
->on_dblclick_right
= windowCloseDblClick
;
1202 wwin
->frame
->on_mousedown_titlebar
= titlebarMouseDown
;
1203 wwin
->frame
->on_dblclick_titlebar
= titlebarDblClick
;
1205 wwin
->frame
->on_mousedown_resizebar
= resizebarMouseDown
;
1208 XSelectInput(dpy
, wwin
->client_win
,
1209 wwin
->event_mask
& ~StructureNotifyMask
);
1211 XReparentWindow(dpy
, wwin
->client_win
, wwin
->frame
->core
->window
,
1212 0, wwin
->frame
->top_width
);
1214 XSelectInput(dpy
, wwin
->client_win
, wwin
->event_mask
);
1220 wClientGetGravityOffsets(wwin
, &gx
, &gy
);
1222 /* if gravity is to the south, account for the border sizes */
1224 y
-= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
1228 * wWindowConfigure() will init the client window's size
1229 * (wwin->client.{width,height}) and all other geometry
1230 * related variables (frame_x,frame_y)
1232 wWindowConfigure(wwin
, x
, y
, width
, height
);
1234 /* to make sure the window receives it's new position after reparenting */
1235 wWindowSynthConfigureNotify(wwin
);
1238 *--------------------------------------------------
1240 * Setup descriptors and save window to internal
1243 *--------------------------------------------------
1246 if (wwin
->main_window
!=None
) {
1250 /* Leader windows do not necessary set themselves as leaders.
1251 * If this is the case, point the leader of this window to
1253 leader
= wWindowFor(wwin
->main_window
);
1254 if (leader
&& leader
->main_window
==None
) {
1255 leader
->main_window
= leader
->client_win
;
1257 app
= wApplicationCreate(scr
, wwin
->main_window
);
1259 app
->last_workspace
= workspace
;
1261 app
->main_window_desc
->fake_group
= wwin
->fake_group
;
1264 * Do application specific stuff, like setting application
1268 if (wwin
->flags
.hidden
) {
1269 /* if the window was set to hidden because it was hidden
1270 * in a previous incarnation and that state was restored */
1271 app
->flags
.hidden
= 1;
1272 } else if (app
->flags
.hidden
) {
1273 if (WFLAGP(app
->main_window_desc
, start_hidden
)) {
1274 wwin
->flags
.hidden
= 1;
1276 wUnhideApplication(app
, False
, False
);
1283 /* setup the frame descriptor */
1284 wwin
->frame
->core
->descriptor
.handle_mousedown
= frameMouseDown
;
1285 wwin
->frame
->core
->descriptor
.parent
= wwin
;
1286 wwin
->frame
->core
->descriptor
.parent_type
= WCLASS_WINDOW
;
1288 /* don't let windows go away if we die */
1289 XAddToSaveSet(dpy
, window
);
1291 XLowerWindow(dpy
, window
);
1293 /* if window is in this workspace and should be mapped, then map it */
1294 if (!wwin
->flags
.miniaturized
1295 && (workspace
== scr
->current_workspace
|| IS_OMNIPRESENT(wwin
))
1296 && !wwin
->flags
.hidden
&& !withdraw
) {
1298 /* The following "if" is to avoid crashing of clients that expect
1299 * WM_STATE set before they get mapped. Else WM_STATE is set later,
1300 * after the return from this function.
1302 if (wwin
->wm_hints
&& (wwin
->wm_hints
->flags
& StateHint
)) {
1303 wClientSetState(wwin
, wwin
->wm_hints
->initial_state
, None
);
1305 wClientSetState(wwin
, NormalState
, None
);
1309 /* if not auto focus, then map the window under the currently
1311 #define _WIDTH(w) (w)->frame->core->width
1312 #define _HEIGHT(w) (w)->frame->core->height
1313 if (!wPreferences
.auto_focus
&& scr
->focused_window
1314 && !scr
->flags
.startup
&& !transientOwner
1315 && ((wWindowObscuresWindow(wwin
, scr
->focused_window
)
1316 && (_WIDTH(wwin
) > (_WIDTH(scr
->focused_window
)*5)/3
1317 || _HEIGHT(wwin
) > (_HEIGHT(scr
->focused_window
)*5)/3)
1318 && WINDOW_LEVEL(scr
->focused_window
) == WINDOW_LEVEL(wwin
))
1319 || wwin
->flags
.maximized
)) {
1320 MoveInStackListUnder(scr
->focused_window
->frame
->core
,
1328 if (wPreferences
.superfluous
&& !wPreferences
.no_animations
1329 && !scr
->flags
.startup
&&
1330 (wwin
->transient_for
==None
|| wwin
->transient_for
==scr
->root_win
)
1332 * The brain damaged idiotic non-click to focus modes will
1333 * have trouble with this because:
1335 * 1. window is created and mapped by the client
1336 * 2. window is mapped by wmaker in small size
1337 * 3. window is animated to grow to normal size
1338 * 4. this function returns to normal event loop
1339 * 5. eventually, the EnterNotify event that would trigger
1340 * the window focusing (if the mouse is over that window)
1341 * will be processed by wmaker.
1342 * But since this event will be rather delayed
1343 * (step 3 has a large delay) the time when the event ocurred
1344 * and when it is processed, the client that owns that window
1345 * will reject the XSetInputFocus() for it.
1347 && (wPreferences
.focus_mode
==WKF_CLICK
1348 || wPreferences
.auto_focus
)) {
1349 DoWindowBirth(wwin
);
1355 /* setup stacking descriptor */
1356 if (transientOwner
) {
1357 wwin
->frame
->core
->stacking
->child_of
= transientOwner
->frame
->core
;
1359 wwin
->frame
->core
->stacking
->child_of
= NULL
;
1363 if (!scr
->focused_window
) {
1364 /* first window on the list */
1367 scr
->focused_window
= wwin
;
1371 /* add window at beginning of focus window list */
1372 tmp
= scr
->focused_window
;
1380 /* raise is set to true if we un-hid the app when this window was born.
1381 * we raise, else old windows of this app will be above this new one. */
1383 wRaiseFrame(wwin
->frame
->core
);
1386 /* Update name must come after WApplication stuff is done */
1387 wWindowUpdateName(wwin
, title
);
1394 *--------------------------------------------------
1396 * Final preparations before window is ready to go
1398 *--------------------------------------------------
1401 wFrameWindowChangeState(wwin
->frame
, WS_UNFOCUSED
);
1404 if (!wwin
->flags
.miniaturized
&& workspace
== scr
->current_workspace
1405 && !wwin
->flags
.hidden
) {
1406 if (((transientOwner
&& transientOwner
->flags
.focused
)
1407 || wPreferences
.auto_focus
) && !WFLAGP(wwin
, no_focusable
))
1408 wSetFocusTo(scr
, wwin
);
1410 wWindowResetMouseGrabs(wwin
);
1412 if (!WFLAGP(wwin
, no_bind_keys
)) {
1413 wWindowSetKeyGrabs(wwin
);
1417 WMPostNotificationName(WMNManaged
, wwin
, NULL
);
1420 wColormapInstallForWindow(scr
, scr
->cmap_window
);
1424 if (wwin
->client_flags
.olwm_warp_to_pin
&& wwin
->frame
->titlebar
!= NULL
1425 && !WFLAGP(wwin
, no_close_button
) && !withdraw
) {
1427 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0,
1428 wwin
->frame_x
+ width
- wwin
->frame
->titlebar
->height
* 2,
1434 *------------------------------------------------------------
1435 * Setup Notification Observers
1436 *------------------------------------------------------------
1438 WMAddNotificationObserver(appearanceObserver
, wwin
,
1439 WNWindowAppearanceSettingsChanged
, wwin
);
1443 *--------------------------------------------------
1445 * Cleanup temporary stuff
1447 *--------------------------------------------------
1451 wWindowDeleteSavedState(win_state
);
1453 /* If the window must be withdrawed, then do it now.
1454 * Must do some optimization, 'though */
1456 wwin
->flags
.mapped
= 0;
1457 wClientSetState(wwin
, WithdrawnState
, None
);
1458 wUnmanageWindow(wwin
, True
, False
);
1470 wManageInternalWindow(WScreen
*scr
, Window window
, Window owner
,
1471 char *title
, int x
, int y
, int width
, int height
)
1476 wwin
= wWindowCreate();
1478 WMAddNotificationObserver(appearanceObserver
, wwin
,
1479 WNWindowAppearanceSettingsChanged
, wwin
);
1481 wwin
->flags
.internal_window
= 1;
1483 WSETUFLAG(wwin
, omnipresent
, 1);
1484 WSETUFLAG(wwin
, no_shadeable
, 1);
1485 WSETUFLAG(wwin
, no_resizable
, 1);
1486 WSETUFLAG(wwin
, no_miniaturizable
, 1);
1488 wwin
->focus_mode
= WFM_PASSIVE
;
1490 wwin
->client_win
= window
;
1491 wwin
->screen_ptr
= scr
;
1493 wwin
->transient_for
= owner
;
1497 wwin
->client
.width
= width
;
1498 wwin
->client
.height
= height
;
1500 wwin
->frame_x
= wwin
->client
.x
;
1501 wwin
->frame_y
= wwin
->client
.y
;
1504 foo
= WFF_RIGHT_BUTTON
|WFF_BORDER
;
1505 foo
|= WFF_TITLEBAR
;
1506 #ifdef XKB_BUTTON_HINT
1507 foo
|= WFF_LANGUAGE_BUTTON
;
1510 wwin
->frame
= wFrameWindowCreate(scr
, WMFloatingLevel
,
1511 wwin
->frame_x
, wwin
->frame_y
,
1513 &wPreferences
.window_title_clearance
, foo
,
1514 scr
->window_title_texture
,
1515 scr
->resizebar_texture
,
1516 scr
->window_title_pixel
,
1519 XSaveContext(dpy
, window
, wWinContext
, (XPointer
)&wwin
->client_descriptor
);
1521 wwin
->frame
->flags
.is_client_window_frame
= 1;
1522 wwin
->frame
->flags
.justification
= wPreferences
.title_justification
;
1524 wFrameWindowChangeTitle(wwin
->frame
, title
);
1526 /* setup button images */
1527 wWindowUpdateButtonImages(wwin
);
1530 wFrameWindowHideButton(wwin
->frame
, WFF_RIGHT_BUTTON
);
1532 wwin
->frame
->child
= wwin
;
1534 wwin
->frame
->workspace
= wwin
->screen_ptr
->current_workspace
;
1536 #ifdef XKB_BUTTON_HINT
1537 if (wPreferences
.modelock
)
1538 wwin
->frame
->on_click_language
= windowLanguageClick
;
1541 wwin
->frame
->on_click_right
= windowCloseClick
;
1543 wwin
->frame
->on_mousedown_titlebar
= titlebarMouseDown
;
1544 wwin
->frame
->on_dblclick_titlebar
= titlebarDblClick
;
1546 wwin
->frame
->on_mousedown_resizebar
= resizebarMouseDown
;
1548 wwin
->client
.y
+= wwin
->frame
->top_width
;
1549 XReparentWindow(dpy
, wwin
->client_win
, wwin
->frame
->core
->window
,
1550 0, wwin
->frame
->top_width
);
1552 wWindowConfigure(wwin
, wwin
->frame_x
, wwin
->frame_y
,
1553 wwin
->client
.width
, wwin
->client
.height
);
1555 /* setup the frame descriptor */
1556 wwin
->frame
->core
->descriptor
.handle_mousedown
= frameMouseDown
;
1557 wwin
->frame
->core
->descriptor
.parent
= wwin
;
1558 wwin
->frame
->core
->descriptor
.parent_type
= WCLASS_WINDOW
;
1561 XLowerWindow(dpy
, window
);
1562 XMapSubwindows(dpy
, wwin
->frame
->core
->window
);
1564 /* setup stacking descriptor */
1565 if (wwin
->transient_for
!=None
&& wwin
->transient_for
!=scr
->root_win
) {
1567 tmp
= wWindowFor(wwin
->transient_for
);
1569 wwin
->frame
->core
->stacking
->child_of
= tmp
->frame
->core
;
1571 wwin
->frame
->core
->stacking
->child_of
= NULL
;
1575 if (!scr
->focused_window
) {
1576 /* first window on the list */
1579 scr
->focused_window
= wwin
;
1583 /* add window at beginning of focus window list */
1584 tmp
= scr
->focused_window
;
1592 if (wwin
->flags
.is_gnustep
== 0)
1593 wFrameWindowChangeState(wwin
->frame
, WS_UNFOCUSED
);
1595 /* if (wPreferences.auto_focus)*/
1596 wSetFocusTo(scr
, wwin
);
1598 wWindowResetMouseGrabs(wwin
);
1600 wWindowSetKeyGrabs(wwin
);
1607 *----------------------------------------------------------------------
1609 * Removes the frame window from a window and destroys all data
1610 * related to it. The window will be reparented back to the root window
1611 * if restore is True.
1614 * Everything related to the window is destroyed and the window
1615 * is removed from the window lists. Focus is set to the previous on the
1617 *----------------------------------------------------------------------
1620 wUnmanageWindow(WWindow
*wwin
, Bool restore
, Bool destroyed
)
1622 WCoreWindow
*frame
= wwin
->frame
->core
;
1623 WWindow
*owner
= NULL
;
1624 WWindow
*newFocusedWindow
= NULL
;
1626 WScreen
*scr
= wwin
->screen_ptr
;
1629 /* First close attribute editor window if open */
1630 if (wwin
->flags
.inspector_open
) {
1631 wCloseInspectorForWindow(wwin
);
1634 /* Close window menu if it's open for this window */
1635 if (wwin
->flags
.menu_open_for_me
) {
1636 CloseWindowMenu(scr
);
1640 if (!wwin
->flags
.internal_window
)
1641 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
1643 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
1645 XUngrabButton(dpy
, AnyButton
, AnyModifier
, wwin
->client_win
);
1646 XUngrabKey(dpy
, AnyKey
, AnyModifier
, wwin
->client_win
);
1649 XUnmapWindow(dpy
, frame
->window
);
1651 XUnmapWindow(dpy
, wwin
->client_win
);
1653 /* deselect window */
1654 wSelectWindow(wwin
, False
);
1656 /* remove all pending events on window */
1657 /* I think this only matters for autoraise */
1658 if (wPreferences
.raise_delay
)
1659 WMDeleteTimerWithClientData(wwin
->frame
->core
);
1663 /* reparent the window back to the root */
1665 wClientRestore(wwin
);
1667 if (wwin
->transient_for
!=scr
->root_win
) {
1668 owner
= wWindowFor(wwin
->transient_for
);
1670 if (!owner
->flags
.semi_focused
) {
1673 owner
->flags
.semi_focused
= 0;
1678 wasFocused
= wwin
->flags
.focused
;
1680 /* remove from window focus list */
1681 if (!wwin
->prev
&& !wwin
->next
) {
1682 /* was the only window */
1683 scr
->focused_window
= NULL
;
1684 newFocusedWindow
= NULL
;
1689 wwin
->prev
->next
= wwin
->next
;
1691 wwin
->next
->prev
= wwin
->prev
;
1693 scr
->focused_window
= wwin
->prev
;
1694 scr
->focused_window
->next
= NULL
;
1697 if (wPreferences
.focus_mode
==WKF_CLICK
) {
1699 /* if in click to focus mode and the window
1700 * was a transient, focus the owner window
1703 if (wPreferences
.focus_mode
==WKF_CLICK
) {
1704 tmp
= wWindowFor(wwin
->transient_for
);
1705 if (tmp
&& (!tmp
->flags
.mapped
|| WFLAGP(tmp
, no_focusable
))) {
1709 /* otherwise, focus the next one in the focus list */
1711 tmp
= scr
->focused_window
;
1712 while (tmp
) { /* look for one in the window list first */
1713 if (!WFLAGP(tmp
, no_focusable
) && !WFLAGP(tmp
, skip_window_list
)
1714 && (tmp
->flags
.mapped
|| tmp
->flags
.shaded
))
1718 if (!tmp
) { /* if unsuccessful, choose any focusable window */
1719 tmp
= scr
->focused_window
;
1721 if (!WFLAGP(tmp
, no_focusable
)
1722 && (tmp
->flags
.mapped
|| tmp
->flags
.shaded
))
1729 newFocusedWindow
= tmp
;
1731 } else if (wPreferences
.focus_mode
==WKF_SLOPPY
) {
1736 /* This is to let the root window get the keyboard input
1737 * if Sloppy focus mode and no other window get focus.
1738 * This way keybindings will not freeze.
1741 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
,
1742 &foo
, &foo
, &foo
, &foo
, &mask
))
1743 tmp
= wWindowFor(win
);
1746 newFocusedWindow
= tmp
;
1748 newFocusedWindow
= NULL
;
1752 if (!wwin
->flags
.internal_window
) {
1753 WMPostNotificationName(WMNUnmanaged
, wwin
, NULL
);
1757 printf("destroying window %x frame %x\n", (unsigned)wwin
->client_win
,
1758 (unsigned)frame
->window
);
1762 if (newFocusedWindow
!= owner
&& owner
) {
1763 if (wwin
->flags
.is_gnustep
== 0)
1764 wFrameWindowChangeState(owner
->frame
, WS_UNFOCUSED
);
1766 wSetFocusTo(scr
, newFocusedWindow
);
1768 wWindowDestroy(wwin
);
1774 wWindowMap(WWindow
*wwin
)
1776 XMapWindow(dpy
, wwin
->frame
->core
->window
);
1777 if (!wwin
->flags
.shaded
) {
1778 /* window will be remapped when getting MapNotify */
1779 XSelectInput(dpy
, wwin
->client_win
,
1780 wwin
->event_mask
& ~StructureNotifyMask
);
1781 XMapWindow(dpy
, wwin
->client_win
);
1782 XSelectInput(dpy
, wwin
->client_win
, wwin
->event_mask
);
1784 wwin
->flags
.mapped
= 1;
1790 wWindowUnmap(WWindow
*wwin
)
1792 wwin
->flags
.mapped
= 0;
1794 /* prevent window withdrawal when getting UnmapNotify */
1795 XSelectInput(dpy
, wwin
->client_win
,
1796 wwin
->event_mask
& ~StructureNotifyMask
);
1797 XUnmapWindow(dpy
, wwin
->client_win
);
1798 XSelectInput(dpy
, wwin
->client_win
, wwin
->event_mask
);
1800 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
1806 wWindowFocus(WWindow
*wwin
, WWindow
*owin
)
1811 #ifdef KEEP_XKB_LOCK_STATUS
1812 if (wPreferences
.modelock
) {
1813 XkbLockGroup(dpy
, XkbUseCoreKbd
, wwin
->frame
->languagemode
);
1815 #endif /* KEEP_XKB_LOCK_STATUS */
1817 wwin
->flags
.semi_focused
= 0;
1819 if (wwin
->flags
.is_gnustep
== 0)
1820 wFrameWindowChangeState(wwin
->frame
, WS_FOCUSED
);
1822 wwin
->flags
.focused
= 1;
1824 wWindowResetMouseGrabs(wwin
);
1826 WMPostNotificationName(WMNChangedFocus
, wwin
, (void*)True
);
1828 if (owin
== wwin
|| !owin
)
1831 nowner
= wWindowFor(wwin
->transient_for
);
1833 /* new window is a transient for the old window */
1834 if (nowner
== owin
) {
1835 owin
->flags
.semi_focused
= 1;
1836 wWindowUnfocus(nowner
);
1840 oowner
= wWindowFor(owin
->transient_for
);
1842 /* new window is owner of old window */
1843 if (wwin
== oowner
) {
1844 wWindowUnfocus(owin
);
1849 wWindowUnfocus(owin
);
1853 /* new window has same owner of old window */
1854 if (oowner
== nowner
) {
1855 /* prevent unfocusing of owner */
1856 oowner
->flags
.semi_focused
= 0;
1857 wWindowUnfocus(owin
);
1858 oowner
->flags
.semi_focused
= 1;
1863 /* nowner != NULL && oowner != nowner */
1864 nowner
->flags
.semi_focused
= 1;
1865 wWindowUnfocus(nowner
);
1866 wWindowUnfocus(owin
);
1871 wWindowUnfocus(WWindow
*wwin
)
1873 CloseWindowMenu(wwin
->screen_ptr
);
1875 if (wwin
->flags
.is_gnustep
== 0)
1876 wFrameWindowChangeState(wwin
->frame
, wwin
->flags
.semi_focused
1877 ? WS_PFOCUSED
: WS_UNFOCUSED
);
1879 if (wwin
->transient_for
!=None
1880 && wwin
->transient_for
!=wwin
->screen_ptr
->root_win
) {
1882 owner
= wWindowFor(wwin
->transient_for
);
1883 if (owner
&& owner
->flags
.semi_focused
) {
1884 owner
->flags
.semi_focused
= 0;
1885 if (owner
->flags
.mapped
|| owner
->flags
.shaded
) {
1886 wWindowUnfocus(owner
);
1887 wFrameWindowPaint(owner
->frame
);
1891 wwin
->flags
.focused
= 0;
1893 wWindowResetMouseGrabs(wwin
);
1895 WMPostNotificationName(WMNChangedFocus
, wwin
, (void*)False
);
1900 wWindowUpdateName(WWindow
*wwin
, char *newTitle
)
1907 wwin
->flags
.wm_name_changed
= 1;
1910 /* the hint was removed */
1911 title
= DEF_WINDOW_TITLE
;
1916 if (wFrameWindowChangeTitle(wwin
->frame
, title
)) {
1917 WMPostNotificationName(WMNChangedName
, wwin
, NULL
);
1924 *----------------------------------------------------------------------
1926 * wWindowConstrainSize--
1927 * Constrains size for the client window, taking the maximal size,
1928 * window resize increments and other size hints into account.
1931 * The closest size to what was given that the client window can
1934 *----------------------------------------------------------------------
1937 wWindowConstrainSize(WWindow
*wwin
, int *nwidth
, int *nheight
)
1939 int width
= *nwidth
;
1940 int height
= *nheight
;
1943 int minW
= 1, minH
= 1;
1944 int maxW
= wwin
->screen_ptr
->scr_width
*2;
1945 int maxH
= wwin
->screen_ptr
->scr_height
*2;
1946 int minAX
= -1, minAY
= -1;
1947 int maxAX
= -1, maxAY
= -1;
1951 if (wwin
->normal_hints
) {
1952 winc
= wwin
->normal_hints
->width_inc
;
1953 hinc
= wwin
->normal_hints
->height_inc
;
1954 minW
= wwin
->normal_hints
->min_width
;
1955 minH
= wwin
->normal_hints
->min_height
;
1956 maxW
= wwin
->normal_hints
->max_width
;
1957 maxH
= wwin
->normal_hints
->max_height
;
1958 if (wwin
->normal_hints
->flags
& PAspect
) {
1959 minAX
= wwin
->normal_hints
->min_aspect
.x
;
1960 minAY
= wwin
->normal_hints
->min_aspect
.y
;
1961 maxAX
= wwin
->normal_hints
->max_aspect
.x
;
1962 maxAY
= wwin
->normal_hints
->max_aspect
.y
;
1965 baseW
= wwin
->normal_hints
->base_width
;
1966 baseH
= wwin
->normal_hints
->base_height
;
1979 /* aspect ratio code borrowed from olwm */
1981 /* adjust max aspect ratio */
1982 if (!(maxAX
== 1 && maxAY
== 1) && width
* maxAY
> height
* maxAX
) {
1983 if (maxAX
> maxAY
) {
1984 height
= (width
* maxAY
) / maxAX
;
1985 if (height
> maxH
) {
1987 width
= (height
* maxAX
) / maxAY
;
1990 width
= (height
* maxAX
) / maxAY
;
1993 height
= (width
* maxAY
) / maxAX
;
1998 /* adjust min aspect ratio */
1999 if (!(minAX
== 1 && minAY
== 1) && width
* minAY
< height
* minAX
) {
2000 if (minAX
> minAY
) {
2001 height
= (width
* minAY
) / minAX
;
2002 if (height
< minH
) {
2004 width
= (height
* minAX
) / minAY
;
2007 width
= (height
* minAX
) / minAY
;
2010 height
= (width
* minAY
) / minAX
;
2017 width
= (((width
- baseW
) / winc
) * winc
) + baseW
;
2019 width
= (((width
- minW
) / winc
) * winc
) + minW
;
2023 height
= (((height
- baseH
) / hinc
) * hinc
) + baseH
;
2025 height
= (((height
- minH
) / hinc
) * hinc
) + minH
;
2028 /* broken stupid apps may cause preposterous values for these.. */
2037 wWindowCropSize(WWindow
*wwin
, int maxW
, int maxH
,
2038 int *width
, int *height
)
2040 int baseW
= 0, baseH
= 0;
2041 int winc
= 1, hinc
= 1;
2043 if (wwin
->normal_hints
) {
2044 baseW
= wwin
->normal_hints
->base_width
;
2045 baseH
= wwin
->normal_hints
->base_height
;
2047 winc
= wwin
->normal_hints
->width_inc
;
2048 hinc
= wwin
->normal_hints
->height_inc
;
2052 *width
= maxW
- (maxW
- baseW
) % winc
;
2055 *height
= maxH
- (maxH
- baseH
) % hinc
;
2060 wWindowChangeWorkspace(WWindow
*wwin
, int workspace
)
2062 WScreen
*scr
= wwin
->screen_ptr
;
2066 if (workspace
>= scr
->workspace_count
|| workspace
< 0
2067 || workspace
== wwin
->frame
->workspace
)
2070 if (workspace
!= scr
->current_workspace
) {
2071 /* Sent to other workspace. Unmap window */
2072 if ((wwin
->flags
.mapped
2073 || wwin
->flags
.shaded
2074 || (wwin
->flags
.miniaturized
&& !wPreferences
.sticky_icons
))
2075 && !IS_OMNIPRESENT(wwin
) && !wwin
->flags
.changing_workspace
) {
2077 wapp
= wApplicationOf(wwin
->main_window
);
2079 wapp
->last_workspace
= workspace
;
2081 if (wwin
->flags
.miniaturized
) {
2083 XUnmapWindow(dpy
, wwin
->icon
->core
->window
);
2084 wwin
->icon
->mapped
= 0;
2088 wSetFocusTo(scr
, NULL
);
2092 /* brought to current workspace. Map window */
2093 if (wwin
->flags
.miniaturized
&& !wPreferences
.sticky_icons
) {
2095 XMapWindow(dpy
, wwin
->icon
->core
->window
);
2096 wwin
->icon
->mapped
= 1;
2098 } else if (!wwin
->flags
.mapped
&&
2099 !(wwin
->flags
.miniaturized
|| wwin
->flags
.hidden
)) {
2103 if (!IS_OMNIPRESENT(wwin
)) {
2104 int oldWorkspace
= wwin
->frame
->workspace
;
2106 wwin
->frame
->workspace
= workspace
;
2108 WMPostNotificationName(WMNChangedWorkspace
, wwin
, (void*)oldWorkspace
);
2118 wWindowSynthConfigureNotify(WWindow
*wwin
)
2122 sevent
.type
= ConfigureNotify
;
2123 sevent
.xconfigure
.display
= dpy
;
2124 sevent
.xconfigure
.event
= wwin
->client_win
;
2125 sevent
.xconfigure
.window
= wwin
->client_win
;
2127 sevent
.xconfigure
.x
= wwin
->client
.x
;
2128 sevent
.xconfigure
.y
= wwin
->client
.y
;
2129 sevent
.xconfigure
.width
= wwin
->client
.width
;
2130 sevent
.xconfigure
.height
= wwin
->client
.height
;
2132 sevent
.xconfigure
.border_width
= wwin
->old_border_width
;
2133 if (WFLAGP(wwin
, no_titlebar
))
2134 sevent
.xconfigure
.above
= None
;
2136 sevent
.xconfigure
.above
= wwin
->frame
->titlebar
->window
;
2138 sevent
.xconfigure
.override_redirect
= False
;
2139 XSendEvent(dpy
, wwin
->client_win
, False
, StructureNotifyMask
, &sevent
);
2141 wKWMSendEventMessage(wwin
, WKWMChangedClient
);
2148 *----------------------------------------------------------------------
2149 * wWindowConfigure--
2150 * Configures the frame, decorations and client window to the
2151 * specified geometry. The geometry is not checked for validity,
2152 * wWindowConstrainSize() must be used for that.
2153 * The size parameters are for the client window, but the position is
2155 * The client window receives a ConfigureNotify event, according
2156 * to what ICCCM says.
2162 * Window size and position are changed and client window receives
2163 * a ConfigureNotify event.
2164 *----------------------------------------------------------------------
2167 wWindowConfigure(wwin
, req_x
, req_y
, req_width
, req_height
)
2169 int req_x
, req_y
; /* new position of the frame */
2170 int req_width
, req_height
; /* new size of the client */
2172 int synth_notify
= False
;
2175 resize
= (req_width
!=wwin
->client
.width
2176 || req_height
!=wwin
->client
.height
);
2178 * if the window is being moved but not resized then
2179 * send a synthetic ConfigureNotify
2181 if ((req_x
!=wwin
->frame_x
|| req_y
!=wwin
->frame_y
) && !resize
) {
2182 synth_notify
= True
;
2185 if (WFLAGP(wwin
, dont_move_off
))
2186 wScreenBringInside(wwin
->screen_ptr
, &req_x
, &req_y
,
2187 req_width
, req_height
);
2189 if (req_width
< MIN_WINDOW_SIZE
)
2190 req_width
= MIN_WINDOW_SIZE
;
2191 if (req_height
< MIN_WINDOW_SIZE
)
2192 req_height
= MIN_WINDOW_SIZE
;
2194 /* If growing, resize inner part before frame,
2195 * if shrinking, resize frame before.
2196 * This will prevent the frame (that can have a different color)
2197 * to be exposed, causing flicker */
2198 if (req_height
> wwin
->frame
->core
->height
2199 || req_width
> wwin
->frame
->core
->width
)
2200 XResizeWindow(dpy
, wwin
->client_win
, req_width
, req_height
);
2202 if (wwin
->flags
.shaded
) {
2203 wFrameWindowConfigure(wwin
->frame
, req_x
, req_y
,
2204 req_width
, wwin
->frame
->core
->height
);
2205 wwin
->old_geometry
.height
= req_height
;
2209 h
= req_height
+ wwin
->frame
->top_width
2210 + wwin
->frame
->bottom_width
;
2212 wFrameWindowConfigure(wwin
->frame
, req_x
, req_y
, req_width
, h
);
2215 if (!(req_height
> wwin
->frame
->core
->height
2216 || req_width
> wwin
->frame
->core
->width
))
2217 XResizeWindow(dpy
, wwin
->client_win
, req_width
, req_height
);
2219 wwin
->client
.x
= req_x
;
2220 wwin
->client
.y
= req_y
+ wwin
->frame
->top_width
;
2221 wwin
->client
.width
= req_width
;
2222 wwin
->client
.height
= req_height
;
2224 wwin
->client
.x
= req_x
;
2225 wwin
->client
.y
= req_y
+ wwin
->frame
->top_width
;
2227 XMoveWindow(dpy
, wwin
->frame
->core
->window
, req_x
, req_y
);
2229 wwin
->frame_x
= req_x
;
2230 wwin
->frame_y
= req_y
;
2231 if (!WFLAGP(wwin
, no_border
)) {
2232 wwin
->client
.x
+= FRAME_BORDER_WIDTH
;
2233 wwin
->client
.y
+= FRAME_BORDER_WIDTH
;
2237 if (wShapeSupported
&& wwin
->flags
.shaped
&& resize
) {
2238 wWindowSetShape(wwin
);
2243 wWindowSynthConfigureNotify(wwin
);
2249 wWindowMove(wwin
, req_x
, req_y
)
2251 int req_x
, req_y
; /* new position of the frame */
2253 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
2254 int synth_notify
= False
;
2256 /* Send a synthetic ConfigureNotify event for every window movement. */
2257 if ((req_x
!=wwin
->frame_x
|| req_y
!=wwin
->frame_y
)) {
2258 synth_notify
= True
;
2261 /* A single synthetic ConfigureNotify event is sent at the end of
2262 * a completed (opaque) movement in moveres.c */
2265 if (WFLAGP(wwin
, dont_move_off
))
2266 wScreenBringInside(wwin
->screen_ptr
, &req_x
, &req_y
,
2267 wwin
->frame
->core
->width
, wwin
->frame
->core
->height
);
2269 wwin
->client
.x
= req_x
;
2270 wwin
->client
.y
= req_y
+ wwin
->frame
->top_width
;
2271 if (!WFLAGP(wwin
, no_border
)) {
2272 wwin
->client
.x
+= FRAME_BORDER_WIDTH
;
2273 wwin
->client
.y
+= FRAME_BORDER_WIDTH
;
2276 XMoveWindow(dpy
, wwin
->frame
->core
->window
, req_x
, req_y
);
2278 wwin
->frame_x
= req_x
;
2279 wwin
->frame_y
= req_y
;
2281 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
2283 wWindowSynthConfigureNotify(wwin
);
2289 wWindowUpdateButtonImages(WWindow
*wwin
)
2291 WScreen
*scr
= wwin
->screen_ptr
;
2292 Pixmap pixmap
, mask
;
2293 WFrameWindow
*fwin
= wwin
->frame
;
2295 if (WFLAGP(wwin
, no_titlebar
))
2298 /* miniaturize button */
2300 if (!WFLAGP(wwin
, no_miniaturize_button
)) {
2301 if (wwin
->wm_gnustep_attr
2302 && wwin
->wm_gnustep_attr
->flags
& GSMiniaturizePixmapAttr
) {
2303 pixmap
= wwin
->wm_gnustep_attr
->miniaturize_pixmap
;
2305 if (wwin
->wm_gnustep_attr
->flags
&GSMiniaturizeMaskAttr
) {
2306 mask
= wwin
->wm_gnustep_attr
->miniaturize_mask
;
2311 if (fwin
->lbutton_image
2312 && (fwin
->lbutton_image
->image
!= pixmap
2313 || fwin
->lbutton_image
->mask
!= mask
)) {
2314 wPixmapDestroy(fwin
->lbutton_image
);
2315 fwin
->lbutton_image
= NULL
;
2318 if (!fwin
->lbutton_image
) {
2319 fwin
->lbutton_image
= wPixmapCreate(scr
, pixmap
, mask
);
2320 fwin
->lbutton_image
->client_owned
= 1;
2321 fwin
->lbutton_image
->client_owned_mask
= 1;
2324 if (fwin
->lbutton_image
&& !fwin
->lbutton_image
->shared
) {
2325 wPixmapDestroy(fwin
->lbutton_image
);
2327 fwin
->lbutton_image
= scr
->b_pixmaps
[WBUT_ICONIFY
];
2331 #ifdef XKB_BUTTON_HINT
2332 if (!WFLAGP(wwin
, no_language_button
)) {
2333 if (fwin
->languagebutton_image
&&
2334 !fwin
->languagebutton_image
->shared
) {
2335 wPixmapDestroy(fwin
->languagebutton_image
);
2337 fwin
->languagebutton_image
=
2338 scr
->b_pixmaps
[WBUT_XKBGROUP1
+ fwin
->languagemode
];
2344 /* redefine WFLAGP to MGFLAGP to allow broken close operation */
2345 #define MGFLAGP(wwin, FLAG) (wwin)->client_flags.FLAG
2347 if (!WFLAGP(wwin
, no_close_button
)) {
2348 if (wwin
->wm_gnustep_attr
2349 && wwin
->wm_gnustep_attr
->flags
& GSClosePixmapAttr
) {
2350 pixmap
= wwin
->wm_gnustep_attr
->close_pixmap
;
2352 if (wwin
->wm_gnustep_attr
->flags
&GSCloseMaskAttr
)
2353 mask
= wwin
->wm_gnustep_attr
->close_mask
;
2357 if (fwin
->rbutton_image
&& (fwin
->rbutton_image
->image
!= pixmap
2358 || fwin
->rbutton_image
->mask
!= mask
)) {
2359 wPixmapDestroy(fwin
->rbutton_image
);
2360 fwin
->rbutton_image
= NULL
;
2363 if (!fwin
->rbutton_image
) {
2364 fwin
->rbutton_image
= wPixmapCreate(scr
, pixmap
, mask
);
2365 fwin
->rbutton_image
->client_owned
= 1;
2366 fwin
->rbutton_image
->client_owned_mask
= 1;
2369 } else if (WFLAGP(wwin
, kill_close
)) {
2371 if (fwin
->rbutton_image
&& !fwin
->rbutton_image
->shared
)
2372 wPixmapDestroy(fwin
->rbutton_image
);
2374 fwin
->rbutton_image
= scr
->b_pixmaps
[WBUT_KILL
];
2376 } else if (MGFLAGP(wwin
, broken_close
)) {
2378 if (fwin
->rbutton_image
&& !fwin
->rbutton_image
->shared
)
2379 wPixmapDestroy(fwin
->rbutton_image
);
2381 fwin
->rbutton_image
= scr
->b_pixmaps
[WBUT_BROKENCLOSE
];
2385 if (fwin
->rbutton_image
&& !fwin
->rbutton_image
->shared
)
2386 wPixmapDestroy(fwin
->rbutton_image
);
2388 fwin
->rbutton_image
= scr
->b_pixmaps
[WBUT_CLOSE
];
2392 /* force buttons to be redrawn */
2393 fwin
->flags
.need_texture_change
= 1;
2394 wFrameWindowPaint(fwin
);
2399 *---------------------------------------------------------------------------
2400 * wWindowConfigureBorders--
2401 * Update window border configuration according to attribute flags.
2403 *---------------------------------------------------------------------------
2406 wWindowConfigureBorders(WWindow
*wwin
)
2412 flags
= WFF_LEFT_BUTTON
|WFF_RIGHT_BUTTON
;
2413 #ifdef XKB_BUTTON_HINT
2414 flags
|= WFF_LANGUAGE_BUTTON
;
2416 if (!WFLAGP(wwin
, no_titlebar
))
2417 flags
|= WFF_TITLEBAR
;
2418 if (!WFLAGP(wwin
, no_resizebar
))
2419 flags
|= WFF_RESIZEBAR
;
2420 if (!WFLAGP(wwin
, no_border
))
2421 flags
|= WFF_BORDER
;
2422 if (wwin
->flags
.shaded
)
2423 flags
|= WFF_IS_SHADED
;
2425 oldh
= wwin
->frame
->top_width
;
2426 wFrameWindowUpdateBorders(wwin
->frame
, flags
);
2427 if (oldh
!= wwin
->frame
->top_width
) {
2428 newy
= wwin
->frame_y
+ oldh
- wwin
->frame
->top_width
;
2430 XMoveWindow(dpy
, wwin
->client_win
, 0, wwin
->frame
->top_width
);
2431 wWindowConfigure(wwin
, wwin
->frame_x
, newy
,
2432 wwin
->client
.width
, wwin
->client
.height
);
2436 if (!WFLAGP(wwin
, no_miniaturize_button
)
2437 && wwin
->frame
->flags
.hide_left_button
)
2438 flags
|= WFF_LEFT_BUTTON
;
2440 #ifdef XKB_BUTTON_HINT
2441 if (!WFLAGP(wwin
, no_language_button
)
2442 && wwin
->frame
->flags
.hide_language_button
)
2443 flags
|= WFF_LANGUAGE_BUTTON
;
2446 if (!WFLAGP(wwin
, no_close_button
)
2447 && wwin
->frame
->flags
.hide_right_button
)
2448 flags
|= WFF_RIGHT_BUTTON
;
2451 wWindowUpdateButtonImages(wwin
);
2452 wFrameWindowShowButton(wwin
->frame
, flags
);
2456 if (WFLAGP(wwin
, no_miniaturize_button
)
2457 && !wwin
->frame
->flags
.hide_left_button
)
2458 flags
|= WFF_LEFT_BUTTON
;
2460 #ifdef XKB_BUTTON_HINT
2461 if (WFLAGP(wwin
, no_language_button
)
2462 && !wwin
->frame
->flags
.hide_language_button
)
2463 flags
|= WFF_LANGUAGE_BUTTON
;
2466 if (WFLAGP(wwin
, no_close_button
)
2467 && !wwin
->frame
->flags
.hide_right_button
)
2468 flags
|= WFF_RIGHT_BUTTON
;
2471 wFrameWindowHideButton(wwin
->frame
, flags
);
2474 if (wShapeSupported
&& wwin
->flags
.shaped
) {
2475 wWindowSetShape(wwin
);
2483 wWindowSaveState(WWindow
*wwin
)
2488 memset(data
, 0, sizeof(CARD32
)*10);
2489 data
[0] = wwin
->frame
->workspace
;
2490 data
[1] = wwin
->flags
.miniaturized
;
2491 data
[2] = wwin
->flags
.shaded
;
2492 data
[3] = wwin
->flags
.hidden
;
2493 data
[4] = wwin
->flags
.maximized
;
2494 if (wwin
->flags
.maximized
== 0) {
2495 data
[5] = wwin
->frame_x
;
2496 data
[6] = wwin
->frame_y
;
2497 data
[7] = wwin
->frame
->core
->width
;
2498 data
[8] = wwin
->frame
->core
->height
;
2500 data
[5] = wwin
->old_geometry
.x
;
2501 data
[6] = wwin
->old_geometry
.y
;
2502 data
[7] = wwin
->old_geometry
.width
;
2503 data
[8] = wwin
->old_geometry
.height
;
2506 for (i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
2507 if (wwin
->screen_ptr
->shortcutWindows
[i
] &&
2508 WMCountInArray(wwin
->screen_ptr
->shortcutWindows
[i
], wwin
))
2511 XChangeProperty(dpy
, wwin
->client_win
, _XA_WINDOWMAKER_STATE
,
2512 _XA_WINDOWMAKER_STATE
, 32, PropModeReplace
,
2513 (unsigned char *)data
, 10);
2518 getSavedState(Window window
, WSavedState
**state
)
2522 unsigned long nitems_ret
;
2523 unsigned long bytes_after_ret
;
2526 if (XGetWindowProperty(dpy
, window
, _XA_WINDOWMAKER_STATE
, 0, 10,
2527 True
, _XA_WINDOWMAKER_STATE
,
2528 &type_ret
, &fmt_ret
, &nitems_ret
, &bytes_after_ret
,
2529 (unsigned char **)&data
)!=Success
|| !data
)
2532 *state
= wmalloc(sizeof(WSavedState
));
2534 (*state
)->workspace
= data
[0];
2535 (*state
)->miniaturized
= data
[1];
2536 (*state
)->shaded
= data
[2];
2537 (*state
)->hidden
= data
[3];
2538 (*state
)->maximized
= data
[4];
2539 (*state
)->x
= data
[5];
2540 (*state
)->y
= data
[6];
2541 (*state
)->w
= data
[7];
2542 (*state
)->h
= data
[8];
2543 (*state
)->window_shortcuts
= data
[9];
2547 if (*state
&& type_ret
==_XA_WINDOWMAKER_STATE
)
2556 wWindowClearShape(WWindow
*wwin
)
2558 XShapeCombineMask(dpy
, wwin
->frame
->core
->window
, ShapeBounding
,
2559 0, wwin
->frame
->top_width
, None
, ShapeSet
);
2564 wWindowSetShape(WWindow
*wwin
)
2568 #ifdef OPTIMIZE_SHAPE
2573 /* only shape is the client's */
2574 if (WFLAGP(wwin
, no_titlebar
) && WFLAGP(wwin
, no_resizebar
)) {
2578 /* Get array of rectangles describing the shape mask */
2579 rects
= XShapeGetRectangles(dpy
, wwin
->client_win
, ShapeBounding
,
2585 urec
= malloc(sizeof(XRectangle
)*(count
+2));
2591 /* insert our decoration rectangles in the rect list */
2592 memcpy(urec
, rects
, sizeof(XRectangle
)*count
);
2595 if (!WFLAGP(wwin
, no_titlebar
)) {
2597 urec
[count
].y
= -1 - wwin
->frame
->top_width
;
2598 urec
[count
].width
= wwin
->frame
->core
->width
+ 2;
2599 urec
[count
].height
= wwin
->frame
->top_width
+ 1;
2602 if (!WFLAGP(wwin
, no_resizebar
)) {
2604 urec
[count
].y
= wwin
->frame
->core
->height
2605 - wwin
->frame
->bottom_width
- wwin
->frame
->top_width
;
2606 urec
[count
].width
= wwin
->frame
->core
->width
+ 2;
2607 urec
[count
].height
= wwin
->frame
->bottom_width
+ 1;
2611 /* shape our frame window */
2612 XShapeCombineRectangles(dpy
, wwin
->frame
->core
->window
, ShapeBounding
,
2613 0, wwin
->frame
->top_width
, urec
, count
,
2614 ShapeSet
, Unsorted
);
2620 #endif /* OPTIMIZE_SHAPE */
2622 if (!WFLAGP(wwin
, no_titlebar
)) {
2625 rect
[count
].width
= wwin
->frame
->core
->width
+ 2;
2626 rect
[count
].height
= wwin
->frame
->top_width
+ 1;
2629 if (!WFLAGP(wwin
, no_resizebar
)) {
2631 rect
[count
].y
= wwin
->frame
->core
->height
- wwin
->frame
->bottom_width
;
2632 rect
[count
].width
= wwin
->frame
->core
->width
+ 2;
2633 rect
[count
].height
= wwin
->frame
->bottom_width
+ 1;
2637 XShapeCombineRectangles(dpy
, wwin
->frame
->core
->window
, ShapeBounding
,
2638 0, 0, rect
, count
, ShapeSet
, Unsorted
);
2640 XShapeCombineShape(dpy
, wwin
->frame
->core
->window
, ShapeBounding
,
2641 0, wwin
->frame
->top_width
, wwin
->client_win
,
2642 ShapeBounding
, (count
> 0 ? ShapeUnion
: ShapeSet
));
2647 /* ====================================================================== */
2650 getFocusMode(WWindow
*wwin
)
2654 if ((wwin
->wm_hints
) && (wwin
->wm_hints
->flags
& InputHint
)) {
2655 if (wwin
->wm_hints
->input
== True
) {
2656 if (wwin
->protocols
.TAKE_FOCUS
)
2657 mode
= WFM_LOCALLY_ACTIVE
;
2661 if (wwin
->protocols
.TAKE_FOCUS
)
2662 mode
= WFM_GLOBALLY_ACTIVE
;
2664 mode
= WFM_NO_INPUT
;
2674 wWindowSetKeyGrabs(WWindow
*wwin
)
2679 for (i
=0; i
<WKBD_LAST
; i
++) {
2680 key
= &wKeyBindings
[i
];
2682 if (key
->keycode
==0)
2684 if (key
->modifier
!=AnyModifier
) {
2685 XGrabKey(dpy
, key
->keycode
, key
->modifier
|LockMask
,
2686 wwin
->frame
->core
->window
, True
, GrabModeAsync
, GrabModeAsync
);
2688 /* Also grab all modifier combinations possible that include,
2689 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
2690 * work even if the NumLock/ScrollLock key is on.
2692 wHackedGrabKey(key
->keycode
, key
->modifier
,
2693 wwin
->frame
->core
->window
, True
, GrabModeAsync
,
2697 XGrabKey(dpy
, key
->keycode
, key
->modifier
,
2698 wwin
->frame
->core
->window
, True
, GrabModeAsync
, GrabModeAsync
);
2702 wRootMenuBindShortcuts(wwin
->frame
->core
->window
);
2709 wWindowResetMouseGrabs(WWindow
*wwin
)
2711 /* Mouse grabs can't be done on the client window because of
2712 * ICCCM and because clients that try to do the same will crash.
2714 * But there is a problem wich makes tbar buttons of unfocused
2715 * windows not usable as the click goes to the frame window instead
2716 * of the button itself. Must figure a way to fix that.
2719 XUngrabButton(dpy
, AnyButton
, AnyModifier
, wwin
->client_win
);
2721 if (!WFLAGP(wwin
, no_bind_mouse
)) {
2722 /* grabs for Meta+drag */
2723 wHackedGrabButton(AnyButton
, MOD_MASK
, wwin
->client_win
,
2724 True
, ButtonPressMask
, GrabModeSync
,
2725 GrabModeAsync
, None
, None
);
2728 if (!wwin
->flags
.focused
&& !WFLAGP(wwin
, no_focusable
)
2729 && !wwin
->flags
.is_gnustep
) {
2730 /* the passive grabs to focus the window */
2731 /* if (wPreferences.focus_mode == WKF_CLICK) */
2732 XGrabButton(dpy
, AnyButton
, AnyModifier
, wwin
->client_win
,
2733 True
, ButtonPressMask
, GrabModeSync
, GrabModeAsync
,
2741 wWindowUpdateGNUstepAttr(WWindow
*wwin
, GNUstepWMAttributes
*attr
)
2743 if (attr
->flags
& GSExtraFlagsAttr
) {
2744 if (MGFLAGP(wwin
, broken_close
) !=
2745 (attr
->extra_flags
& GSDocumentEditedFlag
)) {
2746 wwin
->client_flags
.broken_close
= !MGFLAGP(wwin
, broken_close
);
2747 wWindowUpdateButtonImages(wwin
);
2754 wWindowAddSavedState(char *instance
, char *class, char *command
,
2755 pid_t pid
, WSavedState
*state
)
2757 WWindowState
*wstate
;
2759 wstate
= malloc(sizeof(WWindowState
));
2763 memset(wstate
, 0, sizeof(WWindowState
));
2766 wstate
->instance
= wstrdup(instance
);
2768 wstate
->class = wstrdup(class);
2770 wstate
->command
= wstrdup(command
);
2771 wstate
->state
= state
;
2773 wstate
->next
= windowState
;
2774 windowState
= wstate
;
2777 printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate
, instance
,
2785 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
2789 wWindowGetSavedState(Window win
)
2791 char *instance
, *class, *command
=NULL
;
2792 WWindowState
*wstate
= windowState
;
2799 if (XGetCommand(dpy
, win
, &argv
, &argc
)) {
2801 command
= wtokenjoin(argv
, argc
);
2802 XFreeStringList(argv
);
2807 if (PropGetWMClass(win
, &class, &instance
)) {
2809 if (SAME(instance
, wstate
->instance
) &&
2810 SAME(class, wstate
->class) &&
2811 SAME(command
, wstate
->command
)) {
2814 wstate
= wstate
->next
;
2821 printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate
, instance
,
2825 if (command
) wfree(command
);
2826 if (instance
) XFree(instance
);
2827 if (class) XFree(class);
2834 wWindowDeleteSavedState(WMagicNumber id
)
2836 WWindowState
*tmp
, *wstate
=(WWindowState
*)id
;
2838 if (!wstate
|| !windowState
)
2843 windowState
= wstate
->next
;
2845 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2846 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
2848 if (wstate
->instance
) wfree(wstate
->instance
);
2849 if (wstate
->class) wfree(wstate
->class);
2850 if (wstate
->command
) wfree(wstate
->command
);
2851 wfree(wstate
->state
);
2855 if (tmp
->next
==wstate
) {
2856 tmp
->next
=wstate
->next
;
2858 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2859 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
2861 if (wstate
->instance
) wfree(wstate
->instance
);
2862 if (wstate
->class) wfree(wstate
->class);
2863 if (wstate
->command
) wfree(wstate
->command
);
2864 wfree(wstate
->state
);
2875 wWindowDeleteSavedStatesForPID(pid_t pid
)
2877 WWindowState
*tmp
, *wstate
;
2883 if (tmp
->pid
== pid
) {
2884 wstate
= windowState
;
2885 windowState
= tmp
->next
;
2887 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2888 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
2890 if (wstate
->instance
) wfree(wstate
->instance
);
2891 if (wstate
->class) wfree(wstate
->class);
2892 if (wstate
->command
) wfree(wstate
->command
);
2893 wfree(wstate
->state
);
2897 if (tmp
->next
->pid
==pid
) {
2899 tmp
->next
= wstate
->next
;
2901 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2902 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
2904 if (wstate
->instance
) wfree(wstate
->instance
);
2905 if (wstate
->class) wfree(wstate
->class);
2906 if (wstate
->command
) wfree(wstate
->command
);
2907 wfree(wstate
->state
);
2918 wWindowSetOmnipresent(WWindow
*wwin
, Bool flag
)
2920 wwin
->flags
.omnipresent
= flag
;
2922 WMPostNotificationName(WMNChangedState
, wwin
, "omnipresent");
2926 /* ====================================================================== */
2929 resizebarMouseDown(WCoreWindow
*sender
, void *data
, XEvent
*event
)
2931 WWindow
*wwin
= data
;
2933 #ifndef NUMLOCK_HACK
2934 if ((event
->xbutton
.state
& ValidModMask
)
2935 != (event
->xbutton
.state
& ~LockMask
)) {
2936 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2937 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2941 event
->xbutton
.state
&= ValidModMask
;
2943 CloseWindowMenu(wwin
->screen_ptr
);
2945 if (wPreferences
.focus_mode
==WKF_CLICK
2946 && !(event
->xbutton
.state
&ControlMask
)
2947 && !WFLAGP(wwin
, no_focusable
)) {
2948 wSetFocusTo(wwin
->screen_ptr
, wwin
);
2951 if (event
->xbutton
.button
== Button1
)
2952 wRaiseFrame(wwin
->frame
->core
);
2954 if (event
->xbutton
.window
!= wwin
->frame
->resizebar
->window
) {
2955 if (XGrabPointer(dpy
, wwin
->frame
->resizebar
->window
, True
,
2956 ButtonMotionMask
|ButtonReleaseMask
|ButtonPressMask
,
2957 GrabModeAsync
, GrabModeAsync
, None
,
2958 None
, CurrentTime
)!=GrabSuccess
) {
2960 wwarning("pointer grab failed for window move");
2966 if (event
->xbutton
.state
& MOD_MASK
) {
2967 /* move the window */
2968 wMouseMoveWindow(wwin
, event
);
2969 XUngrabPointer(dpy
, CurrentTime
);
2971 wMouseResizeWindow(wwin
, event
);
2972 XUngrabPointer(dpy
, CurrentTime
);
2979 titlebarDblClick(WCoreWindow
*sender
, void *data
, XEvent
*event
)
2981 WWindow
*wwin
= data
;
2983 event
->xbutton
.state
&= ValidModMask
;
2985 if (event
->xbutton
.button
==Button1
) {
2986 if (event
->xbutton
.state
== 0) {
2987 if (!WFLAGP(wwin
, no_shadeable
)) {
2989 if (wwin
->flags
.shaded
)
2990 wUnshadeWindow(wwin
);
2997 if (event
->xbutton
.state
& ControlMask
)
2998 dir
|= MAX_VERTICAL
;
3000 if (event
->xbutton
.state
& ShiftMask
) {
3001 dir
|= MAX_HORIZONTAL
;
3002 if (!(event
->xbutton
.state
& ControlMask
))
3003 wSelectWindow(wwin
, !wwin
->flags
.selected
);
3006 /* maximize window */
3007 if (dir
!=0 && !WFLAGP(wwin
, no_resizable
)) {
3008 int ndir
= dir
^ wwin
->flags
.maximized
;
3009 if (wwin
->flags
.maximized
!= 0)
3010 wUnmaximizeWindow(wwin
);
3012 wMaximizeWindow(wwin
, ndir
);
3015 } else if (event
->xbutton
.button
==Button3
) {
3016 if (event
->xbutton
.state
& MOD_MASK
) {
3017 wHideOtherApplications(wwin
);
3019 } else if (event
->xbutton
.button
==Button2
) {
3020 wSelectWindow(wwin
, !wwin
->flags
.selected
);
3021 } else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
) {
3023 } else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
) {
3024 wUnshadeWindow(wwin
);
3030 frameMouseDown(WObjDescriptor
*desc
, XEvent
*event
)
3032 WWindow
*wwin
= desc
->parent
;
3034 event
->xbutton
.state
&= ValidModMask
;
3036 CloseWindowMenu(wwin
->screen_ptr
);
3038 if (/*wPreferences.focus_mode==WKF_CLICK
3039 &&*/ !(event
->xbutton
.state
&ControlMask
)
3040 && !WFLAGP(wwin
, no_focusable
)) {
3041 wSetFocusTo(wwin
->screen_ptr
, wwin
);
3043 if (event
->xbutton
.button
== Button1
) {
3044 wRaiseFrame(wwin
->frame
->core
);
3047 if (event
->xbutton
.state
& MOD_MASK
) {
3048 /* move the window */
3049 if (XGrabPointer(dpy
, wwin
->client_win
, False
,
3050 ButtonMotionMask
|ButtonReleaseMask
|ButtonPressMask
,
3051 GrabModeAsync
, GrabModeAsync
, None
,
3052 None
, CurrentTime
)!=GrabSuccess
) {
3054 wwarning("pointer grab failed for window move");
3058 if (event
->xbutton
.button
== Button3
&& !WFLAGP(wwin
, no_resizable
))
3059 wMouseResizeWindow(wwin
, event
);
3061 wMouseMoveWindow(wwin
, event
);
3062 XUngrabPointer(dpy
, CurrentTime
);
3068 titlebarMouseDown(WCoreWindow
*sender
, void *data
, XEvent
*event
)
3070 WWindow
*wwin
= (WWindow
*)data
;
3072 #ifndef NUMLOCK_HACK
3073 if ((event
->xbutton
.state
& ValidModMask
)
3074 != (event
->xbutton
.state
& ~LockMask
)) {
3075 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
3076 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
3079 event
->xbutton
.state
&= ValidModMask
;
3081 CloseWindowMenu(wwin
->screen_ptr
);
3083 if (wPreferences
.focus_mode
==WKF_CLICK
3084 && !(event
->xbutton
.state
&ControlMask
)
3085 && !WFLAGP(wwin
, no_focusable
)) {
3086 wSetFocusTo(wwin
->screen_ptr
, wwin
);
3089 if (event
->xbutton
.button
== Button1
3090 || event
->xbutton
.button
== Button2
) {
3092 if (event
->xbutton
.button
== Button1
) {
3093 if (event
->xbutton
.state
& MOD_MASK
) {
3094 wLowerFrame(wwin
->frame
->core
);
3096 wRaiseFrame(wwin
->frame
->core
);
3099 if ((event
->xbutton
.state
& ShiftMask
)
3100 && !(event
->xbutton
.state
& ControlMask
)) {
3101 wSelectWindow(wwin
, !wwin
->flags
.selected
);
3104 if (event
->xbutton
.window
!= wwin
->frame
->titlebar
->window
3105 && XGrabPointer(dpy
, wwin
->frame
->titlebar
->window
, False
,
3106 ButtonMotionMask
|ButtonReleaseMask
|ButtonPressMask
,
3107 GrabModeAsync
, GrabModeAsync
, None
,
3108 None
, CurrentTime
)!=GrabSuccess
) {
3110 wwarning("pointer grab failed for window move");
3115 /* move the window */
3116 wMouseMoveWindow(wwin
, event
);
3118 XUngrabPointer(dpy
, CurrentTime
);
3119 } else if (event
->xbutton
.button
== Button3
&& event
->xbutton
.state
==0
3120 && !wwin
->flags
.internal_window
3121 && !WCHECK_STATE(WSTATE_MODAL
)) {
3122 WObjDescriptor
*desc
;
3124 if (event
->xbutton
.window
!= wwin
->frame
->titlebar
->window
3125 && XGrabPointer(dpy
, wwin
->frame
->titlebar
->window
, False
,
3126 ButtonMotionMask
|ButtonReleaseMask
|ButtonPressMask
,
3127 GrabModeAsync
, GrabModeAsync
, None
,
3128 None
, CurrentTime
)!=GrabSuccess
) {
3130 wwarning("pointer grab failed for window move");
3135 OpenWindowMenu(wwin
, event
->xbutton
.x_root
,
3136 wwin
->frame_y
+wwin
->frame
->top_width
, False
);
3138 /* allow drag select */
3139 desc
= &wwin
->screen_ptr
->window_menu
->menu
->descriptor
;
3140 event
->xany
.send_event
= True
;
3141 (*desc
->handle_mousedown
)(desc
, event
);
3143 XUngrabPointer(dpy
, CurrentTime
);
3150 windowCloseClick(WCoreWindow
*sender
, void *data
, XEvent
*event
)
3152 WWindow
*wwin
= data
;
3154 event
->xbutton
.state
&= ValidModMask
;
3156 CloseWindowMenu(wwin
->screen_ptr
);
3158 if (event
->xbutton
.button
< Button1
|| event
->xbutton
.button
> Button3
)
3161 /* if control-click, kill the client */
3162 if (event
->xbutton
.state
& ControlMask
) {
3166 if (wwin
->flags
.olwm_push_pin_out
) {
3168 wwin
->flags
.olwm_push_pin_out
= 0;
3170 wOLWMChangePushpinState(wwin
, True
);
3172 wFrameWindowUpdatePushButton(wwin
->frame
, False
);
3177 if (wwin
->protocols
.DELETE_WINDOW
&& event
->xbutton
.state
==0) {
3178 /* send delete message */
3179 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
, LastTimestamp
);
3186 windowCloseDblClick(WCoreWindow
*sender
, void *data
, XEvent
*event
)
3188 WWindow
*wwin
= data
;
3190 CloseWindowMenu(wwin
->screen_ptr
);
3192 if (event
->xbutton
.button
< Button1
|| event
->xbutton
.button
> Button3
)
3195 /* send delete message */
3196 if (wwin
->protocols
.DELETE_WINDOW
) {
3197 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
, LastTimestamp
);
3204 #ifdef XKB_BUTTON_HINT
3206 windowLanguageClick(WCoreWindow
*sender
, void *data
, XEvent
*event
)
3208 WWindow
*wwin
= data
;
3209 WFrameWindow
*fwin
= wwin
->frame
;
3210 WScreen
*scr
= fwin
->screen_ptr
;
3211 XkbStateRec staterec
;
3214 if (event
->xbutton
.button
!= Button1
&& event
->xbutton
.button
!= Button3
)
3216 tl
= wwin
->frame
->languagemode
;
3217 wwin
->frame
->languagemode
= wwin
->frame
->last_languagemode
;
3218 wwin
->frame
->last_languagemode
= tl
;
3219 wSetFocusTo(scr
, wwin
);
3220 wwin
->frame
->languagebutton_image
=
3221 wwin
->frame
->screen_ptr
->b_pixmaps
[WBUT_XKBGROUP1
+
3222 wwin
->frame
->languagemode
];
3223 wFrameWindowUpdateLanguageButton(wwin
->frame
);
3224 if (event
->xbutton
.button
== Button3
)
3226 wRaiseFrame(fwin
->core
);
3232 windowIconifyClick(WCoreWindow
*sender
, void *data
, XEvent
*event
)
3234 WWindow
*wwin
= data
;
3236 event
->xbutton
.state
&= ValidModMask
;
3238 CloseWindowMenu(wwin
->screen_ptr
);
3240 if (event
->xbutton
.button
< Button1
|| event
->xbutton
.button
> Button3
)
3243 if (wwin
->protocols
.MINIATURIZE_WINDOW
&& event
->xbutton
.state
==0) {
3244 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
3248 if ((event
->xbutton
.state
& ControlMask
) ||
3249 (event
->xbutton
.button
== Button3
)) {
3251 wapp
= wApplicationOf(wwin
->main_window
);
3252 if (wapp
&& !WFLAGP(wwin
, no_appicon
))
3253 wHideApplication(wapp
);
3254 } else if (event
->xbutton
.state
==0) {
3255 wIconifyWindow(wwin
);