changed indentation to use spaces only
[wmaker-crm.git] / src / window.c
blobd93a4fc24a760e15d9ee5dfadee1e597cfb972d7
1 /* window.c - client window managing stuffs
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 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,
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>
37 /* For getting mouse wheel mappings from WINGs */
38 #include <WINGs/WINGsP.h>
40 #include "WindowMaker.h"
41 #include "GNUstep.h"
42 #include "wcore.h"
43 #include "framewin.h"
44 #include "texture.h"
45 #include "window.h"
46 #include "winspector.h"
47 #include "icon.h"
48 #include "properties.h"
49 #include "actions.h"
50 #include "client.h"
51 #include "funcs.h"
52 #include "keybind.h"
53 #include "stacking.h"
54 #include "defaults.h"
55 #include "workspace.h"
56 #include "xinerama.h"
59 #ifdef MWM_HINTS
60 # include "motif.h"
61 #endif
62 #ifdef KWM_HINTS
63 # include "kwm.h"
64 #endif
65 #ifdef GNOME_STUFF
66 # include "gnome.h"
67 #endif
68 #ifdef OLWM_HINTS
69 # include "openlook.h"
70 #endif
71 #ifdef NETWM_HINTS
72 # include "wmspec.h"
73 #endif
75 /****** Global Variables ******/
77 extern WShortKey wKeyBindings[WKBD_LAST];
79 #ifdef SHAPE
80 extern Bool wShapeSupported;
81 #endif
83 /* contexts */
84 extern XContext wWinContext;
86 /* cursors */
87 extern Cursor wCursor[WCUR_LAST];
89 /* protocol atoms */
90 extern Atom _XA_WM_DELETE_WINDOW;
91 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
93 extern Atom _XA_WINDOWMAKER_STATE;
95 extern WPreferences wPreferences;
97 #define MOD_MASK wPreferences.modifier_mask
99 extern Time LastTimestamp;
101 /* superfluous... */
102 extern void DoWindowBirth(WWindow*);
106 /***** Local Stuff *****/
109 static WWindowState *windowState=NULL;
113 /* local functions */
114 static FocusMode getFocusMode(WWindow *wwin);
116 static int getSavedState(Window window, WSavedState **state);
118 static void setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints);
120 /* event handlers */
123 /* frame window (during window grabs) */
124 static void frameMouseDown(WObjDescriptor *desc, XEvent *event);
126 /* close button */
127 static void windowCloseClick(WCoreWindow *sender, void *data, XEvent *event);
128 static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event);
130 /* iconify button */
131 static void windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event);
133 #ifdef XKB_BUTTON_HINT
134 static void windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event);
135 #endif
137 static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
138 static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event);
140 static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
143 /****** Notification Observers ******/
145 static void
146 appearanceObserver(void *self, WMNotification *notif)
148 WWindow *wwin = (WWindow*)self;
149 int flags = (int)WMGetNotificationClientData(notif);
151 if (!wwin->frame || (!wwin->frame->titlebar && !wwin->frame->resizebar))
152 return;
154 if (flags & WFontSettings) {
155 wWindowConfigureBorders(wwin);
156 if(wwin->flags.shaded) {
157 wFrameWindowResize(wwin->frame, wwin->frame->core->width,
158 wwin->frame->top_width - 1);
160 wwin->client.y = wwin->frame_y - wwin->client.height
161 + wwin->frame->top_width;
162 wWindowSynthConfigureNotify(wwin);
165 if (flags & WTextureSettings) {
166 wwin->frame->flags.need_texture_remake = 1;
168 if (flags & (WTextureSettings | WColorSettings)) {
169 if (wwin->frame->titlebar)
170 XClearWindow(dpy, wwin->frame->titlebar->window);
172 wFrameWindowPaint(wwin->frame);
176 /************************************/
178 WWindow*
179 wWindowFor(Window window)
181 WObjDescriptor *desc;
183 if (window==None)
184 return NULL;
186 if (XFindContext(dpy, window, wWinContext, (XPointer*)&desc)==XCNOENT)
187 return NULL;
189 if (desc->parent_type==WCLASS_WINDOW)
190 return desc->parent;
191 else if (desc->parent_type==WCLASS_FRAME) {
192 WFrameWindow *frame = (WFrameWindow*)desc->parent;
193 if (frame->flags.is_client_window_frame)
194 return frame->child;
197 return NULL;
201 WWindow*
202 wWindowCreate()
204 WWindow *wwin;
206 wwin = wmalloc(sizeof(WWindow));
207 wretain(wwin);
209 memset(wwin, 0, sizeof(WWindow));
211 wwin->client_descriptor.handle_mousedown = frameMouseDown;
212 wwin->client_descriptor.parent = wwin;
213 wwin->client_descriptor.self = wwin;
214 wwin->client_descriptor.parent_type = WCLASS_WINDOW;
216 return wwin;
220 void
221 wWindowDestroy(WWindow *wwin)
223 int i;
225 if (wwin->screen_ptr->cmap_window == wwin) {
226 wwin->screen_ptr->cmap_window = NULL;
229 WMRemoveNotificationObserver(wwin);
231 wwin->flags.destroyed = 1;
233 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
234 if (!wwin->screen_ptr->shortcutWindows[i])
235 continue;
237 WMRemoveFromArray(wwin->screen_ptr->shortcutWindows[i], wwin);
239 if (!WMGetArrayItemCount(wwin->screen_ptr->shortcutWindows[i])) {
240 WMFreeArray(wwin->screen_ptr->shortcutWindows[i]);
241 wwin->screen_ptr->shortcutWindows[i] = NULL;
245 if (wwin->fake_group && wwin->fake_group->retainCount>0) {
246 wwin->fake_group->retainCount--;
247 if (wwin->fake_group->retainCount==0 && wwin->fake_group->leader!=None) {
248 XDestroyWindow(dpy, wwin->fake_group->leader);
249 wwin->fake_group->leader = None;
250 wwin->fake_group->origLeader = None;
251 XFlush(dpy);
255 if (wwin->normal_hints)
256 XFree(wwin->normal_hints);
258 if (wwin->wm_hints)
259 XFree(wwin->wm_hints);
261 if (wwin->wm_instance)
262 XFree(wwin->wm_instance);
264 if (wwin->wm_class)
265 XFree(wwin->wm_class);
267 if (wwin->wm_gnustep_attr)
268 wfree(wwin->wm_gnustep_attr);
270 if (wwin->cmap_windows)
271 XFree(wwin->cmap_windows);
273 XDeleteContext(dpy, wwin->client_win, wWinContext);
275 if (wwin->frame)
276 wFrameWindowDestroy(wwin->frame);
278 if (wwin->icon) {
279 RemoveFromStackList(wwin->icon->core);
280 wIconDestroy(wwin->icon);
281 if (wPreferences.auto_arrange_icons)
282 wArrangeIcons(wwin->screen_ptr, True);
285 #ifdef NETWM_HINTS
286 if (wwin->net_icon_image)
287 RReleaseImage(wwin->net_icon_image);
288 #endif
290 wrelease(wwin);
294 static void
295 setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints)
297 if (gs_hints->flags & GSWindowStyleAttr) {
298 if (gs_hints->window_style == WMBorderlessWindowMask) {
299 wwin->client_flags.no_border = 1;
300 wwin->client_flags.no_titlebar = 1;
301 wwin->client_flags.no_closable = 1;
302 wwin->client_flags.no_miniaturizable = 1;
303 wwin->client_flags.no_resizable = 1;
304 wwin->client_flags.no_close_button = 1;
305 wwin->client_flags.no_miniaturize_button = 1;
306 wwin->client_flags.no_resizebar = 1;
307 } else {
308 wwin->client_flags.no_close_button =
309 ((gs_hints->window_style & WMClosableWindowMask)?0:1);
311 wwin->client_flags.no_closable =
312 ((gs_hints->window_style & WMClosableWindowMask)?0:1);
314 wwin->client_flags.no_miniaturize_button =
315 ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1);
317 wwin->client_flags.no_miniaturizable =
318 wwin->client_flags.no_miniaturize_button;
320 wwin->client_flags.no_resizebar =
321 ((gs_hints->window_style & WMResizableWindowMask)?0:1);
323 wwin->client_flags.no_resizable = wwin->client_flags.no_resizebar;
325 /* these attributes supposedly imply in the existence
326 * of a titlebar */
327 if (gs_hints->window_style & (WMResizableWindowMask|
328 WMClosableWindowMask|
329 WMMiniaturizableWindowMask)) {
330 wwin->client_flags.no_titlebar = 0;
331 } else {
332 wwin->client_flags.no_titlebar =
333 ((gs_hints->window_style & WMTitledWindowMask)?0:1);
337 } else {
338 /* setup the defaults */
339 wwin->client_flags.no_border = 0;
340 wwin->client_flags.no_titlebar = 0;
341 wwin->client_flags.no_closable = 0;
342 wwin->client_flags.no_miniaturizable = 0;
343 wwin->client_flags.no_resizable = 0;
344 wwin->client_flags.no_close_button = 0;
345 wwin->client_flags.no_miniaturize_button = 0;
346 wwin->client_flags.no_resizebar = 0;
348 if (gs_hints->extra_flags & GSNoApplicationIconFlag) {
349 wwin->client_flags.no_appicon = 1;
354 void
355 wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags,
356 WWindowAttributes *mask)
358 if (wflags->no_appicon && mask->no_appicon)
359 wflags->emulate_appicon = 0;
361 if (wwin->main_window!=None) {
362 WApplication *wapp = wApplicationOf(wwin->main_window);
363 if (wapp && !wapp->flags.emulated)
364 wflags->emulate_appicon = 0;
367 if (wwin->transient_for!=None
368 && wwin->transient_for!=wwin->screen_ptr->root_win)
369 wflags->emulate_appicon = 0;
371 if (wflags->sunken && mask->sunken && wflags->floating && mask->floating)
372 wflags->sunken = 0;
377 void
378 wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace)
380 WScreen *scr = wwin->screen_ptr;
382 /* sets global default stuff */
383 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
384 &wwin->client_flags, NULL, True);
386 * Decoration setting is done in this precedence (lower to higher)
387 * - use global default in the resource database
388 * - guess some settings
389 * - use GNUstep/external window attributes
390 * - set hints specified for the app in the resource DB
393 WSETUFLAG(wwin, broken_close, 0);
395 if (wwin->protocols.DELETE_WINDOW)
396 WSETUFLAG(wwin, kill_close, 0);
397 else
398 WSETUFLAG(wwin, kill_close, 1);
400 /* transients can't be iconified or maximized */
401 if (wwin->transient_for!=None && wwin->transient_for!=scr->root_win) {
402 WSETUFLAG(wwin, no_miniaturizable, 1);
403 WSETUFLAG(wwin, no_miniaturize_button, 1);
406 /* if the window can't be resized, remove the resizebar */
407 if (wwin->normal_hints->flags & (PMinSize|PMaxSize)
408 && (wwin->normal_hints->min_width==wwin->normal_hints->max_width)
409 && (wwin->normal_hints->min_height==wwin->normal_hints->max_height)) {
410 WSETUFLAG(wwin, no_resizable, 1);
411 WSETUFLAG(wwin, no_resizebar, 1);
414 /* set GNUstep window attributes */
415 if (wwin->wm_gnustep_attr) {
416 setupGNUstepHints(wwin, wwin->wm_gnustep_attr);
418 if (wwin->wm_gnustep_attr->flags & GSWindowLevelAttr) {
420 *level = wwin->wm_gnustep_attr->window_level;
422 * INT_MIN is the only illegal window level.
424 if (*level == INT_MIN)
425 *level = INT_MIN + 1;
426 } else {
427 /* setup defaults */
428 *level = WMNormalLevel;
430 } else {
431 int tmp_workspace = -1;
432 int tmp_level = INT_MIN; /* INT_MIN is never used by the window levels */
433 Bool check;
435 check = False;
437 #ifdef MWM_HINTS
438 wMWMCheckClientHints(wwin);
439 #endif /* MWM_HINTS */
441 #ifdef NETWM_HINTS
442 if (!check)
443 check = wNETWMCheckClientHints(wwin, &tmp_level, &tmp_workspace);
444 #endif
446 #ifdef GNOME_STUFF
447 if (!check)
448 check = wGNOMECheckClientHints(wwin, &tmp_level, &tmp_workspace);
449 #endif /* GNOME_STUFF */
451 #ifdef KWM_HINTS
452 if (!check)
453 check = wKWMCheckClientHints(wwin, &tmp_level, &tmp_workspace);
454 #endif /* KWM_HINTS */
456 #ifdef OLWM_HINTS
457 wOLWMCheckClientHints(wwin);
458 #endif /* OLWM_HINTS */
460 /* window levels are between INT_MIN+1 and INT_MAX, so if we still
461 * have INT_MIN that means that no window level was requested. -Dan
463 if (tmp_level == INT_MIN) {
464 if (WFLAGP(wwin, floating))
465 *level = WMFloatingLevel;
466 else if (WFLAGP(wwin, sunken))
467 *level = WMSunkenLevel;
468 else
469 *level = WMNormalLevel;
470 } else {
471 *level = tmp_level;
474 if (wwin->transient_for!=None && wwin->transient_for != scr->root_win) {
475 WWindow * transientOwner = wWindowFor(wwin->transient_for);
476 if (transientOwner) {
477 int ownerLevel = transientOwner->frame->core->stacking->window_level;
478 if (ownerLevel > *level) *level = ownerLevel;
482 if (tmp_workspace >= 0) {
483 *workspace = tmp_workspace % scr->workspace_count;
488 * Set attributes specified only for that window/class.
489 * This might do duplicate work with the 1st wDefaultFillAttributes().
491 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
492 &wwin->user_flags, &wwin->defined_user_flags,
493 False);
495 * Sanity checks for attributes that depend on other attributes
497 if (wwin->user_flags.no_appicon && wwin->defined_user_flags.no_appicon)
498 wwin->user_flags.emulate_appicon = 0;
500 if (wwin->main_window!=None) {
501 WApplication *wapp = wApplicationOf(wwin->main_window);
502 if (wapp && !wapp->flags.emulated)
503 wwin->user_flags.emulate_appicon = 0;
506 if (wwin->transient_for!=None
507 && wwin->transient_for!=wwin->screen_ptr->root_win)
508 wwin->user_flags.emulate_appicon = 0;
510 if (wwin->user_flags.sunken && wwin->defined_user_flags.sunken
511 && wwin->user_flags.floating && wwin->defined_user_flags.floating)
512 wwin->user_flags.sunken = 0;
514 WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
517 /* windows that have takefocus=False shouldn't take focus at all */
518 if (wwin->focus_mode == WFM_NO_INPUT) {
519 wwin->client_flags.no_focusable = 1;
526 Bool
527 wWindowCanReceiveFocus(WWindow *wwin)
529 if (!wwin->flags.mapped && (!wwin->flags.shaded || wwin->flags.hidden))
530 return False;
531 if (WFLAGP(wwin, no_focusable) || wwin->flags.miniaturized)
532 return False;
533 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
534 return False;
536 return True;
540 Bool
541 wWindowObscuresWindow(WWindow *wwin, WWindow *obscured)
543 int w1, h1, w2, h2;
545 w1 = wwin->frame->core->width;
546 h1 = wwin->frame->core->height;
547 w2 = obscured->frame->core->width;
548 h2 = obscured->frame->core->height;
550 if (!IS_OMNIPRESENT(wwin) && !IS_OMNIPRESENT(obscured)
551 && wwin->frame->workspace != obscured->frame->workspace)
552 return False;
554 if (wwin->frame_x + w1 < obscured->frame_x
555 || wwin->frame_y + h1 < obscured->frame_y
556 || wwin->frame_x > obscured->frame_x + w2
557 || wwin->frame_y > obscured->frame_y + h2) {
558 return False;
561 return True;
565 static void
566 fixLeaderProperties(WWindow *wwin)
568 XClassHint *classHint;
569 XWMHints *hints, *clientHints;
570 Window leaders[2], window;
571 char **argv, *command;
572 int argc, i, pid;
573 Bool haveCommand;
575 classHint = XAllocClassHint();
576 clientHints = XGetWMHints(dpy, wwin->client_win);
577 pid = GetPidForWindow(wwin->client_win);
578 if (pid > 0) {
579 haveCommand = GetCommandForPid(pid, &argv, &argc);
580 } else {
581 haveCommand = False;
584 leaders[0] = wwin->client_leader;
585 leaders[1] = wwin->group_id;
587 if (haveCommand) {
588 command = GetCommandForWindow(wwin->client_win);
589 if (command) {
590 /* command already set. nothing to do. */
591 wfree(command);
592 } else {
593 XSetCommand(dpy, wwin->client_win, argv, argc);
597 for (i=0; i<2; i++) {
598 window = leaders[i];
599 if (window) {
600 if (XGetClassHint(dpy, window, classHint) == 0) {
601 classHint->res_name = wwin->wm_instance;
602 classHint->res_class = wwin->wm_class;
603 XSetClassHint(dpy, window, classHint);
605 hints = XGetWMHints(dpy, window);
606 if (hints) {
607 XFree(hints);
608 } else if (clientHints) {
609 /* set window group leader to self */
610 clientHints->window_group = window;
611 clientHints->flags |= WindowGroupHint;
612 XSetWMHints(dpy, window, clientHints);
615 if (haveCommand) {
616 command = GetCommandForWindow(window);
617 if (command) {
618 /* command already set. nothing to do. */
619 wfree(command);
620 } else {
621 XSetCommand(dpy, window, argv, argc);
627 XFree(classHint);
628 if (clientHints) {
629 XFree(clientHints);
631 if (haveCommand) {
632 wfree(argv);
637 static Window
638 createFakeWindowGroupLeader(WScreen *scr, Window win, char *instance, char *class)
640 XClassHint *classHint;
641 XWMHints *hints;
642 Window leader;
643 int argc;
644 char **argv;
646 leader = XCreateSimpleWindow(dpy, scr->root_win, 10, 10, 10, 10, 0, 0, 0);
647 /* set class hint */
648 classHint = XAllocClassHint();
649 classHint->res_name = instance;
650 classHint->res_class = class;
651 XSetClassHint(dpy, leader, classHint);
652 XFree(classHint);
654 /* inherit these from the original leader if available */
655 hints = XGetWMHints(dpy, win);
656 if (!hints) {
657 hints = XAllocWMHints();
658 hints->flags = 0;
660 /* set window group leader to self */
661 hints->window_group = leader;
662 hints->flags |= WindowGroupHint;
663 XSetWMHints(dpy, leader, hints);
664 XFree(hints);
666 if (XGetCommand(dpy, win, &argv, &argc)!=0 && argc > 0) {
667 XSetCommand(dpy, leader, argv, argc);
668 XFreeStringList(argv);
671 return leader;
675 static int
676 matchIdentifier(void *item, void *cdata)
678 return (strcmp(((WFakeGroupLeader*)item)->identifier, (char*)cdata)==0);
683 *----------------------------------------------------------------
684 * wManageWindow--
685 * reparents the window and allocates a descriptor for it.
686 * Window manager hints and other hints are fetched to configure
687 * the window decoration attributes and others. User preferences
688 * for the window are used if available, to configure window
689 * decorations and some behaviour.
690 * If in startup, windows that are override redirect,
691 * unmapped and never were managed and are Withdrawn are not
692 * managed.
694 * Returns:
695 * the new window descriptor
697 * Side effects:
698 * The window is reparented and appropriate notification
699 * is done to the client. Input mask for the window is setup.
700 * The window descriptor is also associated with various window
701 * contexts and inserted in the head of the window list.
702 * Event handler contexts are associated for some objects
703 * (buttons, titlebar and resizebar)
705 *----------------------------------------------------------------
707 WWindow*
708 wManageWindow(WScreen *scr, Window window)
710 WWindow *wwin;
711 int x, y;
712 unsigned width, height;
713 XWindowAttributes wattribs;
714 XSetWindowAttributes attribs;
715 WWindowState *win_state;
716 WWindow *transientOwner = NULL;
717 int window_level;
718 int wm_state;
719 int foo;
720 int workspace = -1;
721 char *title;
722 Bool withdraw = False;
723 Bool raise = False;
725 /* mutex. */
726 /* XGrabServer(dpy); */
727 XSync(dpy, False);
728 /* make sure the window is still there */
729 if (!XGetWindowAttributes(dpy, window, &wattribs)) {
730 XUngrabServer(dpy);
731 return NULL;
734 /* if it's an override-redirect, ignore it */
735 if (wattribs.override_redirect) {
736 XUngrabServer(dpy);
737 return NULL;
740 wm_state = PropGetWindowState(window);
742 /* if it's startup and the window is unmapped, don't manage it */
743 if (scr->flags.startup && wm_state < 0 && wattribs.map_state==IsUnmapped) {
744 XUngrabServer(dpy);
745 return NULL;
748 if (!wFetchName(dpy, window, &title)) {
749 title = NULL;
752 #ifdef KWM_HINTS
753 if (title && !wKWMManageableClient(scr, window, title)) {
754 XFree(title);
755 XUngrabServer(dpy);
756 return NULL;
758 #endif /* KWM_HINTS */
761 wwin = wWindowCreate();
763 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
765 #ifdef DEBUG
766 printf("managing window %x\n", (unsigned)window);
767 #endif
769 #ifdef SHAPE
770 if (wShapeSupported) {
771 int junk;
772 unsigned int ujunk;
773 int b_shaped;
775 XShapeSelectInput(dpy, window, ShapeNotifyMask);
776 XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk,
777 &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
778 wwin->flags.shaped = b_shaped;
780 #endif
783 *--------------------------------------------------
785 * Get hints and other information in properties
787 *--------------------------------------------------
789 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
791 /* setup descriptor */
792 wwin->client_win = window;
793 wwin->screen_ptr = scr;
795 wwin->old_border_width = wattribs.border_width;
797 wwin->event_mask = CLIENT_EVENTS;
798 attribs.event_mask = CLIENT_EVENTS;
799 attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
800 attribs.save_under = False;
801 XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate
802 |CWSaveUnder, &attribs);
803 XSetWindowBorderWidth(dpy, window, 0);
805 /* get hints from GNUstep app */
806 if (wwin->wm_class != 0 && strcmp(wwin->wm_class, "GNUstep") == 0) {
807 wwin->flags.is_gnustep = 1;
809 if (!PropGetGNUstepWMAttr(window, &wwin->wm_gnustep_attr)) {
810 wwin->wm_gnustep_attr = NULL;
813 wwin->client_leader = PropGetClientLeader(window);
814 if (wwin->client_leader!=None)
815 wwin->main_window = wwin->client_leader;
817 wwin->wm_hints = XGetWMHints(dpy, window);
819 if (wwin->wm_hints) {
820 if (wwin->wm_hints->flags & StateHint) {
822 if (wwin->wm_hints->initial_state == IconicState) {
824 wwin->flags.miniaturized = 1;
826 } else if (wwin->wm_hints->initial_state == WithdrawnState) {
828 withdraw = True;
832 if (wwin->wm_hints->flags & WindowGroupHint) {
833 wwin->group_id = wwin->wm_hints->window_group;
834 /* window_group has priority over CLIENT_LEADER */
835 wwin->main_window = wwin->group_id;
836 } else {
837 wwin->group_id = None;
840 if (wwin->wm_hints->flags & UrgencyHint)
841 wwin->flags.urgent = 1;
842 } else {
843 wwin->group_id = None;
846 PropGetProtocols(window, &wwin->protocols);
848 if (!XGetTransientForHint(dpy, window, &wwin->transient_for)) {
849 wwin->transient_for = None;
850 } else {
851 if (wwin->transient_for==None || wwin->transient_for==window) {
852 wwin->transient_for = scr->root_win;
853 } else {
854 transientOwner = wWindowFor(wwin->transient_for);
855 if (transientOwner && transientOwner->main_window!=None) {
856 wwin->main_window = transientOwner->main_window;
857 } /*else {
858 wwin->main_window = None;
863 /* guess the focus mode */
864 wwin->focus_mode = getFocusMode(wwin);
866 /* get geometry stuff */
867 wClientGetNormalHints(wwin, &wattribs, True, &x, &y, &width, &height);
869 /* printf("wManageWindow: %d %d %d %d\n", x, y, width, height);*/
871 /* get colormap windows */
872 GetColormapWindows(wwin);
875 *--------------------------------------------------
877 * Setup the decoration/window attributes and
878 * geometry
880 *--------------------------------------------------
883 wWindowSetupInitialAttributes(wwin, &window_level, &workspace);
885 #ifdef OLWM_HINTS
886 if (wwin->client_flags.olwm_transient && wwin->transient_for==None
887 && wwin->group_id != None && wwin->group_id != window) {
889 transientOwner = wWindowFor(wwin->group_id);
891 if (transientOwner) {
892 wwin->transient_for = wwin->group_id;
894 /* transients can't be iconified or maximized */
895 if (wwin->transient_for) {
896 WSETUFLAG(wwin, no_miniaturizable, 1);
897 WSETUFLAG(wwin, no_miniaturize_button, 1);
901 #endif /* OLWM_HINTS */
903 /* Make broken apps behave as a nice app. */
904 if (WFLAGP(wwin, emulate_appicon)) {
905 wwin->main_window = wwin->client_win;
908 fixLeaderProperties(wwin);
910 wwin->orig_main_window = wwin->main_window;
912 if (wwin->flags.is_gnustep) {
913 WSETUFLAG(wwin, shared_appicon, 0);
916 if (wwin->main_window) {
917 extern Atom _XA_WINDOWMAKER_MENU;
918 XTextProperty text_prop;
920 if (XGetTextProperty(dpy, wwin->main_window, &text_prop,
921 _XA_WINDOWMAKER_MENU)) {
922 WSETUFLAG(wwin, shared_appicon, 0);
926 if (!withdraw && wwin->main_window && WFLAGP(wwin, shared_appicon)) {
927 char *buffer, *instance, *class;
928 WFakeGroupLeader *fPtr;
929 int index;
931 #define ADEQUATE(x) ((x)!=None && (x)!=wwin->client_win && (x)!=fPtr->leader)
933 // only enter here if PropGetWMClass() succeds
934 PropGetWMClass(wwin->main_window, &class, &instance);
935 buffer = StrConcatDot(instance, class);
937 index = WMFindInArray(scr->fakeGroupLeaders, matchIdentifier, (void*)buffer);
938 if (index != WANotFound) {
939 fPtr = WMGetFromArray(scr->fakeGroupLeaders, index);
940 if (fPtr->retainCount == 0) {
941 fPtr->leader = createFakeWindowGroupLeader(scr, wwin->main_window,
942 instance, class);
944 fPtr->retainCount++;
945 #undef method2
946 if (fPtr->origLeader==None) {
947 #ifdef method2
948 if (ADEQUATE(wwin->group_id)) {
949 fPtr->retainCount++;
950 fPtr->origLeader = wwin->group_id;
951 } else if (ADEQUATE(wwin->client_leader)) {
952 fPtr->retainCount++;
953 fPtr->origLeader = wwin->client_leader;
954 } else if (ADEQUATE(wwin->main_window)) {
955 fPtr->retainCount++;
956 fPtr->origLeader = wwin->main_window;
958 #else
959 if (ADEQUATE(wwin->main_window)) {
960 fPtr->retainCount++;
961 fPtr->origLeader = wwin->main_window;
963 #endif
965 wwin->fake_group = fPtr;
966 /*wwin->group_id = fPtr->leader;*/
967 wwin->main_window = fPtr->leader;
968 wfree(buffer);
969 } else {
970 fPtr = (WFakeGroupLeader*)wmalloc(sizeof(WFakeGroupLeader));
972 fPtr->identifier = buffer;
973 fPtr->leader = createFakeWindowGroupLeader(scr, wwin->main_window,
974 instance, class);
975 fPtr->origLeader = None;
976 fPtr->retainCount = 1;
978 WMAddToArray(scr->fakeGroupLeaders, fPtr);
980 #ifdef method2
981 if (ADEQUATE(wwin->group_id)) {
982 fPtr->retainCount++;
983 fPtr->origLeader = wwin->group_id;
984 } else if (ADEQUATE(wwin->client_leader)) {
985 fPtr->retainCount++;
986 fPtr->origLeader = wwin->client_leader;
987 } else if (ADEQUATE(wwin->main_window)) {
988 fPtr->retainCount++;
989 fPtr->origLeader = wwin->main_window;
991 #else
992 if (ADEQUATE(wwin->main_window)) {
993 fPtr->retainCount++;
994 fPtr->origLeader = wwin->main_window;
996 #endif
997 wwin->fake_group = fPtr;
998 /*wwin->group_id = fPtr->leader;*/
999 wwin->main_window = fPtr->leader;
1001 if (instance)
1002 XFree(instance);
1003 if (class)
1004 XFree(class);
1006 #undef method2
1007 #undef ADEQUATE
1011 *------------------------------------------------------------
1013 * Setup the initial state of the window
1015 *------------------------------------------------------------
1018 if (WFLAGP(wwin, start_miniaturized) && !WFLAGP(wwin, no_miniaturizable)) {
1019 wwin->flags.miniaturized = 1;
1022 if (WFLAGP(wwin, start_maximized) && IS_RESIZABLE(wwin)) {
1023 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
1027 #if defined(NETWM_HINTS) || defined(GNOME_STUFF) || defined(KWM_HINTS)
1028 Bool bla = False;
1029 #endif
1031 #ifdef NETWM_HINTS
1032 if (!bla)
1033 bla = wNETWMCheckInitialClientState(wwin);
1034 #endif
1035 #ifdef GNOME_STUFF
1036 if (!bla)
1037 bla = wGNOMECheckInitialClientState(wwin);
1038 #endif
1039 #ifdef KWM_HINTS
1040 if (!bla)
1041 bla = wKWMCheckClientInitialState(wwin);
1042 #endif
1045 /* apply previous state if it exists and we're in startup */
1046 if (scr->flags.startup && wm_state >= 0) {
1048 if (wm_state == IconicState) {
1050 wwin->flags.miniaturized = 1;
1052 } else if (wm_state == WithdrawnState) {
1054 withdraw = True;
1058 /* if there is a saved state (from file), restore it */
1059 win_state = NULL;
1060 if (wwin->main_window!=None/* && wwin->main_window!=window*/) {
1061 win_state = (WWindowState*)wWindowGetSavedState(wwin->main_window);
1062 } else {
1063 win_state = (WWindowState*)wWindowGetSavedState(window);
1065 if (win_state && !withdraw) {
1067 if (win_state->state->hidden>0)
1068 wwin->flags.hidden = win_state->state->hidden;
1070 if (win_state->state->shaded>0 && !WFLAGP(wwin, no_shadeable))
1071 wwin->flags.shaded = win_state->state->shaded;
1073 if (win_state->state->miniaturized>0 &&
1074 !WFLAGP(wwin, no_miniaturizable)) {
1075 wwin->flags.miniaturized = win_state->state->miniaturized;
1078 if (!IS_OMNIPRESENT(wwin)) {
1079 int w = wDefaultGetStartWorkspace(scr, wwin->wm_instance,
1080 wwin->wm_class);
1081 if (w < 0 || w >= scr->workspace_count) {
1082 workspace = win_state->state->workspace;
1083 if (workspace >= scr->workspace_count)
1084 workspace = scr->current_workspace;
1085 } else {
1086 workspace = w;
1088 } else {
1089 workspace = scr->current_workspace;
1093 /* if we're restarting, restore saved state (from hints).
1094 * This will overwrite previous */
1096 WSavedState *wstate;
1098 if (getSavedState(window, &wstate)) {
1099 wwin->flags.shaded = wstate->shaded;
1100 wwin->flags.hidden = wstate->hidden;
1101 wwin->flags.miniaturized = wstate->miniaturized;
1102 wwin->flags.maximized = wstate->maximized;
1103 if (wwin->flags.maximized) {
1104 wwin->old_geometry.x = wstate->x;
1105 wwin->old_geometry.y = wstate->y;
1106 wwin->old_geometry.width = wstate->w;
1107 wwin->old_geometry.height = wstate->h;
1110 workspace = wstate->workspace;
1111 } else {
1112 wstate = NULL;
1115 /* restore window shortcut */
1116 if (wstate != NULL || win_state != NULL) {
1117 unsigned mask = 0;
1119 if (win_state != NULL)
1120 mask = win_state->state->window_shortcuts;
1122 if (wstate != NULL && mask == 0)
1123 mask = wstate->window_shortcuts;
1125 if (mask > 0) {
1126 int i;
1128 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
1129 if (mask & (1<<i)) {
1130 if (!scr->shortcutWindows[i])
1131 scr->shortcutWindows[i] = WMCreateArray(4);
1133 WMAddToArray(scr->shortcutWindows[i], wwin);
1138 if (wstate != NULL) {
1139 wfree(wstate);
1143 /* don't let transients start miniaturized if their owners are not */
1144 if (transientOwner && !transientOwner->flags.miniaturized
1145 && wwin->flags.miniaturized && !withdraw) {
1146 wwin->flags.miniaturized = 0;
1147 if (wwin->wm_hints)
1148 wwin->wm_hints->initial_state = NormalState;
1151 /* set workspace on which the window starts */
1152 if (workspace >= 0) {
1153 if (workspace > scr->workspace_count-1) {
1154 workspace = workspace % scr->workspace_count;
1156 } else {
1157 int w;
1159 w = wDefaultGetStartWorkspace(scr, wwin->wm_instance, wwin->wm_class);
1161 if (w >= 0 && w < scr->workspace_count && !(IS_OMNIPRESENT(wwin))) {
1163 workspace = w;
1165 } else {
1166 if (wPreferences.open_transients_with_parent && transientOwner) {
1168 workspace = transientOwner->frame->workspace;
1170 } else {
1172 workspace = scr->current_workspace;
1177 /* setup window geometry */
1178 if (win_state && win_state->state->w > 0) {
1179 width = win_state->state->w;
1180 height = win_state->state->h;
1182 wWindowConstrainSize(wwin, &width, &height);
1184 /* do not ask for window placement if the window is
1185 * transient, during startup, if the initial workspace is another one
1186 * or if the window wants to start iconic.
1187 * If geometry was saved, restore it. */
1189 Bool dontBring = False;
1191 if (win_state && win_state->state->w > 0) {
1192 x = win_state->state->x;
1193 y = win_state->state->y;
1194 } else if ((wwin->transient_for==None
1195 || wPreferences.window_placement!=WPM_MANUAL)
1196 && !scr->flags.startup
1197 && workspace == scr->current_workspace
1198 && !wwin->flags.miniaturized
1199 && !wwin->flags.maximized
1200 && !(wwin->normal_hints->flags & (USPosition|PPosition))) {
1202 if (transientOwner && transientOwner->flags.mapped) {
1203 int offs = WMAX(20, 2*transientOwner->frame->top_width);
1204 WMRect rect;
1205 int head;
1207 x = transientOwner->frame_x +
1208 abs((transientOwner->frame->core->width - width)/2) + offs;
1209 y = transientOwner->frame_y +
1210 abs((transientOwner->frame->core->height - height)/3) + offs;
1213 * limit transient windows to be inside their parent's head
1215 rect.pos.x = transientOwner->frame_x;
1216 rect.pos.y = transientOwner->frame_y;
1217 rect.size.width = transientOwner->frame->core->width;
1218 rect.size.height = transientOwner->frame->core->height;
1220 head = wGetHeadForRect(scr, rect);
1221 rect = wGetRectForHead(scr, head);
1223 if (x < rect.pos.x)
1224 x = rect.pos.x;
1225 else if (x + width > rect.pos.x + rect.size.width)
1226 x = rect.pos.x + rect.size.width - width;
1228 if (y < rect.pos.y)
1229 y = rect.pos.y;
1230 else if (y + height > rect.pos.y + rect.size.height)
1231 y = rect.pos.y + rect.size.height - height;
1233 } else {
1234 PlaceWindow(wwin, &x, &y, width, height);
1236 if (wPreferences.window_placement == WPM_MANUAL) {
1237 dontBring = True;
1239 } else if (scr->xine_info.count &&
1240 (wwin->normal_hints->flags & PPosition)) {
1241 int head, flags;
1242 WMRect rect;
1243 int reposition = 0;
1246 * Make spash screens come out in the center of a head
1247 * trouble is that most splashies never get here
1248 * they are managed trough atoms but god knows where.
1249 * Dan, do you know ? -peter
1251 * Most of them are not managed, they have set
1252 * OverrideRedirect, which means we can't do anything about
1253 * them. -alfredo
1255 #if 0
1256 printf("xinerama PPosition: x: %d %d\n", x, (scr->scr_width - width)/2);
1257 printf("xinerama PPosition: y: %d %d\n", y, (scr->scr_height - height)/2);
1259 if ((unsigned)(x + (width - scr->scr_width)/2 + 10) < 20 &&
1260 (unsigned)(y + (height - scr->scr_height)/2 + 10) < 20) {
1262 reposition = 1;
1264 } else
1265 #endif
1268 * xinerama checks for: across head and dead space
1270 rect.pos.x = x;
1271 rect.pos.y = y;
1272 rect.size.width = width;
1273 rect.size.height = height;
1275 head = wGetRectPlacementInfo(scr, rect, &flags);
1277 if (flags & XFLAG_DEAD)
1278 reposition = 1;
1280 if (flags & XFLAG_MULTIPLE)
1281 reposition = 2;
1284 switch (reposition) {
1285 case 1:
1286 head = wGetHeadForPointerLocation(scr);
1287 rect = wGetRectForHead(scr, head);
1289 x = rect.pos.x + (x * rect.size.width)/scr->scr_width;
1290 y = rect.pos.y + (y * rect.size.height)/scr->scr_height;
1291 break;
1293 case 2:
1294 rect = wGetRectForHead(scr, head);
1296 if (x < rect.pos.x)
1297 x = rect.pos.x;
1298 else if (x + width > rect.pos.x + rect.size.width)
1299 x = rect.pos.x + rect.size.width - width;
1301 if (y < rect.pos.y)
1302 y = rect.pos.y;
1303 else if (y + height > rect.pos.y + rect.size.height)
1304 y = rect.pos.y + rect.size.height - height;
1306 break;
1308 default:
1309 break;
1313 if (WFLAGP(wwin, dont_move_off) && dontBring)
1314 wScreenBringInside(scr, &x, &y, width, height);
1317 #ifdef NETWM_HINTS
1318 wNETWMPositionSplash(wwin, &x, &y, width, height);
1319 #endif
1321 if (wwin->flags.urgent) {
1322 if (!IS_OMNIPRESENT(wwin))
1323 wwin->flags.omnipresent ^= 1;
1327 *--------------------------------------------------
1329 * Create frame, borders and do reparenting
1331 *--------------------------------------------------
1333 foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
1334 #ifdef XKB_BUTTON_HINT
1335 if (wPreferences.modelock)
1336 foo |= WFF_LANGUAGE_BUTTON;
1337 #endif
1338 if (HAS_TITLEBAR(wwin))
1339 foo |= WFF_TITLEBAR;
1340 if (HAS_RESIZEBAR(wwin))
1341 foo |= WFF_RESIZEBAR;
1342 if (HAS_BORDER(wwin))
1343 foo |= WFF_BORDER;
1345 wwin->frame = wFrameWindowCreate(scr, window_level,
1346 x, y, width, height,
1347 &wPreferences.window_title_clearance, foo,
1348 scr->window_title_texture,
1349 scr->resizebar_texture,
1350 scr->window_title_color,
1351 &scr->title_font);
1353 wwin->frame->flags.is_client_window_frame = 1;
1354 wwin->frame->flags.justification = wPreferences.title_justification;
1356 /* setup button images */
1357 wWindowUpdateButtonImages(wwin);
1359 /* hide unused buttons */
1360 foo = 0;
1361 if (WFLAGP(wwin, no_close_button))
1362 foo |= WFF_RIGHT_BUTTON;
1363 if (WFLAGP(wwin, no_miniaturize_button))
1364 foo |= WFF_LEFT_BUTTON;
1365 #ifdef XKB_BUTTON_HINT
1366 if (WFLAGP(wwin, no_language_button) || WFLAGP(wwin, no_focusable))
1367 foo |= WFF_LANGUAGE_BUTTON;
1368 #endif
1369 if (foo!=0)
1370 wFrameWindowHideButton(wwin->frame, foo);
1372 wwin->frame->child = wwin;
1374 #ifdef OLWM_HINTS
1375 /* emulate olwm push pin. Make the button look as pushed-in for
1376 * the pinned-out state. When the button is clicked, it will
1377 * revert to the normal position, which means the pin is pinned-in.
1379 if (wwin->flags.olwm_push_pin_out)
1380 wFrameWindowUpdatePushButton(wwin->frame, True);
1381 #endif /* OLWM_HINTS */
1384 wwin->frame->workspace = workspace;
1386 wwin->frame->on_click_left = windowIconifyClick;
1387 #ifdef XKB_BUTTON_HINT
1388 if (wPreferences.modelock)
1389 wwin->frame->on_click_language = windowLanguageClick;
1390 #endif
1392 wwin->frame->on_click_right = windowCloseClick;
1393 wwin->frame->on_dblclick_right = windowCloseDblClick;
1395 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
1396 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
1398 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
1401 XSelectInput(dpy, wwin->client_win,
1402 wwin->event_mask & ~StructureNotifyMask);
1404 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
1405 0, wwin->frame->top_width);
1407 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
1411 int gx, gy;
1413 wClientGetGravityOffsets(wwin, &gx, &gy);
1415 /* if gravity is to the south, account for the border sizes */
1416 if (gy > 0)
1417 y -= wwin->frame->top_width + wwin->frame->bottom_width;
1421 * wWindowConfigure() will init the client window's size
1422 * (wwin->client.{width,height}) and all other geometry
1423 * related variables (frame_x,frame_y)
1425 wWindowConfigure(wwin, x, y, width, height);
1427 /* to make sure the window receives it's new position after reparenting */
1428 wWindowSynthConfigureNotify(wwin);
1431 *--------------------------------------------------
1433 * Setup descriptors and save window to internal
1434 * lists
1436 *--------------------------------------------------
1439 if (wwin->main_window!=None) {
1440 WApplication *app;
1441 WWindow *leader;
1443 /* Leader windows do not necessary set themselves as leaders.
1444 * If this is the case, point the leader of this window to
1445 * itself */
1446 leader = wWindowFor(wwin->main_window);
1447 if (leader && leader->main_window==None) {
1448 leader->main_window = leader->client_win;
1450 app = wApplicationCreate(wwin);
1451 if (app) {
1452 app->last_workspace = workspace;
1455 * Do application specific stuff, like setting application
1456 * wide attributes.
1459 if (wwin->flags.hidden) {
1460 /* if the window was set to hidden because it was hidden
1461 * in a previous incarnation and that state was restored */
1462 app->flags.hidden = 1;
1463 } else if (app->flags.hidden) {
1464 if (WFLAGP(app->main_window_desc, start_hidden)) {
1465 wwin->flags.hidden = 1;
1466 } else {
1467 wUnhideApplication(app, False, False);
1468 raise = True;
1474 /* setup the frame descriptor */
1475 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
1476 wwin->frame->core->descriptor.parent = wwin;
1477 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
1479 /* don't let windows go away if we die */
1480 XAddToSaveSet(dpy, window);
1482 XLowerWindow(dpy, window);
1484 /* if window is in this workspace and should be mapped, then map it */
1485 if (!wwin->flags.miniaturized
1486 && (workspace == scr->current_workspace || IS_OMNIPRESENT(wwin))
1487 && !wwin->flags.hidden && !withdraw) {
1489 /* The following "if" is to avoid crashing of clients that expect
1490 * WM_STATE set before they get mapped. Else WM_STATE is set later,
1491 * after the return from this function.
1493 if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint)) {
1494 wClientSetState(wwin, wwin->wm_hints->initial_state, None);
1495 } else {
1496 wClientSetState(wwin, NormalState, None);
1499 #if 0
1500 /* if not auto focus, then map the window under the currently
1501 * focused window */
1502 #define _WIDTH(w) (w)->frame->core->width
1503 #define _HEIGHT(w) (w)->frame->core->height
1504 if (!wPreferences.auto_focus && scr->focused_window
1505 && !scr->flags.startup && !transientOwner
1506 && ((wWindowObscuresWindow(wwin, scr->focused_window)
1507 && (_WIDTH(wwin) > (_WIDTH(scr->focused_window)*5)/3
1508 || _HEIGHT(wwin) > (_HEIGHT(scr->focused_window)*5)/3)
1509 && WINDOW_LEVEL(scr->focused_window) == WINDOW_LEVEL(wwin))
1510 || wwin->flags.maximized)) {
1511 MoveInStackListUnder(scr->focused_window->frame->core,
1512 wwin->frame->core);
1514 #undef _WIDTH
1515 #undef _HEIGHT
1517 #endif
1519 if (wPreferences.superfluous && !wPreferences.no_animations
1520 && !scr->flags.startup &&
1521 (wwin->transient_for==None || wwin->transient_for==scr->root_win)
1523 * The brain damaged idiotic non-click to focus modes will
1524 * have trouble with this because:
1526 * 1. window is created and mapped by the client
1527 * 2. window is mapped by wmaker in small size
1528 * 3. window is animated to grow to normal size
1529 * 4. this function returns to normal event loop
1530 * 5. eventually, the EnterNotify event that would trigger
1531 * the window focusing (if the mouse is over that window)
1532 * will be processed by wmaker.
1533 * But since this event will be rather delayed
1534 * (step 3 has a large delay) the time when the event ocurred
1535 * and when it is processed, the client that owns that window
1536 * will reject the XSetInputFocus() for it.
1538 && (wPreferences.focus_mode==WKF_CLICK
1539 || wPreferences.auto_focus)) {
1540 DoWindowBirth(wwin);
1543 wWindowMap(wwin);
1546 /* setup stacking descriptor */
1547 if (transientOwner) {
1548 wwin->frame->core->stacking->child_of = transientOwner->frame->core;
1549 } else {
1550 wwin->frame->core->stacking->child_of = NULL;
1554 if (!scr->focused_window) {
1555 /* first window on the list */
1556 wwin->next = NULL;
1557 wwin->prev = NULL;
1558 scr->focused_window = wwin;
1559 } else {
1560 WWindow *tmp;
1562 /* add window at beginning of focus window list */
1563 tmp = scr->focused_window;
1564 while (tmp->prev)
1565 tmp = tmp->prev;
1566 tmp->prev = wwin;
1567 wwin->next = tmp;
1568 wwin->prev = NULL;
1571 /* raise is set to true if we un-hid the app when this window was born.
1572 * we raise, else old windows of this app will be above this new one. */
1573 if (raise) {
1574 wRaiseFrame(wwin->frame->core);
1577 /* Update name must come after WApplication stuff is done */
1578 wWindowUpdateName(wwin, title);
1579 if (title)
1580 XFree(title);
1582 XUngrabServer(dpy);
1585 *--------------------------------------------------
1587 * Final preparations before window is ready to go
1589 *--------------------------------------------------
1592 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1595 if (!wwin->flags.miniaturized && workspace == scr->current_workspace
1596 && !wwin->flags.hidden) {
1597 if (((transientOwner && transientOwner->flags.focused)
1598 || wPreferences.auto_focus) && !WFLAGP(wwin, no_focusable))
1599 wSetFocusTo(scr, wwin);
1601 wWindowResetMouseGrabs(wwin);
1603 if (!WFLAGP(wwin, no_bind_keys)) {
1604 wWindowSetKeyGrabs(wwin);
1608 WMPostNotificationName(WMNManaged, wwin, NULL);
1611 wColormapInstallForWindow(scr, scr->cmap_window);
1614 #ifdef OLWM_HINTS
1615 if (wwin->client_flags.olwm_warp_to_pin && wwin->frame->titlebar != NULL
1616 && !WFLAGP(wwin, no_close_button) && !withdraw) {
1618 XWarpPointer(dpy, None, None, 0, 0, 0, 0,
1619 wwin->frame_x + width - wwin->frame->titlebar->height * 2,
1620 wwin->frame_y);
1622 #endif
1625 *------------------------------------------------------------
1626 * Setup Notification Observers
1627 *------------------------------------------------------------
1629 WMAddNotificationObserver(appearanceObserver, wwin,
1630 WNWindowAppearanceSettingsChanged, wwin);
1634 *--------------------------------------------------
1636 * Cleanup temporary stuff
1638 *--------------------------------------------------
1641 if (win_state)
1642 wWindowDeleteSavedState(win_state);
1644 /* If the window must be withdrawed, then do it now.
1645 * Must do some optimization, 'though */
1646 if (withdraw) {
1647 wwin->flags.mapped = 0;
1648 wClientSetState(wwin, WithdrawnState, None);
1649 wUnmanageWindow(wwin, True, False);
1650 wwin = NULL;
1653 return wwin;
1660 WWindow*
1661 wManageInternalWindow(WScreen *scr, Window window, Window owner,
1662 char *title, int x, int y, int width, int height)
1664 WWindow *wwin;
1665 int foo;
1667 wwin = wWindowCreate();
1669 WMAddNotificationObserver(appearanceObserver, wwin,
1670 WNWindowAppearanceSettingsChanged, wwin);
1672 wwin->flags.internal_window = 1;
1674 WSETUFLAG(wwin, omnipresent, 1);
1675 WSETUFLAG(wwin, no_shadeable, 1);
1676 WSETUFLAG(wwin, no_resizable, 1);
1677 WSETUFLAG(wwin, no_miniaturizable, 1);
1679 wwin->focus_mode = WFM_PASSIVE;
1681 wwin->client_win = window;
1682 wwin->screen_ptr = scr;
1684 wwin->transient_for = owner;
1686 wwin->client.x = x;
1687 wwin->client.y = y;
1688 wwin->client.width = width;
1689 wwin->client.height = height;
1691 wwin->frame_x = wwin->client.x;
1692 wwin->frame_y = wwin->client.y;
1695 foo = WFF_RIGHT_BUTTON|WFF_BORDER;
1696 foo |= WFF_TITLEBAR;
1697 #ifdef XKB_BUTTON_HINT
1698 foo |= WFF_LANGUAGE_BUTTON;
1699 #endif
1701 wwin->frame = wFrameWindowCreate(scr, WMFloatingLevel,
1702 wwin->frame_x, wwin->frame_y,
1703 width, height,
1704 &wPreferences.window_title_clearance, foo,
1705 scr->window_title_texture,
1706 scr->resizebar_texture,
1707 scr->window_title_color,
1708 &scr->title_font);
1710 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
1712 wwin->frame->flags.is_client_window_frame = 1;
1713 wwin->frame->flags.justification = wPreferences.title_justification;
1715 wFrameWindowChangeTitle(wwin->frame, title);
1717 /* setup button images */
1718 wWindowUpdateButtonImages(wwin);
1720 /* hide buttons */
1721 wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON);
1723 wwin->frame->child = wwin;
1725 wwin->frame->workspace = wwin->screen_ptr->current_workspace;
1727 #ifdef XKB_BUTTON_HINT
1728 if (wPreferences.modelock)
1729 wwin->frame->on_click_language = windowLanguageClick;
1730 #endif
1732 wwin->frame->on_click_right = windowCloseClick;
1734 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
1735 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
1737 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
1739 wwin->client.y += wwin->frame->top_width;
1740 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
1741 0, wwin->frame->top_width);
1743 wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y,
1744 wwin->client.width, wwin->client.height);
1746 /* setup the frame descriptor */
1747 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
1748 wwin->frame->core->descriptor.parent = wwin;
1749 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
1752 XLowerWindow(dpy, window);
1753 XMapSubwindows(dpy, wwin->frame->core->window);
1755 /* setup stacking descriptor */
1756 if (wwin->transient_for!=None && wwin->transient_for!=scr->root_win) {
1757 WWindow *tmp;
1758 tmp = wWindowFor(wwin->transient_for);
1759 if (tmp)
1760 wwin->frame->core->stacking->child_of = tmp->frame->core;
1761 } else {
1762 wwin->frame->core->stacking->child_of = NULL;
1766 if (!scr->focused_window) {
1767 /* first window on the list */
1768 wwin->next = NULL;
1769 wwin->prev = NULL;
1770 scr->focused_window = wwin;
1771 } else {
1772 WWindow *tmp;
1774 /* add window at beginning of focus window list */
1775 tmp = scr->focused_window;
1776 while (tmp->prev)
1777 tmp = tmp->prev;
1778 tmp->prev = wwin;
1779 wwin->next = tmp;
1780 wwin->prev = NULL;
1783 if (wwin->flags.is_gnustep == 0)
1784 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1786 /* if (wPreferences.auto_focus)*/
1787 wSetFocusTo(scr, wwin);
1789 wWindowResetMouseGrabs(wwin);
1791 wWindowSetKeyGrabs(wwin);
1793 return wwin;
1798 *----------------------------------------------------------------------
1799 * wUnmanageWindow--
1800 * Removes the frame window from a window and destroys all data
1801 * related to it. The window will be reparented back to the root window
1802 * if restore is True.
1804 * Side effects:
1805 * Everything related to the window is destroyed and the window
1806 * is removed from the window lists. Focus is set to the previous on the
1807 * window list.
1808 *----------------------------------------------------------------------
1810 void
1811 wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed)
1813 WCoreWindow *frame = wwin->frame->core;
1814 WWindow *owner = NULL;
1815 WWindow *newFocusedWindow = NULL;
1816 int wasFocused;
1817 WScreen *scr = wwin->screen_ptr;
1820 /* First close attribute editor window if open */
1821 if (wwin->flags.inspector_open) {
1822 wCloseInspectorForWindow(wwin);
1825 /* Close window menu if it's open for this window */
1826 if (wwin->flags.menu_open_for_me) {
1827 CloseWindowMenu(scr);
1830 if (!destroyed) {
1831 if (!wwin->flags.internal_window)
1832 XRemoveFromSaveSet(dpy, wwin->client_win);
1834 XSelectInput(dpy, wwin->client_win, NoEventMask);
1836 XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
1837 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->client_win);
1840 XUnmapWindow(dpy, frame->window);
1842 XUnmapWindow(dpy, wwin->client_win);
1844 /* deselect window */
1845 wSelectWindow(wwin, False);
1847 /* remove all pending events on window */
1848 /* I think this only matters for autoraise */
1849 if (wPreferences.raise_delay)
1850 WMDeleteTimerWithClientData(wwin->frame->core);
1852 XFlush(dpy);
1854 /* reparent the window back to the root */
1855 if (restore)
1856 wClientRestore(wwin);
1858 if (wwin->transient_for!=scr->root_win) {
1859 owner = wWindowFor(wwin->transient_for);
1860 if (owner) {
1861 if (!owner->flags.semi_focused) {
1862 owner = NULL;
1863 } else {
1864 owner->flags.semi_focused = 0;
1869 wasFocused = wwin->flags.focused;
1871 /* remove from window focus list */
1872 if (!wwin->prev && !wwin->next) {
1873 /* was the only window */
1874 scr->focused_window = NULL;
1875 newFocusedWindow = NULL;
1876 } else {
1877 WWindow *tmp;
1879 if (wwin->prev)
1880 wwin->prev->next = wwin->next;
1881 if (wwin->next)
1882 wwin->next->prev = wwin->prev;
1883 else {
1884 scr->focused_window = wwin->prev;
1885 scr->focused_window->next = NULL;
1888 if (wPreferences.focus_mode==WKF_CLICK) {
1890 /* if in click to focus mode and the window
1891 * was a transient, focus the owner window
1893 tmp = NULL;
1894 if (wPreferences.focus_mode==WKF_CLICK) {
1895 tmp = wWindowFor(wwin->transient_for);
1896 if (tmp && (!tmp->flags.mapped || WFLAGP(tmp, no_focusable))) {
1897 tmp = NULL;
1900 /* otherwise, focus the next one in the focus list */
1901 if (!tmp) {
1902 tmp = scr->focused_window;
1903 while (tmp) { /* look for one in the window list first */
1904 if (!WFLAGP(tmp, no_focusable) && !WFLAGP(tmp, skip_window_list)
1905 && (tmp->flags.mapped || tmp->flags.shaded))
1906 break;
1907 tmp = tmp->prev;
1909 if (!tmp) { /* if unsuccessful, choose any focusable window */
1910 tmp = scr->focused_window;
1911 while (tmp) {
1912 if (!WFLAGP(tmp, no_focusable)
1913 && (tmp->flags.mapped || tmp->flags.shaded))
1914 break;
1915 tmp = tmp->prev;
1920 newFocusedWindow = tmp;
1922 } else if (wPreferences.focus_mode==WKF_SLOPPY) {
1923 unsigned int mask;
1924 int foo;
1925 Window bar, win;
1927 /* This is to let the root window get the keyboard input
1928 * if Sloppy focus mode and no other window get focus.
1929 * This way keybindings will not freeze.
1931 tmp = NULL;
1932 if (XQueryPointer(dpy, scr->root_win, &bar, &win,
1933 &foo, &foo, &foo, &foo, &mask))
1934 tmp = wWindowFor(win);
1935 if (tmp == wwin)
1936 tmp = NULL;
1937 newFocusedWindow = tmp;
1938 } else {
1939 newFocusedWindow = NULL;
1943 if (!wwin->flags.internal_window) {
1944 WMPostNotificationName(WMNUnmanaged, wwin, NULL);
1947 #ifdef DEBUG
1948 printf("destroying window %x frame %x\n", (unsigned)wwin->client_win,
1949 (unsigned)frame->window);
1950 #endif
1952 if (wasFocused) {
1953 if (newFocusedWindow != owner && owner) {
1954 if (wwin->flags.is_gnustep == 0)
1955 wFrameWindowChangeState(owner->frame, WS_UNFOCUSED);
1957 wSetFocusTo(scr, newFocusedWindow);
1959 wWindowDestroy(wwin);
1960 XFlush(dpy);
1964 void
1965 wWindowMap(WWindow *wwin)
1967 XMapWindow(dpy, wwin->frame->core->window);
1968 if (!wwin->flags.shaded) {
1969 /* window will be remapped when getting MapNotify */
1970 XSelectInput(dpy, wwin->client_win,
1971 wwin->event_mask & ~StructureNotifyMask);
1972 XMapWindow(dpy, wwin->client_win);
1973 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
1975 wwin->flags.mapped = 1;
1980 void
1981 wWindowUnmap(WWindow *wwin)
1983 wwin->flags.mapped = 0;
1985 /* prevent window withdrawal when getting UnmapNotify */
1986 XSelectInput(dpy, wwin->client_win,
1987 wwin->event_mask & ~StructureNotifyMask);
1988 XUnmapWindow(dpy, wwin->client_win);
1989 XSelectInput(dpy, wwin->client_win, wwin->event_mask);
1991 XUnmapWindow(dpy, wwin->frame->core->window);
1996 void
1997 wWindowFocus(WWindow *wwin, WWindow *owin)
1999 WWindow *nowner;
2000 WWindow *oowner;
2002 #ifdef KEEP_XKB_LOCK_STATUS
2003 if (wPreferences.modelock) {
2004 XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
2006 #endif /* KEEP_XKB_LOCK_STATUS */
2008 wwin->flags.semi_focused = 0;
2010 if (wwin->flags.is_gnustep == 0)
2011 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
2013 wwin->flags.focused = 1;
2015 wWindowResetMouseGrabs(wwin);
2017 WMPostNotificationName(WMNChangedFocus, wwin, (void*)True);
2019 if (owin == wwin || !owin)
2020 return;
2022 nowner = wWindowFor(wwin->transient_for);
2024 /* new window is a transient for the old window */
2025 if (nowner == owin) {
2026 owin->flags.semi_focused = 1;
2027 wWindowUnfocus(nowner);
2028 return;
2031 oowner = wWindowFor(owin->transient_for);
2033 /* new window is owner of old window */
2034 if (wwin == oowner) {
2035 wWindowUnfocus(owin);
2036 return;
2039 if (!nowner) {
2040 wWindowUnfocus(owin);
2041 return;
2044 /* new window has same owner of old window */
2045 if (oowner == nowner) {
2046 /* prevent unfocusing of owner */
2047 oowner->flags.semi_focused = 0;
2048 wWindowUnfocus(owin);
2049 oowner->flags.semi_focused = 1;
2051 return;
2054 /* nowner != NULL && oowner != nowner */
2055 nowner->flags.semi_focused = 1;
2056 wWindowUnfocus(nowner);
2057 wWindowUnfocus(owin);
2061 void
2062 wWindowUnfocus(WWindow *wwin)
2064 CloseWindowMenu(wwin->screen_ptr);
2066 if (wwin->flags.is_gnustep == 0)
2067 wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused
2068 ? WS_PFOCUSED : WS_UNFOCUSED);
2070 if (wwin->transient_for!=None
2071 && wwin->transient_for!=wwin->screen_ptr->root_win) {
2072 WWindow *owner;
2073 owner = wWindowFor(wwin->transient_for);
2074 if (owner && owner->flags.semi_focused) {
2075 owner->flags.semi_focused = 0;
2076 if (owner->flags.mapped || owner->flags.shaded) {
2077 wWindowUnfocus(owner);
2078 wFrameWindowPaint(owner->frame);
2082 wwin->flags.focused = 0;
2084 wWindowResetMouseGrabs(wwin);
2086 WMPostNotificationName(WMNChangedFocus, wwin, (void*)False);
2090 void
2091 wWindowUpdateName(WWindow *wwin, char *newTitle)
2093 char *title;
2095 if (!wwin->frame)
2096 return;
2098 wwin->flags.wm_name_changed = 1;
2100 if (!newTitle) {
2101 /* the hint was removed */
2102 title = DEF_WINDOW_TITLE;
2103 } else {
2104 title = newTitle;
2107 if (wFrameWindowChangeTitle(wwin->frame, title)) {
2108 WMPostNotificationName(WMNChangedName, wwin, NULL);
2115 *----------------------------------------------------------------------
2117 * wWindowConstrainSize--
2118 * Constrains size for the client window, taking the maximal size,
2119 * window resize increments and other size hints into account.
2121 * Returns:
2122 * The closest size to what was given that the client window can
2123 * have.
2125 *----------------------------------------------------------------------
2127 void
2128 wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight)
2130 int width = *nwidth;
2131 int height = *nheight;
2132 int winc = 1;
2133 int hinc = 1;
2134 int minW = 1, minH = 1;
2135 int maxW = wwin->screen_ptr->scr_width*2;
2136 int maxH = wwin->screen_ptr->scr_height*2;
2137 int minAX = -1, minAY = -1;
2138 int maxAX = -1, maxAY = -1;
2139 int baseW = 0;
2140 int baseH = 0;
2142 if (wwin->normal_hints) {
2143 winc = wwin->normal_hints->width_inc;
2144 hinc = wwin->normal_hints->height_inc;
2145 minW = wwin->normal_hints->min_width;
2146 minH = wwin->normal_hints->min_height;
2147 maxW = wwin->normal_hints->max_width;
2148 maxH = wwin->normal_hints->max_height;
2149 if (wwin->normal_hints->flags & PAspect) {
2150 minAX = wwin->normal_hints->min_aspect.x;
2151 minAY = wwin->normal_hints->min_aspect.y;
2152 maxAX = wwin->normal_hints->max_aspect.x;
2153 maxAY = wwin->normal_hints->max_aspect.y;
2156 baseW = wwin->normal_hints->base_width;
2157 baseH = wwin->normal_hints->base_height;
2160 if (width < minW)
2161 width = minW;
2162 if (height < minH)
2163 height = minH;
2165 if (width > maxW)
2166 width = maxW;
2167 if (height > maxH)
2168 height = maxH;
2170 /* aspect ratio code borrowed from olwm */
2171 if (minAX > 0) {
2172 /* adjust max aspect ratio */
2173 if (!(maxAX == 1 && maxAY == 1) && width * maxAY > height * maxAX) {
2174 if (maxAX > maxAY) {
2175 height = (width * maxAY) / maxAX;
2176 if (height > maxH) {
2177 height = maxH;
2178 width = (height * maxAX) / maxAY;
2180 } else {
2181 width = (height * maxAX) / maxAY;
2182 if (width > maxW) {
2183 width = maxW;
2184 height = (width * maxAY) / maxAX;
2189 /* adjust min aspect ratio */
2190 if (!(minAX == 1 && minAY == 1) && width * minAY < height * minAX) {
2191 if (minAX > minAY) {
2192 height = (width * minAY) / minAX;
2193 if (height < minH) {
2194 height = minH;
2195 width = (height * minAX) / minAY;
2197 } else {
2198 width = (height * minAX) / minAY;
2199 if (width < minW) {
2200 width = minW;
2201 height = (width * minAY) / minAX;
2207 if (baseW != 0) {
2208 width = (((width - baseW) / winc) * winc) + baseW;
2209 } else {
2210 width = (((width - minW) / winc) * winc) + minW;
2213 if (baseH != 0) {
2214 height = (((height - baseH) / hinc) * hinc) + baseH;
2215 } else {
2216 height = (((height - minH) / hinc) * hinc) + minH;
2219 /* broken stupid apps may cause preposterous values for these.. */
2220 if (width > 0)
2221 *nwidth = width;
2222 if (height > 0)
2223 *nheight = height;
2227 void
2228 wWindowCropSize(WWindow *wwin, int maxW, int maxH,
2229 int *width, int *height)
2231 int baseW = 0, baseH = 0;
2232 int winc = 1, hinc = 1;
2234 if (wwin->normal_hints) {
2235 baseW = wwin->normal_hints->base_width;
2236 baseH = wwin->normal_hints->base_height;
2238 winc = wwin->normal_hints->width_inc;
2239 hinc = wwin->normal_hints->height_inc;
2242 if (*width > maxW)
2243 *width = maxW - (maxW - baseW) % winc;
2245 if (*height > maxH)
2246 *height = maxH - (maxH - baseH) % hinc;
2250 void
2251 wWindowChangeWorkspace(WWindow *wwin, int workspace)
2253 WScreen *scr = wwin->screen_ptr;
2254 WApplication *wapp;
2255 int unmap = 0;
2257 if (workspace >= scr->workspace_count || workspace < 0
2258 || workspace == wwin->frame->workspace)
2259 return;
2261 if (workspace != scr->current_workspace) {
2262 /* Sent to other workspace. Unmap window */
2263 if ((wwin->flags.mapped
2264 || wwin->flags.shaded
2265 || (wwin->flags.miniaturized && !wPreferences.sticky_icons))
2266 && !IS_OMNIPRESENT(wwin) && !wwin->flags.changing_workspace) {
2268 wapp = wApplicationOf(wwin->main_window);
2269 if (wapp) {
2270 wapp->last_workspace = workspace;
2272 if (wwin->flags.miniaturized) {
2273 if (wwin->icon) {
2274 XUnmapWindow(dpy, wwin->icon->core->window);
2275 wwin->icon->mapped = 0;
2277 } else {
2278 unmap = 1;
2279 wSetFocusTo(scr, NULL);
2282 } else {
2283 /* brought to current workspace. Map window */
2284 if (wwin->flags.miniaturized && !wPreferences.sticky_icons) {
2285 if (wwin->icon) {
2286 XMapWindow(dpy, wwin->icon->core->window);
2287 wwin->icon->mapped = 1;
2289 } else if (!wwin->flags.mapped &&
2290 !(wwin->flags.miniaturized || wwin->flags.hidden)) {
2291 wWindowMap(wwin);
2294 if (!IS_OMNIPRESENT(wwin)) {
2295 int oldWorkspace = wwin->frame->workspace;
2297 wwin->frame->workspace = workspace;
2299 WMPostNotificationName(WMNChangedWorkspace, wwin, (void*)oldWorkspace);
2302 if (unmap) {
2303 wWindowUnmap(wwin);
2308 void
2309 wWindowSynthConfigureNotify(WWindow *wwin)
2311 XEvent sevent;
2313 sevent.type = ConfigureNotify;
2314 sevent.xconfigure.display = dpy;
2315 sevent.xconfigure.event = wwin->client_win;
2316 sevent.xconfigure.window = wwin->client_win;
2318 sevent.xconfigure.x = wwin->client.x;
2319 sevent.xconfigure.y = wwin->client.y;
2320 sevent.xconfigure.width = wwin->client.width;
2321 sevent.xconfigure.height = wwin->client.height;
2323 sevent.xconfigure.border_width = wwin->old_border_width;
2324 if (!HAS_TITLEBAR(wwin))
2325 sevent.xconfigure.above = None;
2326 else
2327 sevent.xconfigure.above = wwin->frame->titlebar->window;
2329 sevent.xconfigure.override_redirect = False;
2330 XSendEvent(dpy, wwin->client_win, False, StructureNotifyMask, &sevent);
2331 #ifdef KWM_HINTS
2332 wKWMSendEventMessage(wwin, WKWMChangedClient);
2333 #endif
2334 XFlush(dpy);
2339 *----------------------------------------------------------------------
2340 * wWindowConfigure--
2341 * Configures the frame, decorations and client window to the
2342 * specified geometry. The geometry is not checked for validity,
2343 * wWindowConstrainSize() must be used for that.
2344 * The size parameters are for the client window, but the position is
2345 * for the frame.
2346 * The client window receives a ConfigureNotify event, according
2347 * to what ICCCM says.
2349 * Returns:
2350 * None
2352 * Side effects:
2353 * Window size and position are changed and client window receives
2354 * a ConfigureNotify event.
2355 *----------------------------------------------------------------------
2357 void
2358 wWindowConfigure(wwin, req_x, req_y, req_width, req_height)
2359 WWindow *wwin;
2360 int req_x, req_y; /* new position of the frame */
2361 int req_width, req_height; /* new size of the client */
2363 int synth_notify = False;
2364 int resize;
2366 resize = (req_width!=wwin->client.width
2367 || req_height!=wwin->client.height);
2369 * if the window is being moved but not resized then
2370 * send a synthetic ConfigureNotify
2372 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) {
2373 synth_notify = True;
2376 if (WFLAGP(wwin, dont_move_off))
2377 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
2378 req_width, req_height);
2379 if (resize) {
2380 if (req_width < MIN_WINDOW_SIZE)
2381 req_width = MIN_WINDOW_SIZE;
2382 if (req_height < MIN_WINDOW_SIZE)
2383 req_height = MIN_WINDOW_SIZE;
2385 /* If growing, resize inner part before frame,
2386 * if shrinking, resize frame before.
2387 * This will prevent the frame (that can have a different color)
2388 * to be exposed, causing flicker */
2389 if (req_height > wwin->frame->core->height
2390 || req_width > wwin->frame->core->width)
2391 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
2393 if (wwin->flags.shaded) {
2394 wFrameWindowConfigure(wwin->frame, req_x, req_y,
2395 req_width, wwin->frame->core->height);
2396 wwin->old_geometry.height = req_height;
2397 } else {
2398 int h;
2400 h = req_height + wwin->frame->top_width
2401 + wwin->frame->bottom_width;
2403 wFrameWindowConfigure(wwin->frame, req_x, req_y, req_width, h);
2406 if (!(req_height > wwin->frame->core->height
2407 || req_width > wwin->frame->core->width))
2408 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
2410 wwin->client.x = req_x;
2411 wwin->client.y = req_y + wwin->frame->top_width;
2412 wwin->client.width = req_width;
2413 wwin->client.height = req_height;
2414 } else {
2415 wwin->client.x = req_x;
2416 wwin->client.y = req_y + wwin->frame->top_width;
2418 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
2420 wwin->frame_x = req_x;
2421 wwin->frame_y = req_y;
2422 if (HAS_BORDER(wwin)) {
2423 wwin->client.x += FRAME_BORDER_WIDTH;
2424 wwin->client.y += FRAME_BORDER_WIDTH;
2427 #ifdef SHAPE
2428 if (wShapeSupported && wwin->flags.shaped && resize) {
2429 wWindowSetShape(wwin);
2431 #endif
2433 if (synth_notify)
2434 wWindowSynthConfigureNotify(wwin);
2435 XFlush(dpy);
2439 void
2440 wWindowMove(wwin, req_x, req_y)
2441 WWindow *wwin;
2442 int req_x, req_y; /* new position of the frame */
2444 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
2445 int synth_notify = False;
2447 /* Send a synthetic ConfigureNotify event for every window movement. */
2448 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y)) {
2449 synth_notify = True;
2451 #else
2452 /* A single synthetic ConfigureNotify event is sent at the end of
2453 * a completed (opaque) movement in moveres.c */
2454 #endif
2456 if (WFLAGP(wwin, dont_move_off))
2457 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
2458 wwin->frame->core->width, wwin->frame->core->height);
2460 wwin->client.x = req_x;
2461 wwin->client.y = req_y + wwin->frame->top_width;
2462 if (HAS_BORDER(wwin)) {
2463 wwin->client.x += FRAME_BORDER_WIDTH;
2464 wwin->client.y += FRAME_BORDER_WIDTH;
2467 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
2469 wwin->frame_x = req_x;
2470 wwin->frame_y = req_y;
2472 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
2473 if (synth_notify)
2474 wWindowSynthConfigureNotify(wwin);
2475 #endif
2479 void
2480 wWindowUpdateButtonImages(WWindow *wwin)
2482 WScreen *scr = wwin->screen_ptr;
2483 Pixmap pixmap, mask;
2484 WFrameWindow *fwin = wwin->frame;
2486 if (!HAS_TITLEBAR(wwin))
2487 return;
2489 /* miniaturize button */
2491 if (!WFLAGP(wwin, no_miniaturize_button)) {
2492 if (wwin->wm_gnustep_attr
2493 && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) {
2494 pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap;
2496 if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) {
2497 mask = wwin->wm_gnustep_attr->miniaturize_mask;
2498 } else {
2499 mask = None;
2502 if (fwin->lbutton_image
2503 && (fwin->lbutton_image->image != pixmap
2504 || fwin->lbutton_image->mask != mask)) {
2505 wPixmapDestroy(fwin->lbutton_image);
2506 fwin->lbutton_image = NULL;
2509 if (!fwin->lbutton_image) {
2510 fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask);
2511 fwin->lbutton_image->client_owned = 1;
2512 fwin->lbutton_image->client_owned_mask = 1;
2514 } else {
2515 if (fwin->lbutton_image && !fwin->lbutton_image->shared) {
2516 wPixmapDestroy(fwin->lbutton_image);
2518 fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
2522 #ifdef XKB_BUTTON_HINT
2523 if (!WFLAGP(wwin, no_language_button)) {
2524 if (fwin->languagebutton_image &&
2525 !fwin->languagebutton_image->shared) {
2526 wPixmapDestroy(fwin->languagebutton_image);
2528 fwin->languagebutton_image =
2529 scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
2531 #endif
2533 /* close button */
2535 /* redefine WFLAGP to MGFLAGP to allow broken close operation */
2536 #define MGFLAGP(wwin, FLAG) (wwin)->client_flags.FLAG
2538 if (!WFLAGP(wwin, no_close_button)) {
2539 if (wwin->wm_gnustep_attr
2540 && wwin->wm_gnustep_attr->flags & GSClosePixmapAttr) {
2541 pixmap = wwin->wm_gnustep_attr->close_pixmap;
2543 if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr)
2544 mask = wwin->wm_gnustep_attr->close_mask;
2545 else
2546 mask = None;
2548 if (fwin->rbutton_image && (fwin->rbutton_image->image != pixmap
2549 || fwin->rbutton_image->mask != mask)) {
2550 wPixmapDestroy(fwin->rbutton_image);
2551 fwin->rbutton_image = NULL;
2554 if (!fwin->rbutton_image) {
2555 fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask);
2556 fwin->rbutton_image->client_owned = 1;
2557 fwin->rbutton_image->client_owned_mask = 1;
2560 } else if (WFLAGP(wwin, kill_close)) {
2562 if (fwin->rbutton_image && !fwin->rbutton_image->shared)
2563 wPixmapDestroy(fwin->rbutton_image);
2565 fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL];
2567 } else if (MGFLAGP(wwin, broken_close)) {
2569 if (fwin->rbutton_image && !fwin->rbutton_image->shared)
2570 wPixmapDestroy(fwin->rbutton_image);
2572 fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE];
2574 } else {
2576 if (fwin->rbutton_image && !fwin->rbutton_image->shared)
2577 wPixmapDestroy(fwin->rbutton_image);
2579 fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE];
2583 /* force buttons to be redrawn */
2584 fwin->flags.need_texture_change = 1;
2585 wFrameWindowPaint(fwin);
2590 *---------------------------------------------------------------------------
2591 * wWindowConfigureBorders--
2592 * Update window border configuration according to attribute flags.
2594 *---------------------------------------------------------------------------
2596 void
2597 wWindowConfigureBorders(WWindow *wwin)
2599 if (wwin->frame) {
2600 int flags;
2601 int newy, oldh;
2603 flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON;
2605 #ifdef XKB_BUTTON_HINT
2606 flags |= WFF_LANGUAGE_BUTTON;
2607 #endif
2609 if (HAS_TITLEBAR(wwin))
2610 flags |= WFF_TITLEBAR;
2611 if (HAS_RESIZEBAR(wwin) && IS_RESIZABLE(wwin))
2612 flags |= WFF_RESIZEBAR;
2613 if (HAS_BORDER(wwin))
2614 flags |= WFF_BORDER;
2615 if (wwin->flags.shaded)
2616 flags |= WFF_IS_SHADED;
2618 oldh = wwin->frame->top_width;
2619 wFrameWindowUpdateBorders(wwin->frame, flags);
2620 if (oldh != wwin->frame->top_width) {
2621 newy = wwin->frame_y + oldh - wwin->frame->top_width;
2623 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
2624 wWindowConfigure(wwin, wwin->frame_x, newy,
2625 wwin->client.width, wwin->client.height);
2628 flags = 0;
2629 if (!WFLAGP(wwin, no_miniaturize_button)
2630 && wwin->frame->flags.hide_left_button)
2631 flags |= WFF_LEFT_BUTTON;
2633 #ifdef XKB_BUTTON_HINT
2634 if (!WFLAGP(wwin, no_language_button)
2635 && wwin->frame->flags.hide_language_button) {
2636 flags |= WFF_LANGUAGE_BUTTON;
2638 #endif
2640 if (!WFLAGP(wwin, no_close_button)
2641 && wwin->frame->flags.hide_right_button)
2642 flags |= WFF_RIGHT_BUTTON;
2644 if (flags!=0) {
2645 wWindowUpdateButtonImages(wwin);
2646 wFrameWindowShowButton(wwin->frame, flags);
2649 flags = 0;
2650 if (WFLAGP(wwin, no_miniaturize_button)
2651 && !wwin->frame->flags.hide_left_button)
2652 flags |= WFF_LEFT_BUTTON;
2654 #ifdef XKB_BUTTON_HINT
2655 if (WFLAGP(wwin, no_language_button)
2656 && !wwin->frame->flags.hide_language_button)
2657 flags |= WFF_LANGUAGE_BUTTON;
2658 #endif
2660 if (WFLAGP(wwin, no_close_button)
2661 && !wwin->frame->flags.hide_right_button)
2662 flags |= WFF_RIGHT_BUTTON;
2664 if (flags!=0)
2665 wFrameWindowHideButton(wwin->frame, flags);
2667 #ifdef SHAPE
2668 if (wShapeSupported && wwin->flags.shaped) {
2669 wWindowSetShape(wwin);
2671 #endif
2676 void
2677 wWindowSaveState(WWindow *wwin)
2679 CARD32 data[10];
2680 int i;
2682 memset(data, 0, sizeof(CARD32)*10);
2683 data[0] = wwin->frame->workspace;
2684 data[1] = wwin->flags.miniaturized;
2685 data[2] = wwin->flags.shaded;
2686 data[3] = wwin->flags.hidden;
2687 data[4] = wwin->flags.maximized;
2688 if (wwin->flags.maximized == 0) {
2689 data[5] = wwin->frame_x;
2690 data[6] = wwin->frame_y;
2691 data[7] = wwin->frame->core->width;
2692 data[8] = wwin->frame->core->height;
2693 } else {
2694 data[5] = wwin->old_geometry.x;
2695 data[6] = wwin->old_geometry.y;
2696 data[7] = wwin->old_geometry.width;
2697 data[8] = wwin->old_geometry.height;
2700 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
2701 if (wwin->screen_ptr->shortcutWindows[i] &&
2702 WMCountInArray(wwin->screen_ptr->shortcutWindows[i], wwin))
2703 data[9] |= 1<<i;
2705 XChangeProperty(dpy, wwin->client_win, _XA_WINDOWMAKER_STATE,
2706 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
2707 (unsigned char *)data, 10);
2711 static int
2712 getSavedState(Window window, WSavedState **state)
2714 Atom type_ret;
2715 int fmt_ret;
2716 unsigned long nitems_ret;
2717 unsigned long bytes_after_ret;
2718 CARD32 *data;
2720 if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0, 10,
2721 True, _XA_WINDOWMAKER_STATE,
2722 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
2723 (unsigned char **)&data)!=Success || !data)
2724 return 0;
2726 *state = wmalloc(sizeof(WSavedState));
2728 (*state)->workspace = data[0];
2729 (*state)->miniaturized = data[1];
2730 (*state)->shaded = data[2];
2731 (*state)->hidden = data[3];
2732 (*state)->maximized = data[4];
2733 (*state)->x = data[5];
2734 (*state)->y = data[6];
2735 (*state)->w = data[7];
2736 (*state)->h = data[8];
2737 (*state)->window_shortcuts = data[9];
2739 XFree(data);
2741 if (*state && type_ret==_XA_WINDOWMAKER_STATE)
2742 return 1;
2743 else
2744 return 0;
2748 #ifdef SHAPE
2749 void
2750 wWindowClearShape(WWindow *wwin)
2752 XShapeCombineMask(dpy, wwin->frame->core->window, ShapeBounding,
2753 0, wwin->frame->top_width, None, ShapeSet);
2754 XFlush(dpy);
2757 void
2758 wWindowSetShape(WWindow *wwin)
2760 XRectangle rect[2];
2761 int count;
2762 #ifdef OPTIMIZE_SHAPE
2763 XRectangle *rects;
2764 XRectangle *urec;
2765 int ordering;
2767 /* only shape is the client's */
2768 if (!HAS_TITLEBAR(wwin) && !HAS_RESIZEBAR(wwin)) {
2769 goto alt_code;
2772 /* Get array of rectangles describing the shape mask */
2773 rects = XShapeGetRectangles(dpy, wwin->client_win, ShapeBounding,
2774 &count, &ordering);
2775 if (!rects) {
2776 goto alt_code;
2779 urec = malloc(sizeof(XRectangle)*(count+2));
2780 if (!urec) {
2781 XFree(rects);
2782 goto alt_code;
2785 /* insert our decoration rectangles in the rect list */
2786 memcpy(urec, rects, sizeof(XRectangle)*count);
2787 XFree(rects);
2789 if (HAS_TITLEBAR(wwin)) {
2790 urec[count].x = -1;
2791 urec[count].y = -1 - wwin->frame->top_width;
2792 urec[count].width = wwin->frame->core->width + 2;
2793 urec[count].height = wwin->frame->top_width + 1;
2794 count++;
2796 if (HAS_RESIZEBAR(wwin)) {
2797 urec[count].x = -1;
2798 urec[count].y = wwin->frame->core->height
2799 - wwin->frame->bottom_width - wwin->frame->top_width;
2800 urec[count].width = wwin->frame->core->width + 2;
2801 urec[count].height = wwin->frame->bottom_width + 1;
2802 count++;
2805 /* shape our frame window */
2806 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
2807 0, wwin->frame->top_width, urec, count,
2808 ShapeSet, Unsorted);
2809 XFlush(dpy);
2810 wfree(urec);
2811 return;
2813 alt_code:
2814 #endif /* OPTIMIZE_SHAPE */
2815 count = 0;
2816 if (HAS_TITLEBAR(wwin)) {
2817 rect[count].x = -1;
2818 rect[count].y = -1;
2819 rect[count].width = wwin->frame->core->width + 2;
2820 rect[count].height = wwin->frame->top_width + 1;
2821 count++;
2823 if (HAS_RESIZEBAR(wwin)) {
2824 rect[count].x = -1;
2825 rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width;
2826 rect[count].width = wwin->frame->core->width + 2;
2827 rect[count].height = wwin->frame->bottom_width + 1;
2828 count++;
2830 if (count > 0) {
2831 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
2832 0, 0, rect, count, ShapeSet, Unsorted);
2834 XShapeCombineShape(dpy, wwin->frame->core->window, ShapeBounding,
2835 0, wwin->frame->top_width, wwin->client_win,
2836 ShapeBounding, (count > 0 ? ShapeUnion : ShapeSet));
2837 XFlush(dpy);
2839 #endif /* SHAPE */
2841 /* ====================================================================== */
2843 static FocusMode
2844 getFocusMode(WWindow *wwin)
2846 FocusMode mode;
2848 if ((wwin->wm_hints) && (wwin->wm_hints->flags & InputHint)) {
2849 if (wwin->wm_hints->input == True) {
2850 if (wwin->protocols.TAKE_FOCUS)
2851 mode = WFM_LOCALLY_ACTIVE;
2852 else
2853 mode = WFM_PASSIVE;
2854 } else {
2855 if (wwin->protocols.TAKE_FOCUS)
2856 mode = WFM_GLOBALLY_ACTIVE;
2857 else
2858 mode = WFM_NO_INPUT;
2860 } else {
2861 mode = WFM_PASSIVE;
2863 return mode;
2867 void
2868 wWindowSetKeyGrabs(WWindow *wwin)
2870 int i;
2871 WShortKey *key;
2873 for (i=0; i<WKBD_LAST; i++) {
2874 key = &wKeyBindings[i];
2876 if (key->keycode==0)
2877 continue;
2878 if (key->modifier!=AnyModifier) {
2879 XGrabKey(dpy, key->keycode, key->modifier|LockMask,
2880 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
2881 #ifdef NUMLOCK_HACK
2882 /* Also grab all modifier combinations possible that include,
2883 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
2884 * work even if the NumLock/ScrollLock key is on.
2886 wHackedGrabKey(key->keycode, key->modifier,
2887 wwin->frame->core->window, True, GrabModeAsync,
2888 GrabModeAsync);
2889 #endif
2891 XGrabKey(dpy, key->keycode, key->modifier,
2892 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
2895 #ifndef LITE
2896 wRootMenuBindShortcuts(wwin->frame->core->window);
2897 #endif
2902 void
2903 wWindowResetMouseGrabs(WWindow *wwin)
2905 /* Mouse grabs can't be done on the client window because of
2906 * ICCCM and because clients that try to do the same will crash.
2908 * But there is a problem wich makes tbar buttons of unfocused
2909 * windows not usable as the click goes to the frame window instead
2910 * of the button itself. Must figure a way to fix that.
2913 XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
2915 if (!WFLAGP(wwin, no_bind_mouse)) {
2916 /* grabs for Meta+drag */
2917 wHackedGrabButton(AnyButton, MOD_MASK, wwin->client_win,
2918 True, ButtonPressMask|ButtonReleaseMask,
2919 GrabModeSync, GrabModeAsync, None, None);
2922 if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable)
2923 && !wwin->flags.is_gnustep) {
2924 /* the passive grabs to focus the window */
2925 /* if (wPreferences.focus_mode == WKF_CLICK) */
2926 XGrabButton(dpy, AnyButton, AnyModifier, wwin->client_win,
2927 True, ButtonPressMask|ButtonReleaseMask,
2928 GrabModeSync, GrabModeAsync, None, None);
2930 XFlush(dpy);
2934 void
2935 wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr)
2937 if (attr->flags & GSExtraFlagsAttr) {
2938 if (MGFLAGP(wwin, broken_close) !=
2939 (attr->extra_flags & GSDocumentEditedFlag)) {
2940 wwin->client_flags.broken_close = !MGFLAGP(wwin, broken_close);
2941 wWindowUpdateButtonImages(wwin);
2947 WMagicNumber
2948 wWindowAddSavedState(char *instance, char *class, char *command,
2949 pid_t pid, WSavedState *state)
2951 WWindowState *wstate;
2953 wstate = malloc(sizeof(WWindowState));
2954 if (!wstate)
2955 return 0;
2957 memset(wstate, 0, sizeof(WWindowState));
2958 wstate->pid = pid;
2959 if (instance)
2960 wstate->instance = wstrdup(instance);
2961 if (class)
2962 wstate->class = wstrdup(class);
2963 if (command)
2964 wstate->command = wstrdup(command);
2965 wstate->state = state;
2967 wstate->next = windowState;
2968 windowState = wstate;
2970 #ifdef DEBUG
2971 printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
2972 class, command);
2973 #endif
2975 return wstate;
2979 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
2982 WMagicNumber
2983 wWindowGetSavedState(Window win)
2985 char *instance, *class, *command=NULL;
2986 WWindowState *wstate = windowState;
2988 if (!wstate)
2989 return NULL;
2991 command = GetCommandForWindow(win);
2992 if (!command)
2993 return NULL;
2995 if (PropGetWMClass(win, &class, &instance)) {
2996 while (wstate) {
2997 if (SAME(instance, wstate->instance) &&
2998 SAME(class, wstate->class) &&
2999 SAME(command, wstate->command)) {
3000 break;
3002 wstate = wstate->next;
3004 } else {
3005 wstate = NULL;
3008 #ifdef DEBUG
3009 printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
3010 class, command);
3011 #endif
3013 if (command) wfree(command);
3014 if (instance) XFree(instance);
3015 if (class) XFree(class);
3017 return wstate;
3021 void
3022 wWindowDeleteSavedState(WMagicNumber id)
3024 WWindowState *tmp, *wstate=(WWindowState*)id;
3026 if (!wstate || !windowState)
3027 return;
3029 tmp = windowState;
3030 if (tmp==wstate) {
3031 windowState = wstate->next;
3032 #ifdef DEBUG
3033 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
3034 wstate, wstate->instance, wstate->class, wstate->command);
3035 #endif
3036 if (wstate->instance) wfree(wstate->instance);
3037 if (wstate->class) wfree(wstate->class);
3038 if (wstate->command) wfree(wstate->command);
3039 wfree(wstate->state);
3040 wfree(wstate);
3041 } else {
3042 while (tmp->next) {
3043 if (tmp->next==wstate) {
3044 tmp->next=wstate->next;
3045 #ifdef DEBUG
3046 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
3047 wstate, wstate->instance, wstate->class, wstate->command);
3048 #endif
3049 if (wstate->instance) wfree(wstate->instance);
3050 if (wstate->class) wfree(wstate->class);
3051 if (wstate->command) wfree(wstate->command);
3052 wfree(wstate->state);
3053 wfree(wstate);
3054 break;
3056 tmp = tmp->next;
3062 void
3063 wWindowDeleteSavedStatesForPID(pid_t pid)
3065 WWindowState *tmp, *wstate;
3067 if (!windowState)
3068 return;
3070 tmp = windowState;
3071 if (tmp->pid == pid) {
3072 wstate = windowState;
3073 windowState = tmp->next;
3074 #ifdef DEBUG
3075 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
3076 wstate, wstate->instance, wstate->class, wstate->command);
3077 #endif
3078 if (wstate->instance) wfree(wstate->instance);
3079 if (wstate->class) wfree(wstate->class);
3080 if (wstate->command) wfree(wstate->command);
3081 wfree(wstate->state);
3082 wfree(wstate);
3083 } else {
3084 while (tmp->next) {
3085 if (tmp->next->pid==pid) {
3086 wstate = tmp->next;
3087 tmp->next = wstate->next;
3088 #ifdef DEBUG
3089 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
3090 wstate, wstate->instance, wstate->class, wstate->command);
3091 #endif
3092 if (wstate->instance) wfree(wstate->instance);
3093 if (wstate->class) wfree(wstate->class);
3094 if (wstate->command) wfree(wstate->command);
3095 wfree(wstate->state);
3096 wfree(wstate);
3097 break;
3099 tmp = tmp->next;
3105 void
3106 wWindowSetOmnipresent(WWindow *wwin, Bool flag)
3108 if (wwin->flags.omnipresent == flag)
3109 return;
3111 wwin->flags.omnipresent = flag;
3112 WMPostNotificationName(WMNChangedState, wwin, "omnipresent");
3116 /* ====================================================================== */
3118 static void
3119 resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
3121 WWindow *wwin = data;
3123 #ifndef NUMLOCK_HACK
3124 if ((event->xbutton.state & ValidModMask)
3125 != (event->xbutton.state & ~LockMask)) {
3126 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
3127 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
3129 #endif
3131 event->xbutton.state &= ValidModMask;
3133 CloseWindowMenu(wwin->screen_ptr);
3135 if (wPreferences.focus_mode==WKF_CLICK
3136 && !(event->xbutton.state&ControlMask)
3137 && !WFLAGP(wwin, no_focusable)) {
3138 wSetFocusTo(wwin->screen_ptr, wwin);
3141 if (event->xbutton.button == Button1)
3142 wRaiseFrame(wwin->frame->core);
3144 if (event->xbutton.window != wwin->frame->resizebar->window) {
3145 if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
3146 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
3147 GrabModeAsync, GrabModeAsync, None,
3148 None, CurrentTime)!=GrabSuccess) {
3149 #ifdef DEBUG0
3150 wwarning("pointer grab failed for window move");
3151 #endif
3152 return;
3156 if (event->xbutton.state & MOD_MASK) {
3157 /* move the window */
3158 wMouseMoveWindow(wwin, event);
3159 XUngrabPointer(dpy, CurrentTime);
3160 } else {
3161 wMouseResizeWindow(wwin, event);
3162 XUngrabPointer(dpy, CurrentTime);
3168 static void
3169 titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event)
3171 WWindow *wwin = data;
3173 event->xbutton.state &= ValidModMask;
3175 if (event->xbutton.button==Button1) {
3176 if (event->xbutton.state == 0) {
3177 if (!WFLAGP(wwin, no_shadeable)) {
3178 /* shade window */
3179 if (wwin->flags.shaded)
3180 wUnshadeWindow(wwin);
3181 else
3182 wShadeWindow(wwin);
3184 } else {
3185 int dir = 0;
3187 if (event->xbutton.state & ControlMask)
3188 dir |= MAX_VERTICAL;
3190 if (event->xbutton.state & ShiftMask) {
3191 dir |= MAX_HORIZONTAL;
3192 if (!(event->xbutton.state & ControlMask))
3193 wSelectWindow(wwin, !wwin->flags.selected);
3196 /* maximize window */
3197 if (dir!=0 && IS_RESIZABLE(wwin)) {
3198 int ndir = dir ^ wwin->flags.maximized;
3200 if (ndir != 0) {
3201 wMaximizeWindow(wwin, ndir);
3202 } else {
3203 wUnmaximizeWindow(wwin);
3207 } else if (event->xbutton.button==Button3) {
3208 if (event->xbutton.state & MOD_MASK) {
3209 wHideOtherApplications(wwin);
3211 } else if (event->xbutton.button==Button2) {
3212 wSelectWindow(wwin, !wwin->flags.selected);
3213 } else if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
3214 wShadeWindow(wwin);
3215 } else if (event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
3216 wUnshadeWindow(wwin);
3221 static void
3222 frameMouseDown(WObjDescriptor *desc, XEvent *event)
3224 WWindow *wwin = desc->parent;
3226 event->xbutton.state &= ValidModMask;
3228 CloseWindowMenu(wwin->screen_ptr);
3230 if (/*wPreferences.focus_mode==WKF_CLICK
3231 &&*/ !(event->xbutton.state&ControlMask)
3232 && !WFLAGP(wwin, no_focusable)) {
3233 wSetFocusTo(wwin->screen_ptr, wwin);
3235 if (event->xbutton.button == Button1) {
3236 wRaiseFrame(wwin->frame->core);
3239 if (event->xbutton.state & MOD_MASK) {
3240 /* move the window */
3241 if (XGrabPointer(dpy, wwin->client_win, False,
3242 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
3243 GrabModeAsync, GrabModeAsync, None,
3244 None, CurrentTime)!=GrabSuccess) {
3245 #ifdef DEBUG0
3246 wwarning("pointer grab failed for window move");
3247 #endif
3248 return;
3250 if (event->xbutton.button == Button3)
3251 wMouseResizeWindow(wwin, event);
3252 else if (event->xbutton.button==Button1 || event->xbutton.button==Button2)
3253 wMouseMoveWindow(wwin, event);
3254 XUngrabPointer(dpy, CurrentTime);
3259 static void
3260 titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
3262 WWindow *wwin = (WWindow*)data;
3264 #ifndef NUMLOCK_HACK
3265 if ((event->xbutton.state & ValidModMask)
3266 != (event->xbutton.state & ~LockMask)) {
3267 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
3268 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
3270 #endif
3271 event->xbutton.state &= ValidModMask;
3273 CloseWindowMenu(wwin->screen_ptr);
3275 if (wPreferences.focus_mode==WKF_CLICK
3276 && !(event->xbutton.state&ControlMask)
3277 && !WFLAGP(wwin, no_focusable)) {
3278 wSetFocusTo(wwin->screen_ptr, wwin);
3281 if (event->xbutton.button == Button1
3282 || event->xbutton.button == Button2) {
3284 if (event->xbutton.button == Button1) {
3285 if (event->xbutton.state & MOD_MASK) {
3286 wLowerFrame(wwin->frame->core);
3287 } else {
3288 wRaiseFrame(wwin->frame->core);
3291 if ((event->xbutton.state & ShiftMask)
3292 && !(event->xbutton.state & ControlMask)) {
3293 wSelectWindow(wwin, !wwin->flags.selected);
3294 return;
3296 if (event->xbutton.window != wwin->frame->titlebar->window
3297 && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
3298 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
3299 GrabModeAsync, GrabModeAsync, None,
3300 None, CurrentTime)!=GrabSuccess) {
3301 #ifdef DEBUG0
3302 wwarning("pointer grab failed for window move");
3303 #endif
3304 return;
3307 /* move the window */
3308 wMouseMoveWindow(wwin, event);
3310 XUngrabPointer(dpy, CurrentTime);
3311 } else if (event->xbutton.button == Button3 && event->xbutton.state==0
3312 && !wwin->flags.internal_window
3313 && !WCHECK_STATE(WSTATE_MODAL)) {
3314 WObjDescriptor *desc;
3316 if (event->xbutton.window != wwin->frame->titlebar->window
3317 && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
3318 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
3319 GrabModeAsync, GrabModeAsync, None,
3320 None, CurrentTime)!=GrabSuccess) {
3321 #ifdef DEBUG0
3322 wwarning("pointer grab failed for window move");
3323 #endif
3324 return;
3327 OpenWindowMenu(wwin, event->xbutton.x_root,
3328 wwin->frame_y+wwin->frame->top_width, False);
3330 /* allow drag select */
3331 desc = &wwin->screen_ptr->window_menu->menu->descriptor;
3332 event->xany.send_event = True;
3333 (*desc->handle_mousedown)(desc, event);
3335 XUngrabPointer(dpy, CurrentTime);
3341 static void
3342 windowCloseClick(WCoreWindow *sender, void *data, XEvent *event)
3344 WWindow *wwin = data;
3346 event->xbutton.state &= ValidModMask;
3348 CloseWindowMenu(wwin->screen_ptr);
3350 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
3351 return;
3353 /* if control-click, kill the client */
3354 if (event->xbutton.state & ControlMask) {
3355 wClientKill(wwin);
3356 } else {
3357 #ifdef OLWM_HINTS
3358 if (wwin->flags.olwm_push_pin_out) {
3360 wwin->flags.olwm_push_pin_out = 0;
3362 wOLWMChangePushpinState(wwin, True);
3364 wFrameWindowUpdatePushButton(wwin->frame, False);
3366 return;
3368 #endif
3369 if (wwin->protocols.DELETE_WINDOW && event->xbutton.state==0) {
3370 /* send delete message */
3371 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
3377 static void
3378 windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
3380 WWindow *wwin = data;
3382 CloseWindowMenu(wwin->screen_ptr);
3384 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
3385 return;
3387 /* send delete message */
3388 if (wwin->protocols.DELETE_WINDOW) {
3389 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
3390 } else {
3391 wClientKill(wwin);
3396 #ifdef XKB_BUTTON_HINT
3397 static void
3398 windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event)
3400 WWindow *wwin = data;
3401 WFrameWindow *fwin = wwin->frame;
3402 WScreen *scr = fwin->screen_ptr;
3403 XkbStateRec staterec;
3404 int tl;
3406 if (event->xbutton.button != Button1 && event->xbutton.button != Button3)
3407 return;
3408 tl = wwin->frame->languagemode;
3409 wwin->frame->languagemode = wwin->frame->last_languagemode;
3410 wwin->frame->last_languagemode = tl;
3411 wSetFocusTo(scr, wwin);
3412 wwin->frame->languagebutton_image =
3413 wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 +
3414 wwin->frame->languagemode];
3415 wFrameWindowUpdateLanguageButton(wwin->frame);
3416 if (event->xbutton.button == Button3)
3417 return;
3418 wRaiseFrame(fwin->core);
3420 #endif
3423 static void
3424 windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event)
3426 WWindow *wwin = data;
3428 event->xbutton.state &= ValidModMask;
3430 CloseWindowMenu(wwin->screen_ptr);
3432 if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
3433 return;
3435 if (wwin->protocols.MINIATURIZE_WINDOW && event->xbutton.state==0) {
3436 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
3437 LastTimestamp);
3438 } else {
3439 WApplication *wapp;
3440 if ((event->xbutton.state & ControlMask) ||
3441 (event->xbutton.button == Button3)) {
3443 wapp = wApplicationOf(wwin->main_window);
3444 if (wapp && !WFLAGP(wwin, no_appicon))
3445 wHideApplication(wapp);
3446 } else if (event->xbutton.state==0) {
3447 wIconifyWindow(wwin);