Merge lp:~noskcaj/ubuntu/trusty/xfwm4/merge into lp:ubuntu/trusty/xfwm4

Proposed by Jackson Doak
Status: Merged
Merge reported by: Dmitry Shachnev
Merged at revision: not available
Proposed branch: lp:~noskcaj/ubuntu/trusty/xfwm4/merge
Merge into: lp:ubuntu/trusty/xfwm4
Diff against target: 4137 lines (+77/-3988)
8 files modified
.pc/8563.patch/src/client.c (+0/-3926)
.pc/applied-patches (+0/-1)
debian/changelog (+19/-0)
debian/patches/0001-fix-fullscreen-qt4-behavior-bug-8563.patch (+50/-0)
debian/patches/8563.patch (+0/-50)
debian/patches/series (+1/-1)
debian/rules (+1/-0)
src/client.c (+6/-10)
To merge this branch: bzr merge lp:~noskcaj/ubuntu/trusty/xfwm4/merge
Reviewer Review Type Date Requested Status
Dmitry Shachnev Approve
Ubuntu branches Pending
Review via email: mp+208941@code.launchpad.net

Description of the change

Merge from debian (no real changes)
Add build flags to enable xubuntu seamless greeter to desktop transition.

To post a comment you must log in.
Revision history for this message
Dmitry Shachnev (mitya57) wrote :

I took the liberty to replace CFLAGS to CPPFLAGS (since defines are taken care of by the preprocessor), and uploaded. Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed directory '.pc/8563.patch'
=== removed directory '.pc/8563.patch/src'
=== removed file '.pc/8563.patch/src/client.c'
--- .pc/8563.patch/src/client.c 2013-12-03 15:24:16 +0000
+++ .pc/8563.patch/src/client.c 1970-01-01 00:00:00 +0000
@@ -1,3926 +0,0 @@
1/* $Id$
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA.
17
18
19 oroborus - (c) 2001 Ken Lynch
20 xfwm4 - (c) 2002-2011 Olivier Fourdan
21
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <sys/types.h>
29#include <signal.h>
30#include <unistd.h>
31#include <errno.h>
32
33#include <X11/X.h>
34#include <X11/Xlib.h>
35#include <X11/Xutil.h>
36#include <X11/Xatom.h>
37#include <X11/extensions/shape.h>
38
39#include <glib.h>
40#include <gdk/gdk.h>
41#include <gdk/gdkx.h>
42#include <gtk/gtk.h>
43#include <libxfce4util/libxfce4util.h>
44
45#include "client.h"
46#include "compositor.h"
47#include "focus.h"
48#include "frame.h"
49#include "hints.h"
50#include "icons.h"
51#include "misc.h"
52#include "moveresize.h"
53#include "mypixmap.h"
54#include "mywindow.h"
55#include "netwm.h"
56#include "placement.h"
57#include "screen.h"
58#include "session.h"
59#include "settings.h"
60#include "stacking.h"
61#include "startup_notification.h"
62#include "transients.h"
63#include "workspaces.h"
64#include "xsync.h"
65#include "event_filter.h"
66
67/* Event mask definition */
68
69#define POINTER_EVENT_MASK \
70 ButtonPressMask|\
71 ButtonReleaseMask
72
73#define FRAME_EVENT_MASK \
74 SubstructureNotifyMask|\
75 SubstructureRedirectMask|\
76 PointerMotionMask|\
77 ButtonMotionMask|\
78 FocusChangeMask|\
79 EnterWindowMask|\
80 PropertyChangeMask
81
82#define CLIENT_EVENT_MASK \
83 StructureNotifyMask|\
84 FocusChangeMask|\
85 PropertyChangeMask
86
87#define BUTTON_EVENT_MASK \
88 EnterWindowMask|\
89 LeaveWindowMask
90
91/* Useful macros */
92#define START_ICONIC(c) \
93 ((c->wmhints) && \
94 (c->wmhints->initial_state == IconicState) && \
95 !clientIsTransientOrModal (c))
96
97#define OPACITY_SET_STEP (guint) 0x16000000
98#define OPACITY_SET_MIN (guint) 0x40000000
99
100typedef struct _ButtonPressData ButtonPressData;
101struct _ButtonPressData
102{
103 int b;
104 Client *c;
105};
106
107/* Forward decl */
108static void
109clientUpdateIconPix (Client *c);
110static gboolean
111clientNewMaxSize (Client *c, XWindowChanges *wc, GdkRectangle *, tilePositionType tile);
112
113Display *
114clientGetXDisplay (Client *c)
115{
116 g_return_val_if_fail (c, NULL);
117
118 return myScreenGetXDisplay (c->screen_info);
119}
120
121void
122clientInstallColormaps (Client *c)
123{
124 XWindowAttributes attr;
125 gboolean installed;
126 int i;
127
128 g_return_if_fail (c != NULL);
129 TRACE ("entering clientInstallColormaps");
130
131 installed = FALSE;
132 if (c->ncmap)
133 {
134 for (i = c->ncmap - 1; i >= 0; i--)
135 {
136 XGetWindowAttributes (clientGetXDisplay (c), c->cmap_windows[i], &attr);
137 XInstallColormap (clientGetXDisplay (c), attr.colormap);
138 if (c->cmap_windows[i] == c->window)
139 {
140 installed = TRUE;
141 }
142 }
143 }
144 if ((!installed) && (c->cmap))
145 {
146 XInstallColormap (clientGetXDisplay (c), c->cmap);
147 }
148}
149
150void
151clientUpdateColormaps (Client *c)
152{
153 g_return_if_fail (c != NULL);
154 TRACE ("entering clientUpdateColormaps");
155
156 if (c->ncmap)
157 {
158 XFree (c->cmap_windows);
159 c->ncmap = 0;
160 }
161 if (!XGetWMColormapWindows (clientGetXDisplay (c), c->window, &c->cmap_windows, &c->ncmap))
162 {
163 c->cmap_windows = NULL;
164 c->ncmap = 0;
165 }
166}
167
168static gchar*
169clientCreateTitleName (Client *c, gchar *name, gchar *hostname)
170{
171 ScreenInfo *screen_info;
172 DisplayInfo *display_info;
173 gchar *title;
174
175 g_return_val_if_fail (c != NULL, NULL);
176 TRACE ("entering clientCreateTitleName");
177
178 screen_info = c->screen_info;
179 display_info = screen_info->display_info;
180
181 if (strlen (hostname) && (display_info->hostname) && (g_ascii_strcasecmp (display_info->hostname, hostname)))
182 {
183 /* TRANSLATORS: "(on %s)" is like "running on" the name of the other host */
184 title = g_strdup_printf (_("%s (on %s)"), name, hostname);
185 }
186 else
187 {
188 title = g_strdup (name);
189 }
190
191 return title;
192}
193
194void
195clientUpdateName (Client *c)
196{
197 ScreenInfo *screen_info;
198 DisplayInfo *display_info;
199 gchar *hostname;
200 gchar *wm_name;
201 gchar *name;
202 gboolean refresh;
203
204 g_return_if_fail (c != NULL);
205 TRACE ("entering clientUpdateName");
206
207 screen_info = c->screen_info;
208 display_info = screen_info->display_info;
209
210 getWindowName (display_info, c->window, &wm_name);
211 getWindowHostname (display_info, c->window, &hostname);
212 refresh = FALSE;
213
214 /* Update hostname too, as it's used when terminating a client */
215 if (hostname)
216 {
217 if (c->hostname)
218 {
219 g_free (c->hostname);
220 }
221 c->hostname = hostname;
222 }
223
224 if (wm_name)
225 {
226 name = clientCreateTitleName (c, wm_name, hostname);
227 g_free (wm_name);
228 if (c->name)
229 {
230 if (strcmp (name, c->name))
231 {
232 refresh = TRUE;
233 FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
234 }
235 g_free (c->name);
236 }
237 c->name = name;
238 }
239
240 if (refresh)
241 {
242 frameQueueDraw (c, TRUE);
243 }
244}
245
246void
247clientUpdateAllFrames (ScreenInfo *screen_info, int mask)
248{
249 Client *c;
250 XWindowChanges wc;
251 guint i;
252
253 g_return_if_fail (screen_info != NULL);
254
255 TRACE ("entering clientRedrawAllFrames");
256 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, i++)
257 {
258 unsigned long configure_flags = 0L;
259
260 if (mask & UPDATE_BUTTON_GRABS)
261 {
262 clientUngrabButtons (c);
263 clientGrabButtons (c);
264 clientGrabMouseButton (c);
265 }
266 if (mask & UPDATE_CACHE)
267 {
268 clientUpdateIconPix (c);
269 }
270 if (mask & UPDATE_GRAVITY)
271 {
272 clientCoordGravitate (c, c->gravity, REMOVE, &c->x, &c->y);
273 clientCoordGravitate (c, c->gravity, APPLY, &c->x, &c->y);
274 setNetFrameExtents (screen_info->display_info,
275 c->window,
276 frameTop (c),
277 frameLeft (c),
278 frameRight (c),
279 frameBottom (c));
280 configure_flags |= CFG_FORCE_REDRAW;
281 mask &= ~UPDATE_FRAME;
282 }
283 if (mask & UPDATE_MAXIMIZE)
284 {
285 unsigned long maximization_flags = 0L;
286
287 /* Recompute size and position of maximized windows */
288 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT))
289 {
290 maximization_flags = c->flags & CLIENT_FLAG_MAXIMIZED;
291
292 /* Force an update by clearing the internal flags */
293 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
294 clientToggleMaximized (c, maximization_flags, FALSE);
295
296 configure_flags |= CFG_FORCE_REDRAW;
297 mask &= ~UPDATE_FRAME;
298 }
299 }
300 if (configure_flags != 0L)
301 {
302 wc.x = c->x;
303 wc.y = c->y;
304 wc.width = c->width;
305 wc.height = c->height;
306 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, configure_flags);
307 }
308 if (mask & UPDATE_FRAME)
309 {
310 frameQueueDraw (c, TRUE);
311 }
312
313 }
314}
315
316void
317clientGrabButtons (Client *c)
318{
319 ScreenInfo *screen_info;
320
321 g_return_if_fail (c != NULL);
322 TRACE ("entering clientGrabButtons");
323 TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
324
325 screen_info = c->screen_info;
326 if (screen_info->params->easy_click)
327 {
328 grabButton(clientGetXDisplay (c), AnyButton, screen_info->params->easy_click, c->window);
329 }
330}
331
332void
333clientUngrabButtons (Client *c)
334{
335 g_return_if_fail (c != NULL);
336 TRACE ("entering clientUngrabButtons");
337 TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
338
339 XUngrabButton (clientGetXDisplay (c), AnyButton, AnyModifier, c->window);
340}
341
342static gboolean
343urgent_cb (gpointer data)
344{
345 Client *c;
346 ScreenInfo *screen_info;
347
348 c = (Client *) data;
349 g_return_val_if_fail (c != NULL, FALSE);
350 TRACE ("entering urgent_cb, iteration %i", c->blink_iterations);
351 screen_info = c->screen_info;
352
353 if (c != clientGetFocus ())
354 {
355 /*
356 * If we do not blink on urgency, check if the window was last
357 * drawn focused and redraw it unfocused.
358 * This is for th case when the tuser changes the settings
359 * in between two redraws.
360 */
361 if (!screen_info->params->urgent_blink)
362 {
363 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE))
364 {
365 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
366 frameQueueDraw (c, FALSE);
367 }
368
369 if (c->blink_iterations)
370 {
371 c->blink_iterations = 0;
372 }
373 return TRUE;
374 }
375 /*
376 * If we blink on urgency, check if we've not reach the number
377 * of iterations and if not, simply change the status and redraw
378 */
379 if (c->blink_iterations < (2 * MAX_BLINK_ITERATIONS))
380 {
381 c->blink_iterations++;
382 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
383 frameQueueDraw (c, FALSE);
384 return TRUE;
385 }
386 /*
387 * If we reached the max number of iterations, check if we
388 * repeat. If repeat_urgent_blink is set, redraw the frame and
389 * restart counting from 1
390 */
391 if (screen_info->params->repeat_urgent_blink)
392 {
393 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
394 frameQueueDraw (c, FALSE);
395 c->blink_iterations = 1;
396 return TRUE;
397 }
398 }
399 else if (c->blink_iterations)
400 {
401 c->blink_iterations = 0;
402 }
403 return (TRUE);
404}
405
406void
407clientUpdateUrgency (Client *c)
408{
409 g_return_if_fail (c != NULL);
410
411 TRACE ("entering clientUpdateUrgency");
412
413 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
414 if (c->blink_timeout_id)
415 {
416 g_source_remove (c->blink_timeout_id);
417 frameQueueDraw (c, FALSE);
418 }
419 FLAG_UNSET (c->wm_flags, WM_FLAG_URGENT);
420
421 c->blink_timeout_id = 0;
422 c->blink_iterations = 0;
423 if ((c->wmhints) && (c->wmhints->flags & XUrgencyHint))
424 {
425 FLAG_SET (c->wm_flags, WM_FLAG_URGENT);
426 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
427 {
428 c->blink_timeout_id =
429 g_timeout_add_full (G_PRIORITY_DEFAULT,
430 CLIENT_BLINK_TIMEOUT,
431 (GtkFunction) urgent_cb,
432 (gpointer) c, NULL);
433 }
434 }
435 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE)
436 && !FLAG_TEST (c->wm_flags, WM_FLAG_URGENT)
437 && (c != clientGetFocus ()))
438 {
439 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
440 frameQueueDraw (c, FALSE);
441 }
442}
443
444void
445clientCoordGravitate (Client *c, int gravity, int mode, int *x, int *y)
446{
447 int dx, dy;
448
449 g_return_if_fail (c != NULL);
450 TRACE ("entering clientCoordGravitate");
451
452 switch (gravity)
453 {
454 case CenterGravity:
455 dx = (c->border_width * 2) - ((frameLeft (c) +
456 frameRight (c)) / 2);
457 dy = (c->border_width * 2) - ((frameTop (c) +
458 frameBottom (c)) / 2);
459 break;
460 case NorthGravity:
461 dx = (c->border_width * 2) - ((frameLeft (c) +
462 frameRight (c)) / 2);
463 dy = frameTop (c);
464 break;
465 case SouthGravity:
466 dx = (c->border_width * 2) - ((frameLeft (c) +
467 frameRight (c)) / 2);
468 dy = (c->border_width * 2) - frameBottom (c);
469 break;
470 case EastGravity:
471 dx = (c->border_width * 2) - frameRight (c);
472 dy = (c->border_width * 2) - ((frameTop (c) +
473 frameBottom (c)) / 2);
474 break;
475 case WestGravity:
476 dx = frameLeft (c);
477 dy = (c->border_width * 2) - ((frameTop (c) +
478 frameBottom (c)) / 2);
479 break;
480 case NorthWestGravity:
481 dx = frameLeft (c);
482 dy = frameTop (c);
483 break;
484 case NorthEastGravity:
485 dx = (c->border_width * 2) - frameRight (c);
486 dy = frameTop (c);
487 break;
488 case SouthWestGravity:
489 dx = frameLeft (c);
490 dy = (c->border_width * 2) - frameBottom (c);
491 break;
492 case SouthEastGravity:
493 dx = (c->border_width * 2) - frameRight (c);
494 dy = (c->border_width * 2) - frameBottom (c);
495 break;
496 default:
497 dx = 0;
498 dy = 0;
499 break;
500 }
501 *x = *x + (dx * mode);
502 *y = *y + (dy * mode);
503}
504
505void
506clientAdjustCoordGravity (Client *c, int gravity, unsigned long *mask, XWindowChanges *wc)
507{
508 int tx, ty, dw, dh;
509
510 g_return_if_fail (c != NULL);
511 TRACE ("entering clientAdjustCoordGravity");
512
513 tx = wc->x;
514 ty = wc->y;
515 clientCoordGravitate (c, gravity, APPLY, &tx, &ty);
516
517 switch (gravity)
518 {
519 case CenterGravity:
520 dw = (c->width - wc->width) / 2;
521 dh = (c->height - wc->height) / 2;
522 break;
523 case NorthGravity:
524 dw = (c->width - wc->width) / 2;
525 dh = 0;
526 break;
527 case SouthGravity:
528 dw = (c->width - wc->width) / 2;
529 dh = (c->height - wc->height);
530 break;
531 case EastGravity:
532 dw = (c->width - wc->width);
533 dh = (c->height - wc->height) / 2;
534 break;
535 case WestGravity:
536 dw = 0;
537 dh = (c->height - wc->height) / 2;
538 break;
539 case NorthWestGravity:
540 dw = 0;
541 dh = 0;
542 break;
543 case NorthEastGravity:
544 dw = (c->width - wc->width);
545 dh = 0;
546 break;
547 case SouthWestGravity:
548 dw = 0;
549 dh = (c->height - wc->height);
550 break;
551 case SouthEastGravity:
552 dw = (c->width - wc->width);
553 dh = (c->height - wc->height);
554 break;
555 default:
556 dw = 0;
557 dh = 0;
558 break;
559 }
560
561 if (*mask & CWX)
562 {
563 wc->x = tx;
564 }
565 else if (*mask & CWWidth)
566 {
567 wc->x = c->x + dw;
568 *mask |= CWX;
569 }
570
571 if (*mask & CWY)
572 {
573 wc->y = ty;
574 }
575 else if (*mask & CWHeight)
576 {
577 wc->y = c->y + dh;
578 *mask |= CWY;
579 }
580}
581
582#define WIN_MOVED (mask & (CWX | CWY))
583#define WIN_RESIZED (mask & (CWWidth | CWHeight))
584
585static void
586clientConfigureWindows (Client *c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
587{
588 unsigned long change_mask_frame, change_mask_client;
589 XWindowChanges change_values;
590 DisplayInfo *display_info;
591 ScreenInfo *screen_info;
592
593 screen_info = c->screen_info;
594 display_info = screen_info->display_info;
595
596 change_mask_frame = mask & (CWX | CWY | CWWidth | CWHeight);
597 change_mask_client = mask & (CWWidth | CWHeight);
598
599 if ((WIN_RESIZED) || (flags & CFG_FORCE_REDRAW))
600 {
601 frameDraw (c, (flags & CFG_FORCE_REDRAW));
602 }
603
604 if (flags & CFG_FORCE_REDRAW)
605 {
606 change_mask_client |= (CWX | CWY);
607 }
608
609 if (change_mask_frame & (CWX | CWY | CWWidth | CWHeight))
610 {
611 change_values.x = frameX (c);
612 change_values.y = frameY (c);
613 change_values.width = frameWidth (c);
614 change_values.height = frameHeight (c);
615 XConfigureWindow (display_info->dpy, c->frame, change_mask_frame, &change_values);
616 }
617
618 if (change_mask_client & (CWX | CWY | CWWidth | CWHeight))
619 {
620 change_values.x = frameLeft (c);
621 change_values.y = frameTop (c);
622 change_values.width = c->width;
623 change_values.height = c->height;
624 XConfigureWindow (display_info->dpy, c->window, change_mask_client, &change_values);
625 }
626 if (WIN_RESIZED)
627 {
628 compositorResizeWindow (display_info, c->frame, frameX (c), frameY (c), frameWidth (c), frameHeight (c));
629 }
630}
631
632void
633clientConfigure (Client *c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
634{
635 XConfigureEvent ce;
636 int px, py, pwidth, pheight;
637
638 g_return_if_fail (c != NULL);
639 g_return_if_fail (c->window != None);
640
641 TRACE ("entering clientConfigure");
642 TRACE ("configuring client \"%s\" (0x%lx) %s, type %u", c->name,
643 c->window, flags & CFG_CONSTRAINED ? "constrained" : "not contrained", c->type);
644
645 px = c->x;
646 py = c->y;
647 pwidth = c->width;
648 pheight = c->height;
649
650 if (mask & CWX)
651 {
652 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
653 {
654 c->x = wc->x;
655 }
656 }
657 if (mask & CWY)
658 {
659 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
660 {
661 c->y = wc->y;
662 }
663 }
664 if (mask & CWWidth)
665 {
666 clientSetWidth (c, wc->width, flags & CFG_REQUEST);
667 }
668 if (mask & CWHeight)
669 {
670 clientSetHeight (c, wc->height, flags & CFG_REQUEST);
671 }
672 if (mask & CWBorderWidth)
673 {
674 c->border_width = wc->border_width;
675 }
676 if (mask & CWStackMode)
677 {
678 switch (wc->stack_mode)
679 {
680 /*
681 * Limitation: we don't support neither
682 * TopIf, BottomIf nor Opposite ...
683 */
684 case Above:
685 TRACE ("Above");
686 if (mask & CWSibling)
687 {
688 clientRaise (c, wc->sibling);
689 }
690 else
691 {
692 clientRaise (c, None);
693 }
694 break;
695 case Below:
696 TRACE ("Below");
697 if (mask & CWSibling)
698 {
699 clientLower (c, wc->sibling);
700 }
701 else
702 {
703 clientLower (c, None);
704 }
705
706 break;
707 case Opposite:
708 case TopIf:
709 case BottomIf:
710 default:
711 break;
712 }
713 }
714 mask &= ~(CWStackMode | CWSibling);
715
716 /* Keep control over what the application does. */
717 if (((flags & (CFG_CONSTRAINED | CFG_REQUEST)) == (CFG_CONSTRAINED | CFG_REQUEST))
718 && CONSTRAINED_WINDOW (c))
719 {
720 clientConstrainPos (c, flags & CFG_KEEP_VISIBLE);
721
722 if (c->x != px)
723 {
724 mask |= CWX;
725 }
726 else
727 {
728 mask &= ~CWX;
729 }
730
731 if (c->y != py)
732 {
733 mask |= CWY;
734 }
735 else
736 {
737 mask &= ~CWY;
738 }
739
740 if (c->width != pwidth)
741 {
742 mask |= CWWidth;
743 }
744 else
745 {
746 mask &= ~CWWidth;
747 }
748 if (c->height != pheight)
749 {
750 mask |= CWHeight;
751 }
752 else
753 {
754 mask &= ~CWHeight;
755 }
756 }
757
758 clientConfigureWindows (c, wc, mask, flags);
759 /*
760
761 We reparent the client window. According to the ICCCM spec, the
762 WM must send a senthetic event when the window is moved and not resized.
763
764 But, since we reparent the window, we must also send a synthetic
765 configure event when the window is moved and resized.
766
767 See this thread for the rational:
768 http://www.mail-archive.com/wm-spec-list@gnome.org/msg00379.html
769
770 And specifically this post from Carsten Haitzler:
771 http://www.mail-archive.com/wm-spec-list@gnome.org/msg00382.html
772
773 */
774 if ((WIN_MOVED) || (flags & CFG_NOTIFY) ||
775 ((flags & CFG_REQUEST) && !(WIN_MOVED || WIN_RESIZED)))
776 {
777 DBG ("Sending ConfigureNotify");
778 ce.type = ConfigureNotify;
779 ce.display = clientGetXDisplay (c);
780 ce.event = c->window;
781 ce.window = c->window;
782 ce.x = c->x;
783 ce.y = c->y;
784 ce.width = c->width;
785 ce.height = c->height;
786 ce.border_width = 0;
787 ce.above = c->frame;
788 ce.override_redirect = FALSE;
789 XSendEvent (clientGetXDisplay (c), c->window, FALSE,
790 StructureNotifyMask, (XEvent *) & ce);
791 }
792#undef WIN_MOVED
793#undef WIN_RESIZED
794}
795
796void
797clientMoveResizeWindow (Client *c, XWindowChanges * wc, unsigned long mask)
798{
799 ScreenInfo *screen_info;
800 DisplayInfo *display_info;
801 unsigned short flags;
802
803 g_return_if_fail (c != NULL);
804 TRACE ("entering clientMoveResizeWindow");
805 TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
806
807 screen_info = c->screen_info;
808 display_info = screen_info->display_info;
809 if (c->type == WINDOW_DESKTOP)
810 {
811 /* Ignore stacking request for DESKTOP windows */
812 mask &= ~(CWSibling | CWStackMode);
813 }
814 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
815 || (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
816 && (screen_info->params->borderless_maximize)))
817 {
818 /* Not allowed in fullscreen or maximzed mode */
819 mask &= ~(CWX | CWY | CWWidth | CWHeight);
820 }
821 /*clean up buggy requests that set all flags */
822 if ((mask & CWX) && (wc->x == c->x))
823 {
824 mask &= ~CWX;
825 }
826 if ((mask & CWY) && (wc->y == c->y))
827 {
828 mask &= ~CWY;
829 }
830 if ((mask & CWWidth) && (wc->width == c->width))
831 {
832 mask &= ~CWWidth;
833 }
834 if ((mask & CWHeight) && (wc->height == c->height))
835 {
836 mask &= ~CWHeight;
837 }
838
839 /* Still a move/resize after cleanup? */
840 flags = CFG_REQUEST;
841 if (mask & (CWX | CWY | CWWidth | CWHeight))
842 {
843 /* Clear any previously saved pos flag from screen resize */
844 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SAVED_POS);
845
846 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
847 {
848 clientRemoveMaximizeFlag (c);
849 }
850
851 flags |= CFG_REQUEST | CFG_CONSTRAINED;
852 }
853 if ((mask & (CWWidth | CWHeight)) && !(mask & (CWX | CWY)))
854 {
855 /*
856 * The client is resizing its window, but did not specify a
857 * position, make sure the window remains fully visible in that
858 *case so that the user does not have to relocate the window
859 */
860 flags |= CFG_KEEP_VISIBLE;
861 }
862 /*
863 * Let's say that if the client performs a XRaiseWindow, we show the window if focus
864 * stealing prevention is not activated, otherwise we just set the "demands attention"
865 * flag...
866 */
867 if ((mask & CWStackMode) && (wc->stack_mode == Above) && (wc->sibling == None) && !(c->type & WINDOW_TYPE_DONT_FOCUS))
868 {
869 Client *last_raised;
870
871 last_raised = clientGetLastRaise (screen_info);
872 if (last_raised && (c != last_raised))
873 {
874 if ((screen_info->params->prevent_focus_stealing) && (screen_info->params->activate_action == ACTIVATE_ACTION_NONE))
875 {
876 mask &= ~(CWSibling | CWStackMode);
877 TRACE ("Setting WM_STATE_DEMANDS_ATTENTION flag on \"%s\" (0x%lx)", c->name, c->window);
878 FLAG_SET (c->flags, CLIENT_FLAG_DEMANDS_ATTENTION);
879 clientSetNetState (c);
880 }
881 else
882 {
883 clientActivate (c, getXServerTime (display_info), FALSE);
884 }
885 }
886 }
887 /* And finally, configure the window */
888 clientConfigure (c, wc, mask, flags);
889}
890
891void
892clientGetMWMHints (Client *c, gboolean update)
893{
894 ScreenInfo *screen_info;
895 DisplayInfo *display_info;
896 PropMwmHints *mwm_hints;
897 XWindowChanges wc;
898
899 g_return_if_fail (c != NULL);
900 g_return_if_fail (c->window != None);
901
902 TRACE ("entering clientGetMWMHints client \"%s\" (0x%lx)", c->name,
903 c->window);
904
905 screen_info = c->screen_info;
906 display_info = screen_info->display_info;
907
908 mwm_hints = getMotifHints (display_info, c->window);
909 if (mwm_hints)
910 {
911 if ((mwm_hints->flags & MWM_HINTS_DECORATIONS))
912 {
913 if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_SHAPE))
914 {
915 if (mwm_hints->decorations & MWM_DECOR_ALL)
916 {
917 FLAG_SET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
918 }
919 else
920 {
921 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
922 FLAG_SET (c->xfwm_flags, (mwm_hints-> decorations & (MWM_DECOR_TITLE | MWM_DECOR_BORDER))
923 ? XFWM_FLAG_HAS_BORDER : 0);
924 FLAG_SET (c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MENU))
925 ? XFWM_FLAG_HAS_MENU : 0);
926 /*
927 FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
928 FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
929 FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MINIMIZE)) ? XFWM_FLAG_HAS_HIDE : 0);
930 FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MAXIMIZE)) ? XFWM_FLAG_HAS_MAXIMIZE : 0);
931 */
932 }
933 }
934 }
935 /* The following is from Metacity : */
936 if (mwm_hints->flags & MWM_HINTS_FUNCTIONS)
937 {
938 if (!(mwm_hints->functions & MWM_FUNC_ALL))
939 {
940 FLAG_UNSET (c->xfwm_flags,
941 XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
942 XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
943 XFWM_FLAG_HAS_RESIZE);
944 }
945 else
946 {
947 FLAG_SET (c->xfwm_flags,
948 XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
949 XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
950 XFWM_FLAG_HAS_RESIZE);
951 }
952
953 if (mwm_hints->functions & MWM_FUNC_CLOSE)
954 {
955 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE);
956 }
957 if (mwm_hints->functions & MWM_FUNC_MINIMIZE)
958 {
959 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
960 }
961 if (mwm_hints->functions & MWM_FUNC_MAXIMIZE)
962 {
963 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
964 }
965 if (mwm_hints->functions & MWM_FUNC_RESIZE)
966 {
967 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_RESIZE);
968 }
969 if (mwm_hints->functions & MWM_FUNC_MOVE)
970 {
971 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MOVE);
972 }
973 }
974 g_free (mwm_hints);
975 }
976
977 if (update)
978 {
979 wc.x = c->x;
980 wc.y = c->y;
981 wc.width = c->width;
982 wc.height = c->height;
983
984 /* If client is maximized, we need to update its coordonates and size as well */
985 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
986 {
987 GdkRectangle rect;
988 myScreenFindMonitorAtPoint (screen_info,
989 frameX (c) + (frameWidth (c) / 2),
990 frameY (c) + (frameHeight (c) / 2), &rect);
991 clientNewMaxSize (c, &wc, &rect, TILE_NONE);
992 }
993
994 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_FORCE_REDRAW);
995
996 /* MWM hints can add or remove decorations, update NET_FRAME_EXTENTS accordingly */
997 setNetFrameExtents (display_info,
998 c->window,
999 frameTop (c),
1000 frameLeft (c),
1001 frameRight (c),
1002 frameBottom (c));
1003 }
1004}
1005
1006void
1007clientGetWMNormalHints (Client *c, gboolean update)
1008{
1009 XWindowChanges wc;
1010 unsigned long previous_value;
1011 long dummy;
1012
1013 g_return_if_fail (c != NULL);
1014 g_return_if_fail (c->window != None);
1015
1016 TRACE ("entering clientGetWMNormalHints client \"%s\" (0x%lx)", c->name,
1017 c->window);
1018
1019 if (!c->size)
1020 {
1021 c->size = XAllocSizeHints ();
1022 }
1023 g_assert (c->size);
1024
1025 dummy = 0;
1026 if (!XGetWMNormalHints (clientGetXDisplay (c), c->window, c->size, &dummy))
1027 {
1028 c->size->flags = 0;
1029 }
1030
1031 /* Set/update gravity */
1032 c->gravity = c->size->flags & PWinGravity ? c->size->win_gravity : NorthWestGravity;
1033
1034 previous_value = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1035 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1036
1037 wc.x = c->x;
1038 wc.y = c->y;
1039 wc.width = c->width;
1040 wc.height = c->height;
1041
1042 if (!(c->size->flags & PMaxSize))
1043 {
1044 c->size->max_width = G_MAXINT;
1045 c->size->max_height = G_MAXINT;
1046 c->size->flags |= PMaxSize;
1047 }
1048
1049 if (!(c->size->flags & PBaseSize))
1050 {
1051 c->size->base_width = 0;
1052 c->size->base_height = 0;
1053 }
1054
1055 if (!(c->size->flags & PMinSize))
1056 {
1057 if ((c->size->flags & PBaseSize))
1058 {
1059 c->size->min_width = c->size->base_width;
1060 c->size->min_height = c->size->base_height;
1061 }
1062 else
1063 {
1064 c->size->min_width = 1;
1065 c->size->min_height = 1;
1066 }
1067 c->size->flags |= PMinSize;
1068 }
1069
1070 if (c->size->flags & PResizeInc)
1071 {
1072 if (c->size->width_inc < 1)
1073 {
1074 c->size->width_inc = 1;
1075 }
1076 if (c->size->height_inc < 1)
1077 {
1078 c->size->height_inc = 1;
1079 }
1080 }
1081 else
1082 {
1083 c->size->width_inc = 1;
1084 c->size->height_inc = 1;
1085 }
1086
1087 if (c->size->flags & PAspect)
1088 {
1089 if (c->size->min_aspect.x < 1)
1090 {
1091 c->size->min_aspect.x = 1;
1092 }
1093 if (c->size->min_aspect.y < 1)
1094 {
1095 c->size->min_aspect.y = 1;
1096 }
1097 if (c->size->max_aspect.x < 1)
1098 {
1099 c->size->max_aspect.x = 1;
1100 }
1101 if (c->size->max_aspect.y < 1)
1102 {
1103 c->size->max_aspect.y = 1;
1104 }
1105 }
1106 else
1107 {
1108 c->size->min_aspect.x = 1;
1109 c->size->min_aspect.y = 1;
1110 c->size->max_aspect.x = G_MAXINT;
1111 c->size->max_aspect.y = G_MAXINT;
1112 }
1113
1114 if (c->size->min_width < 1)
1115 {
1116 c->size->min_width = 1;
1117 }
1118 if (c->size->min_height < 1)
1119 {
1120 c->size->min_height = 1;
1121 }
1122 if (c->size->max_width < 1)
1123 {
1124 c->size->max_width = 1;
1125 }
1126 if (c->size->max_height < 1)
1127 {
1128 c->size->max_height = 1;
1129 }
1130 if (wc.width > c->size->max_width)
1131 {
1132 wc.width = c->size->max_width;
1133 }
1134 if (wc.height > c->size->max_height)
1135 {
1136 wc.height = c->size->max_height;
1137 }
1138 if (wc.width < c->size->min_width)
1139 {
1140 wc.width = c->size->min_width;
1141 }
1142 if (wc.height < c->size->min_height)
1143 {
1144 wc.height = c->size->min_height;
1145 }
1146
1147 if ((c->size->min_width < c->size->max_width) ||
1148 (c->size->min_height < c->size->max_height))
1149 {
1150 FLAG_SET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1151 }
1152
1153 if (update)
1154 {
1155 if ((c->width != wc.width) || (c->height != wc.height))
1156 {
1157 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
1158 {
1159 clientRemoveMaximizeFlag (c);
1160 }
1161 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_CONSTRAINED | CFG_FORCE_REDRAW);
1162 }
1163 else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE) != previous_value)
1164 {
1165 frameQueueDraw (c, FALSE);
1166 }
1167 }
1168 else
1169 {
1170 c->width = wc.width;
1171 c->height = wc.height;
1172 }
1173}
1174
1175void
1176clientGetWMProtocols (Client *c)
1177{
1178 ScreenInfo *screen_info;
1179 DisplayInfo *display_info;
1180 unsigned int wm_protocols_flags;
1181
1182 g_return_if_fail (c != NULL);
1183 g_return_if_fail (c->window != None);
1184
1185 TRACE ("entering clientGetWMProtocols client \"%s\" (0x%lx)", c->name,
1186 c->window);
1187
1188 screen_info = c->screen_info;
1189 display_info = screen_info->display_info;
1190
1191 wm_protocols_flags = getWMProtocols (display_info, c->window);
1192 FLAG_SET (c->wm_flags,
1193 (wm_protocols_flags & WM_PROTOCOLS_DELETE_WINDOW) ?
1194 WM_FLAG_DELETE : 0);
1195 FLAG_SET (c->wm_flags,
1196 (wm_protocols_flags & WM_PROTOCOLS_TAKE_FOCUS) ?
1197 WM_FLAG_TAKEFOCUS : 0);
1198 /* KDE extension */
1199 FLAG_SET (c->wm_flags,
1200 (wm_protocols_flags & WM_PROTOCOLS_CONTEXT_HELP) ?
1201 WM_FLAG_CONTEXT_HELP : 0);
1202 /* Ping */
1203 FLAG_SET (c->wm_flags,
1204 (wm_protocols_flags & WM_PROTOCOLS_PING) ?
1205 WM_FLAG_PING : 0);
1206}
1207
1208static void
1209clientFree (Client *c)
1210{
1211 g_return_if_fail (c != NULL);
1212
1213 TRACE ("entering clientFree");
1214 TRACE ("freeing client \"%s\" (0x%lx)", c->name, c->window);
1215
1216 clientClearFocus (c);
1217 if (clientGetLastRaise (c->screen_info) == c)
1218 {
1219 clientClearLastRaise (c->screen_info);
1220 }
1221 if (clientGetDelayedFocus () == c)
1222 {
1223 clientClearDelayedFocus ();
1224 }
1225 if (c->blink_timeout_id)
1226 {
1227 g_source_remove (c->blink_timeout_id);
1228 }
1229 if (c->icon_timeout_id)
1230 {
1231 g_source_remove (c->icon_timeout_id);
1232 }
1233 if (c->frame_timeout_id)
1234 {
1235 g_source_remove (c->frame_timeout_id);
1236 }
1237 if (c->ping_timeout_id)
1238 {
1239 clientRemoveNetWMPing (c);
1240 }
1241 if (c->name)
1242 {
1243 g_free (c->name);
1244 }
1245 if (c->hostname)
1246 {
1247 g_free (c->hostname);
1248 }
1249#ifdef HAVE_XSYNC
1250 if (c->xsync_alarm != None)
1251 {
1252 clientDestroyXSyncAlarm (c);
1253 }
1254 if (c->xsync_timeout_id)
1255 {
1256 g_source_remove (c->xsync_timeout_id);
1257 }
1258#endif /* HAVE_XSYNC */
1259#ifdef HAVE_LIBSTARTUP_NOTIFICATION
1260 if (c->startup_id)
1261 {
1262 g_free (c->startup_id);
1263 }
1264#endif /* HAVE_LIBSTARTUP_NOTIFICATION */
1265 if (c->size)
1266 {
1267 XFree (c->size);
1268 }
1269 if (c->wmhints)
1270 {
1271 XFree (c->wmhints);
1272 }
1273 if ((c->ncmap > 0) && (c->cmap_windows))
1274 {
1275 XFree (c->cmap_windows);
1276 }
1277 if (c->class.res_name)
1278 {
1279 XFree (c->class.res_name);
1280 }
1281 if (c->class.res_class)
1282 {
1283 XFree (c->class.res_class);
1284 }
1285 if (c->dialog_pid)
1286 {
1287 kill (c->dialog_pid, SIGKILL);
1288 }
1289 if (c->dialog_fd >= 0)
1290 {
1291 close (c->dialog_fd);
1292 }
1293
1294 g_free (c);
1295}
1296
1297static void
1298clientApplyInitialState (Client *c)
1299{
1300 g_return_if_fail (c != NULL);
1301
1302 TRACE ("entering clientApplyInitialState");
1303
1304 /* We check that afterwards to make sure all states are now known */
1305 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
1306 {
1307 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1308 {
1309 unsigned long mode = 0L;
1310
1311 TRACE ("Applying client's initial state: maximized");
1312 mode = c->flags & CLIENT_FLAG_MAXIMIZED;
1313
1314 /* Unset fullscreen mode so that clientToggleMaximized() really change the state */
1315 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
1316 clientToggleMaximized (c, mode, FALSE);
1317 }
1318 }
1319 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
1320 {
1321 TRACE ("Applying client's initial state: fullscreen");
1322 clientUpdateFullscreenState (c);
1323 }
1324 if (FLAG_TEST_AND_NOT (c->flags, CLIENT_FLAG_ABOVE, CLIENT_FLAG_BELOW))
1325 {
1326 TRACE ("Applying client's initial state: above");
1327 clientUpdateLayerState (c);
1328 }
1329 if (FLAG_TEST_AND_NOT (c->flags, CLIENT_FLAG_BELOW, CLIENT_FLAG_ABOVE))
1330 {
1331 TRACE ("Applying client's initial state: below");
1332 clientUpdateLayerState (c);
1333 }
1334 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY) &&
1335 FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK))
1336 {
1337 TRACE ("Applying client's initial state: sticky");
1338 clientStick (c, TRUE);
1339 }
1340 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
1341 {
1342 TRACE ("Applying client's initial state: shaded");
1343 clientShade (c);
1344 }
1345}
1346
1347static gboolean
1348clientCheckShape (Client *c)
1349{
1350 ScreenInfo *screen_info;
1351 DisplayInfo *display_info;
1352 int xws, yws, xbs, ybs;
1353 unsigned wws, hws, wbs, hbs;
1354 int boundingShaped, clipShaped;
1355
1356 g_return_val_if_fail (c != NULL, FALSE);
1357
1358 screen_info = c->screen_info;
1359 display_info = screen_info->display_info;
1360
1361 if (display_info->have_shape)
1362 {
1363 XShapeQueryExtents (display_info->dpy, c->window, &boundingShaped, &xws, &yws, &wws,
1364 &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs);
1365 return (boundingShaped != 0);
1366 }
1367 return FALSE;
1368}
1369
1370static void
1371clientUpdateIconPix (Client *c)
1372{
1373 ScreenInfo *screen_info;
1374 DisplayInfo *display_info;
1375 gint size;
1376 GdkPixbuf *icon;
1377 int i;
1378
1379 g_return_if_fail (c != NULL);
1380 g_return_if_fail (c->window != None);
1381
1382 TRACE ("entering clientUpdateIconPix for \"%s\" (0x%lx)", c->name, c->window);
1383
1384 screen_info = c->screen_info;
1385 display_info = screen_info->display_info;
1386
1387 for (i = 0; i < STATE_TOGGLED; i++)
1388 {
1389 xfwmPixmapFree (&c->appmenu[i]);
1390 }
1391
1392 if (xfwmPixmapNone(&screen_info->buttons[MENU_BUTTON][ACTIVE]))
1393 {
1394 /* The current theme has no menu button */
1395 return;
1396 }
1397
1398 for (i = 0; i < STATE_TOGGLED; i++)
1399 {
1400 if (!xfwmPixmapNone(&screen_info->buttons[MENU_BUTTON][i]))
1401 {
1402 xfwmPixmapDuplicate (&screen_info->buttons[MENU_BUTTON][i], &c->appmenu[i]);
1403 }
1404 }
1405 size = MIN (screen_info->buttons[MENU_BUTTON][ACTIVE].width,
1406 screen_info->buttons[MENU_BUTTON][ACTIVE].height);
1407
1408 if (size > 1)
1409 {
1410 icon = getAppIcon (display_info, c->window, size, size);
1411
1412 for (i = 0; i < STATE_TOGGLED; i++)
1413 {
1414 if (!xfwmPixmapNone(&c->appmenu[i]))
1415 {
1416 xfwmPixmapRenderGdkPixbuf (&c->appmenu[i], icon);
1417 }
1418 }
1419 g_object_unref (icon);
1420 }
1421}
1422
1423static gboolean
1424update_icon_idle_cb (gpointer data)
1425{
1426 Client *c;
1427
1428 TRACE ("entering update_icon_idle_cb");
1429
1430 c = (Client *) data;
1431 g_return_val_if_fail (c, FALSE);
1432
1433 clientUpdateIconPix (c);
1434 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
1435 {
1436 frameQueueDraw (c, FALSE);
1437 }
1438 c->icon_timeout_id = 0;
1439
1440 return (FALSE);
1441}
1442
1443void
1444clientUpdateIcon (Client *c)
1445{
1446 g_return_if_fail (c);
1447
1448 TRACE ("entering clientUpdateIcon for \"%s\" (0x%lx)", c->name, c->window);
1449
1450 if (c->icon_timeout_id == 0)
1451 {
1452 c->icon_timeout_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1453 update_icon_idle_cb, c, NULL);
1454 }
1455}
1456
1457void
1458clientSaveSizePos (Client *c)
1459{
1460 g_return_if_fail (c != NULL);
1461
1462 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
1463 {
1464 c->old_x = c->x;
1465 c->old_width = c->width;
1466 }
1467
1468 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
1469 {
1470 c->old_y = c->y;
1471 c->old_height = c->height;
1472 }
1473}
1474
1475Client *
1476clientFrame (DisplayInfo *display_info, Window w, gboolean recapture)
1477{
1478 ScreenInfo *screen_info;
1479 XWindowAttributes attr;
1480 XWindowChanges wc;
1481 XSetWindowAttributes attributes;
1482 Client *c = NULL;
1483 gboolean shaped;
1484 unsigned long valuemask;
1485 long pid;
1486 int i;
1487
1488 g_return_val_if_fail (w != None, NULL);
1489 g_return_val_if_fail (display_info != NULL, NULL);
1490
1491 TRACE ("entering clientFrame");
1492 TRACE ("framing client (0x%lx)", w);
1493
1494 gdk_error_trap_push ();
1495 myDisplayGrabServer (display_info);
1496
1497 if (!XGetWindowAttributes (display_info->dpy, w, &attr))
1498 {
1499 g_warning ("Cannot get window attributes for window (0x%lx)", w);
1500 myDisplayUngrabServer (display_info);
1501 gdk_error_trap_pop ();
1502 return NULL;
1503 }
1504
1505 screen_info = myDisplayGetScreenFromRoot (display_info, attr.root);
1506 if (!screen_info)
1507 {
1508 g_warning ("Cannot determine screen info from window (0x%lx)", w);
1509 myDisplayUngrabServer (display_info);
1510 gdk_error_trap_pop ();
1511 return NULL;
1512 }
1513
1514 if (w == screen_info->xfwm4_win)
1515 {
1516 TRACE ("Not managing our own event window");
1517 compositorAddWindow (display_info, w, NULL);
1518 myDisplayUngrabServer (display_info);
1519 gdk_error_trap_pop ();
1520 return NULL;
1521 }
1522
1523#ifdef ENABLE_KDE_SYSTRAY_PROXY
1524 if (checkKdeSystrayWindow (display_info, w))
1525 {
1526 TRACE ("Detected KDE systray windows");
1527 if (screen_info->systray != None)
1528 {
1529 sendSystrayReqDock (display_info, w, screen_info->systray);
1530 myDisplayUngrabServer (display_info);
1531 gdk_error_trap_pop ();
1532 return NULL;
1533 }
1534 TRACE ("No systray found for this screen");
1535 }
1536#endif /* ENABLE_KDE_SYSTRAY_PROXY */
1537
1538 if (attr.override_redirect)
1539 {
1540 TRACE ("Override redirect window 0x%lx", w);
1541 compositorAddWindow (display_info, w, NULL);
1542 myDisplayUngrabServer (display_info);
1543 gdk_error_trap_pop ();
1544 return NULL;
1545 }
1546
1547 c = g_new0 (Client, 1);
1548 if (!c)
1549 {
1550 TRACE ("Cannot allocate memory for the window structure");
1551 myDisplayUngrabServer (display_info);
1552 gdk_error_trap_pop ();
1553 return NULL;
1554 }
1555
1556 c->window = w;
1557 c->screen_info = screen_info;
1558 c->serial = screen_info->client_serial++;
1559
1560 /* Termination dialog */
1561 c->dialog_pid = 0;
1562 c->dialog_fd = -1;
1563
1564 getWindowName (display_info, c->window, &c->name);
1565 getWindowHostname (display_info, c->window, &c->hostname);
1566 getTransientFor (display_info, screen_info->xroot, c->window, &c->transient_for);
1567 XChangeSaveSet(display_info->dpy, c->window, SetModeInsert);
1568
1569 /* Initialize structure */
1570 c->size = NULL;
1571 c->flags = 0L;
1572 c->wm_flags = 0L;
1573 c->xfwm_flags = XFWM_FLAG_INITIAL_VALUES;
1574 c->x = attr.x;
1575 c->y = attr.y;
1576 c->width = attr.width;
1577 c->height = attr.height;
1578
1579#ifdef HAVE_LIBSTARTUP_NOTIFICATION
1580 c->startup_id = NULL;
1581#endif /* HAVE_LIBSTARTUP_NOTIFICATION */
1582
1583#ifdef HAVE_XSYNC
1584 c->xsync_waiting = FALSE;
1585 c->xsync_enabled = FALSE;
1586 c->xsync_counter = None;
1587 c->xsync_alarm = None;
1588 c->xsync_timeout_id = 0;
1589 if (display_info->have_xsync)
1590 {
1591 getXSyncCounter (display_info, c->window, &c->xsync_counter);
1592 if ((c->xsync_counter) && clientCreateXSyncAlarm (c))
1593 {
1594 c->xsync_enabled = TRUE;
1595 }
1596 }
1597#endif /* HAVE_XSYNC */
1598
1599 clientGetWMNormalHints (c, FALSE);
1600
1601 c->size->x = c->x;
1602 c->size->y = c->y;
1603 c->size->width = c->width;
1604 c->size->height = c->height;
1605 c->previous_width = -1;
1606 c->previous_height = -1;
1607 c->border_width = attr.border_width;
1608 c->cmap = attr.colormap;
1609
1610 shaped = clientCheckShape(c);
1611 if (shaped)
1612 {
1613 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER);
1614 FLAG_SET (c->flags, CLIENT_FLAG_HAS_SHAPE);
1615 }
1616
1617 if (((c->size->flags & (PMinSize | PMaxSize)) != (PMinSize | PMaxSize))
1618 || (((c->size->flags & (PMinSize | PMaxSize)) ==
1619 (PMinSize | PMaxSize))
1620 && ((c->size->min_width < c->size->max_width)
1621 || (c->size->min_height < c->size->max_height))))
1622 {
1623 FLAG_SET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1624 }
1625
1626 for (i = 0; i < BUTTON_COUNT; i++)
1627 {
1628 c->button_status[i] = BUTTON_STATE_NORMAL;
1629 }
1630
1631 if (!XGetWMColormapWindows (display_info->dpy, c->window, &c->cmap_windows, &c->ncmap))
1632 {
1633 c->ncmap = 0;
1634 }
1635
1636 c->fullscreen_monitors[0] = 0;
1637 c->fullscreen_monitors[1] = 0;
1638 c->fullscreen_monitors[2] = 0;
1639 c->fullscreen_monitors[3] = 0;
1640
1641 /* Opacity for compositing manager */
1642 c->opacity = NET_WM_OPAQUE;
1643 getOpacity (display_info, c->window, &c->opacity);
1644 c->opacity_applied = c->opacity;
1645 c->opacity_flags = 0;
1646
1647 /* Keep count of blinking iterations */
1648 c->blink_iterations = 0;
1649
1650 if (getOpacityLock (display_info, c->window))
1651 {
1652 FLAG_SET (c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED);
1653 }
1654
1655 /* Timout for asynchronous icon update */
1656 c->icon_timeout_id = 0;
1657 /* Timout for asynchronous frame update */
1658 c->frame_timeout_id = 0;
1659 /* Timeout for blinking on urgency */
1660 c->blink_timeout_id = 0;
1661 /* Ping timeout */
1662 c->ping_timeout_id = 0;
1663 /* Ping timeout */
1664 c->ping_time = 0;
1665
1666 c->class.res_name = NULL;
1667 c->class.res_class = NULL;
1668 XGetClassHint (display_info->dpy, w, &c->class);
1669 c->wmhints = XGetWMHints (display_info->dpy, c->window);
1670 c->group_leader = None;
1671 if (c->wmhints)
1672 {
1673 if (c->wmhints->flags & WindowGroupHint)
1674 {
1675 c->group_leader = c->wmhints->window_group;
1676 }
1677 }
1678 c->client_leader = getClientLeader (display_info, c->window);
1679
1680 TRACE ("\"%s\" (0x%lx) initial map_state = %s",
1681 c->name, c->window,
1682 (attr.map_state == IsUnmapped) ?
1683 "IsUnmapped" :
1684 (attr.map_state == IsViewable) ?
1685 "IsViewable" :
1686 (attr.map_state == IsUnviewable) ?
1687 "IsUnviewable" :
1688 "(unknown)");
1689 if (attr.map_state != IsUnmapped)
1690 {
1691 /* Reparent will send us unmap/map events */
1692 FLAG_SET (c->xfwm_flags, XFWM_FLAG_MAP_PENDING);
1693 }
1694 c->ignore_unmap = 0;
1695 c->type = UNSET;
1696 c->type_atom = None;
1697
1698 FLAG_SET (c->flags, START_ICONIC (c) ? CLIENT_FLAG_ICONIFIED : 0);
1699 FLAG_SET (c->wm_flags, HINTS_ACCEPT_INPUT (c->wmhints) ? WM_FLAG_INPUT : 0);
1700
1701 clientGetWMProtocols (c);
1702 clientGetMWMHints (c, FALSE);
1703 c->win_layer = WIN_LAYER_NORMAL;
1704 c->fullscreen_old_layer = c->win_layer;
1705
1706 /* net_wm_user_time standard */
1707 c->user_time = 0;
1708 c->user_time_win = getNetWMUserTimeWindow(display_info, c->window);
1709 clientAddUserTimeWin (c);
1710 clientGetUserTime (c);
1711
1712 /*client PID */
1713 getHint (display_info, c->window, NET_WM_PID, (long *) &pid);
1714 c->pid = (GPid) pid;
1715 TRACE ("Client \"%s\" (0x%lx) PID = %i", c->name, c->window, c->pid);
1716
1717 /* Apply startup notification properties if available */
1718 sn_client_startup_properties (c);
1719
1720 /* Reload from session */
1721 if (sessionMatchWinToSM (c))
1722 {
1723 FLAG_SET (c->xfwm_flags, XFWM_FLAG_SESSION_MANAGED);
1724 }
1725
1726 /* Beware, order of calls is important here ! */
1727 clientGetNetState (c);
1728 clientGetNetWmType (c);
1729 clientGetInitialNetWmDesktop (c);
1730 /* workarea will be updated when shown, no need to worry here */
1731 clientGetNetStruts (c);
1732
1733 /* Once we know the type of window, we can initialize window position */
1734 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SESSION_MANAGED))
1735 {
1736 clientCoordGravitate (c, c->gravity, APPLY, &c->x, &c->y);
1737 if ((attr.map_state == IsUnmapped))
1738 {
1739 clientInitPosition (c);
1740 }
1741 }
1742
1743 /*
1744 Initialize "old" fields once the position is ensured, to avoid
1745 initially maximized or fullscreen windows being placed offscreen
1746 once de-maximized
1747 */
1748 c->old_x = c->x;
1749 c->old_y = c->y;
1750 c->old_width = c->width;
1751 c->old_height = c->height;
1752
1753 c->fullscreen_old_x = c->x;
1754 c->fullscreen_old_y = c->y;
1755 c->fullscreen_old_width = c->width;
1756 c->fullscreen_old_height = c->height;
1757
1758 /*
1759 We must call clientApplyInitialState() after having placed the
1760 window so that the inital position values are correctly set if the
1761 inital state is maximize or fullscreen
1762 */
1763 clientApplyInitialState (c);
1764
1765 valuemask = CWEventMask|CWBitGravity|CWWinGravity;
1766 attributes.event_mask = (FRAME_EVENT_MASK | POINTER_EVENT_MASK);
1767 attributes.win_gravity = StaticGravity;
1768 attributes.bit_gravity = StaticGravity;
1769
1770#ifdef HAVE_RENDER
1771 if ((attr.depth == 32) && (display_info->have_render))
1772 {
1773 c->visual = attr.visual;
1774 c->depth = attr.depth;
1775
1776 attributes.colormap = attr.colormap;
1777 attributes.background_pixmap = None;
1778 attributes.border_pixel = 0;
1779 attributes.background_pixel = 0;
1780
1781 valuemask |= CWColormap|CWBackPixmap|CWBackPixel|CWBorderPixel;
1782 }
1783 else
1784 {
1785 /* Default depth/visual */
1786 c->visual = screen_info->visual;
1787 c->depth = screen_info->depth;
1788 }
1789#else /* HAVE_RENDER */
1790 /* We don't support multiple depth/visual w/out render */
1791 c->visual = screen_info->visual;
1792 c->depth = screen_info->depth;
1793#endif /* HAVE_RENDER */
1794
1795 c->frame =
1796 XCreateWindow (display_info->dpy, screen_info->xroot, 0, 0, 1, 1, 0,
1797 c->depth, InputOutput, c->visual, valuemask, &attributes);
1798
1799 XSelectInput (display_info->dpy, c->window, NoEventMask);
1800 XSetWindowBorderWidth (display_info->dpy, c->window, 0);
1801 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
1802 {
1803 XUnmapWindow (display_info->dpy, c->window);
1804 }
1805 XReparentWindow (display_info->dpy, c->window, c->frame, frameLeft (c), frameTop (c));
1806 valuemask = CWEventMask;
1807 attributes.event_mask = (CLIENT_EVENT_MASK);
1808 XChangeWindowAttributes (display_info->dpy, c->window, valuemask, &attributes);
1809 if (display_info->have_shape)
1810 {
1811 XShapeSelectInput (display_info->dpy, c->window, ShapeNotifyMask);
1812 }
1813
1814 clientAddToList (c);
1815 clientGrabButtons(c);
1816
1817 /* Initialize per client menu button pixmap */
1818
1819 for (i = 0; i < STATE_TOGGLED; i++)
1820 {
1821 xfwmPixmapInit (screen_info, &c->appmenu[i]);
1822 }
1823
1824 for (i = 0; i < SIDE_TOP; i++) /* Keep SIDE_TOP for later */
1825 {
1826 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
1827 &c->sides[i], NoEventMask,
1828 myDisplayGetCursorResize(screen_info->display_info, CORNER_COUNT + i));
1829 }
1830
1831 for (i = 0; i < CORNER_COUNT; i++)
1832 {
1833 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
1834 &c->corners[i], NoEventMask,
1835 myDisplayGetCursorResize(screen_info->display_info, i));
1836 }
1837
1838 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
1839 &c->title, NoEventMask, None);
1840
1841 /*create the top side window AFTER the title window since they overlap
1842 and the top side window should be on top */
1843
1844 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
1845 &c->sides[SIDE_TOP], NoEventMask,
1846 myDisplayGetCursorResize(screen_info->display_info,
1847 CORNER_COUNT + SIDE_TOP));
1848
1849 for (i = 0; i < BUTTON_COUNT; i++)
1850 {
1851 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
1852 &c->buttons[i], BUTTON_EVENT_MASK, None);
1853 }
1854 clientUpdateIconPix (c);
1855
1856 /* Put the window on top to avoid XShape, that speeds up hw accelerated
1857 GL apps dramatically */
1858 XRaiseWindow (display_info->dpy, c->window);
1859
1860 TRACE ("now calling configure for the new window \"%s\" (0x%lx)", c->name, c->window);
1861 wc.x = c->x;
1862 wc.y = c->y;
1863 wc.width = c->width;
1864 wc.height = c->height;
1865 clientConfigure (c, &wc, CWX | CWY | CWHeight | CWWidth, CFG_NOTIFY | CFG_FORCE_REDRAW);
1866
1867 /* Notify the compositor about this new window */
1868 compositorAddWindow (display_info, c->frame, c);
1869
1870 if (!FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
1871 {
1872 if ((c->win_workspace == screen_info->current_ws) ||
1873 FLAG_TEST(c->flags, CLIENT_FLAG_STICKY))
1874 {
1875 if (recapture)
1876 {
1877 clientRaise (c, None);
1878 clientShow (c, TRUE);
1879 clientSortRing(c);
1880 }
1881 else
1882 {
1883 clientFocusNew(c);
1884 }
1885 }
1886 else
1887 {
1888 clientRaise (c, None);
1889 clientInitFocusFlag (c);
1890 clientSetNetActions (c);
1891 }
1892 }
1893 else
1894 {
1895 clientRaise (c, None);
1896 setWMState (display_info, c->window, IconicState);
1897 clientSetNetActions (c);
1898 }
1899 clientUpdateOpacity (c);
1900 clientGrabMouseButton (c);
1901 setNetFrameExtents (display_info, c->window, frameTop (c), frameLeft (c),
1902 frameRight (c), frameBottom (c));
1903 clientSetNetState (c);
1904
1905 /* Window is reparented now, so we can safely release the grab
1906 * on the server
1907 */
1908 myDisplayUngrabServer (display_info);
1909 gdk_error_trap_pop ();
1910
1911 DBG ("client \"%s\" (0x%lx) is now managed", c->name, c->window);
1912 DBG ("client_count=%d", screen_info->client_count);
1913
1914 return c;
1915}
1916
1917void
1918clientUnframe (Client *c, gboolean remap)
1919{
1920 ScreenInfo *screen_info;
1921 DisplayInfo *display_info;
1922 XEvent ev;
1923 int i;
1924 gboolean reparented;
1925
1926 TRACE ("entering clientUnframe");
1927 TRACE ("unframing client \"%s\" (0x%lx) [%s]",
1928 c->name, c->window, remap ? "remap" : "no remap");
1929
1930 g_return_if_fail (c != NULL);
1931
1932 screen_info = c->screen_info;
1933 display_info = screen_info->display_info;
1934
1935 clientRemoveFromList (c);
1936 compositorSetClient (display_info, c->frame, NULL);
1937
1938 myDisplayGrabServer (display_info);
1939 gdk_error_trap_push ();
1940 clientRemoveUserTimeWin (c);
1941 clientUngrabButtons (c);
1942 XUnmapWindow (display_info->dpy, c->frame);
1943 clientCoordGravitate (c, c->gravity, REMOVE, &c->x, &c->y);
1944 XSelectInput (display_info->dpy, c->window, NoEventMask);
1945 XChangeSaveSet(display_info->dpy, c->window, SetModeDelete);
1946
1947 reparented = XCheckTypedWindowEvent (display_info->dpy, c->window, ReparentNotify, &ev);
1948
1949 if (remap || !reparented)
1950 {
1951 XReparentWindow (display_info->dpy, c->window, c->screen_info->xroot, c->x, c->y);
1952 XSetWindowBorderWidth (display_info->dpy, c->window, c->border_width);
1953 if (remap)
1954 {
1955 compositorAddWindow (display_info, c->window, NULL);
1956 XMapWindow (display_info->dpy, c->window);
1957 }
1958 else
1959 {
1960 XUnmapWindow (display_info->dpy, c->window);
1961 setWMState (display_info, c->window, WithdrawnState);
1962 }
1963 }
1964
1965 if (!remap)
1966 {
1967 XDeleteProperty (display_info->dpy, c->window,
1968 display_info->atoms[NET_WM_STATE]);
1969 XDeleteProperty (display_info->dpy, c->window,
1970 display_info->atoms[NET_WM_DESKTOP]);
1971 XDeleteProperty (display_info->dpy, c->window,
1972 display_info->atoms[NET_WM_ALLOWED_ACTIONS]);
1973 }
1974
1975 xfwmWindowDelete (&c->title);
1976
1977 for (i = 0; i < SIDE_COUNT; i++)
1978 {
1979 xfwmWindowDelete (&c->sides[i]);
1980 }
1981 for (i = 0; i < CORNER_COUNT; i++)
1982 {
1983 xfwmWindowDelete (&c->corners[i]);
1984 }
1985 for (i = 0; i < STATE_TOGGLED; i++)
1986 {
1987 xfwmPixmapFree (&c->appmenu[i]);
1988 }
1989 for (i = 0; i < BUTTON_COUNT; i++)
1990 {
1991 xfwmWindowDelete (&c->buttons[i]);
1992 }
1993 if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STRUT))
1994 {
1995 workspaceUpdateArea (c->screen_info);
1996 }
1997 XDestroyWindow (display_info->dpy, c->frame);
1998
1999 myDisplayUngrabServer (display_info);
2000 gdk_error_trap_pop ();
2001 clientFree (c);
2002}
2003
2004void
2005clientFrameAll (ScreenInfo *screen_info)
2006{
2007 DisplayInfo *display_info;
2008 XWindowAttributes attr;
2009 xfwmWindow shield;
2010 Window w1, w2, *wins;
2011 unsigned int count, i;
2012
2013 TRACE ("entering clientFrameAll");
2014
2015 display_info = screen_info->display_info;
2016 clientSetFocus (screen_info, NULL, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
2017 xfwmWindowTemp (screen_info,
2018 NULL, 0,
2019 screen_info->xroot,
2020 &shield,
2021 0, 0,
2022 screen_info->width,
2023 screen_info->height,
2024 EnterWindowMask,
2025 FALSE);
2026
2027 XSync (display_info->dpy, FALSE);
2028 myDisplayGrabServer (display_info);
2029 XQueryTree (display_info->dpy, screen_info->xroot, &w1, &w2, &wins, &count);
2030 for (i = 0; i < count; i++)
2031 {
2032 XGetWindowAttributes (display_info->dpy, wins[i], &attr);
2033 if ((attr.map_state == IsViewable) && (attr.root == screen_info->xroot))
2034 {
2035 Client *c = clientFrame (display_info, wins[i], TRUE);
2036 if ((c) && ((screen_info->params->raise_on_click) || (screen_info->params->click_to_focus)))
2037 {
2038 clientGrabMouseButton (c);
2039 }
2040 }
2041 else
2042 {
2043 compositorAddWindow (display_info, wins[i], NULL);
2044 }
2045 }
2046 if (wins)
2047 {
2048 XFree (wins);
2049 }
2050 clientFocusTop (screen_info, WIN_LAYER_FULLSCREEN, myDisplayGetCurrentTime (display_info));
2051 xfwmWindowDelete (&shield);
2052 myDisplayUngrabServer (display_info);
2053 XSync (display_info->dpy, FALSE);
2054}
2055
2056void
2057clientUnframeAll (ScreenInfo *screen_info)
2058{
2059 DisplayInfo *display_info;
2060 Client *c;
2061 Window w1, w2, *wins;
2062 unsigned int count, i;
2063
2064 TRACE ("entering clientUnframeAll");
2065
2066 display_info = screen_info->display_info;
2067 clientSetFocus (screen_info, NULL, myDisplayGetCurrentTime (display_info), FOCUS_IGNORE_MODAL);
2068 XSync (display_info->dpy, FALSE);
2069 myDisplayGrabServer (display_info);
2070 XQueryTree (display_info->dpy, screen_info->xroot, &w1, &w2, &wins, &count);
2071 for (i = 0; i < count; i++)
2072 {
2073 c = myScreenGetClientFromWindow (screen_info, wins[i], SEARCH_FRAME);
2074 if (c)
2075 {
2076 clientUnframe (c, TRUE);
2077 }
2078 }
2079 myDisplayUngrabServer (display_info);
2080 XSync(display_info->dpy, FALSE);
2081 if (wins)
2082 {
2083 XFree (wins);
2084 }
2085}
2086
2087Client *
2088clientGetFromWindow (Client *c, Window w, unsigned short mode)
2089{
2090 int b;
2091
2092 g_return_val_if_fail (w != None, NULL);
2093 g_return_val_if_fail (c != NULL, NULL);
2094 TRACE ("entering clientGetFromWindow");
2095
2096 if (mode & SEARCH_WINDOW)
2097 {
2098 if (c->window == w)
2099 {
2100 TRACE ("found \"%s\" (mode WINDOW)", c->name);
2101 return (c);
2102 }
2103 }
2104
2105 if (mode & SEARCH_FRAME)
2106 {
2107 if (c->frame == w)
2108 {
2109 TRACE ("found \"%s\" (mode FRAME)", c->name);
2110 return (c);
2111 }
2112 }
2113
2114 if (mode & SEARCH_WIN_USER_TIME)
2115 {
2116 if (c->user_time_win == w)
2117 {
2118 TRACE ("found \"%s\" (mode WIN_USER_TIME)", c->name);
2119 return (c);
2120 }
2121 }
2122
2123 if (mode & SEARCH_BUTTON)
2124 {
2125 for (b = 0; b < BUTTON_COUNT; b++)
2126 {
2127 if (MYWINDOW_XWINDOW(c->buttons[b]) == w)
2128 {
2129 TRACE ("found \"%s\" (mode BUTTON)", c->name);
2130 return (c);
2131 }
2132 }
2133 }
2134
2135 TRACE ("no client found");
2136
2137 return NULL;
2138}
2139
2140static void
2141clientSetWorkspaceSingle (Client *c, guint ws)
2142{
2143 ScreenInfo *screen_info;
2144 DisplayInfo *display_info;
2145
2146 g_return_if_fail (c != NULL);
2147
2148 TRACE ("entering clientSetWorkspaceSingle");
2149
2150 screen_info = c->screen_info;
2151 display_info = screen_info->display_info;
2152
2153 if (ws > screen_info->workspace_count - 1)
2154 {
2155 ws = screen_info->workspace_count - 1;
2156 TRACE ("value off limits, using %i instead", ws);
2157 }
2158
2159 if (c->win_workspace != ws)
2160 {
2161 TRACE ("setting client \"%s\" (0x%lx) to current_ws %d", c->name, c->window, ws);
2162 c->win_workspace = ws;
2163 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2164 {
2165 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2166 }
2167 else
2168 {
2169 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ws);
2170 }
2171 }
2172 FLAG_SET (c->xfwm_flags, XFWM_FLAG_WORKSPACE_SET);
2173}
2174
2175void
2176clientSetWorkspace (Client *c, guint ws, gboolean manage_mapping)
2177{
2178 Client *c2;
2179 GList *list_of_windows;
2180 GList *list;
2181 guint previous_ws;
2182
2183 g_return_if_fail (c != NULL);
2184
2185 TRACE ("entering clientSetWorkspace");
2186
2187 if (ws > c->screen_info->workspace_count - 1)
2188 {
2189 g_warning ("Requested workspace %d does not exist", ws);
2190 return;
2191 }
2192
2193 list_of_windows = clientListTransientOrModal (c);
2194 for (list = list_of_windows; list; list = g_list_next (list))
2195 {
2196 c2 = (Client *) list->data;
2197
2198 if (c2->win_workspace != ws)
2199 {
2200 TRACE ("setting client \"%s\" (0x%lx) to current_ws %d", c->name, c->window, ws);
2201
2202 previous_ws = c2->win_workspace;
2203 clientSetWorkspaceSingle (c2, ws);
2204
2205 if (manage_mapping && !FLAG_TEST (c2->flags, CLIENT_FLAG_ICONIFIED))
2206 {
2207 if (previous_ws == c2->screen_info->current_ws)
2208 {
2209 clientWithdraw (c2, c2->screen_info->current_ws, FALSE);
2210 }
2211 if (FLAG_TEST (c2->flags, CLIENT_FLAG_STICKY) || (ws == c2->screen_info->current_ws))
2212 {
2213 clientShow (c2, FALSE);
2214 }
2215 }
2216 }
2217 }
2218 g_list_free (list_of_windows);
2219}
2220
2221static void
2222clientShowSingle (Client *c, gboolean deiconify)
2223{
2224 ScreenInfo *screen_info;
2225 DisplayInfo *display_info;
2226
2227 g_return_if_fail (c != NULL);
2228
2229 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2230 {
2231 /* Should we map the window if it is visible? */
2232 return;
2233 }
2234
2235 screen_info = c->screen_info;
2236 display_info = screen_info->display_info;
2237
2238 if ((c->win_workspace == screen_info->current_ws) || FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2239 {
2240 TRACE ("showing client \"%s\" (0x%lx)", c->name, c->window);
2241 FLAG_SET (c->xfwm_flags, XFWM_FLAG_VISIBLE);
2242 XMapWindow (display_info->dpy, c->frame);
2243 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2244 {
2245 XMapWindow (display_info->dpy, c->window);
2246 }
2247 /* Adjust to urgency state as the window is visible */
2248 clientUpdateUrgency (c);
2249 }
2250 if (deiconify)
2251 {
2252 FLAG_UNSET (c->flags, CLIENT_FLAG_ICONIFIED);
2253 setWMState (display_info, c->window, NormalState);
2254 }
2255 clientSetNetActions (c);
2256 clientSetNetState (c);
2257}
2258
2259void
2260clientShow (Client *c, gboolean deiconify)
2261{
2262 Client *c2;
2263 GList *list_of_windows;
2264 GList *list;
2265
2266 g_return_if_fail (c != NULL);
2267 TRACE ("entering clientShow \"%s\" (0x%lx)", c->name, c->window);
2268
2269 list_of_windows = clientListTransientOrModal (c);
2270 for (list = g_list_last (list_of_windows); list; list = g_list_previous (list))
2271 {
2272 c2 = (Client *) list->data;
2273 clientSetWorkspaceSingle (c2, c->win_workspace);
2274 /* Ignore request before if the window is not yet managed */
2275 if (!FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_MANAGED))
2276 {
2277 continue;
2278 }
2279 clientShowSingle (c2, deiconify);
2280 }
2281 g_list_free (list_of_windows);
2282
2283 /* Update working area as windows have been shown */
2284 workspaceUpdateArea (c->screen_info);
2285}
2286
2287static void
2288clientWithdrawSingle (Client *c, GList *exclude_list, gboolean iconify)
2289{
2290 ScreenInfo *screen_info;
2291 DisplayInfo *display_info;
2292
2293 g_return_if_fail (c != NULL);
2294
2295 screen_info = c->screen_info;
2296 display_info = screen_info->display_info;
2297
2298 TRACE ("hiding client \"%s\" (0x%lx)", c->name, c->window);
2299 clientPassFocus(c->screen_info, c, exclude_list);
2300 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2301 {
2302 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_VISIBLE);
2303 c->ignore_unmap++;
2304 /* Adjust to urgency state as the window is not visible */
2305 clientUpdateUrgency (c);
2306 }
2307 XUnmapWindow (display_info->dpy, c->window);
2308 XUnmapWindow (display_info->dpy, c->frame);
2309 if (iconify)
2310 {
2311 FLAG_SET (c->flags, CLIENT_FLAG_ICONIFIED);
2312 setWMState (display_info, c->window, IconicState);
2313 if (!screen_info->show_desktop)
2314 {
2315 clientSetLast (c);
2316 }
2317 }
2318 clientSetNetActions (c);
2319 clientSetNetState (c);
2320}
2321
2322void
2323clientWithdraw (Client *c, guint ws, gboolean iconify)
2324{
2325 Client *c2;
2326 GList *list_of_windows;
2327 GList *list;
2328
2329 g_return_if_fail (c != NULL);
2330 TRACE ("entering clientWithdraw \"%s\" (0x%lx)", c->name, c->window);
2331
2332 list_of_windows = clientListTransientOrModal (c);
2333 for (list = list_of_windows; list; list = g_list_next (list))
2334 {
2335 c2 = (Client *) list->data;
2336
2337 /* Ignore request before if the window is not yet managed */
2338 if (!FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_MANAGED))
2339 {
2340 continue;
2341 }
2342
2343 if (FLAG_TEST (c2->flags, CLIENT_FLAG_STICKY) && !iconify)
2344 {
2345 continue;
2346 }
2347
2348 if (clientIsTransientOrModalForGroup (c2))
2349 {
2350
2351 if (clientTransientOrModalHasAncestor (c2, c2->win_workspace))
2352 {
2353 /* Other ancestors for that transient for group are still
2354 * visible on current workspace, so don't hide it...
2355 */
2356 continue;
2357 }
2358 if ((ws != c2->win_workspace) &&
2359 clientTransientOrModalHasAncestor (c2, ws))
2360 {
2361 /* ws is used when transitioning between desktops, to avoid
2362 hiding a transient for group that will be shown again on the new
2363 workspace (transient for groups can be transients for multiple
2364 ancesors splitted across workspaces...)
2365 */
2366 continue;
2367 }
2368 }
2369 clientWithdrawSingle (c2, list_of_windows, iconify);
2370 }
2371 g_list_free (list_of_windows);
2372
2373 /* Update working area as windows have been hidden */
2374 workspaceUpdateArea (c->screen_info);
2375}
2376
2377void
2378clientWithdrawAll (Client *c, guint ws)
2379{
2380 GList *list;
2381 Client *c2;
2382 ScreenInfo *screen_info;
2383
2384 g_return_if_fail (c != NULL);
2385
2386 TRACE ("entering clientWithdrawAll");
2387
2388 screen_info = c->screen_info;
2389 for (list = screen_info->windows_stack; list; list = g_list_next (list))
2390 {
2391 c2 = (Client *) list->data;
2392
2393 if ((c2 != c)
2394 && CLIENT_CAN_HIDE_WINDOW (c2)
2395 && !clientIsTransientOrModal (c2))
2396 {
2397 if (((!c) && (c2->win_workspace == ws))
2398 || ((c) && !clientIsTransientOrModalFor (c, c2)
2399 && (c2->win_workspace == c->win_workspace)))
2400 {
2401 clientWithdraw (c2, ws, TRUE);
2402 }
2403 }
2404 }
2405}
2406
2407void
2408clientClearAllShowDesktop (ScreenInfo *screen_info)
2409{
2410 GList *list;
2411
2412 TRACE ("entering clientClearShowDesktop");
2413
2414 if (screen_info->show_desktop)
2415 {
2416 for (list = screen_info->windows_stack; list; list = g_list_next (list))
2417 {
2418 Client *c = (Client *) list->data;
2419 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2420 }
2421 screen_info->show_desktop = FALSE;
2422 sendRootMessage (screen_info, NET_SHOWING_DESKTOP, screen_info->show_desktop,
2423 myDisplayGetCurrentTime (screen_info->display_info));
2424 }
2425}
2426
2427void
2428clientToggleShowDesktop (ScreenInfo *screen_info)
2429{
2430 GList *list;
2431
2432 TRACE ("entering clientToggleShowDesktop");
2433
2434 clientSetFocus (screen_info, NULL,
2435 myDisplayGetCurrentTime (screen_info->display_info),
2436 FOCUS_IGNORE_MODAL);
2437 if (screen_info->show_desktop)
2438 {
2439 for (list = screen_info->windows_stack; list; list = g_list_next (list))
2440 {
2441 Client *c = (Client *) list->data;
2442 if ((c->type & WINDOW_REGULAR_FOCUSABLE)
2443 && !FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED | CLIENT_FLAG_SKIP_TASKBAR))
2444 {
2445 FLAG_SET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2446 clientWithdraw (c, c->win_workspace, TRUE);
2447 }
2448 }
2449 clientFocusTop (screen_info, WIN_LAYER_DESKTOP, myDisplayGetCurrentTime (screen_info->display_info));
2450 }
2451 else
2452 {
2453 for (list = g_list_last(screen_info->windows_stack); list; list = g_list_previous (list))
2454 {
2455 Client *c = (Client *) list->data;
2456 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN))
2457 {
2458 clientShow (c, TRUE);
2459 }
2460 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2461 }
2462 clientFocusTop (screen_info, WIN_LAYER_FULLSCREEN, myDisplayGetCurrentTime (screen_info->display_info));
2463 }
2464}
2465
2466void
2467clientActivate (Client *c, guint32 timestamp, gboolean source_is_application)
2468{
2469 ScreenInfo *screen_info;
2470 Client *focused;
2471 Client *sibling;
2472
2473 g_return_if_fail (c != NULL);
2474 TRACE ("entering clientActivate \"%s\" (0x%lx)", c->name, c->window);
2475
2476 screen_info = c->screen_info;
2477 sibling = clientGetTransientFor(c);
2478 focused = clientGetFocus ();
2479
2480 if ((screen_info->current_ws == c->win_workspace) || (screen_info->params->activate_action != ACTIVATE_ACTION_NONE))
2481 {
2482 if ((focused) && (c != focused))
2483 {
2484 /* We might be able to avoid this if we are about to switch workspace */
2485 clientAdjustFullscreenLayer (focused, FALSE);
2486 }
2487 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN))
2488 {
2489 /* We are explicitely activating a window that was shown before show-desktop */
2490 clientClearAllShowDesktop (screen_info);
2491 }
2492 if (screen_info->current_ws != c->win_workspace)
2493 {
2494 if (screen_info->params->activate_action == ACTIVATE_ACTION_BRING)
2495 {
2496 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2497 }
2498 else
2499 {
2500 workspaceSwitch (screen_info, c->win_workspace, NULL, FALSE, timestamp);
2501 }
2502 }
2503 clientRaise (sibling, None);
2504 clientShow (sibling, TRUE);
2505 if (source_is_application || screen_info->params->click_to_focus || (c->type & WINDOW_TYPE_DONT_FOCUS))
2506 {
2507 /*
2508 It's a bit tricky here, we want to honor the activate request only if:
2509
2510 - The window use the _NET_ACTIVE_WINDOW protocol and identify itself as an application,
2511 - Or we use the click to focus model, in that case we focus the raised window anyway,
2512 - Or the request comes from an application that we would not focus by default,
2513 such as panels for example
2514 */
2515 clientSetFocus (screen_info, c, timestamp, NO_FOCUS_FLAG);
2516 }
2517 clientSetLastRaise (c);
2518 }
2519 else
2520 {
2521 TRACE ("Setting WM_STATE_DEMANDS_ATTENTION flag on \"%s\" (0x%lx)", c->name, c->window);
2522 FLAG_SET (c->flags, CLIENT_FLAG_DEMANDS_ATTENTION);
2523 clientSetNetState (c);
2524 }
2525}
2526
2527void
2528clientClose (Client *c)
2529{
2530 ScreenInfo *screen_info;
2531 DisplayInfo *display_info;
2532 guint32 timestamp;
2533
2534 g_return_if_fail (c != NULL);
2535
2536 TRACE ("entering clientClose");
2537 TRACE ("closing client \"%s\" (0x%lx)", c->name, c->window);
2538
2539 screen_info = c->screen_info;
2540 display_info = screen_info->display_info;
2541 timestamp = myDisplayGetCurrentTime (display_info);
2542 timestamp = myDisplayGetTime (display_info, timestamp);
2543
2544 if (FLAG_TEST (c->wm_flags, WM_FLAG_DELETE))
2545 {
2546 sendClientMessage (screen_info, c->window, WM_DELETE_WINDOW, timestamp);
2547 }
2548 else
2549 {
2550 clientKill (c);
2551 }
2552 if (FLAG_TEST (c->wm_flags, WM_FLAG_PING))
2553 {
2554 clientSendNetWMPing (c, timestamp);
2555 }
2556}
2557
2558void
2559clientKill (Client *c)
2560{
2561 g_return_if_fail (c != NULL);
2562 TRACE ("entering clientKill");
2563 TRACE ("killing client \"%s\" (0x%lx)", c->name, c->window);
2564
2565 XKillClient (clientGetXDisplay (c), c->window);
2566}
2567
2568void
2569clientTerminate (Client *c)
2570{
2571 ScreenInfo *screen_info;
2572 DisplayInfo *display_info;
2573
2574 g_return_if_fail (c != NULL);
2575 TRACE ("entering clientTerminate");
2576
2577 screen_info = c->screen_info;
2578 display_info = screen_info->display_info;
2579
2580 if ((c->hostname) && (c->pid > 0))
2581 {
2582 if (!strcmp (display_info->hostname, c->hostname))
2583 {
2584 TRACE ("Sending client %s (pid %i) signal SIGKILL\n", c->name, c->pid);
2585
2586 if (kill (c->pid, SIGKILL) < 0)
2587 {
2588 g_warning ("Failed to kill client id %d: %s", c->pid, strerror (errno));
2589 }
2590 }
2591 }
2592
2593 clientKill (c);
2594}
2595
2596void
2597clientEnterContextMenuState (Client *c)
2598{
2599 ScreenInfo *screen_info;
2600 DisplayInfo *display_info;
2601
2602 g_return_if_fail (c != NULL);
2603
2604 TRACE ("entering clientEnterContextMenuState");
2605 TRACE ("Showing the what's this help for client \"%s\" (0x%lx)", c->name, c->window);
2606
2607 screen_info = c->screen_info;
2608 display_info = screen_info->display_info;
2609
2610 if (FLAG_TEST (c->wm_flags, WM_FLAG_CONTEXT_HELP))
2611 {
2612 sendClientMessage (c->screen_info, c->window, NET_WM_CONTEXT_HELP,
2613 myDisplayGetCurrentTime (display_info));
2614 }
2615}
2616
2617void
2618clientSetLayer (Client *c, guint l)
2619{
2620 GList *list_of_windows = NULL;
2621 GList *list = NULL;
2622 Client *c2 = NULL;
2623
2624 g_return_if_fail (c != NULL);
2625 TRACE ("entering clientSetLayer for \"%s\" (0x%lx) on layer %d", c->name, c->window, l);
2626
2627 list_of_windows = clientListTransientOrModal (c);
2628 for (list = list_of_windows; list; list = g_list_next (list))
2629 {
2630 c2 = (Client *) list->data;
2631 if (c2->win_layer != l)
2632 {
2633 TRACE ("setting client \"%s\" (0x%lx) layer to %d", c2->name,
2634 c2->window, l);
2635 c2->win_layer = l;
2636 }
2637 }
2638 g_list_free (list_of_windows);
2639
2640 if (clientGetLastRaise (c->screen_info) == c)
2641 {
2642 clientClearLastRaise (c->screen_info);
2643 }
2644
2645 c2 = clientGetFocusOrPending ();
2646 if (c2 && (c2 != c) && (c2->win_layer == c->win_layer))
2647 {
2648 TRACE ("Placing %s under %s", c->name, c2->name);
2649 clientLower (c, c2->frame);
2650 }
2651 else
2652 {
2653 TRACE ("Placing %s on top of its layer %lu", c->name, c->win_layer);
2654 clientRaise (c, None);
2655 }
2656}
2657
2658void
2659clientShade (Client *c)
2660{
2661 XWindowChanges wc;
2662 ScreenInfo *screen_info;
2663 DisplayInfo *display_info;
2664 unsigned long mask;
2665
2666 g_return_if_fail (c != NULL);
2667 TRACE ("entering clientToggleShaded");
2668 TRACE ("shading client \"%s\" (0x%lx)", c->name, c->window);
2669
2670 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
2671 || FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
2672 {
2673 TRACE ("cowardly refusing to shade \"%s\" (0x%lx) because it has no border", c->name, c->window);
2674 return;
2675 }
2676 else if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2677 {
2678 TRACE ("\"%s\" (0x%lx) is already shaded", c->name, c->window);
2679 return;
2680 }
2681
2682 screen_info = c->screen_info;
2683 display_info = screen_info->display_info;
2684
2685 FLAG_SET (c->flags, CLIENT_FLAG_SHADED);
2686 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
2687 {
2688 mask = (CWWidth | CWHeight);
2689 if (clientConstrainPos (c, FALSE))
2690 {
2691 wc.x = c->x;
2692 wc.y = c->y;
2693 mask |= (CWX | CWY);
2694 }
2695
2696 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2697 {
2698 c->ignore_unmap++;
2699 }
2700 /*
2701 * Shading unmaps the client window. We therefore have to transfer focus to its frame
2702 * so that focus doesn't return to root. clientSetFocus() will take care of focusing
2703 * the window frame since the SHADED flag is now set.
2704 */
2705 if (c == clientGetFocus ())
2706 {
2707 clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
2708 }
2709 XUnmapWindow (display_info->dpy, c->window);
2710
2711 wc.width = c->width;
2712 wc.height = c->height;
2713 clientConfigure (c, &wc, mask, CFG_FORCE_REDRAW);
2714 }
2715 clientSetNetState (c);
2716}
2717
2718void
2719clientUnshade (Client *c)
2720{
2721 XWindowChanges wc;
2722 ScreenInfo *screen_info;
2723 DisplayInfo *display_info;
2724
2725 g_return_if_fail (c != NULL);
2726 TRACE ("entering clientToggleShaded");
2727 TRACE ("shading/unshading client \"%s\" (0x%lx)", c->name, c->window);
2728
2729 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2730 {
2731 TRACE ("\"%s\" (0x%lx) is not shaded", c->name, c->window);
2732 return;
2733 }
2734
2735 screen_info = c->screen_info;
2736 display_info = screen_info->display_info;
2737
2738 FLAG_UNSET (c->flags, CLIENT_FLAG_SHADED);
2739 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
2740 {
2741 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2742 {
2743 XMapWindow (display_info->dpy, c->window);
2744 }
2745 /*
2746 * Unshading will show the client window, so we need to focus it when unshading.
2747 */
2748 if (c == clientGetFocus ())
2749 {
2750 clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
2751 }
2752
2753 wc.width = c->width;
2754 wc.height = c->height;
2755 clientConfigure (c, &wc, CWWidth | CWHeight, CFG_FORCE_REDRAW);
2756 }
2757 clientSetNetState (c);
2758}
2759
2760void
2761clientToggleShaded (Client *c)
2762{
2763 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2764 {
2765 clientUnshade (c);
2766 }
2767 else
2768 {
2769 clientShade (c);
2770 }
2771}
2772
2773void
2774clientStick (Client *c, gboolean include_transients)
2775{
2776 ScreenInfo *screen_info;
2777 DisplayInfo *display_info;
2778 Client *c2;
2779 GList *list_of_windows;
2780 GList *list;
2781
2782 g_return_if_fail (c != NULL);
2783 TRACE ("entering clientStick");
2784
2785 screen_info = c->screen_info;
2786 display_info = screen_info->display_info;
2787
2788 if (include_transients)
2789 {
2790 list_of_windows = clientListTransientOrModal (c);
2791 for (list = list_of_windows; list; list = g_list_next (list))
2792 {
2793 c2 = (Client *) list->data;
2794 TRACE ("Sticking client \"%s\" (0x%lx)", c2->name, c2->window);
2795 FLAG_SET (c2->flags, CLIENT_FLAG_STICKY);
2796 setHint (display_info, c2->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2797 frameQueueDraw (c2, FALSE);
2798 }
2799 g_list_free (list_of_windows);
2800 }
2801 else
2802 {
2803 TRACE ("Sticking client \"%s\" (0x%lx)", c->name, c->window);
2804 FLAG_SET (c->flags, CLIENT_FLAG_STICKY);
2805 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2806 }
2807 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2808 clientSetNetState (c);
2809}
2810
2811void
2812clientUnstick (Client *c, gboolean include_transients)
2813{
2814 ScreenInfo *screen_info;
2815 DisplayInfo *display_info;
2816 Client *c2;
2817 GList *list_of_windows;
2818 GList *list;
2819
2820 g_return_if_fail (c != NULL);
2821 TRACE ("entering clientUnstick");
2822
2823 screen_info = c->screen_info;
2824 display_info = screen_info->display_info;
2825
2826 if (include_transients)
2827 {
2828 list_of_windows = clientListTransientOrModal (c);
2829 for (list = list_of_windows; list; list = g_list_next (list))
2830 {
2831 c2 = (Client *) list->data;
2832 TRACE ("Unsticking client \"%s\" (0x%lx)", c2->name, c2->window);
2833 FLAG_UNSET (c2->flags, CLIENT_FLAG_STICKY);
2834 setHint (display_info, c2->window, NET_WM_DESKTOP, (unsigned long) screen_info->current_ws);
2835 frameQueueDraw (c2, FALSE);
2836 }
2837 g_list_free (list_of_windows);
2838 }
2839 else
2840 {
2841 TRACE ("Unsticking client \"%s\" (0x%lx)", c->name, c->window);
2842 FLAG_UNSET (c->flags, CLIENT_FLAG_STICKY);
2843 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) screen_info->current_ws);
2844 }
2845 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2846 clientSetNetState (c);
2847}
2848
2849void
2850clientToggleSticky (Client *c, gboolean include_transients)
2851{
2852 g_return_if_fail (c != NULL);
2853 TRACE ("entering clientToggleSticky");
2854 TRACE ("sticking/unsticking client \"%s\" (0x%lx)", c->name, c->window);
2855
2856 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2857 {
2858 clientUnstick (c, include_transients);
2859 }
2860 else
2861 {
2862 clientStick (c, include_transients);
2863 }
2864}
2865
2866void
2867clientUpdateFullscreenSize (Client *c)
2868{
2869 ScreenInfo *screen_info;
2870 XWindowChanges wc;
2871 GdkRectangle monitor, rect;
2872 int i;
2873
2874 g_return_if_fail (c != NULL);
2875 TRACE ("entering clientUpdateFullscreenSize");
2876 TRACE ("Update fullscreen size for client \"%s\" (0x%lx)", c->name, c->window);
2877
2878 screen_info = c->screen_info;
2879
2880 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
2881 {
2882 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREN_MONITORS))
2883 {
2884 gdk_screen_get_monitor_geometry (screen_info->gscr, c->fullscreen_monitors[0], &rect);
2885 for (i = 1; i < 4; i++)
2886 {
2887 gdk_screen_get_monitor_geometry (screen_info->gscr, c->fullscreen_monitors[i], &monitor);
2888 gdk_rectangle_union (&rect, &monitor, &rect);
2889 }
2890 }
2891 else
2892 {
2893 int cx, cy;
2894
2895 cx = frameX (c) + (frameWidth (c) / 2);
2896 cy = frameY (c) + (frameHeight (c) / 2);
2897
2898 myScreenFindMonitorAtPoint (screen_info, cx, cy, &rect);
2899 }
2900
2901 wc.x = rect.x;
2902 wc.y = rect.y;
2903 wc.width = rect.width;
2904 wc.height = rect.height;
2905 }
2906
2907 else
2908 {
2909 wc.x = c->fullscreen_old_x;
2910 wc.y = c->fullscreen_old_y;
2911 wc.width = c->fullscreen_old_width;
2912 wc.height = c->fullscreen_old_height;
2913 }
2914
2915 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
2916 {
2917 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_FORCE_REDRAW);
2918 }
2919 else
2920 {
2921 c->x = wc.x;
2922 c->y = wc.y;
2923 c->height = wc.height;
2924 c->width = wc.width;
2925 }
2926}
2927
2928void clientToggleFullscreen (Client *c)
2929{
2930 g_return_if_fail (c != NULL);
2931 TRACE ("entering clientToggleFullscreen");
2932 TRACE ("toggle fullscreen client \"%s\" (0x%lx)", c->name, c->window);
2933
2934 /*can we switch to full screen, does it make any sense? */
2935 if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN) && (c->size->flags & PMaxSize))
2936 {
2937 GdkRectangle rect;
2938 int cx, cy;
2939
2940 cx = frameX (c) + (frameWidth (c) / 2);
2941 cy = frameY (c) + (frameHeight (c) / 2);
2942
2943 myScreenFindMonitorAtPoint (c->screen_info, cx, cy, &rect);
2944
2945 if ((c->size->max_width < rect.width) || (c->size->max_height < rect.height))
2946 {
2947 return;
2948 }
2949 }
2950
2951 if (!clientIsTransientOrModal (c) && (c->type == WINDOW_NORMAL))
2952 {
2953 FLAG_TOGGLE (c->flags, CLIENT_FLAG_FULLSCREEN);
2954 clientUpdateFullscreenState (c);
2955 }
2956}
2957
2958void clientSetFullscreenMonitor (Client *c, gint top, gint bottom, gint left, gint right)
2959{
2960 ScreenInfo *screen_info;
2961 DisplayInfo *display_info;
2962 gint num_monitors;
2963
2964 g_return_if_fail (c != NULL);
2965 TRACE ("entering clientSetFullscreenMonitor");
2966
2967 screen_info = c->screen_info;
2968 display_info = screen_info->display_info;
2969
2970 num_monitors = gdk_screen_get_n_monitors (screen_info->gscr);
2971 if ((top >= 0) && (top < num_monitors) &&
2972 (bottom >= 0) && (bottom < num_monitors) &&
2973 (left >= 0) && (left < num_monitors) &&
2974 (right >= 0) && (right < num_monitors))
2975 {
2976 c->fullscreen_monitors[0] = top;
2977 c->fullscreen_monitors[1] = bottom;
2978 c->fullscreen_monitors[2] = left;
2979 c->fullscreen_monitors[3] = right;
2980 FLAG_SET (c->flags, CLIENT_FLAG_FULLSCREN_MONITORS);
2981 }
2982 else
2983 {
2984 c->fullscreen_monitors[0] = 0;
2985 c->fullscreen_monitors[1] = 0;
2986 c->fullscreen_monitors[2] = 0;
2987 c->fullscreen_monitors[3] = 0;
2988 FLAG_UNSET (c->flags, CLIENT_FLAG_FULLSCREN_MONITORS);
2989 }
2990 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
2991 {
2992 clientUpdateFullscreenSize (c);
2993 }
2994 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREN_MONITORS))
2995 {
2996 setNetFullscreenMonitors (display_info, c->window, top, bottom, left, right);
2997 }
2998}
2999
3000void clientToggleLayerAbove (Client *c)
3001{
3002 g_return_if_fail (c != NULL);
3003 TRACE ("entering clientToggleAbove");
3004
3005 if ((c->type & WINDOW_REGULAR_FOCUSABLE) &&
3006 !clientIsTransientOrModal (c) &&
3007 !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
3008 {
3009 FLAG_UNSET (c->flags, CLIENT_FLAG_BELOW);
3010 FLAG_TOGGLE (c->flags, CLIENT_FLAG_ABOVE);
3011 clientUpdateLayerState (c);
3012 }
3013}
3014
3015void clientToggleLayerBelow (Client *c)
3016{
3017 g_return_if_fail (c != NULL);
3018 TRACE ("entering clientToggleBelow");
3019
3020 if ((c->type & WINDOW_REGULAR_FOCUSABLE) &&
3021 !clientIsTransientOrModal (c) &&
3022 !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
3023 {
3024 FLAG_UNSET (c->flags, CLIENT_FLAG_ABOVE);
3025 FLAG_TOGGLE (c->flags, CLIENT_FLAG_BELOW);
3026 clientUpdateLayerState (c);
3027 }
3028}
3029
3030void clientSetLayerNormal (Client *c)
3031{
3032 g_return_if_fail (c != NULL);
3033 TRACE ("entering clientSetLayerNormal");
3034
3035 if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
3036 {
3037 FLAG_UNSET (c->flags, CLIENT_FLAG_ABOVE | CLIENT_FLAG_BELOW);
3038 clientUpdateLayerState (c);
3039 }
3040}
3041
3042void
3043clientRemoveMaximizeFlag (Client *c)
3044{
3045 g_return_if_fail (c != NULL);
3046 TRACE ("entering clientRemoveMaximizeFlag");
3047 TRACE ("Removing maximize flag on client \"%s\" (0x%lx)", c->name,
3048 c->window);
3049
3050 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3051 frameQueueDraw (c, FALSE);
3052 clientSetNetActions (c);
3053 clientSetNetState (c);
3054}
3055
3056static void
3057clientNewMaxState (Client *c, XWindowChanges *wc, int mode)
3058{
3059 if (FLAG_TEST_ALL (mode, CLIENT_FLAG_MAXIMIZED))
3060 {
3061 /*
3062 * We need to test specifically for full de-maximization
3063 * otherwise it's too confusing when the window changes
3064 * from horiz to vertical maximization or vice-versa.
3065 */
3066 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
3067 {
3068 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3069 wc->x = c->old_x;
3070 wc->y = c->old_y;
3071 wc->width = c->old_width;
3072 wc->height = c->old_height;
3073
3074 return;
3075 }
3076 }
3077
3078 if (FLAG_TEST (mode, CLIENT_FLAG_MAXIMIZED_HORIZ))
3079 {
3080 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
3081 {
3082 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ);
3083 }
3084 else
3085 {
3086 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ);
3087 wc->x = c->old_x;
3088 wc->y = c->old_y;
3089 wc->width = c->old_width;
3090 wc->height = c->old_height;
3091 }
3092 }
3093
3094 if (FLAG_TEST (mode, CLIENT_FLAG_MAXIMIZED_VERT))
3095 {
3096 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
3097 {
3098 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_VERT);
3099 }
3100 else
3101 {
3102 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_VERT);
3103 wc->x = c->old_x;
3104 wc->y = c->old_y;
3105 wc->width = c->old_width;
3106 wc->height = c->old_height;
3107 }
3108 }
3109}
3110
3111static gboolean
3112clientNewMaxSize (Client *c, XWindowChanges *wc, GdkRectangle *rect, tilePositionType tile)
3113{
3114 ScreenInfo *screen_info;
3115 int full_x, full_y, full_w, full_h;
3116 int tmp_x, tmp_y, tmp_w, tmp_h;
3117
3118 tmp_x = frameX (c);
3119 tmp_y = frameY (c);
3120 tmp_h = frameHeight (c);
3121 tmp_w = frameWidth (c);
3122 screen_info = c->screen_info;
3123
3124 full_x = MAX (screen_info->params->xfwm_margins[STRUTS_LEFT], rect->x);
3125 full_y = MAX (screen_info->params->xfwm_margins[STRUTS_TOP], rect->y);
3126 full_w = MIN (screen_info->width - screen_info->params->xfwm_margins[STRUTS_RIGHT],
3127 rect->x + rect->width) - full_x;
3128 full_h = MIN (screen_info->height - screen_info->params->xfwm_margins[STRUTS_BOTTOM],
3129 rect->y + rect->height) - full_y;
3130
3131 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED))
3132 {
3133 /* Adjust size to the largest size available, not covering struts */
3134 clientMaxSpace (screen_info, &full_x, &full_y, &full_w, &full_h);
3135 wc->x = full_x + frameLeft (c);
3136 wc->y = full_y + frameTop (c);
3137 wc->width = full_w - frameLeft (c) - frameRight (c);
3138 wc->height = full_h - frameTop (c) - frameBottom (c);
3139
3140 return ((wc->width <= c->size->max_width) && (wc->height <= c->size->max_height));
3141 }
3142
3143 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
3144 {
3145 /* Adjust size to the widest size available, for the current vertical position/height */
3146 switch (tile)
3147 {
3148 case TILE_UP:
3149 tmp_h = full_h / 2;
3150 tmp_y = full_y;
3151 clientMaxSpace (screen_info, &full_x, &tmp_y, &full_w, &tmp_h);
3152 wc->y = tmp_y + frameTop (c);
3153 wc->height = tmp_h - frameTop (c) - frameBottom (c);
3154 break;
3155 case TILE_DOWN:
3156 tmp_h = full_h / 2;
3157 tmp_y = full_y + full_h / 2;
3158 clientMaxSpace (screen_info, &full_x, &tmp_y, &full_w, &tmp_h);
3159 wc->y = tmp_y + frameTop (c);
3160 wc->height = tmp_h - frameTop (c) - frameBottom (c);
3161 break;
3162 default:
3163 clientMaxSpace (screen_info, &full_x, &tmp_y, &full_w, &tmp_h);
3164 break;
3165 }
3166
3167 wc->x = full_x + frameLeft (c);
3168 wc->width = full_w - frameLeft (c) - frameRight (c);
3169
3170 return (wc->width <= c->size->max_width);
3171 }
3172
3173 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
3174 {
3175 /* Adjust size to the tallest size available, for the current horizontal position/width */
3176 switch (tile)
3177 {
3178 case TILE_LEFT:
3179 tmp_x = full_x;
3180 tmp_w = full_w / 2;
3181 clientMaxSpace (screen_info, &tmp_x, &full_y, &tmp_w, &full_h);
3182 wc->x = tmp_x + frameLeft (c);
3183 wc->width = tmp_w - frameLeft (c) - frameRight (c);
3184 break;
3185 case TILE_RIGHT:
3186 tmp_x = full_x + full_w /2;
3187 tmp_w = full_w / 2;
3188 clientMaxSpace (screen_info, &tmp_x, &full_y, &tmp_w, &full_h);
3189 wc->x = tmp_x + frameLeft (c);
3190 wc->width = tmp_w - frameLeft (c) - frameRight (c);
3191 break;
3192 default:
3193 clientMaxSpace (screen_info, &tmp_x, &full_y, &tmp_w, &full_h);
3194 break;
3195 }
3196
3197 wc->y = full_y + frameTop (c);
3198 wc->height = full_h - frameTop (c) - frameBottom (c);
3199
3200 return (wc->height <= c->size->max_height);
3201 }
3202
3203 return TRUE;
3204}
3205
3206gboolean
3207clientToggleMaximized (Client *c, int mode, gboolean restore_position)
3208{
3209 DisplayInfo *display_info;
3210 ScreenInfo *screen_info;
3211 XWindowChanges wc;
3212 GdkRectangle rect;
3213 unsigned long old_flags;
3214
3215 g_return_val_if_fail (c != NULL, FALSE);
3216
3217 TRACE ("entering clientToggleMaximized");
3218 TRACE ("maximzing/unmaximizing client \"%s\" (0x%lx)", c->name, c->window);
3219
3220 if (!CLIENT_CAN_MAXIMIZE_WINDOW (c))
3221 {
3222 return FALSE;
3223 }
3224
3225 screen_info = c->screen_info;
3226 display_info = screen_info->display_info;
3227 myScreenFindMonitorAtPoint (screen_info,
3228 frameX (c) + (frameWidth (c) / 2),
3229 frameY (c) + (frameHeight (c) / 2), &rect);
3230
3231 wc.x = c->x;
3232 wc.y = c->y;
3233 wc.width = c->width;
3234 wc.height = c->height;
3235
3236 if (restore_position &&
3237 FLAG_TEST (mode, CLIENT_FLAG_MAXIMIZED) &&
3238 !FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
3239 {
3240 clientSaveSizePos (c);
3241 }
3242
3243 old_flags = c->flags;
3244
3245 /* 1) Compute the new state */
3246 clientNewMaxState (c, &wc, mode);
3247
3248 /* 2) Compute the new size, based on the state */
3249 if (!clientNewMaxSize (c, &wc, &rect, TILE_NONE))
3250 {
3251 c->flags = old_flags;
3252 return FALSE;
3253 }
3254
3255 /* 3) Update size and position fields */
3256 c->x = wc.x;
3257 c->y = wc.y;
3258 c->height = wc.height;
3259 c->width = wc.width;
3260
3261 /* Maximizing may remove decoration on the side, update NET_FRAME_EXTENTS accordingly */
3262 setNetFrameExtents (display_info,
3263 c->window,
3264 frameTop (c),
3265 frameLeft (c),
3266 frameRight (c),
3267 frameBottom (c));
3268
3269 /* Maximized windows w/out border cannot be resized, update allowed actions */
3270 clientSetNetActions (c);
3271 if (restore_position && FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
3272 {
3273 clientConfigure (c, &wc, CWWidth | CWHeight | CWX | CWY, CFG_FORCE_REDRAW);
3274 }
3275 clientSetNetState (c);
3276
3277 return TRUE;
3278}
3279
3280gboolean
3281clientTile (Client *c, gint cx, gint cy, tilePositionType tile, gboolean send_configure)
3282{
3283 DisplayInfo *display_info;
3284 ScreenInfo *screen_info;
3285 XWindowChanges wc;
3286 GdkRectangle rect;
3287 unsigned long old_flags;
3288 int mode;
3289
3290 g_return_val_if_fail (c != NULL, FALSE);
3291
3292 TRACE ("entering clientTile");
3293 TRACE ("Tiling client \"%s\" (0x%lx)", c->name, c->window);
3294
3295 if (!CLIENT_CAN_TILE_WINDOW (c))
3296 {
3297 return FALSE;
3298 }
3299
3300 screen_info = c->screen_info;
3301 display_info = screen_info->display_info;
3302 myScreenFindMonitorAtPoint (screen_info, cx, cy, &rect);
3303
3304 wc.x = c->x;
3305 wc.y = c->y;
3306 wc.width = c->width;
3307 wc.height = c->height;
3308
3309 switch (tile)
3310 {
3311 case TILE_LEFT:
3312 case TILE_RIGHT:
3313 mode = CLIENT_FLAG_MAXIMIZED_VERT;
3314 break;
3315 case TILE_UP:
3316 case TILE_DOWN:
3317 mode = CLIENT_FLAG_MAXIMIZED_HORIZ;
3318 break;
3319 default:
3320 return FALSE;
3321 break;
3322 }
3323
3324 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
3325 {
3326 clientSaveSizePos (c);
3327 }
3328
3329 old_flags = c->flags;
3330 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3331 clientNewMaxState (c, &wc, mode);
3332 if (!clientNewMaxSize (c, &wc, &rect, tile))
3333 {
3334 c->flags = old_flags;
3335 return FALSE;
3336 }
3337
3338 c->x = wc.x;
3339 c->y = wc.y;
3340 c->height = wc.height;
3341 c->width = wc.width;
3342
3343 if (send_configure)
3344 {
3345 setNetFrameExtents (display_info,
3346 c->window,
3347 frameTop (c),
3348 frameLeft (c),
3349 frameRight (c),
3350 frameBottom (c));
3351
3352 clientSetNetActions (c);
3353
3354 clientConfigure (c, &wc, CWWidth | CWHeight | CWX | CWY, CFG_FORCE_REDRAW);
3355 }
3356 clientSetNetState (c);
3357
3358 return TRUE;
3359}
3360
3361void
3362clientUpdateOpacity (Client *c)
3363{
3364 ScreenInfo *screen_info;
3365 DisplayInfo *display_info;
3366 Client *focused;
3367 gboolean opaque;
3368
3369 g_return_if_fail (c != NULL);
3370
3371 screen_info = c->screen_info;
3372 display_info = screen_info->display_info;
3373 if (!compositorIsUsable (display_info))
3374 {
3375 return;
3376 }
3377
3378 focused = clientGetFocus ();
3379 opaque = (FLAG_TEST(c->type, WINDOW_TYPE_DONT_PLACE | WINDOW_TYPE_DONT_FOCUS)
3380 || (focused == c));
3381
3382 clientSetOpacity (c, c->opacity, OPACITY_INACTIVE, opaque ? 0 : OPACITY_INACTIVE);
3383}
3384
3385void
3386clientUpdateAllOpacity (ScreenInfo *screen_info)
3387{
3388 DisplayInfo *display_info;
3389 Client *c;
3390 guint i;
3391
3392 g_return_if_fail (screen_info != NULL);
3393
3394 display_info = screen_info->display_info;
3395 if (!compositorIsUsable (display_info))
3396 {
3397 return;
3398 }
3399
3400 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, ++i)
3401 {
3402 clientUpdateOpacity (c);
3403 }
3404}
3405
3406void
3407clientSetOpacity (Client *c, guint opacity, guint clear, guint xor)
3408{
3409 ScreenInfo *screen_info;
3410 DisplayInfo *display_info;
3411 guint applied;
3412
3413 screen_info = c->screen_info;
3414 display_info = screen_info->display_info;
3415
3416 if (!compositorIsUsable (display_info))
3417 {
3418 return;
3419 }
3420
3421 c->opacity_flags = (c->opacity_flags & ~clear) ^ xor;
3422
3423 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED))
3424 {
3425 applied = c->opacity;
3426 }
3427 else
3428 {
3429 long long multiplier = 1, divisor = 1;
3430
3431 c->opacity = applied = opacity;
3432
3433 if (FLAG_TEST (c->opacity_flags, OPACITY_MOVE))
3434 {
3435 multiplier *= c->screen_info->params->move_opacity;
3436 divisor *= 100;
3437 }
3438 if (FLAG_TEST (c->opacity_flags, OPACITY_RESIZE))
3439 {
3440 multiplier *= c->screen_info->params->resize_opacity;
3441 divisor *= 100;
3442 }
3443 if (FLAG_TEST (c->opacity_flags, OPACITY_INACTIVE))
3444 {
3445 multiplier *= c->screen_info->params->inactive_opacity;
3446 divisor *= 100;
3447 }
3448
3449 applied = (guint) ((long long) applied * multiplier / divisor);
3450 }
3451
3452 if (applied != c->opacity_applied)
3453 {
3454 c->opacity_applied = applied;
3455 compositorWindowSetOpacity (display_info, c->frame, applied);
3456 }
3457}
3458
3459void
3460clientDecOpacity (Client *c)
3461{
3462 ScreenInfo *screen_info;
3463 DisplayInfo *display_info;
3464
3465 screen_info = c->screen_info;
3466 display_info = screen_info->display_info;
3467
3468 if (!compositorIsUsable (display_info))
3469 {
3470 return;
3471 }
3472
3473 if ((c->opacity > OPACITY_SET_MIN) && !(FLAG_TEST (c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED)))
3474 {
3475 clientSetOpacity (c, c->opacity - OPACITY_SET_STEP, 0, 0);
3476 }
3477}
3478
3479void
3480clientIncOpacity (Client *c)
3481{
3482 ScreenInfo *screen_info;
3483 DisplayInfo *display_info;
3484
3485 screen_info = c->screen_info;
3486 display_info = screen_info->display_info;
3487
3488 if (!compositorIsUsable (display_info))
3489 {
3490 return;
3491 }
3492
3493 if ((c->opacity < NET_WM_OPAQUE) && !(FLAG_TEST (c->xfwm_flags, XFWM_FLAG_OPACITY_LOCKED)))
3494 {
3495 guint opacity = c->opacity + OPACITY_SET_STEP;
3496
3497 if (opacity < OPACITY_SET_MIN)
3498 {
3499 opacity = NET_WM_OPAQUE;
3500 }
3501 clientSetOpacity (c, opacity, 0, 0);
3502 }
3503}
3504
3505/* Xrandr stuff: on screen size change, make sure all clients are still visible */
3506void
3507clientScreenResize(ScreenInfo *screen_info, gboolean fully_visible)
3508{
3509 Client *c = NULL;
3510 GList *list, *list_of_windows;
3511 XWindowChanges wc;
3512 unsigned short configure_flags;
3513
3514 list_of_windows = clientGetStackList (screen_info);
3515
3516 if (!list_of_windows)
3517 {
3518 return;
3519 }
3520
3521 /* Revalidate client struts */
3522 for (list = list_of_windows; list; list = g_list_next (list))
3523 {
3524 c = (Client *) list->data;
3525 if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STRUT))
3526 {
3527 clientValidateNetStrut (c);
3528 }
3529 }
3530
3531 for (list = list_of_windows; list; list = g_list_next (list))
3532 {
3533 unsigned long maximization_flags = 0L;
3534
3535 c = (Client *) list->data;
3536 if (!CONSTRAINED_WINDOW (c))
3537 {
3538 continue;
3539 }
3540
3541 /* Recompute size and position of maximized windows */
3542 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
3543 {
3544 maximization_flags = c->flags & CLIENT_FLAG_MAXIMIZED;
3545
3546 /* Force an update by clearing the internal flags */
3547 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3548 clientToggleMaximized (c, maximization_flags, FALSE);
3549
3550 wc.x = c->x;
3551 wc.y = c->y;
3552 wc.width = c->width;
3553 wc.height = c->height;
3554 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_NOTIFY);
3555 }
3556 else if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
3557 {
3558 clientUpdateFullscreenSize (c);
3559 }
3560 else
3561 {
3562 configure_flags = CFG_CONSTRAINED | CFG_REQUEST;
3563 if (fully_visible)
3564 {
3565 configure_flags |= CFG_KEEP_VISIBLE;
3566 }
3567 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SAVED_POS))
3568 {
3569 wc.x = c->saved_x;
3570 wc.y = c->saved_y;
3571 }
3572 else
3573 {
3574 FLAG_SET (c->xfwm_flags, XFWM_FLAG_SAVED_POS);
3575
3576 c->saved_x = c->x;
3577 c->saved_y = c->y;
3578
3579 wc.x = c->x;
3580 wc.y = c->y;
3581 }
3582
3583 clientConfigure (c, &wc, CWX | CWY, configure_flags);
3584 }
3585 }
3586
3587 g_list_free (list_of_windows);
3588}
3589
3590void
3591clientUpdateCursor (Client *c)
3592{
3593 ScreenInfo *screen_info;
3594 DisplayInfo *display_info;
3595 guint i;
3596
3597 g_return_if_fail (c != NULL);
3598
3599 screen_info = c->screen_info;
3600 display_info = screen_info->display_info;
3601
3602 for (i = 0; i <= SIDE_TOP; i++)
3603 {
3604 xfwmWindowSetCursor (&c->sides[i],
3605 myDisplayGetCursorResize(display_info, CORNER_COUNT + i));
3606 }
3607
3608 for (i = 0; i < CORNER_COUNT; i++)
3609 {
3610 xfwmWindowSetCursor (&c->corners[i],
3611 myDisplayGetCursorResize(display_info, i));
3612 }
3613}
3614
3615void
3616clientUpdateAllCursor (ScreenInfo *screen_info)
3617{
3618 Client *c;
3619 guint i;
3620
3621 g_return_if_fail (screen_info != NULL);
3622
3623 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, ++i)
3624 {
3625 clientUpdateCursor (c);
3626 }
3627}
3628
3629static eventFilterStatus
3630clientButtonPressEventFilter (XEvent * xevent, gpointer data)
3631{
3632 ScreenInfo *screen_info;
3633 DisplayInfo *display_info;
3634 Client *c;
3635 ButtonPressData *passdata;
3636 eventFilterStatus status;
3637 int b;
3638 gboolean pressed;
3639
3640 passdata = (ButtonPressData *) data;
3641 c = passdata->c;
3642 b = passdata->b;
3643
3644 screen_info = c->screen_info;
3645 display_info = screen_info->display_info;
3646
3647 /* Update the display time */
3648 myDisplayUpdateCurrentTime (display_info, xevent);
3649
3650 status = EVENT_FILTER_STOP;
3651 pressed = TRUE;
3652
3653 switch (xevent->type)
3654 {
3655 case EnterNotify:
3656 if ((xevent->xcrossing.mode != NotifyGrab) && (xevent->xcrossing.mode != NotifyUngrab))
3657 {
3658 c->button_status[b] = BUTTON_STATE_PRESSED;
3659 frameQueueDraw (c, FALSE);
3660 }
3661 break;
3662 case LeaveNotify:
3663 if ((xevent->xcrossing.mode != NotifyGrab) && (xevent->xcrossing.mode != NotifyUngrab))
3664 {
3665 c->button_status[b] = BUTTON_STATE_NORMAL;
3666 frameQueueDraw (c, FALSE);
3667 }
3668 break;
3669 case ButtonRelease:
3670 pressed = FALSE;
3671 break;
3672 case UnmapNotify:
3673 if (xevent->xunmap.window == c->window)
3674 {
3675 pressed = FALSE;
3676 c->button_status[b] = BUTTON_STATE_NORMAL;
3677 }
3678 break;
3679 case KeyPress:
3680 case KeyRelease:
3681 break;
3682 default:
3683 status = EVENT_FILTER_CONTINUE;
3684 break;
3685 }
3686
3687 if (!pressed)
3688 {
3689 TRACE ("event loop now finished");
3690 gtk_main_quit ();
3691 }
3692
3693 return status;
3694}
3695
3696void
3697clientButtonPress (Client *c, Window w, XButtonEvent * bev)
3698{
3699 ScreenInfo *screen_info;
3700 DisplayInfo *display_info;
3701 ButtonPressData passdata;
3702 int b, g1;
3703
3704 g_return_if_fail (c != NULL);
3705 TRACE ("entering clientButtonPress");
3706
3707 for (b = 0; b < BUTTON_COUNT; b++)
3708 {
3709 if (MYWINDOW_XWINDOW (c->buttons[b]) == w)
3710 {
3711 break;
3712 }
3713 }
3714
3715 screen_info = c->screen_info;
3716 display_info = screen_info->display_info;
3717
3718 g1 = XGrabPointer (display_info->dpy, w, FALSE,
3719 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask,
3720 GrabModeAsync, GrabModeAsync,
3721 screen_info->xroot, None,
3722 myDisplayGetCurrentTime (display_info));
3723
3724 if (g1 != GrabSuccess)
3725 {
3726 TRACE ("grab failed in clientButtonPress");
3727 gdk_beep ();
3728 if (g1 == GrabSuccess)
3729 {
3730 XUngrabKeyboard (display_info->dpy, myDisplayGetCurrentTime (display_info));
3731 }
3732 return;
3733 }
3734
3735 passdata.c = c;
3736 passdata.b = b;
3737
3738 c->button_status[b] = BUTTON_STATE_PRESSED;
3739 frameQueueDraw (c, FALSE);