Update for 0.51.0
[wmaker-crm.git] / src / window.c
blob1f605236d81cffebc87eddaee267198f89875493
1 /* window.c - client window managing class
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 *
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,
20 * USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #ifdef SHAPE
28 #include <X11/extensions/shape.h>
29 #endif
30 #ifdef KEEP_XKB_LOCK_STATUS
31 # include <X11/XKBlib.h>
32 #endif /* KEEP_XKB_LOCK_STATUS */
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
38 #include "WindowMaker.h"
39 #include "GNUstep.h"
40 #include "wcore.h"
41 #include "framewin.h"
42 #include "texture.h"
43 #include "window.h"
44 #include "winspector.h"
45 #include "icon.h"
46 #include "properties.h"
47 #include "actions.h"
48 #include "client.h"
49 #include "funcs.h"
50 #include "keybind.h"
51 #include "stacking.h"
52 #include "defaults.h"
53 #include "workspace.h"
55 #ifdef MWM_HINTS
56 # include "motif.h"
57 #endif
58 #ifdef KWM_HINTS
59 # include "kwm.h"
60 #endif
61 #ifdef GNOME_STUFF
62 # include "gnome.h"
63 #endif
64 #ifdef OLWM_HINTS
65 # include "openlook.h"
66 #endif
68 /****** Global Variables ******/
70 extern WShortKey wKeyBindings[WKBD_LAST];
72 #ifdef SHAPE
73 extern Bool wShapeSupported;
74 #endif
76 /* contexts */
77 extern XContext wWinContext;
79 /* cursors */
80 extern Cursor wCursor[WCUR_LAST];
82 /* protocol atoms */
83 extern Atom _XA_WM_DELETE_WINDOW;
84 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
86 extern Atom _XA_WINDOWMAKER_STATE;
88 extern WPreferences wPreferences;
90 #define MOD_MASK wPreferences.modifier_mask
92 extern Time LastTimestamp;
94 /* superfluous... */
95 extern void DoWindowBirth(WWindow*);
98 /***** Local Stuff *****/
101 static WWindowState *windowState=NULL;
105 /* local functions */
106 static FocusMode getFocusMode(WWindow *wwin);
108 static int getSavedState(Window window, WSavedState **state);
110 static void setupGNUstepHints(WWindow *wwin,
111 GNUstepWMAttributes *gs_hints);
113 /* event handlers */
116 /* frame window (during window grabs) */
117 static void frameMouseDown(WObjDescriptor *desc, XEvent *event);
119 /* close button */
120 static void windowCloseClick(WCoreWindow *sender, void *data, XEvent *event);
121 static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event);
123 /* iconify button */
124 static void windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event);
127 static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
128 static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event);
130 static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
137 WWindow*
138 wWindowFor(Window window)
140 WObjDescriptor *desc;
142 if (window==None)
143 return NULL;
145 if (XFindContext(dpy, window, wWinContext, (XPointer*)&desc)==XCNOENT)
146 return NULL;
148 if (desc->parent_type==WCLASS_WINDOW)
149 return desc->parent;
150 else if (desc->parent_type==WCLASS_FRAME) {
151 WFrameWindow *frame = (WFrameWindow*)desc->parent;
152 if (frame->flags.is_client_window_frame)
153 return frame->child;
155 return NULL;
159 WWindow*
160 wWindowCreate()
162 WWindow *wwin;
164 wwin = wmalloc(sizeof(WWindow));
165 wretain(wwin);
167 memset(wwin, 0, sizeof(WWindow));
169 wwin->client_descriptor.handle_mousedown = frameMouseDown;
170 wwin->client_descriptor.parent = wwin;
171 wwin->client_descriptor.self = wwin;
172 wwin->client_descriptor.parent_type = WCLASS_WINDOW;
173 return wwin;
177 void
178 wWindowDestroy(WWindow *wwin)
180 int i;
182 wwin->flags.destroyed = 1;
184 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
185 if (wwin->screen_ptr->shortcutWindow[i] == wwin) {
186 wwin->screen_ptr->shortcutWindow[i] = NULL;
190 if (wwin->normal_hints)
191 free(wwin->normal_hints);
193 if (wwin->wm_hints)
194 XFree(wwin->wm_hints);
196 if (wwin->wm_instance)
197 XFree(wwin->wm_instance);
199 if (wwin->wm_class)
200 XFree(wwin->wm_class);
202 if (wwin->wm_gnustep_attr)
203 free(wwin->wm_gnustep_attr);
205 if (wwin->cmap_windows)
206 XFree(wwin->cmap_windows);
208 XDeleteContext(dpy, wwin->client_win, wWinContext);
210 if (wwin->frame)
211 wFrameWindowDestroy(wwin->frame);
213 if (wwin->icon) {
214 RemoveFromStackList(wwin->icon->core);
215 wIconDestroy(wwin->icon);
216 if (wPreferences.auto_arrange_icons)
217 wArrangeIcons(wwin->screen_ptr, True);
219 wrelease(wwin);
225 static void
226 setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints)
228 if (gs_hints->flags & GSWindowStyleAttr) {
229 WSETUFLAG(wwin, no_titlebar,
230 ((gs_hints->window_style & WMTitledWindowMask)?0:1));
232 WSETUFLAG(wwin, no_close_button,
233 ((gs_hints->window_style & WMClosableWindowMask)?0:1));
235 WSETUFLAG(wwin, no_closable,
236 ((gs_hints->window_style & WMClosableWindowMask)?0:1));
238 WSETUFLAG(wwin, no_miniaturize_button,
239 ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1));
241 WSETUFLAG(wwin, no_miniaturizable,
242 ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1));
244 WSETUFLAG(wwin, no_resizebar,
245 ((gs_hints->window_style & WMResizableWindowMask)?0:1));
247 WSETUFLAG(wwin, no_resizable,
248 ((gs_hints->window_style & WMResizableWindowMask)?0:1));
249 } else {
250 /* setup the defaults */
251 WSETUFLAG(wwin, no_titlebar, 0);
252 WSETUFLAG(wwin, no_closable, 0);
253 WSETUFLAG(wwin, no_miniaturizable, 0);
254 WSETUFLAG(wwin, no_resizable, 0);
255 WSETUFLAG(wwin, no_close_button, 0);
256 WSETUFLAG(wwin, no_miniaturize_button, 0);
257 WSETUFLAG(wwin, no_resizebar, 0);
260 if (gs_hints->extra_flags & GSNoApplicationIconFlag) {
261 WSETUFLAG(wwin, no_appicon, 1);
266 void
267 wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags,
268 WWindowAttributes *mask)
270 if (wflags->no_appicon && mask->no_appicon)
271 wflags->emulate_appicon = 0;
273 if (wwin->main_window!=None) {
274 WApplication *wapp = wApplicationOf(wwin->main_window);
275 if (wapp && !wapp->flags.emulated)
276 wflags->emulate_appicon = 0;
279 if (wwin->transient_for!=None
280 && wwin->transient_for!=wwin->screen_ptr->root_win)
281 wflags->emulate_appicon = 0;
283 if (wflags->sunken && mask->sunken && wflags->floating && mask->floating)
284 wflags->sunken = 0;
289 void
290 wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace)
292 WScreen *scr = wwin->screen_ptr;
294 /* sets global default stuff */
295 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
296 &wwin->client_flags, NULL, True);
298 * Decoration setting is done in this precedence (lower to higher)
299 * - use global default in the resource database
300 * - guess some settings
301 * - use GNUstep/external window attributes
302 * - set hints specified for the app in the resource DB
305 WSETUFLAG(wwin, broken_close, 0);
307 if (wwin->protocols.DELETE_WINDOW)
308 WSETUFLAG(wwin, kill_close, 0);
309 else
310 WSETUFLAG(wwin, kill_close, 1);
312 /* transients can't be iconified or maximized */
313 if (wwin->transient_for) {
314 WSETUFLAG(wwin, no_miniaturizable, 1);
315 WSETUFLAG(wwin, no_miniaturize_button, 1);
318 /* if the window can't be resized, remove the resizebar */
319 if (wwin->normal_hints->flags & (PMinSize|PMaxSize)
320 && (wwin->normal_hints->min_width==wwin->normal_hints->max_width)
321 && (wwin->normal_hints->min_height==wwin->normal_hints->max_height)) {
322 WSETUFLAG(wwin, no_resizable, 1);
323 WSETUFLAG(wwin, no_resizebar, 1);
326 /* set GNUstep window attributes */
327 if (wwin->wm_gnustep_attr) {
328 setupGNUstepHints(wwin, wwin->wm_gnustep_attr);
330 if (wwin->wm_gnustep_attr->flags & GSWindowLevelAttr) {
332 switch (wwin->wm_gnustep_attr->window_level) {
333 case WMNormalWindowLevel:
334 *level = WMNormalLevel;
335 break;
336 case WMFloatingWindowLevel:
337 *level = WMFloatingLevel;
338 break;
339 case WMDockWindowLevel:
340 *level = WMDockLevel;
341 break;
342 case WMSubmenuWindowLevel:
343 *level = WMSubmenuLevel;
344 break;
345 case WMMainMenuWindowLevel:
346 *level = WMMainMenuLevel;
347 break;
348 default:
349 *level = WMNormalLevel;
350 break;
352 } else {
353 /* setup defaults */
354 *level = WMNormalLevel;
356 } else {
357 int tmp_workspace = -1;
358 int tmp_level = -1;
360 #ifdef MWM_HINTS
361 wMWMCheckClientHints(wwin);
362 #endif /* MWM_HINTS */
364 #ifdef KWM_HINTS
365 wKWMCheckClientHints(wwin, &tmp_workspace);
366 #endif /* KWM_HINTS */
368 #ifdef GNOME_STUFF
369 wGNOMECheckClientHints(wwin, &tmp_level, &tmp_workspace);
370 #endif /* GNOME_STUFF */
372 #ifdef OLWM_HINTS
373 wOLWMCheckClientHints(wwin);
374 #endif /* OLWM_HINTS */
376 if (tmp_level < 0) {
377 if (WFLAGP(wwin, floating))
378 *level = WMFloatingLevel;
379 else if (WFLAGP(wwin, sunken))
380 *level = WMSunkenLevel;
381 else
382 *level = WMNormalLevel;
383 } else {
384 *level = tmp_level;
387 if (tmp_workspace >= 0) {
388 *workspace = tmp_workspace % scr->workspace_count;
393 * Set attributes specified only for that window/class.
394 * This might do duplicate work with the 1st wDefaultFillAttributes().
396 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
397 &wwin->user_flags, &wwin->defined_user_flags,
398 False);
400 * Sanity checks for attributes that depend on other attributes
402 if (wwin->user_flags.no_appicon && wwin->defined_user_flags.no_appicon)
403 wwin->user_flags.emulate_appicon = 0;
405 if (wwin->main_window!=None) {
406 WApplication *wapp = wApplicationOf(wwin->main_window);
407 if (wapp && !wapp->flags.emulated)
408 wwin->user_flags.emulate_appicon = 0;
411 if (wwin->transient_for!=None
412 && wwin->transient_for!=wwin->screen_ptr->root_win)
413 wwin->user_flags.emulate_appicon = 0;
415 if (wwin->user_flags.sunken && wwin->defined_user_flags.sunken
416 && wwin->user_flags.floating && wwin->defined_user_flags.floating)
417 wwin->user_flags.sunken = 0;
419 WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
425 Bool
426 wWindowCanReceiveFocus(WWindow *wwin)
428 if (!wwin->flags.mapped && !wwin->flags.shaded)
429 return False;
430 if (WFLAGP(wwin, no_focusable) || wwin->flags.miniaturized)
431 return False;
432 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
433 return False;
435 return True;
439 Bool
440 wWindowObscuresWindow(WWindow *wwin, WWindow *obscured)
442 int w1, h1, w2, h2;
444 w1 = wwin->frame->core->width;
445 h1 = wwin->frame->core->height;
446 w2 = obscured->frame->core->width;
447 h2 = obscured->frame->core->height;
449 if (!IS_OMNIPRESENT(wwin) && !IS_OMNIPRESENT(obscured)
450 && wwin->frame->workspace != obscured->frame->workspace)
451 return False;
453 if (wwin->frame_x + w1 < obscured->frame_x
454 || wwin->frame_y + h1 < obscured->frame_y
455 || wwin->frame_x > obscured->frame_x + w2
456 || wwin->frame_y > obscured->frame_y + h2) {
457 return False;
460 return True;
465 *----------------------------------------------------------------
466 * wManageWindow--
467 * reparents the window and allocates a descriptor for it.
468 * Window manager hints and other hints are fetched to configure
469 * the window decoration attributes and others. User preferences
470 * for the window are used if available, to configure window
471 * decorations and some behaviour.
473 * Returns:
474 * the new window descriptor
476 * Side effects:
477 * The window is reparented and appropriate notification
478 * is done to the client. Input mask for the window is setup.
479 * The window descriptor is also associated with various window
480 * contexts and inserted in the head of the window list.
481 * Event handler contexts are associated for some objects
482 * (buttons, titlebar and resizebar)
484 *----------------------------------------------------------------
486 WWindow*
487 wManageWindow(WScreen *scr, Window window)
489 WWindow *wwin;
490 int x, y;
491 unsigned width, height;
492 XWindowAttributes wattribs;
493 XSetWindowAttributes attribs;
494 WWindowState *win_state;
495 WWindow *transientOwner = NULL;
496 int window_level;
497 int foo;
498 int workspace = -1;
499 char *title;
501 /* mutex. */
502 XGrabServer(dpy);
503 XSync(dpy, 0);
504 /* make sure the window is still there */
505 if (!XGetWindowAttributes(dpy, window, &wattribs)) {
506 XUngrabServer(dpy);
507 return NULL;
510 if (!wFetchName(dpy, window, &title)) {
511 title = NULL;
514 #ifdef KWM_HINTS
515 if (title && !wKWMManageableClient(scr, window, title)) {
516 XFree(title);
517 XUngrabServer(dpy);
518 return NULL;
520 #endif /* KWM_HINTS */
523 wwin = wWindowCreate();
525 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
527 #ifdef DEBUG
528 printf("managing window %x\n", (unsigned)window);
529 #endif
531 #ifdef SHAPE
532 if (wShapeSupported) {
533 int junk;
534 unsigned int ujunk;
535 int b_shaped;
537 XShapeSelectInput(dpy, window, ShapeNotifyMask);
538 XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk,
539 &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
540 wwin->flags.shaped = b_shaped;
542 #endif
545 *--------------------------------------------------
547 * Get hints and other information in properties
549 *--------------------------------------------------
551 wwin->wm_hints = XGetWMHints(dpy, window);
552 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
554 /* setup descriptor */
555 wwin->client_win = window;
556 wwin->screen_ptr = scr;
558 wwin->old_border_width = wattribs.border_width;
560 attribs.event_mask = CLIENT_EVENTS;
561 attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
562 attribs.save_under = False;
563 XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate
564 |CWSaveUnder, &attribs);
565 XSetWindowBorderWidth(dpy, window, 0);
567 /* get hints from GNUstep app */
568 if (!PropGetGNUstepWMAttr(window, &wwin->wm_gnustep_attr)) {
569 wwin->wm_gnustep_attr=NULL;
572 wwin->client_leader = PropGetClientLeader(window);
573 if (wwin->client_leader!=None)
574 wwin->main_window = wwin->client_leader;
576 if (wwin->wm_hints)
577 XFree(wwin->wm_hints);
579 wwin->wm_hints = XGetWMHints(dpy, window);
581 if (wwin->wm_hints) {
582 if ((wwin->wm_hints->flags&StateHint)
583 && (wwin->wm_hints->initial_state == IconicState)) {
584 wwin->flags.miniaturized = 1;
585 /* don't do iconify animation */
586 wwin->flags.skip_next_animation = 1;
589 if (wwin->wm_hints->flags & WindowGroupHint) {
590 wwin->group_id = wwin->wm_hints->window_group;
591 /* window_group has priority over CLIENT_LEADER */
592 wwin->main_window = wwin->group_id;
593 } else {
594 wwin->group_id = None;
597 if (wwin->wm_hints->flags & UrgencyHint)
598 wwin->flags.urgent = 1;
599 } else {
600 wwin->group_id = None;
603 PropGetProtocols(window, &wwin->protocols);
605 if (!XGetTransientForHint(dpy, window, &wwin->transient_for)) {
606 wwin->transient_for = None;
607 } else {
608 if (wwin->transient_for==None || wwin->transient_for==window) {
609 wwin->transient_for = scr->root_win;
610 } else {
611 transientOwner = wWindowFor(wwin->transient_for);
612 if (transientOwner && transientOwner->main_window!=None) {
613 wwin->main_window = transientOwner->main_window;
614 } /*else {
615 wwin->main_window = None;
620 /* guess the focus mode */
621 wwin->focus_mode = getFocusMode(wwin);
623 /* get geometry stuff */
624 wClientGetNormalHints(wwin, &wattribs, True, &x, &y, &width, &height);
626 /* get colormap windows */
627 GetColormapWindows(wwin);
631 *--------------------------------------------------
633 * Setup the decoration/window attributes and
634 * geometry
636 *--------------------------------------------------
639 wWindowSetupInitialAttributes(wwin, &window_level, &workspace);
641 #ifdef OLWM_HINTS
642 if (wwin->client_flags.olwm_transient && wwin->transient_for==None
643 && wwin->group_id!=None && wwin->group_id != window) {
645 transientOwner = wWindowFor(wwin->group_id);
647 if (transientOwner) {
648 wwin->transient_for = wwin->group_id;
650 /* transients can't be iconified or maximized */
651 if (wwin->transient_for) {
652 WSETUFLAG(wwin, no_miniaturizable, 1);
653 WSETUFLAG(wwin, no_miniaturize_button, 1);
657 #endif /* OLWM_HINTS */
660 * Make broken apps behave as a nice app.
662 if (WFLAGP(wwin, emulate_appicon)) {
663 wwin->main_window = wwin->client_win;
667 *------------------------------------------------------------
669 * Setup the initial state of the window
671 *------------------------------------------------------------
674 if (WFLAGP(wwin, start_miniaturized) && !WFLAGP(wwin, no_miniaturizable)) {
675 wwin->flags.miniaturized = 1;
678 if (WFLAGP(wwin, start_maximized) && !WFLAGP(wwin, no_resizable)) {
679 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
682 #ifdef GNOME_STUFF
683 wGNOMECheckInitialClientState(wwin);
684 #endif
685 #ifdef KWM_HINTS
686 wKWMCheckClientInitialState(wwin);
687 #endif
689 /* if there is a saved state, restore it */
690 win_state = NULL;
691 if (wwin->main_window!=None/* && wwin->main_window!=window*/) {
692 win_state = (WWindowState*)wWindowGetSavedState(wwin->main_window);
693 } else {
694 win_state = (WWindowState*)wWindowGetSavedState(window);
696 if (win_state && !(wwin->wm_hints && wwin->wm_hints->flags&StateHint &&
697 wwin->wm_hints->initial_state==WithdrawnState)) {
698 if (win_state->state->hidden>0)
699 wwin->flags.hidden = win_state->state->hidden;
700 if (win_state->state->shaded>0 && !WFLAGP(wwin, no_shadeable))
701 wwin->flags.shaded = win_state->state->shaded;
702 if (win_state->state->miniaturized>0 &&
703 !WFLAGP(wwin, no_miniaturizable)) {
704 wwin->flags.miniaturized = win_state->state->miniaturized;
706 if (!IS_OMNIPRESENT(wwin)) {
707 int w = wDefaultGetStartWorkspace(scr, wwin->wm_instance,
708 wwin->wm_class);
709 if (w < 0 || w >= scr->workspace_count) {
710 workspace = win_state->state->workspace;
711 if (workspace >= scr->workspace_count)
712 workspace = scr->current_workspace;
713 } else {
714 workspace = w;
716 } else {
717 workspace = scr->current_workspace;
721 /* if we're restarting, restore saved state. This will overwrite previous */
723 WSavedState *wstate;
725 if (getSavedState(window, &wstate)) {
726 wwin->flags.shaded = wstate->shaded;
727 wwin->flags.hidden = wstate->hidden;
728 wwin->flags.miniaturized = 0;
729 workspace = wstate->workspace;
730 free(wstate);
734 /* don't let transients start miniaturized if their owners are not */
735 if (transientOwner && !transientOwner->flags.miniaturized
736 && wwin->flags.miniaturized) {
737 wwin->flags.miniaturized = 0;
738 if (wwin->wm_hints)
739 wwin->wm_hints->initial_state = NormalState;
742 /* set workspace on which the window starts */
743 if (workspace >= 0) {
744 if (workspace > scr->workspace_count-1) {
745 workspace = workspace % scr->workspace_count;
747 } else {
748 int w;
750 w = wDefaultGetStartWorkspace(scr, wwin->wm_instance, wwin->wm_class);
752 if (w >= 0 && w < scr->workspace_count && !(IS_OMNIPRESENT(wwin))) {
754 workspace = w;
756 } else {
757 if (wPreferences.open_transients_with_parent && transientOwner) {
759 workspace = transientOwner->frame->workspace;
761 } else {
763 workspace = scr->current_workspace;
768 /* setup window geometry */
769 if (win_state && win_state->state->use_geometry) {
770 width = win_state->state->w;
771 height = win_state->state->h;
773 wWindowConstrainSize(wwin, &width, &height);
775 /* do not ask for window placement if the window is
776 * transient, during startup, if the initial workspace is another one
777 * or if the window wants to
778 * start iconic.
779 * If geometry was saved, restore it. */
781 Bool dontBring = False;
783 if (win_state && win_state->state->use_geometry) {
784 x = win_state->state->x;
785 y = win_state->state->y;
786 } else if (wwin->transient_for==None && !scr->flags.startup &&
787 workspace==scr->current_workspace
788 && !wwin->flags.miniaturized
789 && !wwin->flags.maximized
790 && !(wwin->normal_hints->flags & (USPosition|PPosition))) {
791 PlaceWindow(wwin, &x, &y, width, height);
792 if (wPreferences.window_placement == WPM_MANUAL)
793 dontBring = True;
796 if (WFLAGP(wwin, dont_move_off) && dontBring)
797 wScreenBringInside(scr, &x, &y, width, height);
800 *--------------------------------------------------
802 * Create frame, borders and do reparenting
804 *--------------------------------------------------
807 foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
808 if (!WFLAGP(wwin, no_titlebar))
809 foo |= WFF_TITLEBAR;
810 if (!WFLAGP(wwin, no_resizebar))
811 foo |= WFF_RESIZEBAR;
813 wwin->frame = wFrameWindowCreate(scr, window_level,
814 x, y, width, height, foo,
815 scr->window_title_texture,
816 (WTexture**)scr->resizebar_texture,
817 scr->window_title_pixel,
818 &scr->window_title_gc,
819 &scr->title_font);
821 wwin->frame->flags.is_client_window_frame = 1;
822 wwin->frame->flags.justification = wPreferences.title_justification;
824 /* setup button images */
825 wWindowUpdateButtonImages(wwin);
827 /* hide unused buttons */
828 foo = 0;
829 if (WFLAGP(wwin, no_close_button))
830 foo |= WFF_RIGHT_BUTTON;
831 if (WFLAGP(wwin, no_miniaturize_button))
832 foo |= WFF_LEFT_BUTTON;
833 if (foo!=0)
834 wFrameWindowHideButton(wwin->frame, foo);
836 wwin->frame->child = wwin;
838 #ifdef OLWM_HINTS
839 /* emulate olwm push pin. Make the button look as pushed-in for
840 * the pinned-out state. When the button is clicked, it will
841 * revert to the normal position, which means the pin is pinned-in.
843 if (wwin->flags.olwm_push_pin_out)
844 wFrameWindowUpdatePushButton(wwin->frame, True);
845 #endif /* OLWM_HINTS */
847 wFrameWindowChangeTitle(wwin->frame, title ? title : DEF_WINDOW_TITLE);
848 if (title)
849 XFree(title);
851 wwin->frame->workspace = workspace;
853 wwin->frame->on_click_left = windowIconifyClick;
855 wwin->frame->on_click_right = windowCloseClick;
856 wwin->frame->on_dblclick_right = windowCloseDblClick;
858 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
859 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
861 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
863 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
864 0, wwin->frame->top_width);
867 int gx, gy;
869 wClientGetGravityOffsets(wwin, &gx, &gy);
871 /* if gravity is to the south, account for the border sizes */
872 if (gy > 0)
873 y -= wwin->frame->top_width + wwin->frame->bottom_width;
877 * wWindowConfigure() will init the client window's size
878 * (wwin->client.{width,height}) and all other geometry
879 * related variables (frame_x,frame_y)
881 wWindowConfigure(wwin, x, y, width, height);
884 *--------------------------------------------------
886 * Setup descriptors and save window to internal
887 * lists
889 *--------------------------------------------------
892 if (wwin->main_window!=None) {
893 WApplication *app;
894 WWindow *leader;
896 /* Leader windows do not necessary set themselves as leaders.
897 * If this is the case, point the leader of this window to
898 * itself */
899 leader = wWindowFor(wwin->main_window);
900 if (leader && leader->main_window==None) {
901 leader->main_window = leader->client_win;
903 app = wApplicationCreate(scr, wwin->main_window);
904 if (app) {
905 app->last_workspace = workspace;
908 * Do application specific stuff, like setting application
909 * wide attributes.
912 if (wwin->flags.hidden) {
913 /* if the window was set to hidden because it was hidden
914 * in a previous incarnation and that state was restored */
915 app->flags.hidden = 1;
918 if (app->flags.hidden) {
919 wwin->flags.hidden = 1;
924 /* setup the frame descriptor */
925 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
926 wwin->frame->core->descriptor.parent = wwin;
927 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
929 /* don't let windows go away if we die */
930 XAddToSaveSet(dpy, window);
932 XLowerWindow(dpy, window);
934 /* if window is in this workspace and should be mapped, then map it */
935 if (!wwin->flags.miniaturized && (workspace == scr->current_workspace
936 || IS_OMNIPRESENT(wwin))
937 && !wwin->flags.hidden
938 && !(wwin->wm_hints && (wwin->wm_hints->flags & StateHint)
939 && wwin->wm_hints->initial_state == WithdrawnState)) {
940 /* The following "if" is to avoid crashing of clients that expect
941 * WM_STATE set before they get mapped. Else WM_STATE is set later,
942 * after the return from this function.
944 if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint)) {
945 wClientSetState(wwin, wwin->wm_hints->initial_state, None);
946 } else {
947 wClientSetState(wwin, NormalState, None);
950 /* if not auto focus, then map the window under the currently
951 * focused window */
952 #define _WIDTH(w) (w)->frame->core->width
953 #define _HEIGHT(w) (w)->frame->core->height
954 if (!wPreferences.auto_focus && scr->focused_window
955 && !scr->flags.startup
956 && wWindowObscuresWindow(wwin, scr->focused_window)
957 && (_WIDTH(wwin) > (_WIDTH(scr->focused_window)*5)/3
958 || _HEIGHT(wwin) > (_HEIGHT(scr->focused_window)*5)/3)
959 && WINDOW_LEVEL(scr->focused_window) == WINDOW_LEVEL(wwin)) {
960 MoveInStackListUnder(scr->focused_window->frame->core,
961 wwin->frame->core);
963 #undef _WIDTH
964 #undef _HEIGHT
966 if (wPreferences.superfluous && !wPreferences.no_animations
967 && !scr->flags.startup && wwin->transient_for==None
969 * The brain damaged idiotic non-click to focus modes will
970 * have trouble with this because:
972 * 1. window is created and mapped by the client
973 * 2. window is mapped by wmaker in small size
974 * 3. window is animated to grow to normal size
975 * 4. this function returns to normal event loop
976 * 5. eventually, the EnterNotify event that would trigger
977 * the window focusing (if the mouse is over that window)
978 * will be processed by wmaker.
979 * But since this event will be rather delayed
980 * (step 3 has a large delay) the time when the event ocurred
981 * and when it is processed, the client that owns that window
982 * will reject the XSetInputFocus() for it.
984 && (wPreferences.focus_mode==WKF_CLICK
985 || wPreferences.auto_focus)) {
986 DoWindowBirth(wwin);
988 XMapSubwindows(dpy, wwin->frame->core->window);
990 wWindowMap(wwin);
991 } else {
992 XMapSubwindows(dpy, wwin->frame->core->window);
995 /* setup stacking descriptor */
996 if (transientOwner) {
997 /* && wPreferences.on_top_transients */
998 if (transientOwner) {
999 wwin->frame->core->stacking->child_of =
1000 transientOwner->frame->core;
1002 } else {
1003 wwin->frame->core->stacking->child_of = NULL;
1007 if (!scr->focused_window) {
1008 /* first window on the list */
1009 wwin->next = NULL;
1010 wwin->prev = NULL;
1011 scr->focused_window = wwin;
1012 } else {
1013 WWindow *tmp;
1015 /* add window at beginning of focus window list */
1016 tmp = scr->focused_window;
1017 while (tmp->prev)
1018 tmp = tmp->prev;
1019 tmp->prev = wwin;
1020 wwin->next = tmp;
1021 wwin->prev = NULL;
1025 #ifdef GNOME_STUFF
1026 wGNOMEUpdateClientStateHint(wwin, True);
1027 #endif
1028 #ifdef KWM_HINTS
1029 wKWMUpdateClientWorkspace(wwin);
1030 wKWMUpdateClientStateHint(wwin, KWMAllFlags);
1031 #endif
1033 XUngrabServer(dpy);
1036 *--------------------------------------------------
1038 * Final preparations before window is ready to go
1040 *--------------------------------------------------
1043 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1046 if (!wwin->flags.miniaturized && workspace == scr->current_workspace) {
1047 if ((transientOwner && transientOwner->flags.focused)
1048 || wPreferences.auto_focus)
1049 wSetFocusTo(scr, wwin);
1050 } else {
1051 wwin->flags.ignore_next_unmap = 1;
1053 wWindowResetMouseGrabs(wwin);
1055 if (!WFLAGP(wwin, no_bind_keys)) {
1056 wWindowSetKeyGrabs(wwin);
1058 #ifdef GNOME_STUFF
1059 wGNOMEUpdateClientListHint(scr);
1060 #endif
1061 #ifdef KWM_HINTS
1062 wKWMSendEventMessage(wwin, WKWMAddWindow);
1063 #endif
1065 * Prevent window withdrawal when getting the
1066 * unmap notifies generated during reparenting
1068 wwin->flags.mapped = 0;
1070 XSync(dpy, 0);
1072 wColormapInstallForWindow(wwin->screen_ptr, scr->cmap_window);
1074 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1076 #ifdef OLWM_HINTS
1077 if (wwin->client_flags.olwm_warp_to_pin && wwin->frame->titlebar != NULL
1078 && !WFLAGP(wwin, no_close_button)) {
1080 XWarpPointer(dpy, None, None, 0, 0, 0, 0,
1081 wwin->frame_x + width - wwin->frame->titlebar->height * 2,
1082 wwin->frame_y);
1084 #endif
1087 *--------------------------------------------------
1088 * Cleanup temporary stuff
1089 *--------------------------------------------------
1092 if (win_state)
1093 wWindowDeleteSavedState(win_state);
1095 return wwin;
1102 WWindow*
1103 wManageInternalWindow(WScreen *scr, Window window, Window owner,
1104 char *title, int x, int y, int width, int height)
1106 WWindow *wwin;
1107 int foo;
1109 wwin = wWindowCreate();
1111 wwin->flags.internal_window = 1;
1113 WSETUFLAG(wwin, omnipresent, 1);
1114 WSETUFLAG(wwin, no_shadeable, 1);
1115 WSETUFLAG(wwin, no_resizable, 1);
1116 WSETUFLAG(wwin, no_miniaturizable, 1);
1118 wwin->focus_mode = WFM_PASSIVE;
1120 wwin->client_win = window;
1121 wwin->screen_ptr = scr;
1123 wwin->transient_for = owner;
1125 wwin->client.x = x;
1126 wwin->client.y = y;
1127 wwin->client.width = width;
1128 wwin->client.height = height;
1130 wwin->frame_x = wwin->client.x;
1131 wwin->frame_y = wwin->client.y;
1134 foo = WFF_RIGHT_BUTTON;
1135 foo |= WFF_TITLEBAR;
1137 wwin->frame = wFrameWindowCreate(scr, WMFloatingLevel,
1138 wwin->frame_x, wwin->frame_y,
1139 width, height, foo,
1140 scr->window_title_texture,
1141 (WTexture**)scr->resizebar_texture,
1142 scr->window_title_pixel,
1143 &scr->window_title_gc,
1144 &scr->title_font);
1146 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
1148 wwin->frame->flags.is_client_window_frame = 1;
1149 wwin->frame->flags.justification = wPreferences.title_justification;
1151 wFrameWindowChangeTitle(wwin->frame, title);
1153 /* setup button images */
1154 wWindowUpdateButtonImages(wwin);
1156 /* hide buttons */
1157 wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON);
1159 wwin->frame->child = wwin;
1161 wwin->frame->workspace = wwin->screen_ptr->current_workspace;
1163 wwin->frame->on_click_right = windowCloseClick;
1165 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
1166 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
1168 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
1170 wwin->client.y += wwin->frame->top_width;
1171 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
1172 0, wwin->frame->top_width);
1174 wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y,
1175 wwin->client.width, wwin->client.height);
1177 /* setup the frame descriptor */
1178 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
1179 wwin->frame->core->descriptor.parent = wwin;
1180 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
1183 XLowerWindow(dpy, window);
1184 XMapSubwindows(dpy, wwin->frame->core->window);
1186 /* setup stacking descriptor */
1187 if (
1188 #ifdef removed
1189 wPreferences.on_top_transients &&
1190 #endif
1191 wwin->transient_for!=None
1192 && wwin->transient_for!=scr->root_win) {
1193 WWindow *tmp;
1194 tmp = wWindowFor(wwin->transient_for);
1195 if (tmp)
1196 wwin->frame->core->stacking->child_of = tmp->frame->core;
1197 } else {
1198 wwin->frame->core->stacking->child_of = NULL;
1202 if (!scr->focused_window) {
1203 /* first window on the list */
1204 wwin->next = NULL;
1205 wwin->prev = NULL;
1206 scr->focused_window = wwin;
1207 } else {
1208 WWindow *tmp;
1210 /* add window at beginning of focus window list */
1211 tmp = scr->focused_window;
1212 while (tmp->prev)
1213 tmp = tmp->prev;
1214 tmp->prev = wwin;
1215 wwin->next = tmp;
1216 wwin->prev = NULL;
1219 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1221 /* if (wPreferences.auto_focus)*/
1222 wSetFocusTo(scr, wwin);
1224 wWindowResetMouseGrabs(wwin);
1226 wWindowSetKeyGrabs(wwin);
1228 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1230 return wwin;
1235 *----------------------------------------------------------------------
1236 * wUnmanageWindow--
1237 * Removes the frame window from a window and destroys all data
1238 * related to it. The window will be reparented back to the root window
1239 * if restore is True.
1241 * Side effects:
1242 * Everything related to the window is destroyed and the window
1243 * is removed from the window lists. Focus is set to the previous on the
1244 * window list.
1245 *----------------------------------------------------------------------
1247 void
1248 wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed)
1250 WCoreWindow *frame = wwin->frame->core;
1251 WWindow *owner = NULL;
1252 WWindow *newFocusedWindow = NULL;
1253 int wasFocused;
1254 WScreen *scr = wwin->screen_ptr;
1257 #ifdef KWM_HINTS
1258 wwin->frame->workspace = -1;
1260 wKWMUpdateClientWorkspace(wwin);
1261 #endif
1263 /* First close attribute editor window if open */
1264 if (wwin->flags.inspector_open) {
1265 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1266 (*pwin->frame->on_click_right)(NULL, pwin, NULL);
1269 /* Close window menu if it's open for this window */
1270 if (wwin->flags.menu_open_for_me) {
1271 CloseWindowMenu(scr);
1274 if (!destroyed) {
1275 if (!wwin->flags.internal_window)
1276 XRemoveFromSaveSet(dpy, wwin->client_win);
1278 XSelectInput(dpy, wwin->client_win, NoEventMask);
1281 XUnmapWindow(dpy, frame->window);
1283 /* deselect window */
1284 wSelectWindow(wwin, False);
1286 /* remove all pending events on window */
1287 /* I think this only matters for autoraise */
1288 if (wPreferences.raise_delay)
1289 WMDeleteTimerWithClientData(wwin->frame->core);
1291 XFlush(dpy);
1293 UpdateSwitchMenu(scr, wwin, ACTION_REMOVE);
1295 /* reparent the window back to the root */
1296 if (restore)
1297 wClientRestore(wwin);
1299 if (wwin->transient_for!=scr->root_win) {
1300 owner = wWindowFor(wwin->transient_for);
1301 if (owner) {
1302 if (!owner->flags.semi_focused) {
1303 owner = NULL;
1304 } else {
1305 owner->flags.semi_focused = 0;
1310 wasFocused = wwin->flags.focused;
1312 /* remove from window focus list */
1313 if (!wwin->prev && !wwin->next) {
1314 /* was the only window */
1315 scr->focused_window = NULL;
1316 newFocusedWindow = NULL;
1317 } else {
1318 WWindow *tmp;
1320 if (wwin->prev)
1321 wwin->prev->next = wwin->next;
1322 if (wwin->next)
1323 wwin->next->prev = wwin->prev;
1324 else {
1325 scr->focused_window = wwin->prev;
1326 scr->focused_window->next = NULL;
1329 /* if in click to focus mode and the window
1330 * was a transient, focus the owner window
1332 tmp = NULL;
1333 if (wPreferences.focus_mode==WKF_CLICK) {
1334 tmp = wWindowFor(wwin->transient_for);
1335 if (tmp && (!tmp->flags.mapped || WFLAGP(tmp, no_focusable))) {
1336 tmp = NULL;
1339 /* otherwise, focus the next one in the focus list */
1340 if (!tmp) {
1341 tmp = scr->focused_window;
1342 while (tmp) {
1343 if (!WFLAGP(tmp, no_focusable)
1344 && (tmp->flags.mapped || tmp->flags.shaded))
1345 break;
1346 tmp = tmp->prev;
1349 if (wPreferences.focus_mode==WKF_CLICK) {
1350 newFocusedWindow = tmp;
1351 } else if (wPreferences.focus_mode==WKF_SLOPPY
1352 || wPreferences.focus_mode==WKF_POINTER) {
1353 unsigned int mask;
1354 int foo;
1355 Window bar, win;
1357 /* This is to let the root window get the keyboard input
1358 * if Sloppy focus mode and no other window get focus.
1359 * This way keybindings will not freeze.
1361 tmp = NULL;
1362 if (XQueryPointer(dpy, scr->root_win, &bar, &win,
1363 &foo, &foo, &foo, &foo, &mask))
1364 tmp = wWindowFor(win);
1365 if (tmp == wwin)
1366 tmp = NULL;
1367 newFocusedWindow = tmp;
1368 } else {
1369 newFocusedWindow = NULL;
1373 if (!wwin->flags.internal_window) {
1374 #ifdef GNOME_STUFF
1375 wGNOMERemoveClient(wwin);
1376 #endif
1377 #ifdef KWM_HINTS
1378 wKWMSendEventMessage(wwin, WKWMRemoveWindow);
1379 #endif
1382 #ifdef DEBUG
1383 printf("destroying window %x frame %x\n", (unsigned)wwin->client_win,
1384 (unsigned)frame->window);
1385 #endif
1387 if (wasFocused) {
1388 if (newFocusedWindow != owner && owner) {
1389 wFrameWindowChangeState(owner->frame, WS_UNFOCUSED);
1391 wSetFocusTo(scr, newFocusedWindow);
1393 wWindowDestroy(wwin);
1394 XFlush(dpy);
1398 void
1399 wWindowFocus(WWindow *wwin)
1401 #ifdef KEEP_XKB_LOCK_STATUS
1402 if (wPreferences.modelock) {
1403 if (!wwin->flags.focused) {
1404 XkbLockGroup(dpy, XkbUseCoreKbd, wwin->languagemode);
1407 #endif /* KEEP_XKB_LOCK_STATUS */
1409 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
1411 wwin->flags.focused=1;
1413 wWindowResetMouseGrabs(wwin);
1415 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1420 void
1421 wWindowMap(WWindow *wwin)
1423 XMapWindow(dpy, wwin->frame->core->window);
1424 if (!wwin->flags.shaded) {
1425 XMapWindow(dpy, wwin->client_win);
1426 wwin->flags.mapped = 1;
1431 void
1432 wWindowUnmap(WWindow *wwin)
1434 XWindowAttributes attribs;
1436 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
1437 wwin->flags.mapped = 0;
1439 /* prevent window withdrawal when getting UnmapNotify */
1440 XSelectInput(dpy, wwin->client_win,
1441 attribs.your_event_mask & ~StructureNotifyMask);
1442 XUnmapWindow(dpy, wwin->client_win);
1443 XSelectInput(dpy, wwin->client_win, attribs.your_event_mask);
1445 XUnmapWindow(dpy, wwin->frame->core->window);
1449 void
1450 wWindowUnfocus(WWindow *wwin)
1452 #ifdef KEEP_XKB_LOCK_STATUS
1453 static XkbStateRec staterec;
1454 if (wPreferences.modelock) {
1455 if (wwin->flags.focused) {
1456 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1457 wwin->languagemode=staterec.compat_state&32?1:0;
1458 XkbLockGroup(dpy,XkbUseCoreKbd,0); /* reset to workspace */
1461 #endif /* KEEP_XKB_LOCK_STATUS */
1463 CloseWindowMenu(wwin->screen_ptr);
1465 wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused
1466 ? WS_PFOCUSED : WS_UNFOCUSED);
1468 if (wwin->transient_for!=None
1469 && wwin->transient_for!=wwin->screen_ptr->root_win) {
1470 WWindow *owner;
1471 owner = wWindowFor(wwin->transient_for);
1472 if (owner && owner->flags.semi_focused) {
1473 owner->flags.semi_focused = 0;
1474 if (owner->flags.mapped || owner->flags.shaded) {
1475 wWindowUnfocus(owner);
1476 wFrameWindowPaint(owner->frame);
1480 wwin->flags.focused=0;
1481 wWindowResetMouseGrabs(wwin);
1483 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1490 *----------------------------------------------------------------------
1492 * wWindowConstrainSize--
1493 * Constrains size for the client window, taking the maximal size,
1494 * window resize increments and other size hints into account.
1496 * Returns:
1497 * The closest size to what was given that the client window can
1498 * have.
1500 *----------------------------------------------------------------------
1502 void
1503 wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight)
1505 XSizeHints *sizeh = wwin->normal_hints;
1506 int width = *nwidth;
1507 int height = *nheight;
1508 int winc = sizeh->width_inc;
1509 int hinc = sizeh->height_inc;
1511 if (width < sizeh->min_width)
1512 width = sizeh->min_width;
1513 if (height < sizeh->min_height)
1514 height = sizeh->min_height;
1516 if (width > sizeh->max_width)
1517 width = sizeh->max_width;
1518 if (height > sizeh->max_height)
1519 height = sizeh->max_height;
1521 /* aspect ratio code borrowed from olwm */
1522 if (sizeh->flags & PAspect) {
1523 /* adjust max aspect ratio */
1524 if (!(sizeh->max_aspect.x==1 && sizeh->max_aspect.y==1)
1525 && width * sizeh->max_aspect.y > height * sizeh->max_aspect.x) {
1526 if (sizeh->max_aspect.x > sizeh->max_aspect.y) {
1527 height = (width * sizeh->max_aspect.y) / sizeh->max_aspect.x;
1528 if (height > sizeh->max_height) {
1529 height = sizeh->max_height;
1530 width = (height*sizeh->max_aspect.x) / sizeh->max_aspect.y;
1532 } else {
1533 width = (height * sizeh->max_aspect.x) / sizeh->max_aspect.y;
1534 if (width > sizeh->max_width) {
1535 width = sizeh->max_width;
1536 height = (width*sizeh->max_aspect.y) / sizeh->max_aspect.x;
1541 /* adjust min aspect ratio */
1542 if (!(sizeh->min_aspect.x==1 && sizeh->min_aspect.y==1)
1543 && width * sizeh->min_aspect.y < height * sizeh->min_aspect.x) {
1544 if (sizeh->min_aspect.x > sizeh->min_aspect.y) {
1545 height = (width * sizeh->min_aspect.y) / sizeh->min_aspect.x;
1546 if (height < sizeh->min_height) {
1547 height = sizeh->min_height;
1548 width = (height*sizeh->min_aspect.x) / sizeh->min_aspect.y;
1550 } else {
1551 width = (height * sizeh->min_aspect.x) / sizeh->min_aspect.y;
1552 if (width > sizeh->min_width) {
1553 width = sizeh->min_width;
1554 height = (width*sizeh->min_aspect.y) / sizeh->min_aspect.x;
1560 if (sizeh->base_width != 0) {
1561 width = (((width - sizeh->base_width) / winc) * winc)
1562 + sizeh->base_width;
1563 } else {
1564 width = (((width - sizeh->min_width) / winc) * winc)
1565 + sizeh->min_width;
1568 if (sizeh->base_width != 0) {
1569 height = (((height - sizeh->base_height) / hinc) * hinc)
1570 + sizeh->base_height;
1571 } else {
1572 height = (((height - sizeh->min_height) / hinc) * hinc)
1573 + sizeh->min_height;
1576 *nwidth = width;
1577 *nheight = height;
1581 void
1582 wWindowChangeWorkspace(WWindow *wwin, int workspace)
1584 WScreen *scr = wwin->screen_ptr;
1585 WApplication *wapp;
1586 int unmap = 0;
1588 if (workspace >= scr->workspace_count || workspace < 0
1589 || workspace == wwin->frame->workspace)
1590 return;
1592 if (workspace != scr->current_workspace) {
1593 /* Sent to other workspace. Unmap window */
1594 if ((wwin->flags.mapped||wwin->flags.shaded)
1595 && !IS_OMNIPRESENT(wwin) && !wwin->flags.changing_workspace) {
1597 wapp = wApplicationOf(wwin->main_window);
1598 if (wapp) {
1599 wapp->last_workspace = workspace;
1601 unmap = 1;
1602 wSetFocusTo(scr, NULL);
1604 } else {
1605 /* brought to current workspace. Map window */
1606 if (!wwin->flags.mapped &&
1607 !(wwin->flags.miniaturized || wwin->flags.hidden)) {
1608 wWindowMap(wwin);
1611 if (!IS_OMNIPRESENT(wwin)) {
1612 wwin->frame->workspace = workspace;
1613 UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
1615 #ifdef GNOME_STUFF
1616 wGNOMEUpdateClientStateHint(wwin, True);
1617 #endif
1618 #ifdef KWM_HINTS
1619 wKWMUpdateClientWorkspace(wwin);
1620 wKWMSendEventMessage(wwin, WKWMChangedClient);
1621 #endif
1622 if (unmap) {
1623 wWindowUnmap(wwin);
1628 void
1629 wWindowSynthConfigureNotify(WWindow *wwin)
1631 XEvent sevent;
1633 sevent.type = ConfigureNotify;
1634 sevent.xconfigure.display = dpy;
1635 sevent.xconfigure.event = wwin->client_win;
1636 sevent.xconfigure.window = wwin->client_win;
1638 sevent.xconfigure.x = wwin->client.x;
1639 sevent.xconfigure.y = wwin->client.y;
1640 sevent.xconfigure.width = wwin->client.width;
1641 sevent.xconfigure.height = wwin->client.height;
1643 sevent.xconfigure.border_width = wwin->old_border_width;
1644 if (WFLAGP(wwin, no_titlebar))
1645 sevent.xconfigure.above = None;
1646 else
1647 sevent.xconfigure.above = wwin->frame->titlebar->window;
1649 sevent.xconfigure.override_redirect = False;
1650 XSendEvent(dpy, wwin->client_win, False, StructureNotifyMask, &sevent);
1651 #ifdef KWM_HINTS
1652 wKWMSendEventMessage(wwin, WKWMChangedClient);
1653 #endif
1654 XFlush(dpy);
1659 *----------------------------------------------------------------------
1660 * wWindowConfigure--
1661 * Configures the frame, decorations and client window to the
1662 * specified geometry. The geometry is not checked for validity,
1663 * wWindowConstrainSize() must be used for that.
1664 * The size parameters are for the client window, but the position is
1665 * for the frame.
1666 * The client window receives a ConfigureNotify event, according
1667 * to what ICCCM says.
1669 * Returns:
1670 * None
1672 * Side effects:
1673 * Window size and position are changed and client window receives
1674 * a ConfigureNotify event.
1675 *----------------------------------------------------------------------
1677 void
1678 wWindowConfigure(wwin, req_x, req_y, req_width, req_height)
1679 WWindow *wwin;
1680 int req_x, req_y; /* new position of the frame */
1681 int req_width, req_height; /* new size of the client */
1683 int synth_notify = False;
1684 int resize;
1686 resize = (req_width!=wwin->client.width
1687 || req_height!=wwin->client.height);
1689 * if the window is being moved but not resized then
1690 * send a synthetic ConfigureNotify
1692 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) {
1693 synth_notify = True;
1696 if (WFLAGP(wwin, dont_move_off))
1697 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1698 req_width, req_height);
1699 if (resize) {
1700 if (req_width < MIN_WINDOW_SIZE)
1701 req_width = MIN_WINDOW_SIZE;
1702 if (req_height < MIN_WINDOW_SIZE)
1703 req_height = MIN_WINDOW_SIZE;
1705 /* If growing, resize inner part before frame,
1706 * if shrinking, resize frame before.
1707 * This will prevent the frame (that can have a different color)
1708 * to be exposed, causing flicker */
1709 if (req_height > wwin->frame->core->height
1710 || req_width > wwin->frame->core->width)
1711 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
1713 if (wwin->flags.shaded) {
1714 wFrameWindowConfigure(wwin->frame, req_x, req_y,
1715 req_width, wwin->frame->core->height);
1716 wwin->old_geometry.height = req_height;
1717 } else {
1718 int h;
1720 h = req_height + wwin->frame->top_width
1721 + wwin->frame->bottom_width;
1723 wFrameWindowConfigure(wwin->frame, req_x, req_y, req_width, h);
1726 if (!(req_height > wwin->frame->core->height
1727 || req_width > wwin->frame->core->width))
1728 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
1730 wwin->client.x = req_x;
1731 wwin->client.y = req_y + wwin->frame->top_width;
1732 wwin->client.width = req_width;
1733 wwin->client.height = req_height;
1734 } else {
1735 wwin->client.x = req_x;
1736 wwin->client.y = req_y + wwin->frame->top_width;
1738 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1740 wwin->frame_x = req_x;
1741 wwin->frame_y = req_y;
1743 #ifdef SHAPE
1744 if (wShapeSupported && wwin->flags.shaped && resize) {
1745 wWindowSetShape(wwin);
1747 #endif
1749 if (synth_notify)
1750 wWindowSynthConfigureNotify(wwin);
1751 XFlush(dpy);
1755 void
1756 wWindowMove(wwin, req_x, req_y)
1757 WWindow *wwin;
1758 int req_x, req_y; /* new position of the frame */
1760 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1761 int synth_notify = False;
1763 /* Send a synthetic ConfigureNotify event for every window movement. */
1764 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y)) {
1765 synth_notify = True;
1767 #else
1768 /* A single synthetic ConfigureNotify event is sent at the end of
1769 * a completed (opaque) movement in moveres.c */
1770 #endif
1772 if (WFLAGP(wwin, dont_move_off))
1773 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1774 wwin->frame->core->width, wwin->frame->core->height);
1776 wwin->client.x = req_x;
1777 wwin->client.y = req_y + wwin->frame->top_width;
1779 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1781 wwin->frame_x = req_x;
1782 wwin->frame_y = req_y;
1784 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1785 if (synth_notify)
1786 wWindowSynthConfigureNotify(wwin);
1787 #endif
1791 void
1792 wWindowUpdateButtonImages(WWindow *wwin)
1794 WScreen *scr = wwin->screen_ptr;
1795 Pixmap pixmap, mask;
1796 WFrameWindow *fwin = wwin->frame;
1798 if (WFLAGP(wwin, no_titlebar))
1799 return;
1801 /* miniaturize button */
1803 if (!WFLAGP(wwin, no_miniaturize_button)) {
1804 if (wwin->wm_gnustep_attr
1805 && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) {
1806 pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap;
1808 if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) {
1809 mask = wwin->wm_gnustep_attr->miniaturize_mask;
1810 } else {
1811 mask = None;
1814 if (fwin->lbutton_image
1815 && (fwin->lbutton_image->image != pixmap
1816 || fwin->lbutton_image->mask != mask)) {
1817 wPixmapDestroy(fwin->lbutton_image);
1818 fwin->lbutton_image = NULL;
1821 if (!fwin->lbutton_image) {
1822 fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask);
1823 fwin->lbutton_image->client_owned = 1;
1824 fwin->lbutton_image->client_owned_mask = 1;
1826 } else {
1827 if (fwin->lbutton_image && !fwin->lbutton_image->shared) {
1828 wPixmapDestroy(fwin->lbutton_image);
1830 fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
1834 /* close button */
1836 if (!WFLAGP(wwin, no_close_button)) {
1837 if (wwin->wm_gnustep_attr
1838 && wwin->wm_gnustep_attr->flags&GSClosePixmapAttr) {
1839 pixmap = wwin->wm_gnustep_attr->close_pixmap;
1841 if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr) {
1842 mask = wwin->wm_gnustep_attr->close_mask;
1843 } else {
1844 mask = None;
1847 if (fwin->rbutton_image
1848 && (fwin->rbutton_image->image != pixmap
1849 || fwin->rbutton_image->mask != mask)) {
1850 wPixmapDestroy(fwin->rbutton_image);
1851 fwin->rbutton_image = NULL;
1854 if (!fwin->rbutton_image) {
1855 fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask);
1856 fwin->rbutton_image->client_owned = 1;
1857 fwin->rbutton_image->client_owned_mask = 1;
1859 } else if (WFLAGP(wwin, kill_close)) {
1860 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1861 wPixmapDestroy(fwin->rbutton_image);
1863 fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL];
1864 } else if (WFLAGP(wwin, broken_close)) {
1865 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1866 wPixmapDestroy(fwin->rbutton_image);
1868 fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE];
1869 } else {
1870 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1871 wPixmapDestroy(fwin->rbutton_image);
1873 fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE];
1877 /* force buttons to be redrawn */
1878 fwin->flags.need_texture_change = 1;
1879 wFrameWindowPaint(fwin);
1884 *---------------------------------------------------------------------------
1885 * wWindowConfigureBorders--
1886 * Update window border configuration according to attribute flags.
1888 *---------------------------------------------------------------------------
1890 void
1891 wWindowConfigureBorders(WWindow *wwin)
1893 if (wwin->frame) {
1894 int flags;
1895 int newy, oldh;
1897 flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON;
1898 if (!WFLAGP(wwin, no_titlebar))
1899 flags |= WFF_TITLEBAR;
1900 if (!WFLAGP(wwin, no_resizebar))
1901 flags |= WFF_RESIZEBAR;
1903 oldh = wwin->frame->top_width;
1904 wFrameWindowUpdateBorders(wwin->frame, flags);
1905 if (oldh != wwin->frame->top_width) {
1906 newy = wwin->frame_y + oldh - wwin->frame->top_width;
1908 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
1909 wWindowConfigure(wwin, wwin->frame_x, newy,
1910 wwin->client.width, wwin->client.height);
1913 flags = 0;
1914 if (!WFLAGP(wwin, no_miniaturize_button)
1915 && wwin->frame->flags.hide_left_button)
1916 flags |= WFF_LEFT_BUTTON;
1918 if (!WFLAGP(wwin, no_close_button)
1919 && wwin->frame->flags.hide_right_button)
1920 flags |= WFF_RIGHT_BUTTON;
1922 if (flags!=0) {
1923 wWindowUpdateButtonImages(wwin);
1924 wFrameWindowShowButton(wwin->frame, flags);
1927 flags = 0;
1928 if (WFLAGP(wwin, no_miniaturize_button)
1929 && !wwin->frame->flags.hide_left_button)
1930 flags |= WFF_LEFT_BUTTON;
1932 if (WFLAGP(wwin, no_close_button)
1933 && !wwin->frame->flags.hide_right_button)
1934 flags |= WFF_RIGHT_BUTTON;
1936 if (flags!=0)
1937 wFrameWindowHideButton(wwin->frame, flags);
1939 #ifdef SHAPE
1940 if (wShapeSupported && wwin->flags.shaped) {
1941 wWindowSetShape(wwin);
1943 #endif
1948 void
1949 wWindowSaveState(WWindow *wwin)
1951 CARD32 data[9];
1953 memset(data, 0, sizeof(CARD32)*9);
1954 data[0] = wwin->frame->workspace;
1955 data[2] = wwin->flags.shaded;
1956 data[3] = wwin->flags.hidden;
1958 XChangeProperty(dpy, wwin->client_win, _XA_WINDOWMAKER_STATE,
1959 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1960 (unsigned char *)data, 9);
1964 static int
1965 getSavedState(Window window, WSavedState **state)
1967 Atom type_ret;
1968 int fmt_ret;
1969 unsigned long nitems_ret;
1970 unsigned long bytes_after_ret;
1971 CARD32 *data;
1973 if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0, 9,
1974 True, _XA_WINDOWMAKER_STATE,
1975 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
1976 (unsigned char **)&data)!=Success || !data)
1977 return 0;
1979 *state = malloc(sizeof(WSavedState));
1981 if (*state) {
1982 (*state)->workspace = data[0];
1983 (*state)->miniaturized = data[1];
1984 (*state)->shaded = data[2];
1985 (*state)->hidden = data[3];
1986 (*state)->use_geometry = data[4];
1987 (*state)->x = data[5];
1988 (*state)->y = data[6];
1989 (*state)->w = data[7];
1990 (*state)->h = data[8];
1992 XFree(data);
1994 if (*state && type_ret==_XA_WINDOWMAKER_STATE)
1995 return 1;
1996 else
1997 return 0;
2001 #ifdef SHAPE
2002 void
2003 wWindowClearShape(WWindow *wwin)
2005 XShapeCombineMask(dpy, wwin->frame->core->window, ShapeBounding,
2006 0, wwin->frame->top_width, None, ShapeSet);
2007 XFlush(dpy);
2010 void
2011 wWindowSetShape(WWindow *wwin)
2013 XRectangle rect[2];
2014 int count;
2015 #ifdef OPTIMIZE_SHAPE
2016 XRectangle *rects;
2017 XRectangle *urec;
2018 int ordering;
2020 /* only shape is the client's */
2021 if (WFLAGP(wwin, no_titlebar) && WFLAGP(wwin, no_resizebar)) {
2022 goto alt_code;
2025 /* Get array of rectangles describing the shape mask */
2026 rects = XShapeGetRectangles(dpy, wwin->client_win, ShapeBounding,
2027 &count, &ordering);
2028 if (!rects) {
2029 goto alt_code;
2032 urec = malloc(sizeof(XRectangle)*(count+2));
2033 if (!urec) {
2034 XFree(rects);
2035 goto alt_code;
2038 /* insert our decoration rectangles in the rect list */
2039 memcpy(urec, rects, sizeof(XRectangle)*count);
2040 XFree(rects);
2042 if (!WFLAGP(wwin, no_titlebar)) {
2043 urec[count].x = -1;
2044 urec[count].y = -1 - wwin->frame->top_width;
2045 urec[count].width = wwin->frame->core->width + 2;
2046 urec[count].height = wwin->frame->top_width + 1;
2047 count++;
2049 if (!WFLAGP(wwin, no_resizebar)) {
2050 urec[count].x = -1;
2051 urec[count].y = wwin->frame->core->height
2052 - wwin->frame->bottom_width - wwin->frame->top_width;
2053 urec[count].width = wwin->frame->core->width + 2;
2054 urec[count].height = wwin->frame->bottom_width + 1;
2055 count++;
2058 /* shape our frame window */
2059 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
2060 0, wwin->frame->top_width, urec, count,
2061 ShapeSet, Unsorted);
2062 XFlush(dpy);
2063 free(urec);
2064 return;
2066 alt_code:
2067 #endif /* OPTIMIZE_SHAPE */
2068 count = 0;
2069 if (!WFLAGP(wwin, no_titlebar)) {
2070 rect[count].x = -1;
2071 rect[count].y = -1;
2072 rect[count].width = wwin->frame->core->width + 2;
2073 rect[count].height = wwin->frame->top_width + 1;
2074 count++;
2076 if (!WFLAGP(wwin, no_resizebar)) {
2077 rect[count].x = -1;
2078 rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width;
2079 rect[count].width = wwin->frame->core->width + 2;
2080 rect[count].height = wwin->frame->bottom_width + 1;
2081 count++;
2083 if (count > 0) {
2084 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
2085 0, 0, rect, count, ShapeSet, Unsorted);
2087 XShapeCombineShape(dpy, wwin->frame->core->window, ShapeBounding,
2088 0, wwin->frame->top_width, wwin->client_win,
2089 ShapeBounding, (count > 0 ? ShapeUnion : ShapeSet));
2090 XFlush(dpy);
2092 #endif /* SHAPE */
2094 /* ====================================================================== */
2096 static FocusMode
2097 getFocusMode(WWindow *wwin)
2099 FocusMode mode;
2101 if ((wwin->wm_hints) && (wwin->wm_hints->flags & InputHint)) {
2102 if (wwin->wm_hints->input == True) {
2103 if (wwin->protocols.TAKE_FOCUS)
2104 mode = WFM_LOCALLY_ACTIVE;
2105 else
2106 mode = WFM_PASSIVE;
2107 } else {
2108 if (wwin->protocols.TAKE_FOCUS)
2109 mode = WFM_GLOBALLY_ACTIVE;
2110 else
2111 mode = WFM_NO_INPUT;
2113 } else {
2114 mode = WFM_PASSIVE;
2116 return mode;
2120 void
2121 wWindowSetKeyGrabs(WWindow *wwin)
2123 int i;
2124 WShortKey *key;
2126 for (i=0; i<WKBD_LAST; i++) {
2127 key = &wKeyBindings[i];
2129 if (key->keycode==0)
2130 continue;
2131 if (key->modifier!=AnyModifier) {
2132 XGrabKey(dpy, key->keycode, key->modifier|LockMask,
2133 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
2134 #ifdef NUMLOCK_HACK
2135 /* Also grab all modifier combinations possible that include,
2136 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
2137 * work even if the NumLock/ScrollLock key is on.
2139 wHackedGrabKey(key->keycode, key->modifier,
2140 wwin->frame->core->window, True, GrabModeAsync,
2141 GrabModeAsync);
2142 #endif
2144 XGrabKey(dpy, key->keycode, key->modifier,
2145 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
2148 #ifndef LITE
2149 wRootMenuBindShortcuts(wwin->frame->core->window);
2150 #endif
2155 void
2156 wWindowResetMouseGrabs(WWindow *wwin)
2158 /* Mouse grabs can't be done on the client window because of
2159 * ICCCM and because clients that try to do the same will crash.
2161 * But there is a problem wich makes tbar buttons of unfocused
2162 * windows not usable as the click goes to the frame window instead
2163 * of the button itself. Must figure a way to fix that.
2166 XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
2168 if (!WFLAGP(wwin, no_bind_mouse)) {
2169 /* grabs for Meta+drag */
2170 wHackedGrabButton(AnyButton, MOD_MASK, wwin->client_win,
2171 True, ButtonPressMask, GrabModeSync,
2172 GrabModeAsync, None, None);
2175 if (!wwin->flags.focused) {
2176 /* the passive grabs to focus the window */
2177 if (wPreferences.focus_mode == WKF_CLICK)
2178 XGrabButton(dpy, AnyButton, AnyModifier, wwin->client_win,
2179 True, ButtonPressMask, GrabModeSync, GrabModeAsync,
2180 None, None);
2182 XFlush(dpy);
2186 void
2187 wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr)
2190 if (attr->flags & GSExtraFlagsAttr) {
2191 if (WFLAGP(wwin, broken_close) !=
2192 (attr->extra_flags & GSDocumentEditedFlag)) {
2194 wwin->client_flags.broken_close = !WFLAGP(wwin, broken_close);
2196 wWindowUpdateButtonImages(wwin);
2203 WMagicNumber
2204 wWindowAddSavedState(char *instance, char *class, char *command,
2205 pid_t pid, WSavedState *state)
2207 WWindowState *wstate;
2209 wstate = malloc(sizeof(WWindowState));
2210 if (!wstate)
2211 return 0;
2213 memset(wstate, 0, sizeof(WWindowState));
2214 wstate->pid = pid;
2215 if (instance)
2216 wstate->instance = wstrdup(instance);
2217 if (class)
2218 wstate->class = wstrdup(class);
2219 if (command)
2220 wstate->command = wstrdup(command);
2221 wstate->state = state;
2223 wstate->next = windowState;
2224 windowState = wstate;
2226 #ifdef DEBUG
2227 printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
2228 class, command);
2229 #endif
2231 return wstate;
2235 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
2238 WMagicNumber
2239 wWindowGetSavedState(Window win)
2241 char *instance, *class, *command=NULL;
2242 WWindowState *wstate = windowState;
2243 char **argv;
2244 int argc;
2246 if (!wstate)
2247 return NULL;
2249 if (XGetCommand(dpy, win, &argv, &argc)) {
2250 if (argc > 0)
2251 command = FlattenStringList(argv, argc);
2252 XFreeStringList(argv);
2254 if (!command)
2255 return NULL;
2257 if (PropGetWMClass(win, &class, &instance)) {
2258 while (wstate) {
2259 if (SAME(instance, wstate->instance) &&
2260 SAME(class, wstate->class) &&
2261 SAME(command, wstate->command)) {
2262 break;
2264 wstate = wstate->next;
2266 } else {
2267 wstate = NULL;
2270 #ifdef DEBUG
2271 printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
2272 class, command);
2273 #endif
2275 if (command) free(command);
2276 if (instance) XFree(instance);
2277 if (class) XFree(class);
2279 return wstate;
2283 void
2284 wWindowDeleteSavedState(WMagicNumber id)
2286 WWindowState *tmp, *wstate=(WWindowState*)id;
2288 if (!wstate || !windowState)
2289 return;
2291 tmp = windowState;
2292 if (tmp==wstate) {
2293 windowState = wstate->next;
2294 #ifdef DEBUG
2295 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2296 wstate, wstate->instance, wstate->class, wstate->command);
2297 #endif
2298 if (wstate->instance) free(wstate->instance);
2299 if (wstate->class) free(wstate->class);
2300 if (wstate->command) free(wstate->command);
2301 free(wstate->state);
2302 free(wstate);
2303 } else {
2304 while (tmp->next) {
2305 if (tmp->next==wstate) {
2306 tmp->next=wstate->next;
2307 #ifdef DEBUG
2308 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2309 wstate, wstate->instance, wstate->class, wstate->command);
2310 #endif
2311 if (wstate->instance) free(wstate->instance);
2312 if (wstate->class) free(wstate->class);
2313 if (wstate->command) free(wstate->command);
2314 free(wstate->state);
2315 free(wstate);
2316 break;
2318 tmp = tmp->next;
2324 void
2325 wWindowDeleteSavedStatesForPID(pid_t pid)
2327 WWindowState *tmp, *wstate;
2329 if (!windowState)
2330 return;
2332 tmp = windowState;
2333 if (tmp->pid == pid) {
2334 wstate = windowState;
2335 windowState = tmp->next;
2336 #ifdef DEBUG
2337 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2338 wstate, wstate->instance, wstate->class, wstate->command);
2339 #endif
2340 if (wstate->instance) free(wstate->instance);
2341 if (wstate->class) free(wstate->class);
2342 if (wstate->command) free(wstate->command);
2343 free(wstate->state);
2344 free(wstate);
2345 } else {
2346 while (tmp->next) {
2347 if (tmp->next->pid==pid) {
2348 wstate = tmp->next;
2349 tmp->next = wstate->next;
2350 #ifdef DEBUG
2351 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2352 wstate, wstate->instance, wstate->class, wstate->command);
2353 #endif
2354 if (wstate->instance) free(wstate->instance);
2355 if (wstate->class) free(wstate->class);
2356 if (wstate->command) free(wstate->command);
2357 free(wstate->state);
2358 free(wstate);
2359 break;
2361 tmp = tmp->next;
2367 /* ====================================================================== */
2369 static void
2370 resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
2372 WWindow *wwin = data;
2374 #ifndef NUMLOCK_HACK
2375 if ((event->xbutton.state & ValidModMask)
2376 != (event->xbutton.state & ~LockMask)) {
2377 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2378 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2380 #endif
2382 event->xbutton.state &= ValidModMask;
2384 CloseWindowMenu(wwin->screen_ptr);
2386 if (wPreferences.focus_mode==WKF_CLICK
2387 && !(event->xbutton.state&ControlMask)) {
2388 wSetFocusTo(wwin->screen_ptr, wwin);
2391 if (event->xbutton.button == Button1)
2392 wRaiseFrame(wwin->frame->core);
2394 if (event->xbutton.window != wwin->frame->resizebar->window) {
2395 if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
2396 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2397 GrabModeAsync, GrabModeAsync, None,
2398 None, CurrentTime)!=GrabSuccess) {
2399 #ifdef DEBUG0
2400 wwarning("pointer grab failed for window move");
2401 #endif
2402 return;
2406 if (event->xbutton.state & MOD_MASK) {
2407 /* move the window */
2408 wMouseMoveWindow(wwin, event);
2409 XUngrabPointer(dpy, CurrentTime);
2410 } else {
2411 wMouseResizeWindow(wwin, event);
2412 XUngrabPointer(dpy, CurrentTime);
2418 static void
2419 titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event)
2421 WWindow *wwin = data;
2423 event->xbutton.state &= ValidModMask;
2425 if (event->xbutton.button==Button1) {
2426 if (event->xbutton.state == 0) {
2427 if (!WFLAGP(wwin, no_shadeable)) {
2428 /* shade window */
2429 if (wwin->flags.shaded)
2430 wUnshadeWindow(wwin);
2431 else
2432 wShadeWindow(wwin);
2434 } else {
2435 int dir = 0;
2437 if (event->xbutton.state & ControlMask)
2438 dir |= MAX_VERTICAL;
2440 if (event->xbutton.state & ShiftMask) {
2441 dir |= MAX_HORIZONTAL;
2442 if (!(event->xbutton.state & ControlMask))
2443 wSelectWindow(wwin, !wwin->flags.selected);
2446 /* maximize window */
2447 if (dir !=0 && !WFLAGP(wwin, no_resizable)) {
2448 if (wwin->flags.maximized)
2449 wUnmaximizeWindow(wwin);
2450 else
2451 wMaximizeWindow(wwin, dir);
2454 } else if (event->xbutton.button==Button3) {
2455 if (event->xbutton.state & MOD_MASK) {
2456 wHideOtherApplications(wwin);
2458 } else if (event->xbutton.button==Button2) {
2459 wSelectWindow(wwin, !wwin->flags.selected);
2464 static void
2465 frameMouseDown(WObjDescriptor *desc, XEvent *event)
2467 WWindow *wwin = desc->parent;
2469 event->xbutton.state &= ValidModMask;
2471 CloseWindowMenu(wwin->screen_ptr);
2473 if (wPreferences.focus_mode==WKF_CLICK
2474 && !(event->xbutton.state&ControlMask)) {
2475 wSetFocusTo(wwin->screen_ptr, wwin);
2477 if (event->xbutton.button == Button1) {
2478 wRaiseFrame(wwin->frame->core);
2481 if (event->xbutton.state & MOD_MASK) {
2482 /* move the window */
2483 if (XGrabPointer(dpy, wwin->client_win, False,
2484 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2485 GrabModeAsync, GrabModeAsync, None,
2486 None, CurrentTime)!=GrabSuccess) {
2487 #ifdef DEBUG0
2488 wwarning("pointer grab failed for window move");
2489 #endif
2490 return;
2492 if (event->xbutton.button == Button3 && !WFLAGP(wwin, no_resizable))
2493 wMouseResizeWindow(wwin, event);
2494 else
2495 wMouseMoveWindow(wwin, event);
2496 XUngrabPointer(dpy, CurrentTime);
2501 static void
2502 titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
2504 WWindow *wwin = (WWindow*)data;
2506 #ifndef NUMLOCK_HACK
2507 if ((event->xbutton.state & ValidModMask)
2508 != (event->xbutton.state & ~LockMask)) {
2509 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2510 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2512 #endif
2513 event->xbutton.state &= ValidModMask;
2515 CloseWindowMenu(wwin->screen_ptr);
2517 if (wPreferences.focus_mode==WKF_CLICK
2518 && !(event->xbutton.state&ControlMask)) {
2519 wSetFocusTo(wwin->screen_ptr, wwin);
2522 if (event->xbutton.button == Button1
2523 || event->xbutton.button == Button2) {
2525 if (event->xbutton.button == Button1) {
2526 if (event->xbutton.state & MOD_MASK) {
2527 wLowerFrame(wwin->frame->core);
2528 } else {
2529 wRaiseFrame(wwin->frame->core);
2532 if ((event->xbutton.state & ShiftMask)
2533 && !(event->xbutton.state & ControlMask)) {
2534 wSelectWindow(wwin, !wwin->flags.selected);
2535 return;
2537 if (event->xbutton.window != wwin->frame->titlebar->window
2538 && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
2539 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2540 GrabModeAsync, GrabModeAsync, None,
2541 None, CurrentTime)!=GrabSuccess) {
2542 #ifdef DEBUG0
2543 wwarning("pointer grab failed for window move");
2544 #endif
2545 return;
2548 /* move the window */
2549 wMouseMoveWindow(wwin, event);
2551 XUngrabPointer(dpy, CurrentTime);
2552 } else if (event->xbutton.button == Button3 && event->xbutton.state==0
2553 && !wwin->flags.internal_window) {
2554 WObjDescriptor *desc;
2556 if (event->xbutton.window != wwin->frame->titlebar->window
2557 && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
2558 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2559 GrabModeAsync, GrabModeAsync, None,
2560 None, CurrentTime)!=GrabSuccess) {
2561 #ifdef DEBUG0
2562 wwarning("pointer grab failed for window move");
2563 #endif
2564 return;
2567 OpenWindowMenu(wwin, event->xbutton.x_root,
2568 wwin->frame_y+wwin->frame->top_width, False);
2570 /* allow drag select */
2571 desc = &wwin->screen_ptr->window_menu->menu->descriptor;
2572 event->xany.send_event = True;
2573 (*desc->handle_mousedown)(desc, event);
2575 XUngrabPointer(dpy, CurrentTime);
2581 static void
2582 windowCloseClick(WCoreWindow *sender, void *data, XEvent *event)
2584 WWindow *wwin = data;
2586 event->xbutton.state &= ValidModMask;
2588 CloseWindowMenu(wwin->screen_ptr);
2590 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
2591 return;
2593 /* if control-click, kill the client */
2594 if (event->xbutton.state & ControlMask) {
2595 wClientKill(wwin);
2596 } else {
2597 #ifdef OLWM_HINTS
2598 if (wwin->flags.olwm_push_pin_out) {
2600 wwin->flags.olwm_push_pin_out = 0;
2602 wOLWMChangePushpinState(wwin, True);
2604 wFrameWindowUpdatePushButton(wwin->frame, False);
2606 return;
2608 #endif
2609 if (wwin->protocols.DELETE_WINDOW && event->xbutton.state==0) {
2610 /* send delete message */
2611 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2617 static void
2618 windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
2620 WWindow *wwin = data;
2622 CloseWindowMenu(wwin->screen_ptr);
2624 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
2625 return;
2627 /* send delete message */
2628 if (wwin->protocols.DELETE_WINDOW) {
2629 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2630 } else {
2631 wClientKill(wwin);
2636 static void
2637 windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event)
2639 WWindow *wwin = data;
2641 event->xbutton.state &= ValidModMask;
2643 CloseWindowMenu(wwin->screen_ptr);
2645 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
2646 return;
2648 if (wwin->protocols.MINIATURIZE_WINDOW && event->xbutton.state==0) {
2649 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
2650 LastTimestamp);
2651 } else {
2652 WApplication *wapp;
2653 if ((event->xbutton.state & ControlMask) ||
2654 (event->xbutton.button == Button3)) {
2656 wapp = wApplicationOf(wwin->main_window);
2657 if (wapp && !WFLAGP(wwin, no_appicon))
2658 wHideApplication(wapp);
2659 } else if (event->xbutton.state==0) {
2660 wIconifyWindow(wwin);