2
* Window Maker window manager
4
* Copyright (c) 1997-2003 Alfredo K. Kojima
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
24
#include <X11/Xutil.h>
25
#include <X11/Xatom.h>
27
#include <X11/extensions/shape.h>
34
#include "WindowMaker.h"
38
#include "properties.h"
51
/****** Global Variables ******/
54
extern XContext wWinContext;
56
extern Atom _XA_WM_STATE;
57
extern Atom _XA_WM_PROTOCOLS;
58
extern Atom _XA_WM_COLORMAP_WINDOWS;
60
extern Atom _XA_WINDOWMAKER_MENU;
62
extern Atom _XA_GNUSTEP_WM_ATTR;
63
extern Atom _XA_GNUSTEP_WM_RESIZEBAR;
66
extern Bool wShapeSupported;
71
*--------------------------------------------------------------------
73
* Reparent the window back to the root window.
75
*--------------------------------------------------------------------
78
wClientRestore(WWindow *wwin)
83
wClientGetGravityOffsets(wwin, &gx, &gy);
84
/* set the positio of the frame on screen */
85
wwin->frame_x -= gx * FRAME_BORDER_WIDTH;
86
wwin->frame_y -= gy * FRAME_BORDER_WIDTH;
87
/* if gravity is to the south, account for the border sizes */
89
wwin->frame_y += (wwin->frame->top_width + wwin->frame->bottom_width);
91
XSetWindowBorderWidth(dpy, wwin->client_win, wwin->old_border_width);
92
XReparentWindow(dpy, wwin->client_win, wwin->screen_ptr->root_win,
93
wwin->frame_x, wwin->frame_y);
95
/* don't let the window get iconified after restart */
97
if (wwin->flags.shaded)
98
wClientSetState(wwin, NormalState, None);
104
*----------------------------------------------------------------------
106
* Set the state of the client window to one of the window
107
* states defined in ICCCM (Iconic, Withdrawn, Normal)
110
* The WM_STATE property of the window is updated as well as the
111
* WWindow.state variable.
112
*----------------------------------------------------------------------
115
wClientSetState(WWindow *wwin, int state, Window icon_win)
121
data[0] = (unsigned long) state;
122
data[1] = (unsigned long) icon_win;
124
XChangeProperty(dpy, wwin->client_win, _XA_WM_STATE, _XA_WM_STATE, 32,
125
PropModeReplace, (unsigned char *) data, 2);
130
wClientGetGravityOffsets(WWindow *wwin, int *ofs_x, int *ofs_y)
132
switch (wwin->normal_hints->win_gravity) {
139
case NorthWestGravity:
147
case NorthEastGravity:
159
case SouthWestGravity:
167
case SouthEastGravity:
177
wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre)
180
int nx, ny, nwidth, nheight;
183
/* printf("configure event: %d %d %d %d\n", xcre->x, xcre->y, xcre->width, xcre->height);*/
187
* configure a window that was not mapped by us
191
xwc.width = xcre->width;
192
xwc.height = xcre->height;
193
xwc.border_width = xcre->border_width;
194
xwc.stack_mode = xcre->detail;
195
xwc.sibling = xcre->above;
196
XConfigureWindow(dpy, xcre->window, xcre->value_mask, &xwc);
200
if (wShapeSupported) {
205
XShapeSelectInput(dpy, wwin->client_win, ShapeNotifyMask);
206
XShapeQueryExtents(dpy, wwin->client_win, &b_shaped, &junk, &junk,
207
&ujunk, &ujunk, &junk, &junk, &junk, &ujunk,
209
wwin->flags.shaped = b_shaped;
212
if (xcre->value_mask & CWStackMode) {
213
WObjDescriptor *desc;
216
if ((xcre->value_mask & CWSibling) &&
217
(XFindContext(dpy, xcre->above, wWinContext,
218
(XPointer *)&desc) == XCSUCCESS)
219
&& (desc->parent_type==WCLASS_WINDOW)) {
220
sibling=desc->parent;
221
xwc.sibling = sibling->frame->core->window;
223
xwc.sibling = xcre->above;
225
xwc.stack_mode = xcre->detail;
226
XConfigureWindow(dpy, wwin->frame->core->window,
227
xcre->value_mask & (CWSibling | CWStackMode), &xwc);
228
/* fix stacking order */
229
RemakeStackList(wwin->screen_ptr);
232
wClientGetGravityOffsets(wwin, &ofs_x, &ofs_y);
234
if (xcre->value_mask & CWBorderWidth) {
235
wwin->old_border_width = xcre->border_width;
238
if (!wwin->flags.shaded) {
239
/* If the window is shaded, wrong height will be set for the window */
240
if (xcre->value_mask & CWX) {
242
if (HAS_BORDER(wwin))
243
nx -= FRAME_BORDER_WIDTH;
248
if (xcre->value_mask & CWY) {
249
ny = xcre->y - ((ofs_y < 0) ? 0 : wwin->frame->top_width);
250
if (HAS_BORDER(wwin))
251
ny -= FRAME_BORDER_WIDTH;
256
if (xcre->value_mask & CWWidth)
257
nwidth = xcre->width;
259
nwidth = wwin->frame->core->width;
261
if (xcre->value_mask & CWHeight)
262
nheight = xcre->height;
264
nheight = wwin->frame->core->height - wwin->frame->top_width - wwin->frame->bottom_width;
266
wWindowConfigure(wwin, nx, ny, nwidth, nheight);
267
wwin->old_geometry.x = nx;
268
wwin->old_geometry.y = ny;
269
wwin->old_geometry.width = nwidth;
270
wwin->old_geometry.height = nheight;
276
wClientSendProtocol(WWindow *wwin, Atom protocol, Time time)
280
event.xclient.type = ClientMessage;
281
event.xclient.message_type = _XA_WM_PROTOCOLS;
282
event.xclient.format = 32;
283
event.xclient.display = dpy;
284
event.xclient.window = wwin->client_win;
285
event.xclient.data.l[0] = protocol;
286
event.xclient.data.l[1] = time;
287
event.xclient.data.l[2] = 0;
288
event.xclient.data.l[3] = 0;
289
XSendEvent(dpy, wwin->client_win, False, NoEventMask, &event);
296
wClientKill(WWindow *wwin)
298
XKillClient(dpy, wwin->client_win);
306
*----------------------------------------------------------------------
307
* wClientCheckProperty--
308
* Handles PropertyNotify'es, verifying which property was
309
* changed and updating internal state according to that, like redrawing
310
* the icon title when it is changed.
313
* Depends on the changed property.
315
* TODO: _GNUSTEP_WM_ATTR
316
*----------------------------------------------------------------------
319
wClientCheckProperty(WWindow *wwin, XPropertyEvent *event)
321
XWindowAttributes attribs;
326
switch (event->atom) {
328
if (!wwin->flags.net_has_title)
330
/* window title was changed */
331
if (!wFetchName(dpy, wwin->client_win, &tmp)) {
332
wWindowUpdateName(wwin, NULL);
334
wWindowUpdateName(wwin, tmp);
341
case XA_WM_ICON_NAME:
342
if (!wwin->flags.net_has_icon_title)
349
/* icon title was changed */
350
wGetIconName(dpy, wwin->client_win, &new_title);
351
wIconChangeTitle(wwin->icon, new_title);
357
if (wwin->main_window!=None) {
358
WApplication *wapp = wApplicationOf(wwin->main_window);
361
if (!wapp || !wapp->app_icon || wapp->app_icon->docked)
364
command = GetCommandForWindow(wwin->main_window);
366
if (wapp->app_icon->command)
367
wfree(wapp->app_icon->command);
368
wapp->app_icon->command = command;
376
new_hints = XGetWMHints(dpy, wwin->client_win);
378
/* group leader update
380
* This means that the window is setting the leader after
381
* it was mapped, changing leaders or removing the leader.
383
* Valid state transitions are:
395
* Where G is the window_group hint, C is CLIENT_LEADER property
396
* and ' indicates the hint is unset.
398
* 1,2 - change group leader to new value of window_group
399
* 3 - change leader to value of CLIENT_LEADER
400
* 4 - change leader to value of window_group
401
* 5 - destroy application
402
* 6 - create application
404
if (new_hints && (new_hints->flags & WindowGroupHint)
405
&& new_hints->window_group!=None) {
410
if (wwin->wm_hints && (wwin->wm_hints->flags & WindowGroupHint)
411
&& wwin->wm_hints->window_group!=None) {
417
if (wwin->client_leader) {
419
&& wwin->wm_hints->window_group!=new_hints->window_group) {
421
} else if (g1 && !g2) {
423
} else if (!g1 && g2) {
430
&& wwin->wm_hints->window_group!=new_hints->window_group) {
432
} else if (g1 && !g2) {
434
} else if (!g1 && g2) {
441
/* Handling this may require more work. -Dan */
442
if (wwin->fake_group!=NULL) {
447
XFree(wwin->wm_hints);
449
wwin->wm_hints = new_hints;
451
/* do action according to state transition */
453
/* 3 - change leader to value of CLIENT_LEADER */
455
wApplicationDestroy(wApplicationOf(wwin->main_window));
456
wwin->main_window = wwin->client_leader;
457
wwin->group_id = None;
458
wApplicationCreate(wwin);
461
/* 1,2,4 - change leader to new value of window_group */
465
wApplicationDestroy(wApplicationOf(wwin->main_window));
466
wwin->main_window = new_hints->window_group;
467
wwin->group_id = wwin->main_window;
468
wApplicationCreate(wwin);
471
/* 5 - destroy application */
473
wApplicationDestroy(wApplicationOf(wwin->main_window));
474
wwin->main_window = None;
475
wwin->group_id = None;
478
/* 6 - create application */
480
wwin->main_window = new_hints->window_group;
481
wwin->group_id = wwin->main_window;
482
wApplicationCreate(wwin);
484
/* 7 - we have a fake window group id, so just ignore anything else */
490
printf("window leader update caused state transition %i\n",i);
494
if (wwin->wm_hints) {
496
if ((wwin->wm_hints->flags & IconPixmapHint)
497
|| (wwin->wm_hints->flags & IconWindowHint)) {
500
if (wwin->flags.miniaturized && wwin->icon) {
501
wIconUpdate(wwin->icon);
503
wapp = wApplicationOf(wwin->main_window);
504
if (wapp && wapp->app_icon) {
505
wIconUpdate(wapp->app_icon->icon);
509
if (wwin->wm_hints->flags & UrgencyHint)
510
wwin->flags.urgent = 1;
512
wwin->flags.urgent = 0;
513
/*} else if (wwin->fake_group!=NULL) {
514
wwin->group_id = wwin->fake_group->leader;*/
516
wwin->group_id = None;
520
case XA_WM_NORMAL_HINTS:
521
/* normal (geometry) hints */
526
XGetWindowAttributes(dpy, wwin->client_win, &attribs);
527
wClientGetNormalHints(wwin, &attribs, False, &foo, &foo,
529
/* TODO: should we check for consistency of the current
530
* size against the new geometry hints? */
534
case XA_WM_TRANSIENT_FOR:
539
if (!XGetTransientForHint(dpy, wwin->client_win, &new_owner)) {
542
if (new_owner==0 || new_owner == wwin->client_win) {
543
new_owner = wwin->screen_ptr->root_win;
546
if (new_owner!=wwin->transient_for) {
547
owner = wWindowFor(wwin->transient_for);
549
if (owner->flags.semi_focused) {
550
owner->flags.semi_focused = 0;
551
if ((owner->flags.mapped || owner->flags.shaded)
553
wFrameWindowPaint(owner->frame);
556
owner = wWindowFor(new_owner);
558
if (!owner->flags.semi_focused) {
559
owner->flags.semi_focused = 1;
560
if ((owner->flags.mapped || owner->flags.shaded)
562
wFrameWindowPaint(owner->frame);
565
wwin->transient_for = new_owner;
566
if (new_owner==None) {
567
if (WFLAGP(wwin, no_miniaturizable)) {
568
WSETUFLAG(wwin, no_miniaturizable, 0);
569
WSETUFLAG(wwin, no_miniaturize_button, 0);
571
wWindowConfigureBorders(wwin);
573
} else if (!WFLAGP(wwin, no_miniaturizable)) {
574
WSETUFLAG(wwin, no_miniaturizable, 1);
575
WSETUFLAG(wwin, no_miniaturize_button, 1);
577
wWindowConfigureBorders(wwin);
584
if (event->atom==_XA_WM_PROTOCOLS) {
586
PropGetProtocols(wwin->client_win, &wwin->protocols);
588
WSETUFLAG(wwin, kill_close, !wwin->protocols.DELETE_WINDOW);
591
wWindowUpdateButtonImages(wwin);
593
} else if (event->atom==_XA_WM_COLORMAP_WINDOWS) {
595
GetColormapWindows(wwin);
596
wColormapInstallForWindow(wwin->screen_ptr, wwin);
598
} else if (event->atom==_XA_WINDOWMAKER_MENU) {
601
wapp = wApplicationOf(wwin->main_window);
605
/* TODO: remake appmenu update */
606
wAppMenuDestroy(wapp->menu);
608
if (wwin->fake_group) {
609
extern WPreferences wPreferences;
610
WScreen *scr = wwin->screen_ptr;
611
WWindow *foo = scr->focused_window;
612
WFakeGroupLeader *fPtr = wwin->fake_group;
614
wApplicationDestroy(wapp);
616
if (foo->fake_group && foo->fake_group==fPtr) {
617
WSETUFLAG(foo, shared_appicon, 0);
618
foo->fake_group = NULL;
619
if (foo->group_id!=None)
620
foo->main_window = foo->group_id;
621
else if (foo->client_leader!=None)
622
foo->main_window = foo->client_leader;
623
else if (WFLAGP(foo, emulate_appicon))
624
foo->main_window = foo->client_win;
626
foo->main_window = None;
627
if (foo->main_window) {
628
wapp = wApplicationCreate(foo);
634
if (fPtr->leader!=None)
635
XDestroyWindow(dpy, fPtr->leader);
636
fPtr->retainCount = 0;
638
fPtr->origLeader = None;
640
wapp = wApplicationOf(wwin->main_window);
642
wapp->menu = wAppMenuGet(scr, wwin->main_window);
644
if (wPreferences.auto_arrange_icons) {
645
wArrangeIcons(wwin->screen_ptr, True);
648
wapp->menu = wAppMenuGet(wwin->screen_ptr, wwin->main_window);
650
/* make the appmenu be mapped */
651
wSetFocusTo(wwin->screen_ptr, NULL);
652
wSetFocusTo(wwin->screen_ptr, wwin->screen_ptr->focused_window);
654
} else if (event->atom==_XA_GNUSTEP_WM_ATTR) {
655
GNUstepWMAttributes *attr;
657
PropGetGNUstepWMAttr(wwin->client_win, &attr);
659
wWindowUpdateGNUstepAttr(wwin, attr);
664
wNETWMCheckClientHintChange(wwin, event);
672
*----------------------------------------------------------------------
673
* wClientGetNormalHints--
674
* Get size (normal) hints and a default geometry for the client
675
* window. The hints are also checked for inconsistency. If geometry is
676
* True, the returned data will account for client specified initial
680
* normal_hints is filled with valid data.
681
*----------------------------------------------------------------------
684
wClientGetNormalHints(WWindow *wwin, XWindowAttributes *wattribs, Bool geometry,
685
int *x, int *y, unsigned *width, unsigned *height)
687
int pre_icccm = 0; /* not used */
689
/* find a position for the window */
690
if (!wwin->normal_hints)
691
wwin->normal_hints = XAllocSizeHints();
693
if (!PropGetNormalHints(wwin->client_win, wwin->normal_hints, &pre_icccm)) {
694
wwin->normal_hints->flags = 0;
699
*width = wattribs->width;
700
*height = wattribs->height;
702
if (!(wwin->normal_hints->flags & PWinGravity)) {
703
wwin->normal_hints->win_gravity = NorthWestGravity;
705
if (!(wwin->normal_hints->flags & PMinSize)) {
706
wwin->normal_hints->min_width = MIN_WINDOW_SIZE;
707
wwin->normal_hints->min_height = MIN_WINDOW_SIZE;
709
if (!(wwin->normal_hints->flags & PBaseSize)) {
710
wwin->normal_hints->base_width = 0;
711
wwin->normal_hints->base_height = 0;
713
if (!(wwin->normal_hints->flags & PMaxSize)) {
714
wwin->normal_hints->max_width = wwin->screen_ptr->scr_width*2;
715
wwin->normal_hints->max_height = wwin->screen_ptr->scr_height*2;
718
/* some buggy apps set weird hints.. */
719
if (wwin->normal_hints->min_width <= 0)
720
wwin->normal_hints->min_width = MIN_WINDOW_SIZE;
722
if (wwin->normal_hints->min_height <= 0)
723
wwin->normal_hints->min_height = MIN_WINDOW_SIZE;
726
if (wwin->normal_hints->max_width < wwin->normal_hints->min_width)
727
wwin->normal_hints->max_width = wwin->normal_hints->min_width;
729
if (wwin->normal_hints->max_height < wwin->normal_hints->min_height)
730
wwin->normal_hints->max_height = wwin->normal_hints->min_height;
732
if (!(wwin->normal_hints->flags & PResizeInc)) {
733
wwin->normal_hints->width_inc = 1;
734
wwin->normal_hints->height_inc = 1;
736
if (wwin->normal_hints->width_inc <= 0)
737
wwin->normal_hints->width_inc = 1;
738
if (wwin->normal_hints->height_inc <= 0)
739
wwin->normal_hints->height_inc = 1;
742
if (wwin->normal_hints->flags & PAspect) {
743
if (wwin->normal_hints->min_aspect.x < 1)
744
wwin->normal_hints->min_aspect.x = 1;
745
if (wwin->normal_hints->min_aspect.y < 1)
746
wwin->normal_hints->min_aspect.y = 1;
748
if (wwin->normal_hints->max_aspect.x < 1)
749
wwin->normal_hints->max_aspect.x = 1;
750
if (wwin->normal_hints->max_aspect.y < 1)
751
wwin->normal_hints->max_aspect.y = 1;
754
if (wwin->normal_hints->min_height > wwin->normal_hints->max_height) {
755
wwin->normal_hints->min_height = wwin->normal_hints->max_height;
757
if (wwin->normal_hints->min_width > wwin->normal_hints->max_width) {
758
wwin->normal_hints->min_width = wwin->normal_hints->max_width;
761
#ifdef IGNORE_PPOSITION
762
wwin->normal_hints->flags &= ~PPosition;
765
if (pre_icccm && !wwin->screen_ptr->flags.startup && geometry) {
766
if (wwin->normal_hints->flags & (USPosition|PPosition)) {
767
*x = wwin->normal_hints->x;
768
*y = wwin->normal_hints->y;
770
if (wwin->normal_hints->flags & (USSize|PSize)) {
771
*width = wwin->normal_hints->width;
772
*height = wwin->normal_hints->height;
779
GetColormapWindows(WWindow *wwin)
782
if (wwin->cmap_windows) {
783
XFree(wwin->cmap_windows);
786
wwin->cmap_windows = NULL;
787
wwin->cmap_window_no = 0;
789
if (!XGetWMColormapWindows(dpy, wwin->client_win, &(wwin->cmap_windows),
790
&(wwin->cmap_window_no))
791
|| !wwin->cmap_windows) {
792
wwin->cmap_window_no = 0;
793
wwin->cmap_windows = NULL;