Initial revision
[wmaker-crm.git] / src / window.c
blobf4de8afc874ecc3666a5fc21c1ef39d83cc4f3bf
1 /* window.c - client window managing class
2 *
3 * WindowMaker 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 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
34 #include "WindowMaker.h"
35 #include "GNUstep.h"
36 #ifdef MWM_HINTS
37 # include "motif.h"
38 #endif
39 #include "wcore.h"
40 #include "framewin.h"
41 #include "texture.h"
42 #include "window.h"
43 #include "winspector.h"
44 #include "icon.h"
45 #include "properties.h"
46 #include "actions.h"
47 #include "client.h"
48 #include "funcs.h"
49 #include "keybind.h"
50 #include "stacking.h"
51 #include "defaults.h"
52 #include "workspace.h"
54 /****** Global Variables ******/
56 extern WShortKey wKeyBindings[WKBD_LAST];
58 /* modules */
59 extern int ModuleNo;
61 /* contexts */
62 extern XContext wWinContext;
64 /* cursors */
65 extern Cursor wCursor[WCUR_LAST];
67 /* protocol atoms */
68 extern Atom _XA_WM_DELETE_WINDOW;
69 extern Atom _XA_WINDOWMAKER_WM_MINIATURIZE_WINDOW;
71 extern Atom _XA_WINDOWMAKER_STATE;
73 extern WPreferences wPreferences;
75 #define MOD_MASK wPreferences.modifier_mask
77 extern Time LastTimestamp;
79 /* superfluous... */
80 extern void DoWindowBirth(WWindow*);
82 /***** Local Stuff *****/
84 /* local functions */
85 static FocusMode getFocusMode(WWindow *wwin);
87 static int getSavedState(Window window, WSavedState **state);
89 static void setupGNUstepHints(WWindowAttributes *attribs,
90 GNUstepWMAttributes *gs_hints);
92 #ifdef MWM_HINTS
93 static void setupMWMHints(WWindowAttributes *attribs, MWMHints *mwm_hints);
94 #endif
96 /* event handlers */
99 /* frame window (during window grabs) */
100 static void frameMouseDown(WObjDescriptor *desc, XEvent *event);
102 /* close button */
103 static void windowCloseClick(WCoreWindow *sender, void *data, XEvent *event);
104 static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event);
106 /* iconify button */
107 static void windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event);
110 static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
111 static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event);
113 static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
116 WWindow*
117 wWindowFor(Window window)
119 WObjDescriptor *desc;
121 if (window==None)
122 return NULL;
124 if (XFindContext(dpy, window, wWinContext, (XPointer*)&desc)==XCNOENT)
125 return NULL;
127 if (desc->parent_type==WCLASS_WINDOW)
128 return desc->parent;
129 else if (desc->parent_type==WCLASS_FRAME) {
130 WFrameWindow *frame = (WFrameWindow*)desc->parent;
131 if (frame->flags.is_client_window_frame)
132 return frame->child;
134 return NULL;
138 WWindow *
139 wWindowCreate()
141 WWindow *wwin;
143 wwin = wmalloc(sizeof(WWindow));
144 wretain(wwin);
146 memset(wwin, 0, sizeof(WWindow));
148 wwin->client_descriptor.handle_mousedown = frameMouseDown;
149 wwin->client_descriptor.parent = wwin;
150 wwin->client_descriptor.self = wwin;
151 wwin->client_descriptor.parent_type = WCLASS_WINDOW;
152 return wwin;
156 void
157 wWindowDestroy(WWindow *wwin)
159 wwin->flags.destroyed = 1;
161 if (wwin->normal_hints)
162 free(wwin->normal_hints);
164 if (wwin->wm_hints)
165 XFree(wwin->wm_hints);
167 if (wwin->wm_instance)
168 XFree(wwin->wm_instance);
170 if (wwin->wm_class)
171 XFree(wwin->wm_class);
173 if (wwin->wm_gnustep_attr)
174 free(wwin->wm_gnustep_attr);
176 if (wwin->cmap_windows)
177 XFree(wwin->cmap_windows);
179 XDeleteContext(dpy, wwin->client_win, wWinContext);
181 if (wwin->frame)
182 wFrameWindowDestroy(wwin->frame);
184 if (wwin->icon) {
185 RemoveFromStackList(wwin->icon->core);
186 wIconDestroy(wwin->icon);
187 if (wPreferences.auto_arrange_icons)
188 wArrangeIcons(wwin->screen_ptr, True);
190 wrelease(wwin);
196 static void
197 setupGNUstepHints(WWindowAttributes *attribs, GNUstepWMAttributes *gs_hints)
199 if (gs_hints->flags & GSWindowStyleAttr) {
200 attribs->no_titlebar =
201 ((gs_hints->window_style & WMTitledWindowMask)?0:1);
203 attribs->no_close_button = attribs->no_closable =
204 ((gs_hints->window_style & WMClosableWindowMask)?0:1);
206 attribs->no_miniaturize_button = attribs->no_miniaturizable =
207 ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1);
209 attribs->no_resizebar = attribs->no_resizable =
210 ((gs_hints->window_style & WMResizableWindowMask)?0:1);
211 } else {
212 /* setup the defaults */
213 attribs->no_titlebar = 0;
214 attribs->no_closable = 0;
215 attribs->no_miniaturizable = 0;
216 attribs->no_resizable = 0;
217 attribs->no_close_button = 0;
218 attribs->no_miniaturize_button = 0;
219 attribs->no_resizebar = 0;
222 if (gs_hints->extra_flags & GSNoApplicationIconFlag) {
223 attribs->no_appicon = 1;
228 #ifdef MWM_HINTS
229 static void
230 setupMWMHints(WWindowAttributes *attribs, MWMHints *mwm_hints)
234 * We will ignore all decoration hints that have an equivalent as
235 * functions, because wmaker does not distinguish decoration hints
238 if (mwm_hints->flags & MWM_HINTS_DECORATIONS) {
239 # ifdef DEBUG
240 fprintf(stderr,"has decor hints [ ");
241 # endif
242 attribs->no_titlebar = 1;
243 attribs->no_close_button = 1;
244 attribs->no_miniaturize_button = 1;
245 attribs->no_resizebar = 1;
247 if (mwm_hints->decorations & MWM_DECOR_ALL) {
248 # ifdef DEBUG
249 fprintf(stderr,"ALL ");
250 # endif
251 attribs->no_titlebar = 0;
252 attribs->no_close_button = 0;
253 attribs->no_closable = 0;
254 attribs->no_miniaturize_button = 0;
255 attribs->no_miniaturizable = 0;
256 attribs->no_resizebar = 0;
257 attribs->no_resizable = 0;
260 if (mwm_hints->decorations & MWM_DECOR_BORDER) {
261 # ifdef DEBUG
262 fprintf(stderr,"(BORDER) ");
263 # endif
267 if (mwm_hints->decorations & MWM_DECOR_RESIZEH) {
268 # ifdef DEBUG
269 fprintf(stderr,"RESIZEH ");
270 # endif
271 attribs->no_resizebar = 0;
274 if (mwm_hints->decorations & MWM_DECOR_TITLE) {
275 # ifdef DEBUG
276 fprintf(stderr,"TITLE+close ");
277 # endif
278 attribs->no_titlebar = 0;
279 attribs->no_close_button = 0;
280 attribs->no_closable = 0;
283 if (mwm_hints->decorations & MWM_DECOR_MENU) {
284 # ifdef DEBUG
285 fprintf(stderr,"(MENU) ");
286 # endif
290 if (mwm_hints->decorations & MWM_DECOR_MINIMIZE) {
291 # ifdef DEBUG
292 fprintf(stderr,"MINIMIZE ");
293 # endif
294 attribs->no_miniaturize_button = 0;
295 attribs->no_miniaturizable = 0;
298 if (mwm_hints->decorations & MWM_DECOR_MAXIMIZE) {
299 # ifdef DEBUG
300 fprintf(stderr,"(MAXIMIZE) ");
301 # endif
304 # ifdef DEBUG
305 fprintf(stderr,"]\n");
306 # endif
310 if (mwm_hints->flags & MWM_HINTS_FUNCTIONS) {
311 # ifdef DEBUG
312 fprintf(stderr,"has function hints [ ");
313 # endif
314 attribs->no_closable = 1;
315 attribs->no_miniaturizable = 1;
316 attribs->no_resizable = 1;
318 if (mwm_hints->functions & MWM_FUNC_ALL) {
319 # ifdef DEBUG
320 fprintf(stderr,"ALL ");
321 # endif
322 attribs->no_closable = 0;
323 attribs->no_miniaturizable = 0;
324 attribs->no_resizable = 0;
326 if (mwm_hints->functions & MWM_FUNC_RESIZE) {
327 # ifdef DEBUG
328 fprintf(stderr,"RESIZE ");
329 # endif
330 attribs->no_resizable = 0;
333 if (mwm_hints->functions & MWM_FUNC_MOVE) {
334 # ifdef DEBUG
335 fprintf(stderr,"(MOVE) ");
336 # endif
339 if (mwm_hints->functions & MWM_FUNC_MINIMIZE) {
340 # ifdef DEBUG
341 fprintf(stderr,"MINIMIZE ");
342 # endif
343 attribs->no_miniaturizable = 0;
345 if (mwm_hints->functions & MWM_FUNC_MAXIMIZE) {
346 # ifdef DEBUG
347 fprintf(stderr,"MAXIMIZE ");
348 /* a window must be resizable to be maximizable */
349 attribs->no_resizable = 0;
350 # endif
352 if (mwm_hints->functions & MWM_FUNC_CLOSE) {
353 # ifdef DEBUG
354 fprintf(stderr,"CLOSE ");
355 # endif
356 attribs->no_closable = 0;
358 # ifdef DEBUG
359 fprintf(stderr,"]\n");
360 # endif
363 #endif /* MWM_HINTS */
366 void
367 wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags)
369 if (wflags->no_appicon)
370 wflags->emulate_appicon = 0;
372 if (wwin->main_window!=None) {
373 WApplication *wapp = wApplicationOf(wwin->main_window);
374 if (wapp && !wapp->flags.emulated)
375 wflags->emulate_appicon = 0;
378 if (wwin->transient_for!=None
379 && wwin->transient_for!=wwin->screen_ptr->root_win)
380 wflags->emulate_appicon = 0;
385 Bool
386 wWindowCanReceiveFocus(WWindow *wwin)
388 if (!wwin->flags.mapped && !wwin->flags.shaded)
389 return False;
390 if (wwin->window_flags.no_focusable || wwin->flags.miniaturized)
391 return False;
392 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
393 return False;
395 return True;
400 *----------------------------------------------------------------
401 * wManageWindow--
402 * reparents the window and allocates a descriptor for it.
403 * Window manager hints and other hints are fetched to configure
404 * the window decoration attributes and others. User preferences
405 * for the window are used if available, to configure window
406 * decorations and some behaviour.
408 * Returns:
409 * the new window descriptor
411 * Side effects:
412 * The window is reparented and appropriate notification
413 * is done to the client. Input mask for the window is setup.
414 * The window descriptor is also associated with various window
415 * contexts and inserted in the head of the window list.
416 * Event handler contexts are associated for some objects
417 * (buttons, titlebar and resizebar)
419 * TODO:
420 * Check if the window_flags setting is correct.
421 *----------------------------------------------------------------
423 WWindow*
424 wManageWindow(WScreen *scr, Window window)
426 WWindow *wwin;
427 int width, height;
428 XWindowAttributes wattribs;
429 XSetWindowAttributes attribs;
430 int iconic = 0;
431 WSavedState *wstate;
432 WWindowState *win_state;
433 #ifdef MWM_HINTS
434 MWMHints *motif_hints = NULL;
435 #endif
436 int window_level;
437 int foo, gx, gy;
438 int resized_client;
439 int workspace = -1;
440 char *title;
442 /* mutex. */
443 XGrabServer(dpy);
444 XSync(dpy, 0);
445 /* make sure the window is still there */
446 if (!XGetWindowAttributes(dpy, window, &wattribs)) {
447 XUngrabServer(dpy);
448 return NULL;
450 wwin = wWindowCreate();
452 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
454 #ifdef DEBUG
455 printf("managing window %x\n", (unsigned)window);
456 #endif
458 #ifdef SHAPE
460 int junk;
461 unsigned int ujunk;
462 int b_shaped;
464 XShapeSelectInput(dpy, window, ShapeNotifyMask);
465 XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk,
466 &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
467 wwin->flags.shaped = b_shaped;
469 #endif
472 *--------------------------------------------------
474 * Get hints and other information in properties
476 *--------------------------------------------------
478 wwin->wm_hints = XGetWMHints(dpy, window);
479 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
481 /* setup descriptor */
482 wwin->client_win = window;
483 wwin->screen_ptr = scr;
485 wwin->old_border_width = wattribs.border_width;
487 attribs.event_mask = CLIENT_EVENTS;
488 attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
489 attribs.save_under = False;
490 XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate
491 |CWSaveUnder, &attribs);
492 XSetWindowBorderWidth(dpy, window, 0);
494 /* fill in property/hint data */
495 if (!wFetchName(dpy, window, &title)) {
496 title = NULL;
498 /* get hints from GNUstep app */
499 if (!PropGetGNUstepWMAttr(window, &wwin->wm_gnustep_attr)) {
500 wwin->wm_gnustep_attr=NULL;
503 #ifdef MWM_HINTS
504 PropGetMotifWMHints(window, &motif_hints);
505 #endif /* MWM_HINTS */
507 if (!PropGetClientLeader(window, &wwin->client_leader)) {
508 wwin->client_leader = None;
509 } else {
510 wwin->main_window = wwin->client_leader;
513 if (wwin->wm_hints)
514 XFree(wwin->wm_hints);
516 wwin->wm_hints = XGetWMHints(dpy, window);
518 if (wwin->wm_hints) {
519 if ((wwin->wm_hints->flags&StateHint)
520 && (wwin->wm_hints->initial_state == IconicState)) {
521 iconic = 1;
522 /* don't do iconify animation */
523 wwin->flags.skip_next_animation = 1;
526 if (wwin->wm_hints->flags & WindowGroupHint) {
527 wwin->group_id = wwin->wm_hints->window_group;
528 /* window_group has priority over CLIENT_LEADER */
529 wwin->main_window = wwin->group_id;
530 } else {
531 wwin->group_id = None;
534 if (wwin->wm_hints->flags & UrgencyHint)
535 wwin->flags.urgent = 1;
536 } else {
537 wwin->group_id = None;
540 PropGetProtocols(window, &wwin->protocols);
542 if (!XGetTransientForHint(dpy, window, &wwin->transient_for)) {
543 wwin->transient_for = None;
544 } else {
545 if (wwin->transient_for==None || wwin->transient_for==window) {
546 wwin->transient_for = scr->root_win;
547 } else {
548 WWindow *owner;
549 owner = wWindowFor(wwin->transient_for);
550 if (owner && owner->main_window!=None) {
551 wwin->main_window = owner->main_window;
552 } /*else {
553 wwin->main_window = None;
556 /* don't let transients start miniaturized if their owners
557 * are not */
558 if (owner && !owner->flags.miniaturized && iconic) {
559 iconic = 0;
560 if (wwin->wm_hints)
561 wwin->wm_hints->initial_state = NormalState;
566 /* guess the focus mode */
567 wwin->focus_mode = getFocusMode(wwin);
569 /* get geometry stuff */
570 GetNormalHints(wwin, &wattribs, True);
572 /* get colormap windows */
573 GetColormapWindows(wwin);
577 *--------------------------------------------------
579 * Setup the decoration/window attributes and
580 * geometry
582 *--------------------------------------------------
584 /* sets global default stuff */
585 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
586 &wwin->window_flags, True);
588 * Decoration setting is done in this precedence (lower to higher)
589 * - use default in the resource database
590 * - guess some settings
591 * - use GNUstep/external window attributes
592 * - set hints specified for the app in the resource DB
594 wwin->window_flags.broken_close = 0;
596 if (wwin->protocols.DELETE_WINDOW)
597 wwin->window_flags.kill_close = 0;
598 else
599 wwin->window_flags.kill_close = 1;
601 /* transients can't be iconified or maximized */
602 if (wwin->transient_for) {
603 wwin->window_flags.no_miniaturizable = 1;
604 wwin->window_flags.no_miniaturize_button = 1;
605 #ifdef DEBUG
606 printf("%x is transient for %x\n", (unsigned)window,
607 (unsigned)wwin->transient_for);
608 #endif
611 /* if the window can't be resized, remove the resizebar */
612 if (wwin->normal_hints->flags & (PMinSize|PMaxSize)
613 && (wwin->normal_hints->min_width==wwin->normal_hints->max_width)
614 && (wwin->normal_hints->min_height==wwin->normal_hints->max_height)) {
615 wwin->window_flags.no_resizable = 1;
616 wwin->window_flags.no_resizebar = 1;
619 /* set GNUstep window attributes */
620 if (wwin->wm_gnustep_attr) {
621 setupGNUstepHints(&wwin->window_flags, wwin->wm_gnustep_attr);
622 if (wwin->wm_gnustep_attr->flags & GSWindowLevelAttr) {
623 window_level = wwin->wm_gnustep_attr->window_level;
624 } else {
625 /* setup defaults */
626 window_level = WMNormalWindowLevel;
628 } else {
629 #ifdef MWM_HINTS
630 if (motif_hints) {
631 setupMWMHints(&wwin->window_flags, motif_hints);
633 #endif /* MWM_HINTS */
634 if (wwin->window_flags.floating)
635 window_level = WMFloatingWindowLevel;
636 else
637 window_level = WMNormalWindowLevel;
639 #ifdef MWM_HINTS
640 if (motif_hints)
641 XFree(motif_hints);
642 #endif
645 * Set attributes specified only for that window/class.
646 * This might do duplicate work with the 1st wDefaultFillAttributes().
647 * TODO: Do something about that.
649 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
650 &wwin->window_flags, False);
654 * Sanity checks for attributes that depend on other attributes
656 wWindowCheckAttributeSanity(wwin, &wwin->window_flags);
658 wwin->window_flags.no_shadeable = wwin->window_flags.no_titlebar;
661 * Make broken apps behave as a nice app.
663 if (wwin->window_flags.emulate_appicon) {
664 wwin->main_window = wwin->client_win;
668 *------------------------------------------------------------
670 * Setup the initial state of the window
672 *------------------------------------------------------------
674 if (wwin->window_flags.start_miniaturized
675 && !wwin->window_flags.no_miniaturizable) {
676 wwin->flags.miniaturized = 1;
677 iconic = 1;
680 /* if there is a saved state, restore it */
681 win_state = NULL;
682 if (wwin->main_window!=None/* && wwin->main_window!=window*/) {
683 win_state = (WWindowState*)wGetWindowSavedState(wwin->main_window);
684 } else {
685 win_state = (WWindowState*)wGetWindowSavedState(window);
687 if (win_state && !(wwin->wm_hints && wwin->wm_hints->flags&StateHint &&
688 wwin->wm_hints->initial_state==WithdrawnState)) {
689 if (win_state->state->hidden>0)
690 wwin->flags.hidden = win_state->state->hidden;
691 if (win_state->state->shaded>0 && !wwin->window_flags.no_shadeable)
692 wwin->flags.shaded = win_state->state->shaded;
693 if (win_state->state->miniaturized>0 &&
694 !wwin->window_flags.no_miniaturizable) {
695 wwin->flags.miniaturized = win_state->state->miniaturized;
696 iconic = 1;
698 if (!wwin->window_flags.omnipresent) {
699 int w = wDefaultGetStartWorkspace(scr, wwin->wm_instance,
700 wwin->wm_class);
701 if (w < 0 || w >= scr->workspace_count) {
702 workspace = win_state->state->workspace;
703 if (workspace>=scr->workspace_count)
704 workspace = scr->current_workspace;
705 } else {
706 workspace = w;
708 } else {
709 workspace = scr->current_workspace;
712 /* if we're restarting, restore saved state. This will overwrite previous */
713 if (!getSavedState(window, &wstate)) {
714 wstate = NULL;
715 } else {
716 wwin->flags.shaded = wstate->shaded;
717 wwin->flags.hidden = wstate->hidden;
718 wwin->flags.miniaturized = 0;
719 workspace = wstate->workspace;
723 /* set workspace on which the window starts */
725 if (workspace >= 0) {
726 if (workspace > scr->workspace_count-1) {
727 wWorkspaceMake(scr, workspace - scr->workspace_count + 1);
728 workspace = scr->workspace_count - 1;
730 } else {
731 int w;
733 w = wDefaultGetStartWorkspace(scr, wwin->wm_instance, wwin->wm_class);
734 if (w>=0 && w<scr->workspace_count && !wwin->window_flags.omnipresent) {
735 workspace = w;
736 } else {
737 workspace = scr->current_workspace;
742 /* setup window geometry */
743 if (win_state && win_state->state->use_geometry) {
744 width = win_state->state->w;
745 height = win_state->state->h;
746 } else {
747 width = wwin->client.width;
748 height = wwin->client.height;
751 wWindowConstrainSize(wwin, &width, &height);
753 resized_client = 0;
754 if (wwin->client.width != width) {
755 wwin->client.width = width;
756 resized_client = 1;
758 if (wwin->client.height != height) {
759 wwin->client.height = height;
760 resized_client = 1;
763 /* do not ask for window placement if the window is
764 * transient, during startup, if the initial workspace is another one
765 * or if the window wants to
766 * start iconic.
767 * If geometry was saved, restore it. */
768 if (win_state && win_state->state->use_geometry) {
769 wwin->frame_x = win_state->state->x;
770 wwin->frame_y = win_state->state->y;
771 } else if (wwin->transient_for==None && !scr->flags.startup &&
772 workspace==scr->current_workspace && !iconic &&
773 !(wwin->normal_hints->flags & (USPosition|PPosition))) {
774 PlaceWindow(wwin, &wwin->frame_x, &wwin->frame_y);
775 } else {
776 wwin->frame_x = wwin->client.x;
777 wwin->frame_y = wwin->client.y;
780 if (wwin->window_flags.dont_move_off)
781 wScreenBringInside(scr, &wwin->frame_x, &wwin->frame_y, width, height);
784 *--------------------------------------------------
786 * Create frame, borders and do reparenting
788 *--------------------------------------------------
791 foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
792 if (!wwin->window_flags.no_titlebar)
793 foo |= WFF_TITLEBAR;
794 if (!wwin->window_flags.no_resizebar)
795 foo |= WFF_RESIZEBAR;
797 wwin->frame = wFrameWindowCreate(scr, window_level,
798 wwin->frame_x, wwin->frame_y,
799 width, height, foo,
800 scr->window_title_texture,
801 (WTexture**)scr->resizebar_texture,
802 scr->window_title_pixel,
803 &scr->window_title_gc,
804 &scr->title_font);
807 wwin->frame->flags.is_client_window_frame = 1;
808 wwin->frame->flags.justification = wPreferences.title_justification;
810 /* setup button images */
811 wWindowUpdateButtonImages(wwin);
813 /* hide unused buttons */
814 foo = 0;
815 if (wwin->window_flags.no_close_button)
816 foo |= WFF_RIGHT_BUTTON;
817 if (wwin->window_flags.no_miniaturize_button)
818 foo |= WFF_LEFT_BUTTON;
819 if (foo!=0)
820 wFrameWindowHideButton(wwin->frame, foo);
823 wwin->frame->child = wwin;
825 wFrameWindowChangeTitle(wwin->frame, title ? title : DEF_WINDOW_TITLE);
826 if (title)
827 XFree(title);
829 wwin->frame->workspace = workspace;
831 wwin->frame->on_click_left = windowIconifyClick;
833 wwin->frame->on_click_right = windowCloseClick;
834 wwin->frame->on_dblclick_right = windowCloseDblClick;
836 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
837 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
839 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
841 wwin->client.y += wwin->frame->top_width;
842 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
843 0, wwin->frame->top_width);
845 wClientGetGravityOffsets(wwin, &gx, &gy);
846 /* set the positio of the frame on screen */
847 wwin->frame_x += gx * (wwin->old_border_width - FRAME_BORDER_WIDTH);
848 wwin->frame_y += gy * (wwin->old_border_width - FRAME_BORDER_WIDTH);
849 /* if gravity is to the south, account for the border sizes */
850 if (gy > 0)
851 wwin->frame_y -= wwin->frame->top_width + wwin->frame->bottom_width;
854 * force wWindowConfigure() to update the client window's size
856 wwin->client.width = 0;
857 wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y, width, height);
860 *--------------------------------------------------
862 * Setup descriptors and save window to internal
863 * lists
865 *--------------------------------------------------
868 if (wwin->main_window!=None) {
869 WApplication *app;
870 WWindow *leader;
872 /* Leader windows do not necessary set themselves as leaders.
873 * If this is the case, point the leader of this window to
874 * itself */
875 leader = wWindowFor(wwin->main_window);
876 if (leader && leader->main_window==None) {
877 leader->main_window = leader->client_win;
880 app = wApplicationCreate(scr, wwin->main_window);
881 if (app) {
882 app->last_workspace = workspace;
885 * Do application specific stuff, like setting application
886 * wide attributes.
889 if (wwin->flags.hidden) {
890 /* if the window was set to hidden because it was hidden
891 * in a previous incarnation and that state was restored */
892 app->flags.hidden = 1;
895 if (app->flags.hidden) {
896 wwin->flags.hidden = 1;
901 /* setup the frame descriptor */
902 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
903 wwin->frame->core->descriptor.parent = wwin;
904 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
906 /* don't let windows go away if we die */
907 XAddToSaveSet(dpy, window);
909 XLowerWindow(dpy, window);
911 /* if window is in this workspace and should be mapped, then map it */
913 printf("%s %i %i %i %i\n", wwin->wm_class,iconic,workspace == scr->current_workspace,
914 wwin->flags.hidden,(wwin->wm_hints && (wwin->wm_hints->flags & StateHint)
915 && wwin->wm_hints->initial_state == WithdrawnState));
916 * */
917 if (!iconic && (workspace == scr->current_workspace
918 || wwin->window_flags.omnipresent)
919 && !wwin->flags.hidden
920 && !(wwin->wm_hints && (wwin->wm_hints->flags & StateHint)
921 && wwin->wm_hints->initial_state == WithdrawnState)) {
922 /* The following "if" is to avoid crashing of clients that expect
923 * WM_STATE set before they get mapped. Else WM_STATE is set later,
924 * after the return from this function.
926 if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint)) {
927 wClientSetState(wwin, wwin->wm_hints->initial_state, None);
928 } else {
929 wClientSetState(wwin, NormalState, None);
931 if (wPreferences.superfluous && !wPreferences.no_animations
932 && !scr->flags.startup && wwin->transient_for==None) {
933 DoWindowBirth(wwin);
935 XMapSubwindows(dpy, wwin->frame->core->window);
936 wWindowMap(wwin);
937 } else {
938 XMapSubwindows(dpy, wwin->frame->core->window);
941 /* setup stacking descriptor */
942 if (wPreferences.on_top_transients && wwin->transient_for!=None
943 && wwin->transient_for!=scr->root_win) {
944 WWindow *tmp;
945 tmp = wWindowFor(wwin->transient_for);
946 if (tmp)
947 wwin->frame->core->stacking->child_of = tmp->frame->core;
948 } else {
949 wwin->frame->core->stacking->child_of = NULL;
953 if (!scr->focused_window) {
954 /* first window on the list */
955 wwin->next = NULL;
956 wwin->prev = NULL;
957 scr->focused_window = wwin;
958 } else {
959 WWindow *tmp;
961 /* add window at beginning of focus window list */
962 tmp = scr->focused_window;
963 while (tmp->prev)
964 tmp = tmp->prev;
965 tmp->prev = wwin;
966 wwin->next = tmp;
967 wwin->prev = NULL;
971 *--------------------------------------------------
973 * Final preparations before window is ready to go
975 *--------------------------------------------------
978 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
981 if (!iconic && workspace == scr->current_workspace) {
982 WWindow *tmp = wWindowFor(wwin->transient_for);
984 if ((tmp && tmp->flags.focused) || wPreferences.auto_focus)
985 wSetFocusTo(scr, wwin);
986 } else {
987 wwin->flags.ignore_next_unmap = 1;
989 wWindowResetMouseGrabs(wwin);
991 if (!wwin->window_flags.no_bind_keys) {
992 wWindowSetKeyGrabs(wwin);
996 * Prevent window withdrawal when getting the
997 * unmap notifies generated during reparenting
999 wwin->flags.mapped=0;
1001 XUngrabServer(dpy);
1002 XSync(dpy, 0);
1003 wColormapInstallForWindow(wwin->screen_ptr, scr->cmap_window);
1005 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1007 *--------------------------------------------------
1008 * Cleanup temporary stuff
1009 *--------------------------------------------------
1011 if (wstate)
1012 XFree(wstate);
1014 if (win_state)
1015 wDeleteWindowSavedState(win_state);
1017 return wwin;
1024 WWindow*
1025 wManageInternalWindow(WScreen *scr, Window window, Window owner,
1026 char *title, int x, int y, int width, int height)
1028 WWindow *wwin;
1029 int foo;
1031 wwin = wWindowCreate();
1033 wwin->flags.internal_window = 1;
1034 wwin->window_flags.omnipresent = 1;
1035 wwin->window_flags.no_shadeable = 1;
1036 wwin->window_flags.no_resizable = 1;
1038 wwin->focus_mode = WFM_PASSIVE;
1040 wwin->client_win = window;
1041 wwin->screen_ptr = scr;
1043 wwin->transient_for = owner;
1045 wwin->client.x = x;
1046 wwin->client.y = y;
1047 wwin->client.width = width;
1048 wwin->client.height = height;
1050 wwin->frame_x = wwin->client.x;
1051 wwin->frame_y = wwin->client.y;
1054 foo = WFF_RIGHT_BUTTON;
1055 foo |= WFF_TITLEBAR;
1057 wwin->frame = wFrameWindowCreate(scr, WMFloatingWindowLevel,
1058 wwin->frame_x, wwin->frame_y,
1059 width, height, foo,
1060 scr->window_title_texture,
1061 (WTexture**)scr->resizebar_texture,
1062 scr->window_title_pixel,
1063 &scr->window_title_gc,
1064 &scr->title_font);
1066 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
1068 wwin->frame->flags.is_client_window_frame = 1;
1069 wwin->frame->flags.justification = wPreferences.title_justification;
1071 wFrameWindowChangeTitle(wwin->frame, title);
1073 /* setup button images */
1074 wWindowUpdateButtonImages(wwin);
1076 /* hide buttons */
1077 wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON);
1079 wwin->frame->child = wwin;
1081 wwin->frame->workspace = wwin->screen_ptr->current_workspace;
1083 wwin->frame->on_click_right = windowCloseClick;
1085 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
1086 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
1088 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
1090 wwin->client.y += wwin->frame->top_width;
1091 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
1092 0, wwin->frame->top_width);
1094 wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y,
1095 wwin->client.width, wwin->client.height);
1097 /* setup the frame descriptor */
1098 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
1099 wwin->frame->core->descriptor.parent = wwin;
1100 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
1103 XLowerWindow(dpy, window);
1104 XMapSubwindows(dpy, wwin->frame->core->window);
1106 /* setup stacking descriptor */
1107 if (wPreferences.on_top_transients && wwin->transient_for!=None
1108 && wwin->transient_for!=scr->root_win) {
1109 WWindow *tmp;
1110 tmp = wWindowFor(wwin->transient_for);
1111 if (tmp)
1112 wwin->frame->core->stacking->child_of = tmp->frame->core;
1113 } else {
1114 wwin->frame->core->stacking->child_of = NULL;
1118 if (!scr->focused_window) {
1119 /* first window on the list */
1120 wwin->next = NULL;
1121 wwin->prev = NULL;
1122 scr->focused_window = wwin;
1123 } else {
1124 WWindow *tmp;
1126 /* add window at beginning of focus window list */
1127 tmp = scr->focused_window;
1128 while (tmp->prev)
1129 tmp = tmp->prev;
1130 tmp->prev = wwin;
1131 wwin->next = tmp;
1132 wwin->prev = NULL;
1135 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1137 /* if (wPreferences.auto_focus)*/
1138 wSetFocusTo(scr, wwin);
1140 wWindowResetMouseGrabs(wwin);
1142 wWindowSetKeyGrabs(wwin);
1144 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1146 return wwin;
1151 *----------------------------------------------------------------------
1152 * wUnmanageWindow--
1153 * Removes the frame window from a window and destroys all data
1154 * related to it. The window will be reparented back to the root window
1155 * if restore is True.
1157 * Side effects:
1158 * Everything related to the window is destroyed and the window
1159 * is removed from the window lists. Focus is set to the previous on the
1160 * window list.
1161 *----------------------------------------------------------------------
1163 void
1164 wUnmanageWindow(WWindow *wwin, int restore)
1166 WCoreWindow *frame = wwin->frame->core;
1167 WWindow *owner;
1168 WWindow *newFocusedWindow;
1169 int wasNotFocused;
1170 WScreen *scr = wwin->screen_ptr;
1172 /* First close attribute editor window if open */
1173 if (wwin->flags.inspector_open) {
1174 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1175 (*pwin->frame->on_click_right)(NULL, pwin, NULL);
1178 XUnmapWindow(dpy, frame->window);
1180 /* deselect window */
1181 if (wwin->flags.selected)
1182 wSelectWindow(wwin);
1184 /* remove all pending events on window */
1185 /* I think this only matters for autoraise */
1186 if (wPreferences.raise_delay)
1187 WMDeleteTimerWithClientData(wwin->frame->core);
1189 XFlush(dpy);
1191 UpdateSwitchMenu(scr, wwin, ACTION_REMOVE);
1193 /* reparent the window back to the root */
1194 if (restore)
1195 wClientRestore(wwin);
1197 if (wwin->transient_for!=scr->root_win) {
1198 owner = wWindowFor(wwin->transient_for);
1199 if (owner) {
1200 owner->flags.semi_focused = 0;
1201 wFrameWindowChangeState(owner->frame, WS_UNFOCUSED);
1205 wasNotFocused = !wwin->flags.focused;
1207 /* remove from window focus list */
1208 if (!wwin->prev && !wwin->next) {
1209 /* was the only window */
1210 scr->focused_window = NULL;
1211 newFocusedWindow = NULL;
1212 } else {
1213 WWindow *tmp;
1215 if (wwin->prev)
1216 wwin->prev->next = wwin->next;
1217 if (wwin->next)
1218 wwin->next->prev = wwin->prev;
1219 else {
1220 scr->focused_window = wwin->prev;
1221 scr->focused_window->next = NULL;
1224 /* if in click to focus mode and the window
1225 * was a transient, focus the owner window
1227 tmp = NULL;
1228 if (wPreferences.focus_mode==WKF_CLICK) {
1229 tmp = wWindowFor(wwin->transient_for);
1230 if (tmp && (!tmp->flags.mapped || tmp->window_flags.no_focusable)) {
1231 tmp = NULL;
1234 /* otherwise, focus the next one in the focus list */
1235 if (!tmp) {
1236 tmp = scr->focused_window;
1237 while (tmp) {
1238 if (!tmp->window_flags.no_focusable
1239 && (tmp->flags.mapped || tmp->flags.shaded))
1240 break;
1241 tmp = tmp->prev;
1244 if (wPreferences.focus_mode==WKF_CLICK) {
1245 newFocusedWindow = tmp;
1246 } else if (wPreferences.focus_mode==WKF_SLOPPY
1247 || wPreferences.focus_mode==WKF_POINTER) {
1248 unsigned int mask;
1249 int foo;
1250 Window bar, win;
1252 /* This is to let the root window get the keyboard input
1253 * if Sloppy focus mode and no other window get focus.
1254 * This way keybindings will not freeze.
1256 tmp = NULL;
1257 if (XQueryPointer(dpy, scr->root_win, &bar, &win,
1258 &foo, &foo, &foo, &foo, &mask))
1259 tmp = wWindowFor(win);
1260 if (tmp == wwin)
1261 tmp = NULL;
1262 newFocusedWindow = tmp;
1263 } else {
1264 newFocusedWindow = NULL;
1267 #ifdef DEBUG
1268 printf("destroying window %x frame %x\n", (unsigned)wwin->client_win,
1269 (unsigned)frame->window);
1270 #endif
1271 if (!wasNotFocused)
1272 wSetFocusTo(scr, newFocusedWindow);
1273 wWindowDestroy(wwin);
1274 XFlush(dpy);
1278 void
1279 wWindowFocus(WWindow *wwin)
1281 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
1283 wwin->flags.focused=1;
1285 wWindowResetMouseGrabs(wwin);
1287 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1291 void
1292 wWindowMap(WWindow *wwin)
1294 XMapWindow(dpy, wwin->frame->core->window);
1295 wwin->flags.mapped = 1;
1300 void
1301 wWindowUnfocus(WWindow *wwin)
1303 CloseWindowMenu(wwin->screen_ptr);
1305 wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused
1306 ? WS_PFOCUSED : WS_UNFOCUSED);
1308 if (wwin->transient_for!=None
1309 && wwin->transient_for!=wwin->screen_ptr->root_win) {
1310 WWindow *owner;
1311 owner = wWindowFor(wwin->transient_for);
1312 if (owner && owner->flags.semi_focused) {
1313 owner->flags.semi_focused = 0;
1314 if (owner->flags.mapped || owner->flags.shaded) {
1315 wWindowUnfocus(owner);
1316 wFrameWindowPaint(owner->frame);
1320 wwin->flags.focused=0;
1321 wWindowResetMouseGrabs(wwin);
1323 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1329 *----------------------------------------------------------------------
1331 * wWindowConstrainSize--
1332 * Constrains size for the client window, taking the maximal size,
1333 * window resize increments and other size hints into account.
1335 * Returns:
1336 * The closest size to what was given that the client window can
1337 * have.
1339 *----------------------------------------------------------------------
1341 void
1342 wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight)
1344 XSizeHints *sizeh=wwin->normal_hints;
1345 int width = *nwidth;
1346 int height = *nheight;
1347 int winc = sizeh->width_inc;
1348 int hinc = sizeh->height_inc;
1350 if (width < sizeh->min_width)
1351 width = sizeh->min_width;
1352 if (height < sizeh->min_height)
1353 height = sizeh->min_height;
1355 if (width > sizeh->max_width)
1356 width = sizeh->max_width;
1357 if (height > sizeh->max_height)
1358 height = sizeh->max_height;
1360 /* aspect ratio code borrowed from olwm */
1361 if (sizeh->flags & PAspect) {
1362 /* adjust max aspect ratio */
1363 if (!(sizeh->max_aspect.x==1 && sizeh->max_aspect.y==1)
1364 && width * sizeh->max_aspect.y > height * sizeh->max_aspect.x) {
1365 if (sizeh->max_aspect.x > sizeh->max_aspect.y) {
1366 height = (width * sizeh->max_aspect.y) / sizeh->max_aspect.x;
1367 if (height > sizeh->max_height) {
1368 height = sizeh->max_height;
1369 width = (height*sizeh->max_aspect.x) / sizeh->max_aspect.y;
1371 } else {
1372 width = (height * sizeh->max_aspect.x) / sizeh->max_aspect.y;
1373 if (width < sizeh->min_width) {
1374 width = sizeh->min_width;
1375 height = (width*sizeh->max_aspect.y) / sizeh->max_aspect.x;
1380 /* adjust min aspect ratio */
1381 if (!(sizeh->min_aspect.x==1 && sizeh->min_aspect.y==1)
1382 && width * sizeh->min_aspect.y < height * sizeh->min_aspect.x) {
1383 if (sizeh->min_aspect.x > sizeh->min_aspect.y) {
1384 height = (width * sizeh->min_aspect.y) / sizeh->min_aspect.x;
1385 if (height < sizeh->min_height) {
1386 height = sizeh->min_height;
1387 width = (height*sizeh->min_aspect.x) / sizeh->min_aspect.y;
1389 } else {
1390 width = (height * sizeh->min_aspect.x) / sizeh->min_aspect.y;
1391 if (width > sizeh->min_width) {
1392 width = sizeh->min_width;
1393 height = (width*sizeh->min_aspect.y) / sizeh->min_aspect.x;
1399 if (sizeh->base_width != 0)
1401 width = (((width - sizeh->base_width) / winc) * winc)
1402 + sizeh->base_width;
1404 else
1406 width = (((width - sizeh->min_width) / winc) * winc)
1407 + sizeh->min_width;
1410 if (sizeh->base_width != 0)
1412 height = (((height - sizeh->base_height) / hinc) * hinc)
1413 + sizeh->base_height;
1415 else
1417 height = (((height - sizeh->min_height) / hinc) * hinc)
1418 + sizeh->min_height;
1421 *nwidth = width;
1422 *nheight = height;
1426 void
1427 wWindowChangeWorkspace(WWindow *wwin, int workspace)
1429 WScreen *scr = wwin->screen_ptr;
1430 WApplication *wapp;
1432 if (workspace >= scr->workspace_count || workspace < 0
1433 || workspace == wwin->frame->workspace)
1434 return;
1436 if (workspace != scr->current_workspace) {
1437 /* Sent to other workspace. Unmap window */
1438 if ((wwin->flags.mapped||wwin->flags.shaded)
1439 && !wwin->window_flags.omnipresent
1440 && !wwin->flags.changing_workspace) {
1442 wapp = wApplicationOf(wwin->main_window);
1443 if (wapp) {
1444 wapp->last_workspace = workspace;
1446 XUnmapWindow(dpy, wwin->frame->core->window);
1447 wwin->flags.mapped = 0;
1448 wSetFocusTo(scr, NULL);
1450 } else {
1451 /* brought to current workspace. Map window */
1452 if (!wwin->flags.mapped &&
1453 !(wwin->flags.miniaturized || wwin->flags.hidden)) {
1454 wWindowMap(wwin);
1457 if (!wwin->window_flags.omnipresent) {
1458 wwin->frame->workspace = workspace;
1459 UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
1464 void
1465 wWindowSynthConfigureNotify(WWindow *wwin)
1467 XEvent sevent;
1469 sevent.type = ConfigureNotify;
1470 sevent.xconfigure.display = dpy;
1471 sevent.xconfigure.event = wwin->client_win;
1472 sevent.xconfigure.window = wwin->client_win;
1474 sevent.xconfigure.x = wwin->client.x;
1475 sevent.xconfigure.y = wwin->client.y;
1476 sevent.xconfigure.width = wwin->client.width;
1477 sevent.xconfigure.height = wwin->client.height;
1479 sevent.xconfigure.border_width = wwin->old_border_width;
1480 if (wwin->window_flags.no_titlebar)
1481 sevent.xconfigure.above = None;
1482 else
1483 sevent.xconfigure.above = wwin->frame->titlebar->window;
1485 sevent.xconfigure.override_redirect = False;
1486 XSendEvent(dpy, wwin->client_win, False, StructureNotifyMask, &sevent);
1487 XFlush(dpy);
1492 *----------------------------------------------------------------------
1493 * wWindowConfigure--
1494 * Configures the frame, decorations and client window to the
1495 * specified geometry. The geometry is not checked for validity,
1496 * wWindowConstrainSize() must be used for that.
1497 * The size parameters are for the client window, but the position is
1498 * for the frame.
1499 * The client window receives a ConfigureNotify event, according
1500 * to what ICCCM says.
1502 * Returns:
1503 * None
1505 * Side effects:
1506 * Window size and position are changed and client window receives
1507 * a ConfigureNotify event.
1508 *----------------------------------------------------------------------
1510 void
1511 wWindowConfigure(wwin, req_x, req_y, req_width, req_height)
1512 WWindow *wwin;
1513 int req_x, req_y; /* new position of the frame */
1514 int req_width, req_height; /* new size of the client */
1516 int synth_notify = False;
1517 int resize;
1519 resize = (req_width!=wwin->client.width
1520 || req_height!=wwin->client.height);
1522 * if the window is being moved but not resized then
1523 * send a synthetic ConfigureNotify
1525 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) {
1526 synth_notify = True;
1529 if (wwin->window_flags.dont_move_off)
1530 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1531 req_width, req_height);
1533 if (resize) {
1534 if (req_width < MIN_WINDOW_SIZE)
1535 req_width = MIN_WINDOW_SIZE;
1536 if (req_height < MIN_WINDOW_SIZE)
1537 req_height = MIN_WINDOW_SIZE;
1539 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
1541 if (wwin->flags.shaded) {
1542 wFrameWindowResize(wwin->frame, req_width, wwin->frame->core->height);
1543 wwin->old_geometry.height = req_height;
1544 } else {
1545 wFrameWindowResizeInternal(wwin->frame, req_width, req_height);
1548 wwin->client.x = req_x;
1549 wwin->client.y = req_y + wwin->frame->top_width;
1550 wwin->client.width = req_width;
1551 wwin->client.height = req_height;
1553 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1554 } else {
1555 wwin->client.x = req_x;
1556 wwin->client.y = req_y + wwin->frame->top_width;
1558 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1560 wwin->frame_x = req_x;
1561 wwin->frame_y = req_y;
1563 #ifdef SHAPE
1564 if (wwin->flags.shaped && resize) {
1566 * Kluge: it seems that without this delay, wmaker will
1567 * use the shape mask of the client before the resize.
1568 * The usleep() should give some time for the client
1569 * to update itself. Wont work all the time, but thats
1570 * better than nothing, I guess...
1571 * There should be a better way of doing this or I'm just
1572 * doing something wrong elsewhere.
1574 XSync(dpy, False);
1575 wusleep(1000);
1576 wWindowSetShape(wwin);
1577 XSync(dpy, False);
1579 #endif
1581 if (synth_notify)
1582 wWindowSynthConfigureNotify(wwin);
1586 void
1587 wWindowMove(wwin, req_x, req_y)
1588 WWindow *wwin;
1589 int req_x, req_y; /* new position of the frame */
1591 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1592 int synth_notify = False;
1594 /* Send a synthetic ConfigureNotify event for every window movement. */
1595 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y)) {
1596 synth_notify = True;
1598 #else
1599 /* A single synthetic ConfigureNotify event is sent at the end of
1600 * a completed (opaque) movement in moveres.c */
1601 #endif
1603 if (wwin->window_flags.dont_move_off)
1604 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1605 wwin->frame->core->width, wwin->frame->core->height);
1607 wwin->client.x = req_x;
1608 wwin->client.y = req_y + wwin->frame->top_width;
1610 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1612 wwin->frame_x = req_x;
1613 wwin->frame_y = req_y;
1615 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1616 if (synth_notify)
1617 wWindowSynthConfigureNotify(wwin);
1618 #endif
1622 void
1623 wWindowUpdateButtonImages(WWindow *wwin)
1625 WScreen *scr = wwin->screen_ptr;
1626 Pixmap pixmap, mask;
1627 WFrameWindow *fwin = wwin->frame;
1629 if (wwin->window_flags.no_titlebar)
1630 return;
1632 /* miniaturize button */
1634 if (!wwin->window_flags.no_miniaturize_button) {
1635 if (wwin->wm_gnustep_attr
1636 && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) {
1637 pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap;
1639 if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) {
1640 mask = wwin->wm_gnustep_attr->miniaturize_mask;
1641 } else {
1642 mask = None;
1645 if (fwin->lbutton_image
1646 && (fwin->lbutton_image->image != pixmap
1647 || fwin->lbutton_image->mask != mask)) {
1648 wPixmapDestroy(fwin->lbutton_image);
1649 fwin->lbutton_image = NULL;
1652 if (!fwin->lbutton_image) {
1653 fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask);
1654 fwin->lbutton_image->client_owned = 1;
1655 fwin->lbutton_image->client_owned_mask = 1;
1657 } else {
1658 if (fwin->lbutton_image && !fwin->lbutton_image->shared) {
1659 wPixmapDestroy(fwin->lbutton_image);
1661 fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
1665 /* close button */
1667 if (!wwin->window_flags.no_close_button) {
1668 if (wwin->wm_gnustep_attr
1669 && wwin->wm_gnustep_attr->flags&GSClosePixmapAttr) {
1670 pixmap = wwin->wm_gnustep_attr->close_pixmap;
1672 if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr) {
1673 mask = wwin->wm_gnustep_attr->close_mask;
1674 } else {
1675 mask = None;
1678 if (fwin->rbutton_image
1679 && (fwin->rbutton_image->image != pixmap
1680 || fwin->rbutton_image->mask != mask)) {
1681 wPixmapDestroy(fwin->rbutton_image);
1682 fwin->rbutton_image = NULL;
1685 if (!fwin->rbutton_image) {
1686 fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask);
1687 fwin->rbutton_image->client_owned = 1;
1688 fwin->rbutton_image->client_owned_mask = 1;
1690 } else if (wwin->window_flags.kill_close) {
1691 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1692 wPixmapDestroy(fwin->rbutton_image);
1694 fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL];
1695 } else if (wwin->window_flags.broken_close) {
1696 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1697 wPixmapDestroy(fwin->rbutton_image);
1699 fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE];
1700 } else {
1701 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1702 wPixmapDestroy(fwin->rbutton_image);
1704 fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE];
1708 /* force buttons to be redrawn */
1709 fwin->flags.need_texture_change = 1;
1710 wFrameWindowPaint(fwin);
1715 *---------------------------------------------------------------------------
1716 * wWindowConfigureBorders--
1717 * Update window border configuration according to window_flags
1719 *---------------------------------------------------------------------------
1721 void
1722 wWindowConfigureBorders(WWindow *wwin)
1724 if (wwin->frame) {
1725 int flags;
1726 int newy, oldh;
1728 flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON;
1729 if (!wwin->window_flags.no_titlebar)
1730 flags |= WFF_TITLEBAR;
1731 if (!wwin->window_flags.no_resizebar)
1732 flags |= WFF_RESIZEBAR;
1734 oldh = wwin->frame->top_width;
1735 wFrameWindowUpdateBorders(wwin->frame, flags);
1736 if (oldh != wwin->frame->top_width) {
1737 newy = wwin->frame_y + oldh - wwin->frame->top_width;
1739 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
1740 wWindowConfigure(wwin, wwin->frame_x, newy,
1741 wwin->client.width, wwin->client.height);
1744 flags = 0;
1745 if (!wwin->window_flags.no_miniaturize_button
1746 && wwin->frame->flags.hide_left_button)
1747 flags |= WFF_LEFT_BUTTON;
1748 if (!wwin->window_flags.no_close_button
1749 && wwin->frame->flags.hide_right_button)
1750 flags |= WFF_RIGHT_BUTTON;
1751 if (flags!=0) {
1752 wWindowUpdateButtonImages(wwin);
1753 wFrameWindowShowButton(wwin->frame, flags);
1756 flags = 0;
1757 if (wwin->window_flags.no_miniaturize_button
1758 && !wwin->frame->flags.hide_left_button)
1759 flags |= WFF_LEFT_BUTTON;
1760 if (wwin->window_flags.no_close_button
1761 && !wwin->frame->flags.hide_right_button)
1762 flags |= WFF_RIGHT_BUTTON;
1763 if (flags!=0)
1764 wFrameWindowHideButton(wwin->frame, flags);
1769 void
1770 wWindowSaveState(WWindow *wwin)
1772 WSavedState state;
1774 /* if (wwin->flags.miniaturized || wwin->flags.hidden) {
1775 state.workspace = 0;
1776 } else {
1777 state.workspace = wwin->frame->workspace;
1779 state.workspace = wwin->frame->workspace;
1780 state.shaded = wwin->flags.shaded;
1781 state.hidden = wwin->flags.hidden;
1783 XChangeProperty(dpy, wwin->client_win, _XA_WINDOWMAKER_STATE,
1784 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1785 (unsigned char *) &state, sizeof(WSavedState)/sizeof(int));
1789 static int
1790 getSavedState(Window window, WSavedState **state)
1792 Atom type_ret;
1793 int fmt_ret;
1794 unsigned long nitems_ret;
1795 unsigned long bytes_after_ret;
1797 if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0,
1798 sizeof(WSavedState),
1799 True, _XA_WINDOWMAKER_STATE,
1800 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
1801 (unsigned char **)state)!=Success)
1802 return 0;
1803 if (type_ret==_XA_WINDOWMAKER_STATE)
1804 return 1;
1805 else
1806 return 0;
1810 #ifdef SHAPE
1811 void wWindowSetShape(WWindow *wwin)
1813 XRectangle rect[2];
1814 int count=0;
1816 XShapeCombineShape(dpy, wwin->frame->core->window, ShapeBounding,
1817 0, wwin->frame->top_width, wwin->client_win,
1818 ShapeBounding, ShapeSet);
1819 if (!wwin->window_flags.no_titlebar) {
1820 rect[count].x = -1;
1821 rect[count].y = -1;
1822 rect[count].width = wwin->frame->core->width+2;
1823 rect[count].height = wwin->frame->top_width+1;
1824 count++;
1826 if (!wwin->window_flags.no_resizebar) {
1827 rect[count].x = -1;
1828 rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width;
1829 rect[count].width = wwin->frame->core->width+2;
1830 rect[count].height = wwin->frame->bottom_width+1;
1831 count++;
1833 XShapeCombineRectangles(dpy,wwin->frame->core->window,ShapeBounding,
1834 0,0,rect,count,ShapeUnion,Unsorted);
1836 #endif
1838 /* ====================================================================== */
1840 static FocusMode
1841 getFocusMode(WWindow *wwin)
1843 FocusMode mode;
1845 if ((wwin->wm_hints) && (wwin->wm_hints->flags & InputHint)) {
1846 if (wwin->wm_hints->input == True) {
1847 if (wwin->protocols.TAKE_FOCUS)
1848 mode = WFM_LOCALLY_ACTIVE;
1849 else
1850 mode = WFM_PASSIVE;
1851 } else {
1852 if (wwin->protocols.TAKE_FOCUS)
1853 mode = WFM_GLOBALLY_ACTIVE;
1854 else
1855 mode = WFM_NO_INPUT;
1857 } else {
1858 mode = WFM_PASSIVE;
1860 return mode;
1864 void
1865 wWindowSetKeyGrabs(WWindow *wwin)
1867 int i;
1868 WShortKey *key;
1870 for (i=0; i<WKBD_LAST; i++) {
1871 key = &wKeyBindings[i];
1873 if (key->keycode==0)
1874 continue;
1875 if (key->modifier!=AnyModifier) {
1876 XGrabKey(dpy, key->keycode, key->modifier|LockMask,
1877 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
1878 #ifdef NUMLOCK_HACK
1879 /* Also grab all modifier combinations possible that include,
1880 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
1881 * work even if the NumLock/ScrollLock key is on.
1883 wHackedGrabKey(key->keycode, key->modifier,
1884 wwin->frame->core->window, True, GrabModeAsync,
1885 GrabModeAsync);
1886 #endif
1888 XGrabKey(dpy, key->keycode, key->modifier,
1889 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
1892 wRootMenuBindShortcuts(wwin->frame->core->window);
1897 void
1898 wWindowResetMouseGrabs(WWindow *wwin)
1900 XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
1902 if (!wwin->window_flags.no_bind_mouse) {
1903 /* grabs for Meta+drag */
1904 XGrabButton(dpy, AnyButton, MOD_MASK,
1905 wwin->client_win, True, ButtonPressMask, GrabModeSync,
1906 GrabModeAsync, None, wCursor[WCUR_ARROW]);
1907 XGrabButton(dpy, AnyButton, MOD_MASK|LockMask,
1908 wwin->client_win, True, ButtonPressMask, GrabModeSync,
1909 GrabModeAsync, None, wCursor[WCUR_ARROW]);
1910 #ifdef NUMLOCK_HACK
1911 wHackedGrabButton(AnyButton, MOD_MASK, wwin->client_win,
1912 True, ButtonPressMask, GrabModeSync,
1913 GrabModeAsync, None, wCursor[WCUR_ARROW]);
1914 #endif
1917 if (!wwin->flags.focused) {
1918 /* the passive grabs to focus the window */
1919 if (wPreferences.focus_mode == WKF_CLICK)
1920 XGrabButton(dpy, AnyButton, AnyModifier, wwin->client_win,
1921 True, ButtonPressMask, GrabModeSync, GrabModeAsync,
1922 None, None);
1924 XFlush(dpy);
1928 void
1929 wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr)
1932 if (attr->flags & GSExtraFlagsAttr) {
1933 if (wwin->window_flags.broken_close !=
1934 (attr->extra_flags & GSDocumentEditedFlag)) {
1935 wwin->window_flags.broken_close = !wwin->window_flags.broken_close;
1937 wWindowUpdateButtonImages(wwin);
1946 /* ====================================================================== */
1948 static void
1949 resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
1951 WWindow *wwin = data;
1953 #ifndef NUMLOCK_HACK
1954 if ((event->xbutton.state & ValidModMask)
1955 != (event->xbutton.state & ~LockMask)) {
1956 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
1957 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
1959 #endif
1961 event->xbutton.state &= ValidModMask;
1963 CloseWindowMenu(wwin->screen_ptr);
1965 if (wPreferences.focus_mode==WKF_CLICK
1966 && !(event->xbutton.state&ControlMask)) {
1967 wSetFocusTo(wwin->screen_ptr, wwin);
1970 if (event->xbutton.button == Button1)
1971 wRaiseFrame(wwin->frame->core);
1973 if (event->xbutton.state & MOD_MASK) {
1974 /* move the window */
1975 if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
1976 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
1977 GrabModeAsync, GrabModeAsync, None,
1978 None, CurrentTime)!=GrabSuccess) {
1979 #ifdef DEBUG0
1980 wwarning("pointer grab failed for window move");
1981 #endif
1982 return;
1984 wMouseMoveWindow(wwin, event);
1985 XUngrabPointer(dpy, CurrentTime);
1986 } else {
1987 /* resize the window */
1988 if (XGrabPointer(dpy, wwin->frame->resizebar->window, False,
1989 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
1990 GrabModeAsync, GrabModeAsync, None,
1991 None, CurrentTime)!=GrabSuccess) {
1992 #ifdef DEBUG0
1993 wwarning("pointer grab failed for window resize");
1994 #endif
1995 return;
1997 wMouseResizeWindow(wwin, event);
1998 XUngrabPointer(dpy, CurrentTime);
2004 static void
2005 titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event)
2007 WWindow *wwin = data;
2009 event->xbutton.state &= ValidModMask;
2011 if (event->xbutton.button==Button1) {
2012 if (event->xbutton.state == 0) {
2013 if (!wwin->window_flags.no_shadeable) {
2014 /* shade window */
2015 if (wwin->flags.shaded)
2016 wUnshadeWindow(wwin);
2017 else
2018 wShadeWindow(wwin);
2020 } else {
2021 int dir = 0;
2023 if (event->xbutton.state & ControlMask)
2024 dir |= MAX_VERTICAL;
2026 if (event->xbutton.state & ShiftMask) {
2027 dir |= MAX_HORIZONTAL;
2028 if (!(event->xbutton.state & ControlMask))
2029 wSelectWindow(wwin);
2032 /* maximize window */
2033 if (dir !=0 && !wwin->window_flags.no_resizable) {
2034 if (wwin->flags.maximized)
2035 wUnmaximizeWindow(wwin);
2036 else
2037 wMaximizeWindow(wwin, dir);
2040 } else if (event->xbutton.button==Button3) {
2041 if (event->xbutton.state & MOD_MASK) {
2042 wHideOtherApplications(wwin);
2044 } else if (event->xbutton.button==Button2) {
2045 wSelectWindow(wwin);
2050 static void
2051 frameMouseDown(WObjDescriptor *desc, XEvent *event)
2053 WWindow *wwin = desc->parent;
2055 event->xbutton.state &= ValidModMask;
2057 CloseWindowMenu(wwin->screen_ptr);
2059 if (wPreferences.focus_mode==WKF_CLICK
2060 && !(event->xbutton.state&ControlMask)) {
2061 wSetFocusTo(wwin->screen_ptr, wwin);
2063 if (event->xbutton.button == Button1) {
2064 wRaiseFrame(wwin->frame->core);
2067 if (event->xbutton.state & MOD_MASK) {
2068 /* move the window */
2069 if (XGrabPointer(dpy, wwin->client_win, False,
2070 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2071 GrabModeAsync, GrabModeAsync, None,
2072 None, CurrentTime)!=GrabSuccess) {
2073 #ifdef DEBUG0
2074 wwarning("pointer grab failed for window move");
2075 #endif
2076 return;
2078 if (event->xbutton.button == Button3 && !wwin->window_flags.no_resizable)
2079 wMouseResizeWindow(wwin, event);
2080 else
2081 wMouseMoveWindow(wwin, event);
2082 XUngrabPointer(dpy, CurrentTime);
2087 static void
2088 titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
2090 WWindow *wwin = (WWindow*)data;
2092 #ifndef NUMLOCK_HACK
2093 if ((event->xbutton.state & ValidModMask)
2094 != (event->xbutton.state & ~LockMask)) {
2095 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2096 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2098 #endif
2100 event->xbutton.state &= ValidModMask;
2103 CloseWindowMenu(wwin->screen_ptr);
2105 if (wPreferences.focus_mode==WKF_CLICK
2106 && !(event->xbutton.state&ControlMask)) {
2107 wSetFocusTo(wwin->screen_ptr, wwin);
2110 if (event->xbutton.button == Button1
2111 || event->xbutton.button == Button2) {
2113 if (event->xbutton.button == Button1) {
2114 if (event->xbutton.state & MOD_MASK) {
2115 wLowerFrame(wwin->frame->core);
2116 } else {
2117 wRaiseFrame(wwin->frame->core);
2120 if ((event->xbutton.state & ShiftMask)
2121 && !(event->xbutton.state & ControlMask)) {
2122 wSelectWindow(wwin);
2123 return;
2125 if (XGrabPointer(dpy, wwin->frame->titlebar->window, False,
2126 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2127 GrabModeAsync, GrabModeAsync, None,
2128 None, CurrentTime)!=GrabSuccess) {
2129 #ifdef DEBUG0
2130 wwarning("pointer grab failed for window move");
2131 #endif
2132 return;
2134 /* move the window */
2135 wMouseMoveWindow(wwin, event);
2136 XUngrabPointer(dpy, CurrentTime);
2137 } else if (event->xbutton.button == Button3 && event->xbutton.state==0
2138 && !wwin->flags.internal_window) {
2139 WObjDescriptor *desc;
2141 OpenWindowMenu(wwin, event->xbutton.x_root,
2142 wwin->frame_y+wwin->frame->top_width, False);
2144 /* allow drag select */
2145 desc = &wwin->screen_ptr->window_menu->menu->descriptor;
2146 event->xany.send_event = True;
2147 (*desc->handle_mousedown)(desc, event);
2153 static void
2154 windowCloseClick(WCoreWindow *sender, void *data, XEvent *event)
2156 WWindow *wwin = data;
2158 event->xbutton.state &= ValidModMask;
2160 CloseWindowMenu(wwin->screen_ptr);
2162 /* if control-click, kill the client */
2163 if (event->xbutton.state & ControlMask) {
2164 wClientKill(wwin);
2165 } else if (wwin->protocols.DELETE_WINDOW && event->xbutton.state==0) {
2166 /* send delete message */
2167 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2172 static void
2173 windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
2175 WWindow *wwin = data;
2177 CloseWindowMenu(wwin->screen_ptr);
2179 /* send delete message */
2180 if (wwin->protocols.DELETE_WINDOW) {
2181 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2182 } else {
2183 wClientKill(wwin);
2188 static void
2189 windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event)
2191 WWindow *wwin = data;
2193 event->xbutton.state &= ValidModMask;
2195 CloseWindowMenu(wwin->screen_ptr);
2197 if (wwin->protocols.MINIATURIZE_WINDOW && event->xbutton.state==0) {
2198 wClientSendProtocol(wwin, _XA_WINDOWMAKER_WM_MINIATURIZE_WINDOW,
2199 LastTimestamp);
2200 } else {
2201 WApplication *wapp;
2202 if ((event->xbutton.state & ControlMask) ||
2203 (event->xbutton.button == Button3)) {
2205 wapp = wApplicationOf(wwin->main_window);
2206 if (wapp && !wwin->window_flags.no_appicon)
2207 wHideApplication(wapp);
2208 } else if (event->xbutton.state==0) {
2209 wIconifyWindow(wwin);