wmaker: Marked args as unused at places where conditional code is used
[wmaker-crm.git] / src / client.c
blob05b1049869afe20616da5e171ca9ffd51d3138be
1 /*
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 along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "wconfig.h"
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include <X11/Xatom.h>
25 #ifdef SHAPE
26 #include <X11/extensions/shape.h>
27 #endif
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include "WindowMaker.h"
34 #include "framewin.h"
35 #include "window.h"
36 #include "properties.h"
37 #include "actions.h"
38 #include "icon.h"
39 #include "client.h"
40 #include "colormap.h"
41 #include "stacking.h"
42 #include "appicon.h"
43 #include "appmenu.h"
44 #include "wmspec.h"
45 #include "misc.h"
49 *--------------------------------------------------------------------
50 * wClientRestore--
51 * Reparent the window back to the root window.
53 *--------------------------------------------------------------------
55 void wClientRestore(WWindow * wwin)
57 #if 0
58 int gx, gy;
60 wClientGetGravityOffsets(wwin, &gx, &gy);
61 /* set the position of the frame on screen */
62 wwin->frame_x -= gx * wwin->screen_ptr->frame_border_width;
63 wwin->frame_y -= gy * wwin->screen_ptr->frame_border_width;
64 /* if gravity is to the south, account for the border sizes */
65 if (gy > 0)
66 wwin->frame_y += (wwin->frame->top_width + wwin->frame->bottom_width);
67 #endif
68 XSetWindowBorderWidth(dpy, wwin->client_win, wwin->old_border_width);
69 XReparentWindow(dpy, wwin->client_win, wwin->screen_ptr->root_win, wwin->frame_x, wwin->frame_y);
71 /* don't let the window get iconified after restart */
73 if (wwin->flags.shaded)
74 wClientSetState(wwin, NormalState, None);
79 *----------------------------------------------------------------------
80 * wClientSetState--
81 * Set the state of the client window to one of the window
82 * states defined in ICCCM (Iconic, Withdrawn, Normal)
84 * Side effects:
85 * The WM_STATE property of the window is updated as well as the
86 * WWindow.state variable.
87 *----------------------------------------------------------------------
89 void wClientSetState(WWindow * wwin, int state, Window icon_win)
91 long data[2];
93 wwin->state = state;
95 data[0] = (unsigned long)state;
96 data[1] = (unsigned long)icon_win;
98 XChangeProperty(dpy, wwin->client_win, w_global.atom.wm.state,
99 w_global.atom.wm.state, 32, PropModeReplace,
100 (unsigned char *)data, 2);
103 void wClientGetGravityOffsets(WWindow * wwin, int *ofs_x, int *ofs_y)
105 switch (wwin->normal_hints->win_gravity) {
106 case ForgetGravity:
107 case CenterGravity:
108 case StaticGravity:
109 *ofs_x = 0;
110 *ofs_y = 0;
111 break;
112 case NorthWestGravity:
113 *ofs_x = -1;
114 *ofs_y = -1;
115 break;
116 case NorthGravity:
117 *ofs_x = 0;
118 *ofs_y = -1;
119 break;
120 case NorthEastGravity:
121 *ofs_x = 1;
122 *ofs_y = -1;
123 break;
124 case WestGravity:
125 *ofs_x = -1;
126 *ofs_y = 0;
127 break;
128 case EastGravity:
129 *ofs_x = 1;
130 *ofs_y = 0;
131 break;
132 case SouthWestGravity:
133 *ofs_x = -1;
134 *ofs_y = 1;
135 break;
136 case SouthGravity:
137 *ofs_x = 0;
138 *ofs_y = 1;
139 break;
140 case SouthEastGravity:
141 *ofs_x = 1;
142 *ofs_y = 1;
143 break;
147 void wClientConfigure(WWindow * wwin, XConfigureRequestEvent * xcre)
149 XWindowChanges xwc;
150 int nx, ny, nwidth, nheight;
151 int ofs_x, ofs_y;
153 /* printf("configure event: %d %d %d %d\n", xcre->x, xcre->y, xcre->width, xcre->height); */
155 if (wwin == NULL) {
157 * configure a window that was not mapped by us
159 xwc.x = xcre->x;
160 xwc.y = xcre->y;
161 xwc.width = xcre->width;
162 xwc.height = xcre->height;
163 xwc.border_width = xcre->border_width;
164 xwc.stack_mode = xcre->detail;
165 xwc.sibling = xcre->above;
166 XConfigureWindow(dpy, xcre->window, xcre->value_mask, &xwc);
167 return;
169 #ifdef SHAPE
170 if (w_global.xext.shape.supported) {
171 int junk;
172 unsigned int ujunk;
173 int b_shaped;
175 XShapeSelectInput(dpy, wwin->client_win, ShapeNotifyMask);
176 XShapeQueryExtents(dpy, wwin->client_win, &b_shaped, &junk, &junk,
177 &ujunk, &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
178 wwin->flags.shaped = b_shaped;
180 #endif
181 if (xcre->value_mask & CWStackMode) {
182 WObjDescriptor *desc;
183 WWindow *sibling;
185 if ((xcre->value_mask & CWSibling) &&
186 (XFindContext(dpy, xcre->above, w_global.context.client_win, (XPointer *) & desc) == XCSUCCESS)
187 && (desc->parent_type == WCLASS_WINDOW)) {
188 sibling = desc->parent;
189 xwc.sibling = sibling->frame->core->window;
190 } else {
191 xwc.sibling = xcre->above;
193 xwc.stack_mode = xcre->detail;
194 XConfigureWindow(dpy, wwin->frame->core->window,
195 xcre->value_mask & (CWSibling | CWStackMode), &xwc);
196 /* fix stacking order */
197 RemakeStackList(wwin->screen_ptr);
200 wClientGetGravityOffsets(wwin, &ofs_x, &ofs_y);
202 if (xcre->value_mask & CWBorderWidth) {
203 wwin->old_border_width = xcre->border_width;
206 if (!wwin->flags.shaded) {
207 /* If the window is shaded, wrong height will be set for the window */
208 if (xcre->value_mask & CWX) {
209 nx = xcre->x;
210 /* Subtracting the border makes the window shift by 1 pixel -Dan */
211 /*if (HAS_BORDER(wwin)) {
212 nx -= wwin->screen_ptr->frame_border_width;
213 } */
214 } else {
215 nx = wwin->frame_x;
218 if (xcre->value_mask & CWY) {
219 ny = xcre->y - ((ofs_y < 0) ? 0 : wwin->frame->top_width);
220 /* Subtracting the border makes the window shift by 1 pixel -Dan */
221 /*if (HAS_BORDER(wwin)) {
222 ny -= wwin->screen_ptr->frame_border_width;
223 } */
224 } else {
225 ny = wwin->frame_y;
228 if (xcre->value_mask & CWWidth)
229 nwidth = xcre->width;
230 else
231 nwidth = wwin->frame->core->width;
233 if (xcre->value_mask & CWHeight)
234 nheight = xcre->height;
235 else
236 nheight = wwin->frame->core->height - wwin->frame->top_width - wwin->frame->bottom_width;
238 if (nwidth != wwin->old_geometry.width)
239 wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS);
240 if (nheight != wwin->old_geometry.height)
241 wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
243 wWindowConfigure(wwin, nx, ny, nwidth, nheight);
244 wwin->old_geometry.x = nx;
245 wwin->old_geometry.y = ny;
246 wwin->old_geometry.width = nwidth;
247 wwin->old_geometry.height = nheight;
251 void wClientSendProtocol(WWindow * wwin, Atom protocol, Time time)
253 XEvent event;
255 event.xclient.type = ClientMessage;
256 event.xclient.message_type = w_global.atom.wm.protocols;
257 event.xclient.format = 32;
258 event.xclient.display = dpy;
259 event.xclient.window = wwin->client_win;
260 event.xclient.data.l[0] = protocol;
261 event.xclient.data.l[1] = time;
262 event.xclient.data.l[2] = 0;
263 event.xclient.data.l[3] = 0;
264 XSendEvent(dpy, wwin->client_win, False, NoEventMask, &event);
265 XSync(dpy, False);
268 void wClientKill(WWindow * wwin)
270 XKillClient(dpy, wwin->client_win);
272 XFlush(dpy);
276 *----------------------------------------------------------------------
277 * wClientCheckProperty--
278 * Handles PropertyNotify'es, verifying which property was
279 * changed and updating internal state according to that, like redrawing
280 * the icon title when it is changed.
282 * Side effects:
283 * Depends on the changed property.
285 * TODO: _GNUSTEP_WM_ATTR
286 *----------------------------------------------------------------------
288 void wClientCheckProperty(WWindow * wwin, XPropertyEvent * event)
290 XWindowAttributes attribs;
291 XWMHints *new_hints;
292 int i, g1, g2;
293 char *tmp = NULL;
295 switch (event->atom) {
296 case XA_WM_NAME:
297 if (!wwin->flags.net_has_title) {
298 /* window title was changed */
299 if (!wFetchName(dpy, wwin->client_win, &tmp)) {
300 wWindowUpdateName(wwin, NULL);
301 } else {
302 wWindowUpdateName(wwin, tmp);
304 if (tmp)
305 XFree(tmp);
307 break;
309 case XA_WM_ICON_NAME:
310 /* Title has changed, update the icon title */
311 if (wwin->icon) {
312 wIconChangeTitle(wwin->icon, wwin);
313 wIconPaint(wwin->icon);
315 break;
317 case XA_WM_COMMAND:
318 if (wwin->main_window != None) {
319 WApplication *wapp = wApplicationOf(wwin->main_window);
320 char *command;
322 if (!wapp || !wapp->app_icon || wapp->app_icon->docked)
323 break;
325 command = GetCommandForWindow(wwin->main_window);
326 if (command) {
327 if (wapp->app_icon->command)
328 wfree(wapp->app_icon->command);
329 wapp->app_icon->command = command;
332 break;
334 case XA_WM_HINTS:
335 /* WM_HINTS */
337 new_hints = XGetWMHints(dpy, wwin->client_win);
339 /* group leader update
341 * This means that the window is setting the leader after
342 * it was mapped, changing leaders or removing the leader.
344 * Valid state transitions are:
346 * _1 __2
347 * / \ / \
348 * v | v |
349 * (GC) (GC')
350 * / ^ / ^
351 * 3| |4 5| |6
352 * | | | |
353 * v / v /
354 * (G'C) (G'C')
356 * Where G is the window_group hint, C is CLIENT_LEADER property
357 * and ' indicates the hint is unset.
359 * 1,2 - change group leader to new value of window_group
360 * 3 - change leader to value of CLIENT_LEADER
361 * 4 - change leader to value of window_group
362 * 5 - destroy application
363 * 6 - create application
365 if (new_hints && (new_hints->flags & WindowGroupHint)
366 && new_hints->window_group != None) {
367 g2 = 1;
368 } else {
369 g2 = 0;
371 if (wwin->wm_hints && (wwin->wm_hints->flags & WindowGroupHint)
372 && wwin->wm_hints->window_group != None) {
373 g1 = 1;
374 } else {
375 g1 = 0;
378 if (wwin->client_leader) {
379 if (g1 && g2 && wwin->wm_hints->window_group != new_hints->window_group) {
380 i = 1;
381 } else if (g1 && !g2) {
382 i = 3;
383 } else if (!g1 && g2) {
384 i = 4;
385 } else {
386 i = 0;
388 } else {
389 if (g1 && g2 && wwin->wm_hints->window_group != new_hints->window_group) {
390 i = 2;
391 } else if (g1 && !g2) {
392 i = 5;
393 } else if (!g1 && g2) {
394 i = 6;
395 } else {
396 i = 0;
400 /* Handling this may require more work. -Dan */
401 if (wwin->fake_group != NULL) {
402 i = 7;
405 if (wwin->wm_hints)
406 XFree(wwin->wm_hints);
408 wwin->wm_hints = new_hints;
410 /* do action according to state transition */
411 switch (i) {
412 /* 3 - change leader to value of CLIENT_LEADER */
413 case 3:
414 wApplicationDestroy(wApplicationOf(wwin->main_window));
415 wwin->main_window = wwin->client_leader;
416 wwin->group_id = None;
417 wApplicationCreate(wwin);
418 break;
420 /* 1,2,4 - change leader to new value of window_group */
421 case 1:
422 case 2:
423 case 4:
424 wApplicationDestroy(wApplicationOf(wwin->main_window));
425 wwin->main_window = new_hints->window_group;
426 wwin->group_id = wwin->main_window;
427 wApplicationCreate(wwin);
428 break;
430 /* 5 - destroy application */
431 case 5:
432 wApplicationDestroy(wApplicationOf(wwin->main_window));
433 wwin->main_window = None;
434 wwin->group_id = None;
435 break;
437 /* 6 - create application */
438 case 6:
439 wwin->main_window = new_hints->window_group;
440 wwin->group_id = wwin->main_window;
441 wApplicationCreate(wwin);
442 break;
443 /* 7 - we have a fake window group id, so just ignore anything else */
444 case 7:
445 break;
448 if (wwin->wm_hints) {
449 /* update icon */
450 if ((wwin->wm_hints->flags & IconPixmapHint)
451 || (wwin->wm_hints->flags & IconWindowHint)) {
452 WApplication *wapp;
454 if (wwin->flags.miniaturized && wwin->icon)
455 wIconUpdate(wwin->icon);
457 wapp = wApplicationOf(wwin->main_window);
458 if (wapp && wapp->app_icon) {
459 wIconUpdate(wapp->app_icon->icon);
460 wAppIconPaint(wapp->app_icon);
464 if (wwin->wm_hints->flags & UrgencyHint)
465 wwin->flags.urgent = 1;
466 else
467 wwin->flags.urgent = 0;
468 wAppBounceWhileUrgent(wApplicationOf(wwin->main_window));
469 /*} else if (wwin->fake_group!=NULL) {
470 wwin->group_id = wwin->fake_group->leader; */
471 } else {
472 wwin->group_id = None;
474 break;
476 case XA_WM_NORMAL_HINTS:
477 /* normal (geometry) hints */
479 int foo;
480 unsigned bar;
482 XGetWindowAttributes(dpy, wwin->client_win, &attribs);
483 wClientGetNormalHints(wwin, &attribs, False, &foo, &foo, &bar, &bar);
484 /* TODO: should we check for consistency of the current
485 * size against the new geometry hints? */
487 break;
489 case XA_WM_TRANSIENT_FOR:
491 Window new_owner;
492 WWindow *owner;
494 if (!XGetTransientForHint(dpy, wwin->client_win, &new_owner)) {
495 new_owner = None;
496 } else {
497 if (new_owner == 0 || new_owner == wwin->client_win) {
498 new_owner = wwin->screen_ptr->root_win;
501 if (new_owner != wwin->transient_for) {
502 owner = wWindowFor(wwin->transient_for);
503 if (owner) {
504 if (owner->flags.semi_focused) {
505 owner->flags.semi_focused = 0;
506 if ((owner->flags.mapped || owner->flags.shaded)
507 && owner->frame)
508 wFrameWindowPaint(owner->frame);
511 owner = wWindowFor(new_owner);
512 if (owner) {
513 if (!owner->flags.semi_focused) {
514 owner->flags.semi_focused = 1;
515 if ((owner->flags.mapped || owner->flags.shaded)
516 && owner->frame)
517 wFrameWindowPaint(owner->frame);
520 wwin->transient_for = new_owner;
521 if (new_owner == None) {
522 if (WFLAGP(wwin, no_miniaturizable)) {
523 WSETUFLAG(wwin, no_miniaturizable, 0);
524 WSETUFLAG(wwin, no_miniaturize_button, 0);
525 if (wwin->frame)
526 wWindowConfigureBorders(wwin);
528 } else if (!WFLAGP(wwin, no_miniaturizable)) {
529 WSETUFLAG(wwin, no_miniaturizable, 1);
530 WSETUFLAG(wwin, no_miniaturize_button, 1);
531 if (wwin->frame)
532 wWindowConfigureBorders(wwin);
536 break;
538 default:
539 if (event->atom == w_global.atom.wm.protocols) {
541 PropGetProtocols(wwin->client_win, &wwin->protocols);
543 WSETUFLAG(wwin, kill_close, !wwin->protocols.DELETE_WINDOW);
545 if (wwin->frame)
546 wWindowUpdateButtonImages(wwin);
548 } else if (event->atom == w_global.atom.wm.colormap_windows) {
550 GetColormapWindows(wwin);
551 wColormapInstallForWindow(wwin->screen_ptr, wwin);
553 } else if (event->atom == w_global.atom.wmaker.menu) {
554 WApplication *wapp;
556 wapp = wApplicationOf(wwin->main_window);
557 if (wapp) {
558 if (wapp->menu) {
559 /* update menu */
560 /* TODO: remake appmenu update */
561 wAppMenuDestroy(wapp->menu);
563 if (wwin->fake_group) {
564 WScreen *scr = wwin->screen_ptr;
565 WWindow *foo = scr->focused_window;
566 WFakeGroupLeader *fPtr = wwin->fake_group;
568 wApplicationDestroy(wapp);
569 while (foo) {
570 if (foo->fake_group && foo->fake_group == fPtr) {
571 WSETUFLAG(foo, shared_appicon, 0);
572 foo->fake_group = NULL;
573 if (foo->group_id != None)
574 foo->main_window = foo->group_id;
575 else if (foo->client_leader != None)
576 foo->main_window = foo->client_leader;
577 else if (WFLAGP(foo, emulate_appicon))
578 foo->main_window = foo->client_win;
579 else
580 foo->main_window = None;
581 if (foo->main_window) {
582 wapp = wApplicationCreate(foo);
585 foo = foo->prev;
588 if (fPtr->leader != None)
589 XDestroyWindow(dpy, fPtr->leader);
590 fPtr->retainCount = 0;
591 fPtr->leader = None;
592 fPtr->origLeader = None;
594 wapp = wApplicationOf(wwin->main_window);
595 if (wapp) {
596 wapp->menu = wAppMenuGet(scr, wwin->main_window);
598 if (wPreferences.auto_arrange_icons) {
599 wArrangeIcons(wwin->screen_ptr, True);
601 } else {
602 wapp->menu = wAppMenuGet(wwin->screen_ptr, wwin->main_window);
604 /* make the appmenu be mapped */
605 wSetFocusTo(wwin->screen_ptr, NULL);
606 wSetFocusTo(wwin->screen_ptr, wwin->screen_ptr->focused_window);
608 } else if (event->atom == w_global.atom.gnustep.wm_attr) {
609 GNUstepWMAttributes *attr;
611 PropGetGNUstepWMAttr(wwin->client_win, &attr);
613 wWindowUpdateGNUstepAttr(wwin, attr);
615 XFree(attr);
616 } else {
617 wNETWMCheckClientHintChange(wwin, event);
623 *----------------------------------------------------------------------
624 * wClientGetNormalHints--
625 * Get size (normal) hints and a default geometry for the client
626 * window. The hints are also checked for inconsistency. If geometry is
627 * True, the returned data will account for client specified initial
628 * geometry.
630 * Side effects:
631 * normal_hints is filled with valid data.
632 *----------------------------------------------------------------------
634 void
635 wClientGetNormalHints(WWindow * wwin, XWindowAttributes * wattribs, Bool geometry,
636 int *x, int *y, unsigned *width, unsigned *height)
638 int pre_icccm = 0; /* not used */
640 /* find a position for the window */
641 if (!wwin->normal_hints)
642 wwin->normal_hints = XAllocSizeHints();
644 if (!PropGetNormalHints(wwin->client_win, wwin->normal_hints, &pre_icccm)) {
645 wwin->normal_hints->flags = 0;
647 *x = wattribs->x;
648 *y = wattribs->y;
650 *width = wattribs->width;
651 *height = wattribs->height;
653 if (!(wwin->normal_hints->flags & PWinGravity)) {
654 wwin->normal_hints->win_gravity = NorthWestGravity;
656 if (!(wwin->normal_hints->flags & PMinSize)) {
657 wwin->normal_hints->min_width = MIN_WINDOW_SIZE;
658 wwin->normal_hints->min_height = MIN_WINDOW_SIZE;
660 if (!(wwin->normal_hints->flags & PBaseSize)) {
661 wwin->normal_hints->base_width = 0;
662 wwin->normal_hints->base_height = 0;
664 if (!(wwin->normal_hints->flags & PMaxSize)) {
665 wwin->normal_hints->max_width = wwin->screen_ptr->scr_width * 2;
666 wwin->normal_hints->max_height = wwin->screen_ptr->scr_height * 2;
669 /* some buggy apps set weird hints.. */
670 if (wwin->normal_hints->min_width <= 0)
671 wwin->normal_hints->min_width = MIN_WINDOW_SIZE;
673 if (wwin->normal_hints->min_height <= 0)
674 wwin->normal_hints->min_height = MIN_WINDOW_SIZE;
676 if (wwin->normal_hints->max_width < wwin->normal_hints->min_width)
677 wwin->normal_hints->max_width = wwin->normal_hints->min_width;
679 if (wwin->normal_hints->max_height < wwin->normal_hints->min_height)
680 wwin->normal_hints->max_height = wwin->normal_hints->min_height;
682 if (!(wwin->normal_hints->flags & PResizeInc)) {
683 wwin->normal_hints->width_inc = 1;
684 wwin->normal_hints->height_inc = 1;
685 } else {
686 if (wwin->normal_hints->width_inc <= 0)
687 wwin->normal_hints->width_inc = 1;
688 if (wwin->normal_hints->height_inc <= 0)
689 wwin->normal_hints->height_inc = 1;
692 if (wwin->normal_hints->flags & PAspect) {
693 if (wwin->normal_hints->min_aspect.x < 1)
694 wwin->normal_hints->min_aspect.x = 1;
695 if (wwin->normal_hints->min_aspect.y < 1)
696 wwin->normal_hints->min_aspect.y = 1;
698 if (wwin->normal_hints->max_aspect.x < 1)
699 wwin->normal_hints->max_aspect.x = 1;
700 if (wwin->normal_hints->max_aspect.y < 1)
701 wwin->normal_hints->max_aspect.y = 1;
704 if (wwin->normal_hints->min_height > wwin->normal_hints->max_height) {
705 wwin->normal_hints->min_height = wwin->normal_hints->max_height;
707 if (wwin->normal_hints->min_width > wwin->normal_hints->max_width) {
708 wwin->normal_hints->min_width = wwin->normal_hints->max_width;
710 #ifdef IGNORE_PPOSITION
711 wwin->normal_hints->flags &= ~PPosition;
712 #endif
714 if (pre_icccm && !wwin->screen_ptr->flags.startup && geometry) {
715 if (wwin->normal_hints->flags & (USPosition | PPosition)) {
716 *x = wwin->normal_hints->x;
717 *y = wwin->normal_hints->y;
719 if (wwin->normal_hints->flags & (USSize | PSize)) {
720 *width = wwin->normal_hints->width;
721 *height = wwin->normal_hints->height;
726 void GetColormapWindows(WWindow * wwin)
728 #ifndef NO_CRASHES
729 if (wwin->cmap_windows) {
730 XFree(wwin->cmap_windows);
733 wwin->cmap_windows = NULL;
734 wwin->cmap_window_no = 0;
736 if (!XGetWMColormapWindows(dpy, wwin->client_win, &(wwin->cmap_windows), &(wwin->cmap_window_no))
737 || !wwin->cmap_windows) {
738 wwin->cmap_window_no = 0;
739 wwin->cmap_windows = NULL;
741 #endif