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