Updating to version 0.20.2
[wmaker-crm.git] / src / window.c
blob4d61610c7229b48e1717b4a2081ad480a5490a4b
1 /* window.c - client window managing class
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #ifdef SHAPE
28 #include <X11/extensions/shape.h>
29 #endif
30 #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 #ifdef SHAPE
59 extern Bool wShapeSupported;
60 #endif
62 /* contexts */
63 extern XContext wWinContext;
65 /* cursors */
66 extern Cursor wCursor[WCUR_LAST];
68 /* protocol atoms */
69 extern Atom _XA_WM_DELETE_WINDOW;
70 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
72 extern Atom _XA_WINDOWMAKER_STATE;
74 extern WPreferences wPreferences;
76 #define MOD_MASK wPreferences.modifier_mask
78 extern Time LastTimestamp;
80 /* superfluous... */
81 extern void DoWindowBirth(WWindow*);
84 /***** Local Stuff *****/
87 static WWindowState *windowState=NULL;
91 /* local functions */
92 static FocusMode getFocusMode(WWindow *wwin);
94 static int getSavedState(Window window, WSavedState **state);
96 static void setupGNUstepHints(WWindowAttributes *attribs,
97 GNUstepWMAttributes *gs_hints);
99 #ifdef MWM_HINTS
100 static void setupMWMHints(WWindowAttributes *attribs, MWMHints *mwm_hints);
101 #endif
103 /* event handlers */
106 /* frame window (during window grabs) */
107 static void frameMouseDown(WObjDescriptor *desc, XEvent *event);
109 /* close button */
110 static void windowCloseClick(WCoreWindow *sender, void *data, XEvent *event);
111 static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event);
113 /* iconify button */
114 static void windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event);
117 static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
118 static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event);
120 static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
127 WWindow*
128 wWindowFor(Window window)
130 WObjDescriptor *desc;
132 if (window==None)
133 return NULL;
135 if (XFindContext(dpy, window, wWinContext, (XPointer*)&desc)==XCNOENT)
136 return NULL;
138 if (desc->parent_type==WCLASS_WINDOW)
139 return desc->parent;
140 else if (desc->parent_type==WCLASS_FRAME) {
141 WFrameWindow *frame = (WFrameWindow*)desc->parent;
142 if (frame->flags.is_client_window_frame)
143 return frame->child;
145 return NULL;
149 WWindow *
150 wWindowCreate()
152 WWindow *wwin;
154 wwin = wmalloc(sizeof(WWindow));
155 wretain(wwin);
157 memset(wwin, 0, sizeof(WWindow));
159 wwin->client_descriptor.handle_mousedown = frameMouseDown;
160 wwin->client_descriptor.parent = wwin;
161 wwin->client_descriptor.self = wwin;
162 wwin->client_descriptor.parent_type = WCLASS_WINDOW;
163 return wwin;
167 void
168 wWindowDestroy(WWindow *wwin)
170 wwin->flags.destroyed = 1;
172 if (wwin->normal_hints)
173 free(wwin->normal_hints);
175 if (wwin->wm_hints)
176 XFree(wwin->wm_hints);
178 if (wwin->wm_instance)
179 XFree(wwin->wm_instance);
181 if (wwin->wm_class)
182 XFree(wwin->wm_class);
184 if (wwin->wm_gnustep_attr)
185 free(wwin->wm_gnustep_attr);
187 if (wwin->cmap_windows)
188 XFree(wwin->cmap_windows);
190 XDeleteContext(dpy, wwin->client_win, wWinContext);
192 if (wwin->frame)
193 wFrameWindowDestroy(wwin->frame);
195 if (wwin->icon) {
196 RemoveFromStackList(wwin->icon->core);
197 wIconDestroy(wwin->icon);
198 if (wPreferences.auto_arrange_icons)
199 wArrangeIcons(wwin->screen_ptr, True);
201 wrelease(wwin);
207 static void
208 setupGNUstepHints(WWindowAttributes *attribs, GNUstepWMAttributes *gs_hints)
210 if (gs_hints->flags & GSWindowStyleAttr) {
211 attribs->no_titlebar =
212 ((gs_hints->window_style & WMTitledWindowMask)?0:1);
214 attribs->no_close_button = attribs->no_closable =
215 ((gs_hints->window_style & WMClosableWindowMask)?0:1);
217 attribs->no_miniaturize_button = attribs->no_miniaturizable =
218 ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1);
220 attribs->no_resizebar = attribs->no_resizable =
221 ((gs_hints->window_style & WMResizableWindowMask)?0:1);
222 } else {
223 /* setup the defaults */
224 attribs->no_titlebar = 0;
225 attribs->no_closable = 0;
226 attribs->no_miniaturizable = 0;
227 attribs->no_resizable = 0;
228 attribs->no_close_button = 0;
229 attribs->no_miniaturize_button = 0;
230 attribs->no_resizebar = 0;
233 if (gs_hints->extra_flags & GSNoApplicationIconFlag) {
234 attribs->no_appicon = 1;
239 #ifdef MWM_HINTS
240 static void
241 setupMWMHints(WWindowAttributes *attribs, MWMHints *mwm_hints)
245 * We will ignore all decoration hints that have an equivalent as
246 * functions, because wmaker does not distinguish decoration hints
249 if (mwm_hints->flags & MWM_HINTS_DECORATIONS) {
250 # ifdef DEBUG
251 fprintf(stderr,"has decor hints [ ");
252 # endif
253 attribs->no_titlebar = 1;
254 attribs->no_close_button = 1;
255 attribs->no_miniaturize_button = 1;
256 attribs->no_resizebar = 1;
258 if (mwm_hints->decorations & MWM_DECOR_ALL) {
259 # ifdef DEBUG
260 fprintf(stderr,"ALL ");
261 # endif
262 attribs->no_titlebar = 0;
263 attribs->no_close_button = 0;
264 attribs->no_closable = 0;
265 attribs->no_miniaturize_button = 0;
266 attribs->no_miniaturizable = 0;
267 attribs->no_resizebar = 0;
268 attribs->no_resizable = 0;
271 if (mwm_hints->decorations & MWM_DECOR_BORDER) {
272 # ifdef DEBUG
273 fprintf(stderr,"(BORDER) ");
274 # endif
278 if (mwm_hints->decorations & MWM_DECOR_RESIZEH) {
279 # ifdef DEBUG
280 fprintf(stderr,"RESIZEH ");
281 # endif
282 attribs->no_resizebar = 0;
285 if (mwm_hints->decorations & MWM_DECOR_TITLE) {
286 # ifdef DEBUG
287 fprintf(stderr,"TITLE+close ");
288 # endif
289 attribs->no_titlebar = 0;
290 attribs->no_close_button = 0;
291 attribs->no_closable = 0;
294 if (mwm_hints->decorations & MWM_DECOR_MENU) {
295 # ifdef DEBUG
296 fprintf(stderr,"(MENU) ");
297 # endif
301 if (mwm_hints->decorations & MWM_DECOR_MINIMIZE) {
302 # ifdef DEBUG
303 fprintf(stderr,"MINIMIZE ");
304 # endif
305 attribs->no_miniaturize_button = 0;
306 attribs->no_miniaturizable = 0;
309 if (mwm_hints->decorations & MWM_DECOR_MAXIMIZE) {
310 # ifdef DEBUG
311 fprintf(stderr,"(MAXIMIZE) ");
312 # endif
315 # ifdef DEBUG
316 fprintf(stderr,"]\n");
317 # endif
321 if (mwm_hints->flags & MWM_HINTS_FUNCTIONS) {
322 # ifdef DEBUG
323 fprintf(stderr,"has function hints [ ");
324 # endif
325 attribs->no_closable = 1;
326 attribs->no_miniaturizable = 1;
327 attribs->no_resizable = 1;
329 if (mwm_hints->functions & MWM_FUNC_ALL) {
330 # ifdef DEBUG
331 fprintf(stderr,"ALL ");
332 # endif
333 attribs->no_closable = 0;
334 attribs->no_miniaturizable = 0;
335 attribs->no_resizable = 0;
337 if (mwm_hints->functions & MWM_FUNC_RESIZE) {
338 # ifdef DEBUG
339 fprintf(stderr,"RESIZE ");
340 # endif
341 attribs->no_resizable = 0;
344 if (mwm_hints->functions & MWM_FUNC_MOVE) {
345 # ifdef DEBUG
346 fprintf(stderr,"(MOVE) ");
347 # endif
350 if (mwm_hints->functions & MWM_FUNC_MINIMIZE) {
351 # ifdef DEBUG
352 fprintf(stderr,"MINIMIZE ");
353 # endif
354 attribs->no_miniaturizable = 0;
356 if (mwm_hints->functions & MWM_FUNC_MAXIMIZE) {
357 # ifdef DEBUG
358 fprintf(stderr,"MAXIMIZE ");
359 /* a window must be resizable to be maximizable */
360 attribs->no_resizable = 0;
361 # endif
363 if (mwm_hints->functions & MWM_FUNC_CLOSE) {
364 # ifdef DEBUG
365 fprintf(stderr,"CLOSE ");
366 # endif
367 attribs->no_closable = 0;
369 # ifdef DEBUG
370 fprintf(stderr,"]\n");
371 # endif
374 #endif /* MWM_HINTS */
377 void
378 wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags)
380 if (wflags->no_appicon)
381 wflags->emulate_appicon = 0;
383 if (wwin->main_window!=None) {
384 WApplication *wapp = wApplicationOf(wwin->main_window);
385 if (wapp && !wapp->flags.emulated)
386 wflags->emulate_appicon = 0;
389 if (wwin->transient_for!=None
390 && wwin->transient_for!=wwin->screen_ptr->root_win)
391 wflags->emulate_appicon = 0;
396 Bool
397 wWindowCanReceiveFocus(WWindow *wwin)
399 if (!wwin->flags.mapped && !wwin->flags.shaded)
400 return False;
401 if (wwin->window_flags.no_focusable || wwin->flags.miniaturized)
402 return False;
403 if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
404 return False;
406 return True;
411 *----------------------------------------------------------------
412 * wManageWindow--
413 * reparents the window and allocates a descriptor for it.
414 * Window manager hints and other hints are fetched to configure
415 * the window decoration attributes and others. User preferences
416 * for the window are used if available, to configure window
417 * decorations and some behaviour.
419 * Returns:
420 * the new window descriptor
422 * Side effects:
423 * The window is reparented and appropriate notification
424 * is done to the client. Input mask for the window is setup.
425 * The window descriptor is also associated with various window
426 * contexts and inserted in the head of the window list.
427 * Event handler contexts are associated for some objects
428 * (buttons, titlebar and resizebar)
430 * TODO:
431 * Check if the window_flags setting is correct.
432 *----------------------------------------------------------------
434 WWindow*
435 wManageWindow(WScreen *scr, Window window)
437 WWindow *wwin;
438 int x, y;
439 unsigned width, height;
440 XWindowAttributes wattribs;
441 XSetWindowAttributes attribs;
442 int iconic = 0;
443 WWindowState *win_state;
444 #ifdef MWM_HINTS
445 MWMHints *motif_hints = NULL;
446 #endif
447 int window_level;
448 int foo;
449 int workspace = -1;
450 char *title;
452 /* mutex. */
453 XGrabServer(dpy);
454 XSync(dpy, 0);
455 /* make sure the window is still there */
456 if (!XGetWindowAttributes(dpy, window, &wattribs)) {
457 XUngrabServer(dpy);
458 return NULL;
460 wwin = wWindowCreate();
462 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
464 #ifdef DEBUG
465 printf("managing window %x\n", (unsigned)window);
466 #endif
468 #ifdef SHAPE
469 if (wShapeSupported) {
470 int junk;
471 unsigned int ujunk;
472 int b_shaped;
474 XShapeSelectInput(dpy, window, ShapeNotifyMask);
475 XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk,
476 &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
477 wwin->flags.shaped = b_shaped;
479 #endif
482 *--------------------------------------------------
484 * Get hints and other information in properties
486 *--------------------------------------------------
488 wwin->wm_hints = XGetWMHints(dpy, window);
489 PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
491 /* setup descriptor */
492 wwin->client_win = window;
493 wwin->screen_ptr = scr;
495 wwin->old_border_width = wattribs.border_width;
497 attribs.event_mask = CLIENT_EVENTS;
498 attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
499 attribs.save_under = False;
500 XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate
501 |CWSaveUnder, &attribs);
502 XSetWindowBorderWidth(dpy, window, 0);
504 /* fill in property/hint data */
505 if (!wFetchName(dpy, window, &title)) {
506 title = NULL;
508 /* get hints from GNUstep app */
509 if (!PropGetGNUstepWMAttr(window, &wwin->wm_gnustep_attr)) {
510 wwin->wm_gnustep_attr=NULL;
513 #ifdef MWM_HINTS
514 if (!PropGetMotifWMHints(window, &motif_hints))
515 motif_hints = NULL;
516 #endif /* MWM_HINTS */
518 if (!PropGetClientLeader(window, &wwin->client_leader)) {
519 wwin->client_leader = None;
520 } else {
521 wwin->main_window = wwin->client_leader;
524 if (wwin->wm_hints)
525 XFree(wwin->wm_hints);
527 wwin->wm_hints = XGetWMHints(dpy, window);
529 if (wwin->wm_hints) {
530 if ((wwin->wm_hints->flags&StateHint)
531 && (wwin->wm_hints->initial_state == IconicState)) {
532 iconic = 1;
533 /* don't do iconify animation */
534 wwin->flags.skip_next_animation = 1;
537 if (wwin->wm_hints->flags & WindowGroupHint) {
538 wwin->group_id = wwin->wm_hints->window_group;
539 /* window_group has priority over CLIENT_LEADER */
540 wwin->main_window = wwin->group_id;
541 } else {
542 wwin->group_id = None;
545 if (wwin->wm_hints->flags & UrgencyHint)
546 wwin->flags.urgent = 1;
547 } else {
548 wwin->group_id = None;
551 PropGetProtocols(window, &wwin->protocols);
553 if (!XGetTransientForHint(dpy, window, &wwin->transient_for)) {
554 wwin->transient_for = None;
555 } else {
556 if (wwin->transient_for==None || wwin->transient_for==window) {
557 wwin->transient_for = scr->root_win;
558 } else {
559 WWindow *owner;
560 owner = wWindowFor(wwin->transient_for);
561 if (owner && owner->main_window!=None) {
562 wwin->main_window = owner->main_window;
563 } /*else {
564 wwin->main_window = None;
567 /* don't let transients start miniaturized if their owners
568 * are not */
569 if (owner && !owner->flags.miniaturized && iconic) {
570 iconic = 0;
571 if (wwin->wm_hints)
572 wwin->wm_hints->initial_state = NormalState;
577 /* guess the focus mode */
578 wwin->focus_mode = getFocusMode(wwin);
580 /* get geometry stuff */
581 wClientGetNormalHints(wwin, &wattribs, True, &x, &y, &width, &height);
583 /* get colormap windows */
584 GetColormapWindows(wwin);
588 *--------------------------------------------------
590 * Setup the decoration/window attributes and
591 * geometry
593 *--------------------------------------------------
595 /* sets global default stuff */
596 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
597 &wwin->window_flags, True);
599 * Decoration setting is done in this precedence (lower to higher)
600 * - use default in the resource database
601 * - guess some settings
602 * - use GNUstep/external window attributes
603 * - set hints specified for the app in the resource DB
605 wwin->window_flags.broken_close = 0;
607 if (wwin->protocols.DELETE_WINDOW)
608 wwin->window_flags.kill_close = 0;
609 else
610 wwin->window_flags.kill_close = 1;
612 /* transients can't be iconified or maximized */
613 if (wwin->transient_for) {
614 wwin->window_flags.no_miniaturizable = 1;
615 wwin->window_flags.no_miniaturize_button = 1;
616 #ifdef DEBUG
617 printf("%x is transient for %x\n", (unsigned)window,
618 (unsigned)wwin->transient_for);
619 #endif
622 /* if the window can't be resized, remove the resizebar */
623 if (wwin->normal_hints->flags & (PMinSize|PMaxSize)
624 && (wwin->normal_hints->min_width==wwin->normal_hints->max_width)
625 && (wwin->normal_hints->min_height==wwin->normal_hints->max_height)) {
626 wwin->window_flags.no_resizable = 1;
627 wwin->window_flags.no_resizebar = 1;
630 /* set GNUstep window attributes */
631 if (wwin->wm_gnustep_attr) {
632 setupGNUstepHints(&wwin->window_flags, wwin->wm_gnustep_attr);
633 if (wwin->wm_gnustep_attr->flags & GSWindowLevelAttr) {
634 window_level = wwin->wm_gnustep_attr->window_level;
635 } else {
636 /* setup defaults */
637 window_level = WMNormalWindowLevel;
639 } else {
640 #ifdef MWM_HINTS
641 if (motif_hints) {
642 setupMWMHints(&wwin->window_flags, motif_hints);
644 #endif /* MWM_HINTS */
645 if (wwin->window_flags.floating)
646 window_level = WMFloatingWindowLevel;
647 else
648 window_level = WMNormalWindowLevel;
650 #ifdef MWM_HINTS
651 if (motif_hints)
652 free(motif_hints);
653 #endif
656 * Set attributes specified only for that window/class.
657 * This might do duplicate work with the 1st wDefaultFillAttributes().
658 * TODO: Do something about that.
660 wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
661 &wwin->window_flags, False);
665 * Sanity checks for attributes that depend on other attributes
667 wWindowCheckAttributeSanity(wwin, &wwin->window_flags);
669 wwin->window_flags.no_shadeable = wwin->window_flags.no_titlebar;
672 * Make broken apps behave as a nice app.
674 if (wwin->window_flags.emulate_appicon) {
675 wwin->main_window = wwin->client_win;
679 *------------------------------------------------------------
681 * Setup the initial state of the window
683 *------------------------------------------------------------
685 if (wwin->window_flags.start_miniaturized
686 && !wwin->window_flags.no_miniaturizable) {
687 wwin->flags.miniaturized = 1;
688 iconic = 1;
691 /* if there is a saved state, restore it */
692 win_state = NULL;
693 if (wwin->main_window!=None/* && wwin->main_window!=window*/) {
694 win_state = (WWindowState*)wWindowGetSavedState(wwin->main_window);
695 } else {
696 win_state = (WWindowState*)wWindowGetSavedState(window);
698 if (win_state && !(wwin->wm_hints && wwin->wm_hints->flags&StateHint &&
699 wwin->wm_hints->initial_state==WithdrawnState)) {
700 if (win_state->state->hidden>0)
701 wwin->flags.hidden = win_state->state->hidden;
702 if (win_state->state->shaded>0 && !wwin->window_flags.no_shadeable)
703 wwin->flags.shaded = win_state->state->shaded;
704 if (win_state->state->miniaturized>0 &&
705 !wwin->window_flags.no_miniaturizable) {
706 wwin->flags.miniaturized = win_state->state->miniaturized;
707 iconic = 1;
709 if (!wwin->window_flags.omnipresent) {
710 int w = wDefaultGetStartWorkspace(scr, wwin->wm_instance,
711 wwin->wm_class);
712 if (w < 0 || w >= scr->workspace_count) {
713 workspace = win_state->state->workspace;
714 if (workspace>=scr->workspace_count)
715 workspace = scr->current_workspace;
716 } else {
717 workspace = w;
719 } else {
720 workspace = scr->current_workspace;
724 /* if we're restarting, restore saved state. This will overwrite previous */
726 WSavedState *wstate;
728 if (getSavedState(window, &wstate)) {
729 wwin->flags.shaded = wstate->shaded;
730 wwin->flags.hidden = wstate->hidden;
731 wwin->flags.miniaturized = 0;
732 workspace = wstate->workspace;
733 free(wstate);
738 /* set workspace on which the window starts */
739 if (workspace >= 0) {
740 if (workspace > scr->workspace_count-1) {
741 wWorkspaceMake(scr, workspace - scr->workspace_count + 1);
742 workspace = scr->workspace_count - 1;
744 } else {
745 int w;
747 w = wDefaultGetStartWorkspace(scr, wwin->wm_instance, wwin->wm_class);
748 if (w>=0 && w<scr->workspace_count && !wwin->window_flags.omnipresent) {
749 workspace = w;
750 } else {
751 workspace = scr->current_workspace;
755 /* setup window geometry */
756 if (win_state && win_state->state->use_geometry) {
757 width = win_state->state->w;
758 height = win_state->state->h;
760 wWindowConstrainSize(wwin, &width, &height);
762 /* do not ask for window placement if the window is
763 * transient, during startup, if the initial workspace is another one
764 * or if the window wants to
765 * start iconic.
766 * If geometry was saved, restore it. */
767 if (win_state && win_state->state->use_geometry) {
768 x = win_state->state->x;
769 y = win_state->state->y;
770 } else if (wwin->transient_for==None && !scr->flags.startup &&
771 workspace==scr->current_workspace && !iconic &&
772 !(wwin->normal_hints->flags & (USPosition|PPosition))) {
773 PlaceWindow(wwin, &x, &y);
776 if (wwin->window_flags.dont_move_off)
777 wScreenBringInside(scr, &x, &y, width, height);
780 *--------------------------------------------------
782 * Create frame, borders and do reparenting
784 *--------------------------------------------------
787 foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
788 if (!wwin->window_flags.no_titlebar)
789 foo |= WFF_TITLEBAR;
790 if (!wwin->window_flags.no_resizebar)
791 foo |= WFF_RESIZEBAR;
793 wwin->frame = wFrameWindowCreate(scr, window_level,
794 x, y, width, height, foo,
795 scr->window_title_texture,
796 (WTexture**)scr->resizebar_texture,
797 scr->window_title_pixel,
798 &scr->window_title_gc,
799 &scr->title_font);
801 wwin->frame->flags.is_client_window_frame = 1;
802 wwin->frame->flags.justification = wPreferences.title_justification;
804 /* setup button images */
805 wWindowUpdateButtonImages(wwin);
807 /* hide unused buttons */
808 foo = 0;
809 if (wwin->window_flags.no_close_button)
810 foo |= WFF_RIGHT_BUTTON;
811 if (wwin->window_flags.no_miniaturize_button)
812 foo |= WFF_LEFT_BUTTON;
813 if (foo!=0)
814 wFrameWindowHideButton(wwin->frame, foo);
817 wwin->frame->child = wwin;
819 wFrameWindowChangeTitle(wwin->frame, title ? title : DEF_WINDOW_TITLE);
820 if (title)
821 XFree(title);
823 wwin->frame->workspace = workspace;
825 wwin->frame->on_click_left = windowIconifyClick;
827 wwin->frame->on_click_right = windowCloseClick;
828 wwin->frame->on_dblclick_right = windowCloseDblClick;
830 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
831 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
833 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
835 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
836 0, wwin->frame->top_width);
839 int gx, gy;
841 wClientGetGravityOffsets(wwin, &gx, &gy);
842 /* set the positio of the frame on screen */
843 x += gx * FRAME_BORDER_WIDTH;
844 y += gy * FRAME_BORDER_WIDTH;
845 /* if gravity is to the south, account for the border sizes */
846 if (gy > 0)
847 y -= wwin->frame->top_width + wwin->frame->bottom_width;
851 * wWindowConfigure() will init the client window's size
852 * (wwin->client.{width,height}) and all other geometry
853 * related variables (frame_x,frame_y)
855 wWindowConfigure(wwin, x, y, width, height);
858 *--------------------------------------------------
860 * Setup descriptors and save window to internal
861 * lists
863 *--------------------------------------------------
866 if (wwin->main_window!=None) {
867 WApplication *app;
868 WWindow *leader;
870 /* Leader windows do not necessary set themselves as leaders.
871 * If this is the case, point the leader of this window to
872 * itself */
873 leader = wWindowFor(wwin->main_window);
874 if (leader && leader->main_window==None) {
875 leader->main_window = leader->client_win;
878 app = wApplicationCreate(scr, wwin->main_window);
879 if (app) {
880 app->last_workspace = workspace;
883 * Do application specific stuff, like setting application
884 * wide attributes.
887 if (wwin->flags.hidden) {
888 /* if the window was set to hidden because it was hidden
889 * in a previous incarnation and that state was restored */
890 app->flags.hidden = 1;
893 if (app->flags.hidden) {
894 wwin->flags.hidden = 1;
899 /* setup the frame descriptor */
900 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
901 wwin->frame->core->descriptor.parent = wwin;
902 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
904 /* don't let windows go away if we die */
905 XAddToSaveSet(dpy, window);
907 XLowerWindow(dpy, window);
909 /* if window is in this workspace and should be mapped, then map it */
910 if (!iconic && (workspace == scr->current_workspace
911 || wwin->window_flags.omnipresent)
912 && !wwin->flags.hidden
913 && !(wwin->wm_hints && (wwin->wm_hints->flags & StateHint)
914 && wwin->wm_hints->initial_state == WithdrawnState)) {
915 /* The following "if" is to avoid crashing of clients that expect
916 * WM_STATE set before they get mapped. Else WM_STATE is set later,
917 * after the return from this function.
919 if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint)) {
920 wClientSetState(wwin, wwin->wm_hints->initial_state, None);
921 } else {
922 wClientSetState(wwin, NormalState, None);
924 if (wPreferences.superfluous && !wPreferences.no_animations
925 && !scr->flags.startup && wwin->transient_for==None
927 * The brain damaged idiotic non-click to focus modes will
928 * have trouble with this because:
930 * 1. window is created and mapped by the client
931 * 2. window is mapped by wmaker in small size
932 * 3. window is animated to grow to normal size
933 * 4. this function returns to normal event loop
934 * 5. eventually, the EnterNotify event that would trigger
935 * the window focusing (if the mouse is over that window)
936 * will be processed by wmaker.
937 * But since this event will be rather delayed
938 * (step 3 has a large delay) the time when the event ocurred
939 * and when it is processed, the client that owns that window
940 * will reject the XSetInputFocus() for it.
942 && (wPreferences.focus_mode==WKF_CLICK
943 || wPreferences.auto_focus)) {
944 DoWindowBirth(wwin);
946 XMapSubwindows(dpy, wwin->frame->core->window);
947 wWindowMap(wwin);
948 } else {
949 XMapSubwindows(dpy, wwin->frame->core->window);
952 /* setup stacking descriptor */
953 if (wPreferences.on_top_transients && wwin->transient_for!=None
954 && wwin->transient_for!=scr->root_win) {
955 WWindow *tmp;
956 tmp = wWindowFor(wwin->transient_for);
957 if (tmp)
958 wwin->frame->core->stacking->child_of = tmp->frame->core;
959 } else {
960 wwin->frame->core->stacking->child_of = NULL;
964 if (!scr->focused_window) {
965 /* first window on the list */
966 wwin->next = NULL;
967 wwin->prev = NULL;
968 scr->focused_window = wwin;
969 } else {
970 WWindow *tmp;
972 /* add window at beginning of focus window list */
973 tmp = scr->focused_window;
974 while (tmp->prev)
975 tmp = tmp->prev;
976 tmp->prev = wwin;
977 wwin->next = tmp;
978 wwin->prev = NULL;
982 XUngrabServer(dpy);
985 *--------------------------------------------------
987 * Final preparations before window is ready to go
989 *--------------------------------------------------
992 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
995 if (!iconic && workspace == scr->current_workspace) {
996 WWindow *tmp = wWindowFor(wwin->transient_for);
998 if ((tmp && tmp->flags.focused) || wPreferences.auto_focus)
999 wSetFocusTo(scr, wwin);
1000 } else {
1001 wwin->flags.ignore_next_unmap = 1;
1003 wWindowResetMouseGrabs(wwin);
1005 if (!wwin->window_flags.no_bind_keys) {
1006 wWindowSetKeyGrabs(wwin);
1010 * Prevent window withdrawal when getting the
1011 * unmap notifies generated during reparenting
1013 wwin->flags.mapped=0;
1015 XSync(dpy, 0);
1017 wColormapInstallForWindow(wwin->screen_ptr, scr->cmap_window);
1019 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1021 *--------------------------------------------------
1022 * Cleanup temporary stuff
1023 *--------------------------------------------------
1026 if (win_state)
1027 wWindowDeleteSavedState(win_state);
1029 return wwin;
1036 WWindow*
1037 wManageInternalWindow(WScreen *scr, Window window, Window owner,
1038 char *title, int x, int y, int width, int height)
1040 WWindow *wwin;
1041 int foo;
1043 wwin = wWindowCreate();
1045 wwin->flags.internal_window = 1;
1046 wwin->window_flags.omnipresent = 1;
1047 wwin->window_flags.no_shadeable = 1;
1048 wwin->window_flags.no_resizable = 1;
1050 wwin->focus_mode = WFM_PASSIVE;
1052 wwin->client_win = window;
1053 wwin->screen_ptr = scr;
1055 wwin->transient_for = owner;
1057 wwin->client.x = x;
1058 wwin->client.y = y;
1059 wwin->client.width = width;
1060 wwin->client.height = height;
1062 wwin->frame_x = wwin->client.x;
1063 wwin->frame_y = wwin->client.y;
1066 foo = WFF_RIGHT_BUTTON;
1067 foo |= WFF_TITLEBAR;
1069 wwin->frame = wFrameWindowCreate(scr, WMFloatingWindowLevel,
1070 wwin->frame_x, wwin->frame_y,
1071 width, height, foo,
1072 scr->window_title_texture,
1073 (WTexture**)scr->resizebar_texture,
1074 scr->window_title_pixel,
1075 &scr->window_title_gc,
1076 &scr->title_font);
1078 XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
1080 wwin->frame->flags.is_client_window_frame = 1;
1081 wwin->frame->flags.justification = wPreferences.title_justification;
1083 wFrameWindowChangeTitle(wwin->frame, title);
1085 /* setup button images */
1086 wWindowUpdateButtonImages(wwin);
1088 /* hide buttons */
1089 wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON);
1091 wwin->frame->child = wwin;
1093 wwin->frame->workspace = wwin->screen_ptr->current_workspace;
1095 wwin->frame->on_click_right = windowCloseClick;
1097 wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
1098 wwin->frame->on_dblclick_titlebar = titlebarDblClick;
1100 wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
1102 wwin->client.y += wwin->frame->top_width;
1103 XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
1104 0, wwin->frame->top_width);
1106 wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y,
1107 wwin->client.width, wwin->client.height);
1109 /* setup the frame descriptor */
1110 wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
1111 wwin->frame->core->descriptor.parent = wwin;
1112 wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
1115 XLowerWindow(dpy, window);
1116 XMapSubwindows(dpy, wwin->frame->core->window);
1118 /* setup stacking descriptor */
1119 if (wPreferences.on_top_transients && wwin->transient_for!=None
1120 && wwin->transient_for!=scr->root_win) {
1121 WWindow *tmp;
1122 tmp = wWindowFor(wwin->transient_for);
1123 if (tmp)
1124 wwin->frame->core->stacking->child_of = tmp->frame->core;
1125 } else {
1126 wwin->frame->core->stacking->child_of = NULL;
1130 if (!scr->focused_window) {
1131 /* first window on the list */
1132 wwin->next = NULL;
1133 wwin->prev = NULL;
1134 scr->focused_window = wwin;
1135 } else {
1136 WWindow *tmp;
1138 /* add window at beginning of focus window list */
1139 tmp = scr->focused_window;
1140 while (tmp->prev)
1141 tmp = tmp->prev;
1142 tmp->prev = wwin;
1143 wwin->next = tmp;
1144 wwin->prev = NULL;
1147 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
1149 /* if (wPreferences.auto_focus)*/
1150 wSetFocusTo(scr, wwin);
1152 wWindowResetMouseGrabs(wwin);
1154 wWindowSetKeyGrabs(wwin);
1156 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);
1158 return wwin;
1163 *----------------------------------------------------------------------
1164 * wUnmanageWindow--
1165 * Removes the frame window from a window and destroys all data
1166 * related to it. The window will be reparented back to the root window
1167 * if restore is True.
1169 * Side effects:
1170 * Everything related to the window is destroyed and the window
1171 * is removed from the window lists. Focus is set to the previous on the
1172 * window list.
1173 *----------------------------------------------------------------------
1175 void
1176 wUnmanageWindow(WWindow *wwin, int restore)
1178 WCoreWindow *frame = wwin->frame->core;
1179 WWindow *owner;
1180 WWindow *newFocusedWindow;
1181 int wasNotFocused;
1182 WScreen *scr = wwin->screen_ptr;
1184 /* First close attribute editor window if open */
1185 if (wwin->flags.inspector_open) {
1186 WWindow *pwin = wwin->inspector->frame; /* the inspector window */
1187 (*pwin->frame->on_click_right)(NULL, pwin, NULL);
1190 XUnmapWindow(dpy, frame->window);
1192 /* deselect window */
1193 if (wwin->flags.selected)
1194 wSelectWindow(wwin);
1196 /* remove all pending events on window */
1197 /* I think this only matters for autoraise */
1198 if (wPreferences.raise_delay)
1199 WMDeleteTimerWithClientData(wwin->frame->core);
1201 XFlush(dpy);
1203 UpdateSwitchMenu(scr, wwin, ACTION_REMOVE);
1205 /* reparent the window back to the root */
1206 if (restore)
1207 wClientRestore(wwin);
1209 if (wwin->transient_for!=scr->root_win) {
1210 owner = wWindowFor(wwin->transient_for);
1211 if (owner) {
1212 owner->flags.semi_focused = 0;
1213 wFrameWindowChangeState(owner->frame, WS_UNFOCUSED);
1217 wasNotFocused = !wwin->flags.focused;
1219 /* remove from window focus list */
1220 if (!wwin->prev && !wwin->next) {
1221 /* was the only window */
1222 scr->focused_window = NULL;
1223 newFocusedWindow = NULL;
1224 } else {
1225 WWindow *tmp;
1227 if (wwin->prev)
1228 wwin->prev->next = wwin->next;
1229 if (wwin->next)
1230 wwin->next->prev = wwin->prev;
1231 else {
1232 scr->focused_window = wwin->prev;
1233 scr->focused_window->next = NULL;
1236 /* if in click to focus mode and the window
1237 * was a transient, focus the owner window
1239 tmp = NULL;
1240 if (wPreferences.focus_mode==WKF_CLICK) {
1241 tmp = wWindowFor(wwin->transient_for);
1242 if (tmp && (!tmp->flags.mapped || tmp->window_flags.no_focusable)) {
1243 tmp = NULL;
1246 /* otherwise, focus the next one in the focus list */
1247 if (!tmp) {
1248 tmp = scr->focused_window;
1249 while (tmp) {
1250 if (!tmp->window_flags.no_focusable
1251 && (tmp->flags.mapped || tmp->flags.shaded))
1252 break;
1253 tmp = tmp->prev;
1256 if (wPreferences.focus_mode==WKF_CLICK) {
1257 newFocusedWindow = tmp;
1258 } else if (wPreferences.focus_mode==WKF_SLOPPY
1259 || wPreferences.focus_mode==WKF_POINTER) {
1260 unsigned int mask;
1261 int foo;
1262 Window bar, win;
1264 /* This is to let the root window get the keyboard input
1265 * if Sloppy focus mode and no other window get focus.
1266 * This way keybindings will not freeze.
1268 tmp = NULL;
1269 if (XQueryPointer(dpy, scr->root_win, &bar, &win,
1270 &foo, &foo, &foo, &foo, &mask))
1271 tmp = wWindowFor(win);
1272 if (tmp == wwin)
1273 tmp = NULL;
1274 newFocusedWindow = tmp;
1275 } else {
1276 newFocusedWindow = NULL;
1279 #ifdef DEBUG
1280 printf("destroying window %x frame %x\n", (unsigned)wwin->client_win,
1281 (unsigned)frame->window);
1282 #endif
1283 if (!wasNotFocused)
1284 wSetFocusTo(scr, newFocusedWindow);
1285 wWindowDestroy(wwin);
1286 XFlush(dpy);
1290 void
1291 wWindowFocus(WWindow *wwin)
1293 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
1295 wwin->flags.focused=1;
1297 wWindowResetMouseGrabs(wwin);
1299 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1303 void
1304 wWindowMap(WWindow *wwin)
1306 XMapWindow(dpy, wwin->frame->core->window);
1307 wwin->flags.mapped = 1;
1312 void
1313 wWindowUnfocus(WWindow *wwin)
1315 CloseWindowMenu(wwin->screen_ptr);
1317 wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused
1318 ? WS_PFOCUSED : WS_UNFOCUSED);
1320 if (wwin->transient_for!=None
1321 && wwin->transient_for!=wwin->screen_ptr->root_win) {
1322 WWindow *owner;
1323 owner = wWindowFor(wwin->transient_for);
1324 if (owner && owner->flags.semi_focused) {
1325 owner->flags.semi_focused = 0;
1326 if (owner->flags.mapped || owner->flags.shaded) {
1327 wWindowUnfocus(owner);
1328 wFrameWindowPaint(owner->frame);
1332 wwin->flags.focused=0;
1333 wWindowResetMouseGrabs(wwin);
1335 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
1341 *----------------------------------------------------------------------
1343 * wWindowConstrainSize--
1344 * Constrains size for the client window, taking the maximal size,
1345 * window resize increments and other size hints into account.
1347 * Returns:
1348 * The closest size to what was given that the client window can
1349 * have.
1351 *----------------------------------------------------------------------
1353 void
1354 wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight)
1356 XSizeHints *sizeh = wwin->normal_hints;
1357 int width = *nwidth;
1358 int height = *nheight;
1359 int winc = sizeh->width_inc;
1360 int hinc = sizeh->height_inc;
1362 if (width < sizeh->min_width)
1363 width = sizeh->min_width;
1364 if (height < sizeh->min_height)
1365 height = sizeh->min_height;
1367 if (width > sizeh->max_width)
1368 width = sizeh->max_width;
1369 if (height > sizeh->max_height)
1370 height = sizeh->max_height;
1372 /* aspect ratio code borrowed from olwm */
1373 if (sizeh->flags & PAspect) {
1374 /* adjust max aspect ratio */
1375 if (!(sizeh->max_aspect.x==1 && sizeh->max_aspect.y==1)
1376 && width * sizeh->max_aspect.y > height * sizeh->max_aspect.x) {
1377 if (sizeh->max_aspect.x > sizeh->max_aspect.y) {
1378 height = (width * sizeh->max_aspect.y) / sizeh->max_aspect.x;
1379 if (height > sizeh->max_height) {
1380 height = sizeh->max_height;
1381 width = (height*sizeh->max_aspect.x) / sizeh->max_aspect.y;
1383 } else {
1384 width = (height * sizeh->max_aspect.x) / sizeh->max_aspect.y;
1385 if (width > sizeh->max_width) {
1386 width = sizeh->max_width;
1387 height = (width*sizeh->max_aspect.y) / sizeh->max_aspect.x;
1392 /* adjust min aspect ratio */
1393 if (!(sizeh->min_aspect.x==1 && sizeh->min_aspect.y==1)
1394 && width * sizeh->min_aspect.y < height * sizeh->min_aspect.x) {
1395 if (sizeh->min_aspect.x > sizeh->min_aspect.y) {
1396 height = (width * sizeh->min_aspect.y) / sizeh->min_aspect.x;
1397 if (height < sizeh->min_height) {
1398 height = sizeh->min_height;
1399 width = (height*sizeh->min_aspect.x) / sizeh->min_aspect.y;
1401 } else {
1402 width = (height * sizeh->min_aspect.x) / sizeh->min_aspect.y;
1403 if (width > sizeh->min_width) {
1404 width = sizeh->min_width;
1405 height = (width*sizeh->min_aspect.y) / sizeh->min_aspect.x;
1411 if (sizeh->base_width != 0) {
1412 width = (((width - sizeh->base_width) / winc) * winc)
1413 + sizeh->base_width;
1414 } else {
1415 width = (((width - sizeh->min_width) / winc) * winc)
1416 + sizeh->min_width;
1419 if (sizeh->base_width != 0) {
1420 height = (((height - sizeh->base_height) / hinc) * hinc)
1421 + sizeh->base_height;
1422 } else {
1423 height = (((height - sizeh->min_height) / hinc) * hinc)
1424 + sizeh->min_height;
1427 *nwidth = width;
1428 *nheight = height;
1432 void
1433 wWindowChangeWorkspace(WWindow *wwin, int workspace)
1435 WScreen *scr = wwin->screen_ptr;
1436 WApplication *wapp;
1438 if (workspace >= scr->workspace_count || workspace < 0
1439 || workspace == wwin->frame->workspace)
1440 return;
1442 if (workspace != scr->current_workspace) {
1443 /* Sent to other workspace. Unmap window */
1444 if ((wwin->flags.mapped||wwin->flags.shaded)
1445 && !wwin->window_flags.omnipresent
1446 && !wwin->flags.changing_workspace) {
1448 wapp = wApplicationOf(wwin->main_window);
1449 if (wapp) {
1450 wapp->last_workspace = workspace;
1452 XUnmapWindow(dpy, wwin->frame->core->window);
1453 wwin->flags.mapped = 0;
1454 wSetFocusTo(scr, NULL);
1456 } else {
1457 /* brought to current workspace. Map window */
1458 if (!wwin->flags.mapped &&
1459 !(wwin->flags.miniaturized || wwin->flags.hidden)) {
1460 wWindowMap(wwin);
1463 if (!wwin->window_flags.omnipresent) {
1464 wwin->frame->workspace = workspace;
1465 UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
1470 void
1471 wWindowSynthConfigureNotify(WWindow *wwin)
1473 XEvent sevent;
1475 sevent.type = ConfigureNotify;
1476 sevent.xconfigure.display = dpy;
1477 sevent.xconfigure.event = wwin->client_win;
1478 sevent.xconfigure.window = wwin->client_win;
1480 sevent.xconfigure.x = wwin->client.x;
1481 sevent.xconfigure.y = wwin->client.y;
1482 sevent.xconfigure.width = wwin->client.width;
1483 sevent.xconfigure.height = wwin->client.height;
1485 sevent.xconfigure.border_width = wwin->old_border_width;
1486 if (wwin->window_flags.no_titlebar)
1487 sevent.xconfigure.above = None;
1488 else
1489 sevent.xconfigure.above = wwin->frame->titlebar->window;
1491 sevent.xconfigure.override_redirect = False;
1492 XSendEvent(dpy, wwin->client_win, False, StructureNotifyMask, &sevent);
1493 XFlush(dpy);
1498 *----------------------------------------------------------------------
1499 * wWindowConfigure--
1500 * Configures the frame, decorations and client window to the
1501 * specified geometry. The geometry is not checked for validity,
1502 * wWindowConstrainSize() must be used for that.
1503 * The size parameters are for the client window, but the position is
1504 * for the frame.
1505 * The client window receives a ConfigureNotify event, according
1506 * to what ICCCM says.
1508 * Returns:
1509 * None
1511 * Side effects:
1512 * Window size and position are changed and client window receives
1513 * a ConfigureNotify event.
1514 *----------------------------------------------------------------------
1516 void
1517 wWindowConfigure(wwin, req_x, req_y, req_width, req_height)
1518 WWindow *wwin;
1519 int req_x, req_y; /* new position of the frame */
1520 int req_width, req_height; /* new size of the client */
1522 int synth_notify = False;
1523 int resize;
1525 resize = (req_width!=wwin->client.width
1526 || req_height!=wwin->client.height);
1528 * if the window is being moved but not resized then
1529 * send a synthetic ConfigureNotify
1531 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) {
1532 synth_notify = True;
1535 if (wwin->window_flags.dont_move_off)
1536 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1537 req_width, req_height);
1538 if (resize) {
1539 if (req_width < MIN_WINDOW_SIZE)
1540 req_width = MIN_WINDOW_SIZE;
1541 if (req_height < MIN_WINDOW_SIZE)
1542 req_height = MIN_WINDOW_SIZE;
1544 /* If growing, resize inner part before frame,
1545 * if shrinking, resize frame before.
1546 * This will prevent the frame (that can have a different color)
1547 * to be exposed, causing flicker */
1548 if (req_height > wwin->frame->core->height
1549 || req_width > wwin->frame->core->width)
1550 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
1552 if (wwin->flags.shaded) {
1553 wFrameWindowResize(wwin->frame, req_width, wwin->frame->core->height);
1554 wwin->old_geometry.height = req_height;
1555 } else {
1556 wFrameWindowResizeInternal(wwin->frame, req_width, req_height);
1559 if (!(req_height > wwin->frame->core->height
1560 || req_width > wwin->frame->core->width))
1561 XResizeWindow(dpy, wwin->client_win, req_width, req_height);
1563 wwin->client.x = req_x;
1564 wwin->client.y = req_y + wwin->frame->top_width;
1565 wwin->client.width = req_width;
1566 wwin->client.height = req_height;
1568 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1569 } else {
1570 wwin->client.x = req_x;
1571 wwin->client.y = req_y + wwin->frame->top_width;
1573 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1575 wwin->frame_x = req_x;
1576 wwin->frame_y = req_y;
1578 #ifdef SHAPE
1579 if (wShapeSupported && wwin->flags.shaped && resize) {
1580 wWindowSetShape(wwin);
1582 #endif
1584 if (synth_notify)
1585 wWindowSynthConfigureNotify(wwin);
1586 XFlush(dpy);
1590 void
1591 wWindowMove(wwin, req_x, req_y)
1592 WWindow *wwin;
1593 int req_x, req_y; /* new position of the frame */
1595 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1596 int synth_notify = False;
1598 /* Send a synthetic ConfigureNotify event for every window movement. */
1599 if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y)) {
1600 synth_notify = True;
1602 #else
1603 /* A single synthetic ConfigureNotify event is sent at the end of
1604 * a completed (opaque) movement in moveres.c */
1605 #endif
1607 if (wwin->window_flags.dont_move_off)
1608 wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
1609 wwin->frame->core->width, wwin->frame->core->height);
1611 wwin->client.x = req_x;
1612 wwin->client.y = req_y + wwin->frame->top_width;
1614 XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
1616 wwin->frame_x = req_x;
1617 wwin->frame_y = req_y;
1619 #ifdef CONFIGURE_WINDOW_WHILE_MOVING
1620 if (synth_notify)
1621 wWindowSynthConfigureNotify(wwin);
1622 #endif
1626 void
1627 wWindowUpdateButtonImages(WWindow *wwin)
1629 WScreen *scr = wwin->screen_ptr;
1630 Pixmap pixmap, mask;
1631 WFrameWindow *fwin = wwin->frame;
1633 if (wwin->window_flags.no_titlebar)
1634 return;
1636 /* miniaturize button */
1638 if (!wwin->window_flags.no_miniaturize_button) {
1639 if (wwin->wm_gnustep_attr
1640 && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) {
1641 pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap;
1643 if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) {
1644 mask = wwin->wm_gnustep_attr->miniaturize_mask;
1645 } else {
1646 mask = None;
1649 if (fwin->lbutton_image
1650 && (fwin->lbutton_image->image != pixmap
1651 || fwin->lbutton_image->mask != mask)) {
1652 wPixmapDestroy(fwin->lbutton_image);
1653 fwin->lbutton_image = NULL;
1656 if (!fwin->lbutton_image) {
1657 fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask);
1658 fwin->lbutton_image->client_owned = 1;
1659 fwin->lbutton_image->client_owned_mask = 1;
1661 } else {
1662 if (fwin->lbutton_image && !fwin->lbutton_image->shared) {
1663 wPixmapDestroy(fwin->lbutton_image);
1665 fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
1669 /* close button */
1671 if (!wwin->window_flags.no_close_button) {
1672 if (wwin->wm_gnustep_attr
1673 && wwin->wm_gnustep_attr->flags&GSClosePixmapAttr) {
1674 pixmap = wwin->wm_gnustep_attr->close_pixmap;
1676 if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr) {
1677 mask = wwin->wm_gnustep_attr->close_mask;
1678 } else {
1679 mask = None;
1682 if (fwin->rbutton_image
1683 && (fwin->rbutton_image->image != pixmap
1684 || fwin->rbutton_image->mask != mask)) {
1685 wPixmapDestroy(fwin->rbutton_image);
1686 fwin->rbutton_image = NULL;
1689 if (!fwin->rbutton_image) {
1690 fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask);
1691 fwin->rbutton_image->client_owned = 1;
1692 fwin->rbutton_image->client_owned_mask = 1;
1694 } else if (wwin->window_flags.kill_close) {
1695 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1696 wPixmapDestroy(fwin->rbutton_image);
1698 fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL];
1699 } else if (wwin->window_flags.broken_close) {
1700 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1701 wPixmapDestroy(fwin->rbutton_image);
1703 fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE];
1704 } else {
1705 if (fwin->rbutton_image && !fwin->rbutton_image->shared) {
1706 wPixmapDestroy(fwin->rbutton_image);
1708 fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE];
1712 /* force buttons to be redrawn */
1713 fwin->flags.need_texture_change = 1;
1714 wFrameWindowPaint(fwin);
1719 *---------------------------------------------------------------------------
1720 * wWindowConfigureBorders--
1721 * Update window border configuration according to window_flags
1723 *---------------------------------------------------------------------------
1725 void
1726 wWindowConfigureBorders(WWindow *wwin)
1728 if (wwin->frame) {
1729 int flags;
1730 int newy, oldh;
1732 flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON;
1733 if (!wwin->window_flags.no_titlebar)
1734 flags |= WFF_TITLEBAR;
1735 if (!wwin->window_flags.no_resizebar)
1736 flags |= WFF_RESIZEBAR;
1738 oldh = wwin->frame->top_width;
1739 wFrameWindowUpdateBorders(wwin->frame, flags);
1740 if (oldh != wwin->frame->top_width) {
1741 newy = wwin->frame_y + oldh - wwin->frame->top_width;
1743 XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
1744 wWindowConfigure(wwin, wwin->frame_x, newy,
1745 wwin->client.width, wwin->client.height);
1748 flags = 0;
1749 if (!wwin->window_flags.no_miniaturize_button
1750 && wwin->frame->flags.hide_left_button)
1751 flags |= WFF_LEFT_BUTTON;
1753 if (!wwin->window_flags.no_close_button
1754 && wwin->frame->flags.hide_right_button)
1755 flags |= WFF_RIGHT_BUTTON;
1757 if (flags!=0) {
1758 wWindowUpdateButtonImages(wwin);
1759 wFrameWindowShowButton(wwin->frame, flags);
1762 flags = 0;
1763 if (wwin->window_flags.no_miniaturize_button
1764 && !wwin->frame->flags.hide_left_button)
1765 flags |= WFF_LEFT_BUTTON;
1767 if (wwin->window_flags.no_close_button
1768 && !wwin->frame->flags.hide_right_button)
1769 flags |= WFF_RIGHT_BUTTON;
1771 if (flags!=0)
1772 wFrameWindowHideButton(wwin->frame, flags);
1774 #ifdef SHAPE
1775 if (wShapeSupported && wwin->flags.shaped) {
1776 wWindowSetShape(wwin);
1778 #endif
1783 void
1784 wWindowSaveState(WWindow *wwin)
1786 CARD32 data[9];
1788 memset(data, 0, sizeof(CARD32)*9);
1789 data[0] = wwin->frame->workspace;
1790 data[2] = wwin->flags.shaded;
1791 data[3] = wwin->flags.hidden;
1793 XChangeProperty(dpy, wwin->client_win, _XA_WINDOWMAKER_STATE,
1794 _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
1795 (unsigned char *)data, 9);
1799 static int
1800 getSavedState(Window window, WSavedState **state)
1802 Atom type_ret;
1803 int fmt_ret;
1804 unsigned long nitems_ret;
1805 unsigned long bytes_after_ret;
1806 CARD32 *data;
1808 if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0, 9,
1809 True, _XA_WINDOWMAKER_STATE,
1810 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
1811 (unsigned char **)&data)!=Success || !data)
1812 return 0;
1814 *state = malloc(sizeof(WSavedState));
1816 if (*state) {
1817 (*state)->workspace = data[0];
1818 (*state)->miniaturized = data[1];
1819 (*state)->shaded = data[2];
1820 (*state)->hidden = data[3];
1821 (*state)->use_geometry = data[4];
1822 (*state)->x = data[5];
1823 (*state)->y = data[6];
1824 (*state)->w = data[7];
1825 (*state)->h = data[8];
1827 XFree(data);
1829 if (*state && type_ret==_XA_WINDOWMAKER_STATE)
1830 return 1;
1831 else
1832 return 0;
1836 #ifdef SHAPE
1837 void
1838 wWindowClearShape(WWindow *wwin)
1840 XShapeCombineMask(dpy, wwin->frame->core->window, ShapeBounding,
1841 0, wwin->frame->top_width, None, ShapeSet);
1842 XFlush(dpy);
1845 void
1846 wWindowSetShape(WWindow *wwin)
1848 XRectangle rect[2];
1849 int count;
1850 #ifdef OPTIMIZE_SHAPE
1851 XRectangle *rects;
1852 XRectangle *urec;
1853 int ordering;
1855 /* only shape is the client's */
1856 if (wwin->window_flags.no_titlebar && wwin->window_flags.no_resizebar) {
1857 goto alt_code;
1860 /* Get array of rectangles describing the shape mask */
1861 rects = XShapeGetRectangles(dpy, wwin->client_win, ShapeBounding,
1862 &count, &ordering);
1863 if (!rects) {
1864 goto alt_code;
1867 urec = malloc(sizeof(XRectangle)*(count+2));
1868 if (!urec) {
1869 XFree(rects);
1870 goto alt_code;
1873 /* insert our decoration rectangles in the rect list */
1874 memcpy(urec, rects, sizeof(XRectangle)*count);
1875 XFree(rects);
1877 if (!wwin->window_flags.no_titlebar) {
1878 urec[count].x = -1;
1879 urec[count].y = -1 - wwin->frame->top_width;
1880 urec[count].width = wwin->frame->core->width + 2;
1881 urec[count].height = wwin->frame->top_width + 1;
1882 count++;
1884 if (!wwin->window_flags.no_resizebar) {
1885 urec[count].x = -1;
1886 urec[count].y = wwin->frame->core->height
1887 - wwin->frame->bottom_width - wwin->frame->top_width;
1888 urec[count].width = wwin->frame->core->width + 2;
1889 urec[count].height = wwin->frame->bottom_width + 1;
1890 count++;
1893 /* shape our frame window */
1894 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
1895 0, wwin->frame->top_width, urec, count,
1896 ShapeSet, Unsorted);
1897 XFlush(dpy);
1898 free(urec);
1899 return;
1901 alt_code:
1902 #endif /* OPTIMIZE_SHAPE */
1903 count = 0;
1904 if (!wwin->window_flags.no_titlebar) {
1905 rect[count].x = -1;
1906 rect[count].y = -1;
1907 rect[count].width = wwin->frame->core->width + 2;
1908 rect[count].height = wwin->frame->top_width + 1;
1909 count++;
1911 if (!wwin->window_flags.no_resizebar) {
1912 rect[count].x = -1;
1913 rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width;
1914 rect[count].width = wwin->frame->core->width + 2;
1915 rect[count].height = wwin->frame->bottom_width + 1;
1916 count++;
1918 if (count > 0) {
1919 XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
1920 0, 0, rect, count, ShapeSet, Unsorted);
1922 XShapeCombineShape(dpy, wwin->frame->core->window, ShapeBounding,
1923 0, wwin->frame->top_width, wwin->client_win,
1924 ShapeBounding, (count > 0 ? ShapeUnion : ShapeSet));
1925 XFlush(dpy);
1927 #endif /* SHAPE */
1929 /* ====================================================================== */
1931 static FocusMode
1932 getFocusMode(WWindow *wwin)
1934 FocusMode mode;
1936 if ((wwin->wm_hints) && (wwin->wm_hints->flags & InputHint)) {
1937 if (wwin->wm_hints->input == True) {
1938 if (wwin->protocols.TAKE_FOCUS)
1939 mode = WFM_LOCALLY_ACTIVE;
1940 else
1941 mode = WFM_PASSIVE;
1942 } else {
1943 if (wwin->protocols.TAKE_FOCUS)
1944 mode = WFM_GLOBALLY_ACTIVE;
1945 else
1946 mode = WFM_NO_INPUT;
1948 } else {
1949 mode = WFM_PASSIVE;
1951 return mode;
1955 void
1956 wWindowSetKeyGrabs(WWindow *wwin)
1958 int i;
1959 WShortKey *key;
1961 for (i=0; i<WKBD_LAST; i++) {
1962 key = &wKeyBindings[i];
1964 if (key->keycode==0)
1965 continue;
1966 if (key->modifier!=AnyModifier) {
1967 XGrabKey(dpy, key->keycode, key->modifier|LockMask,
1968 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
1969 #ifdef NUMLOCK_HACK
1970 /* Also grab all modifier combinations possible that include,
1971 * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
1972 * work even if the NumLock/ScrollLock key is on.
1974 wHackedGrabKey(key->keycode, key->modifier,
1975 wwin->frame->core->window, True, GrabModeAsync,
1976 GrabModeAsync);
1977 #endif
1979 XGrabKey(dpy, key->keycode, key->modifier,
1980 wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
1983 wRootMenuBindShortcuts(wwin->frame->core->window);
1988 void
1989 wWindowResetMouseGrabs(WWindow *wwin)
1991 XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
1993 if (!wwin->window_flags.no_bind_mouse) {
1994 /* grabs for Meta+drag */
1995 wHackedGrabButton(AnyButton, MOD_MASK, wwin->client_win,
1996 True, ButtonPressMask, GrabModeSync,
1997 GrabModeAsync, None, wCursor[WCUR_ARROW]);
2000 if (!wwin->flags.focused) {
2001 /* the passive grabs to focus the window */
2002 if (wPreferences.focus_mode == WKF_CLICK)
2003 XGrabButton(dpy, AnyButton, AnyModifier, wwin->client_win,
2004 True, ButtonPressMask, GrabModeSync, GrabModeAsync,
2005 None, None);
2007 XFlush(dpy);
2011 void
2012 wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr)
2015 if (attr->flags & GSExtraFlagsAttr) {
2016 if (wwin->window_flags.broken_close !=
2017 (attr->extra_flags & GSDocumentEditedFlag)) {
2018 wwin->window_flags.broken_close = !wwin->window_flags.broken_close;
2020 wWindowUpdateButtonImages(wwin);
2027 WMagicNumber
2028 wWindowAddSavedState(char *instance, char *class, char *command,
2029 pid_t pid, WSavedState *state)
2031 WWindowState *wstate;
2033 wstate = malloc(sizeof(WWindowState));
2034 if (!wstate)
2035 return 0;
2037 memset(wstate, 0, sizeof(WWindowState));
2038 wstate->pid = pid;
2039 if (instance)
2040 wstate->instance = wstrdup(instance);
2041 if (class)
2042 wstate->class = wstrdup(class);
2043 if (command)
2044 wstate->command = wstrdup(command);
2045 wstate->state = state;
2047 wstate->next = windowState;
2048 windowState = wstate;
2050 #ifdef DEBUG
2051 printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
2052 class, command);
2053 #endif
2055 return wstate;
2059 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
2062 WMagicNumber
2063 wWindowGetSavedState(Window win)
2065 char *instance, *class, *command=NULL;
2066 WWindowState *wstate = windowState;
2067 char **argv;
2068 int argc;
2070 if (!wstate)
2071 return NULL;
2073 if (XGetCommand(dpy, win, &argv, &argc)) {
2074 if (argc > 0)
2075 command = FlattenStringList(argv, argc);
2076 XFreeStringList(argv);
2078 if (!command)
2079 return NULL;
2081 if (PropGetWMClass(win, &class, &instance)) {
2082 while (wstate) {
2083 if (SAME(instance, wstate->instance) &&
2084 SAME(class, wstate->class) &&
2085 SAME(command, wstate->command)) {
2086 break;
2088 wstate = wstate->next;
2090 } else {
2091 wstate = NULL;
2094 #ifdef DEBUG
2095 printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
2096 class, command);
2097 #endif
2099 if (command) free(command);
2100 if (instance) XFree(instance);
2101 if (class) XFree(class);
2103 return wstate;
2107 void
2108 wWindowDeleteSavedState(WMagicNumber id)
2110 WWindowState *tmp, *wstate=(WWindowState*)id;
2112 if (!wstate || !windowState)
2113 return;
2115 tmp = windowState;
2116 if (tmp==wstate) {
2117 windowState = wstate->next;
2118 #ifdef DEBUG
2119 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2120 wstate, wstate->instance, wstate->class, wstate->command);
2121 #endif
2122 if (wstate->instance) free(wstate->instance);
2123 if (wstate->class) free(wstate->class);
2124 if (wstate->command) free(wstate->command);
2125 free(wstate->state);
2126 free(wstate);
2127 } else {
2128 while (tmp->next) {
2129 if (tmp->next==wstate) {
2130 tmp->next=wstate->next;
2131 #ifdef DEBUG
2132 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2133 wstate, wstate->instance, wstate->class, wstate->command);
2134 #endif
2135 if (wstate->instance) free(wstate->instance);
2136 if (wstate->class) free(wstate->class);
2137 if (wstate->command) free(wstate->command);
2138 free(wstate->state);
2139 free(wstate);
2140 break;
2142 tmp = tmp->next;
2148 void
2149 wWindowDeleteSavedStatesForPID(pid_t pid)
2151 WWindowState *tmp, *wstate;
2153 if (!windowState)
2154 return;
2156 tmp = windowState;
2157 if (tmp->pid == pid) {
2158 wstate = windowState;
2159 windowState = tmp->next;
2160 #ifdef DEBUG
2161 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2162 wstate, wstate->instance, wstate->class, wstate->command);
2163 #endif
2164 if (wstate->instance) free(wstate->instance);
2165 if (wstate->class) free(wstate->class);
2166 if (wstate->command) free(wstate->command);
2167 free(wstate->state);
2168 free(wstate);
2169 } else {
2170 while (tmp->next) {
2171 if (tmp->next->pid==pid) {
2172 wstate = tmp->next;
2173 tmp->next = wstate->next;
2174 #ifdef DEBUG
2175 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
2176 wstate, wstate->instance, wstate->class, wstate->command);
2177 #endif
2178 if (wstate->instance) free(wstate->instance);
2179 if (wstate->class) free(wstate->class);
2180 if (wstate->command) free(wstate->command);
2181 free(wstate->state);
2182 free(wstate);
2183 break;
2185 tmp = tmp->next;
2191 /* ====================================================================== */
2193 static void
2194 resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
2196 WWindow *wwin = data;
2198 #ifndef NUMLOCK_HACK
2199 if ((event->xbutton.state & ValidModMask)
2200 != (event->xbutton.state & ~LockMask)) {
2201 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2202 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2204 #endif
2206 event->xbutton.state &= ValidModMask;
2208 CloseWindowMenu(wwin->screen_ptr);
2210 if (wPreferences.focus_mode==WKF_CLICK
2211 && !(event->xbutton.state&ControlMask)) {
2212 wSetFocusTo(wwin->screen_ptr, wwin);
2215 if (event->xbutton.button == Button1)
2216 wRaiseFrame(wwin->frame->core);
2218 if (event->xbutton.state & MOD_MASK) {
2219 /* move the window */
2220 #if 0
2221 if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
2222 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2223 GrabModeAsync, GrabModeAsync, None,
2224 None, CurrentTime)!=GrabSuccess) {
2225 #ifdef DEBUG0
2226 wwarning("pointer grab failed for window move");
2227 #endif
2228 return;
2230 #endif
2231 wMouseMoveWindow(wwin, event);
2232 XUngrabPointer(dpy, CurrentTime);
2233 } else {
2234 #if 0
2235 /* resize the window */
2236 if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
2237 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2238 GrabModeAsync, GrabModeAsync, None,
2239 None, CurrentTime)!=GrabSuccess) {
2240 #ifdef DEBUG0
2241 wwarning("pointer grab failed for window resize");
2242 #endif
2243 return;
2245 #endif
2246 wMouseResizeWindow(wwin, event);
2247 XUngrabPointer(dpy, CurrentTime);
2253 static void
2254 titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event)
2256 WWindow *wwin = data;
2258 event->xbutton.state &= ValidModMask;
2260 if (event->xbutton.button==Button1) {
2261 if (event->xbutton.state == 0) {
2262 if (!wwin->window_flags.no_shadeable) {
2263 /* shade window */
2264 if (wwin->flags.shaded)
2265 wUnshadeWindow(wwin);
2266 else
2267 wShadeWindow(wwin);
2269 } else {
2270 int dir = 0;
2272 if (event->xbutton.state & ControlMask)
2273 dir |= MAX_VERTICAL;
2275 if (event->xbutton.state & ShiftMask) {
2276 dir |= MAX_HORIZONTAL;
2277 if (!(event->xbutton.state & ControlMask))
2278 wSelectWindow(wwin);
2281 /* maximize window */
2282 if (dir !=0 && !wwin->window_flags.no_resizable) {
2283 if (wwin->flags.maximized)
2284 wUnmaximizeWindow(wwin);
2285 else
2286 wMaximizeWindow(wwin, dir);
2289 } else if (event->xbutton.button==Button3) {
2290 if (event->xbutton.state & MOD_MASK) {
2291 wHideOtherApplications(wwin);
2293 } else if (event->xbutton.button==Button2) {
2294 wSelectWindow(wwin);
2299 static void
2300 frameMouseDown(WObjDescriptor *desc, XEvent *event)
2302 WWindow *wwin = desc->parent;
2304 event->xbutton.state &= ValidModMask;
2306 CloseWindowMenu(wwin->screen_ptr);
2308 if (wPreferences.focus_mode==WKF_CLICK
2309 && !(event->xbutton.state&ControlMask)) {
2310 wSetFocusTo(wwin->screen_ptr, wwin);
2312 if (event->xbutton.button == Button1) {
2313 wRaiseFrame(wwin->frame->core);
2316 if (event->xbutton.state & MOD_MASK) {
2317 /* move the window */
2318 if (XGrabPointer(dpy, wwin->client_win, False,
2319 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2320 GrabModeAsync, GrabModeAsync, None,
2321 None, CurrentTime)!=GrabSuccess) {
2322 #ifdef DEBUG0
2323 wwarning("pointer grab failed for window move");
2324 #endif
2325 return;
2327 if (event->xbutton.button == Button3 && !wwin->window_flags.no_resizable)
2328 wMouseResizeWindow(wwin, event);
2329 else
2330 wMouseMoveWindow(wwin, event);
2331 XUngrabPointer(dpy, CurrentTime);
2336 static void
2337 titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
2339 WWindow *wwin = (WWindow*)data;
2341 #ifndef NUMLOCK_HACK
2342 if ((event->xbutton.state & ValidModMask)
2343 != (event->xbutton.state & ~LockMask)) {
2344 wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
2345 "Turn it off or some mouse actions and keyboard shortcuts will not work."));
2347 #endif
2349 event->xbutton.state &= ValidModMask;
2352 CloseWindowMenu(wwin->screen_ptr);
2354 if (wPreferences.focus_mode==WKF_CLICK
2355 && !(event->xbutton.state&ControlMask)) {
2356 wSetFocusTo(wwin->screen_ptr, wwin);
2359 if (event->xbutton.button == Button1
2360 || event->xbutton.button == Button2) {
2362 if (event->xbutton.button == Button1) {
2363 if (event->xbutton.state & MOD_MASK) {
2364 wLowerFrame(wwin->frame->core);
2365 } else {
2366 wRaiseFrame(wwin->frame->core);
2369 if ((event->xbutton.state & ShiftMask)
2370 && !(event->xbutton.state & ControlMask)) {
2371 wSelectWindow(wwin);
2372 return;
2374 #if 0
2375 if (XGrabPointer(dpy, wwin->frame->titlebar->window, False,
2376 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
2377 GrabModeAsync, GrabModeAsync, None,
2378 None, CurrentTime)!=GrabSuccess) {
2379 #ifdef DEBUG0
2380 wwarning("pointer grab failed for window move");
2381 #endif
2382 return;
2384 #endif
2385 /* move the window */
2386 wMouseMoveWindow(wwin, event);
2387 XUngrabPointer(dpy, CurrentTime);
2388 } else if (event->xbutton.button == Button3 && event->xbutton.state==0
2389 && !wwin->flags.internal_window) {
2390 WObjDescriptor *desc;
2392 OpenWindowMenu(wwin, event->xbutton.x_root,
2393 wwin->frame_y+wwin->frame->top_width, False);
2395 /* allow drag select */
2396 desc = &wwin->screen_ptr->window_menu->menu->descriptor;
2397 event->xany.send_event = True;
2398 (*desc->handle_mousedown)(desc, event);
2404 static void
2405 windowCloseClick(WCoreWindow *sender, void *data, XEvent *event)
2407 WWindow *wwin = data;
2409 event->xbutton.state &= ValidModMask;
2411 CloseWindowMenu(wwin->screen_ptr);
2413 /* if control-click, kill the client */
2414 if (event->xbutton.state & ControlMask) {
2415 wClientKill(wwin);
2416 } else if (wwin->protocols.DELETE_WINDOW && event->xbutton.state==0) {
2417 /* send delete message */
2418 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2423 static void
2424 windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
2426 WWindow *wwin = data;
2428 CloseWindowMenu(wwin->screen_ptr);
2430 /* send delete message */
2431 if (wwin->protocols.DELETE_WINDOW) {
2432 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
2433 } else {
2434 wClientKill(wwin);
2439 static void
2440 windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event)
2442 WWindow *wwin = data;
2444 event->xbutton.state &= ValidModMask;
2446 CloseWindowMenu(wwin->screen_ptr);
2448 if (wwin->protocols.MINIATURIZE_WINDOW && event->xbutton.state==0) {
2449 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
2450 LastTimestamp);
2451 } else {
2452 WApplication *wapp;
2453 if ((event->xbutton.state & ControlMask) ||
2454 (event->xbutton.button == Button3)) {
2456 wapp = wApplicationOf(wwin->main_window);
2457 if (wapp && !wwin->window_flags.no_appicon)
2458 wHideApplication(wapp);
2459 } else if (event->xbutton.state==0) {
2460 wIconifyWindow(wwin);