Better error message when defaults file is missing.
[xfwm4.git] / src / client.c
blobe76bee9f6fa1a7063d682c8c46b04e884fe05d64
1 /* $Id$
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 oroborus - (c) 2001 Ken Lynch
18 xfwm4 - (c) 2002-2007 Olivier Fourdan
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <X11/X.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <X11/extensions/shape.h>
32 #include <glib.h>
33 #include <gdk/gdk.h>
34 #include <gdk/gdkx.h>
35 #include <gtk/gtk.h>
36 #include <libxfce4util/libxfce4util.h>
38 #include "client.h"
39 #include "compositor.h"
40 #include "focus.h"
41 #include "frame.h"
42 #include "hints.h"
43 #include "icons.h"
44 #include "misc.h"
45 #include "mypixmap.h"
46 #include "mywindow.h"
47 #include "netwm.h"
48 #include "placement.h"
49 #include "poswin.h"
50 #include "screen.h"
51 #include "session.h"
52 #include "settings.h"
53 #include "stacking.h"
54 #include "startup_notification.h"
55 #include "tabwin.h"
56 #include "transients.h"
57 #include "wireframe.h"
58 #include "workspaces.h"
59 #include "event_filter.h"
61 /* Event mask definition */
63 #define POINTER_EVENT_MASK \
64 ButtonPressMask|\
65 ButtonReleaseMask
67 #define FRAME_EVENT_MASK \
68 SubstructureNotifyMask|\
69 SubstructureRedirectMask|\
70 FocusChangeMask|\
71 EnterWindowMask|\
72 PropertyChangeMask
74 #define CLIENT_EVENT_MASK \
75 StructureNotifyMask|\
76 FocusChangeMask|\
77 PropertyChangeMask
79 #define BUTTON_EVENT_MASK \
80 EnterWindowMask|\
81 LeaveWindowMask
83 /* Useful macros */
84 #define START_ICONIC(c) \
85 ((c->wmhints) && \
86 (c->wmhints->initial_state == IconicState) && \
87 !clientIsValidTransientOrModal (c))
89 #define OPACITY_SET_STEP (guint) 0x16000000
90 #define OPACITY_SET_MIN (guint) 0x40000000
92 typedef struct _MoveResizeData MoveResizeData;
93 struct _MoveResizeData
95 Client *c;
96 gboolean use_keys;
97 gboolean grab;
98 gboolean is_transient;
99 gboolean move_resized;
100 gboolean released;
101 int button;
102 int cancel_x, cancel_y; /* for cancellation (either position or size) */
103 int cancel_workspace;
104 int mx, my;
105 int ox, oy;
106 int oldw, oldh;
107 int corner;
108 Poswin *poswin;
111 typedef struct _ClientCycleData ClientCycleData;
112 struct _ClientCycleData
114 Client *c;
115 Tabwin *tabwin;
116 Window wireframe;
117 int cycle_range;
120 typedef struct _ButtonPressData ButtonPressData;
121 struct _ButtonPressData
123 int b;
124 Client *c;
127 /* Forward decl */
128 static void
129 clientUpdateIconPix (Client * c);
131 Display *
132 clientGetXDisplay (Client * c)
134 g_return_val_if_fail (c, NULL);
136 return myScreenGetXDisplay (c->screen_info);
139 void
140 clientInstallColormaps (Client * c)
142 XWindowAttributes attr;
143 gboolean installed;
144 int i;
146 g_return_if_fail (c != NULL);
147 TRACE ("entering clientInstallColormaps");
149 installed = FALSE;
150 if (c->ncmap)
152 for (i = c->ncmap - 1; i >= 0; i--)
154 XGetWindowAttributes (clientGetXDisplay (c), c->cmap_windows[i], &attr);
155 XInstallColormap (clientGetXDisplay (c), attr.colormap);
156 if (c->cmap_windows[i] == c->window)
158 installed = TRUE;
162 if ((!installed) && (c->cmap))
164 XInstallColormap (clientGetXDisplay (c), c->cmap);
168 void
169 clientUpdateColormaps (Client * c)
171 g_return_if_fail (c != NULL);
172 TRACE ("entering clientUpdateColormaps");
174 if (c->ncmap)
176 XFree (c->cmap_windows);
177 c->ncmap = 0;
179 if (!XGetWMColormapWindows (clientGetXDisplay (c), c->window, &c->cmap_windows, &c->ncmap))
181 c->cmap_windows = NULL;
182 c->ncmap = 0;
186 void
187 clientUpdateName (Client * c)
189 ScreenInfo *screen_info;
190 DisplayInfo *display_info;
191 gchar *name;
193 g_return_if_fail (c != NULL);
194 TRACE ("entering clientUpdateName");
196 screen_info = c->screen_info;
197 display_info = screen_info->display_info;
199 getWindowName (display_info, c->window, &name);
200 if (name)
202 if (c->name)
204 if (strcmp (name, c->name))
206 g_free (c->name);
207 c->name = name;
208 FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
209 frameQueueDraw (c);
215 void
216 clientUpdateAllFrames (ScreenInfo *screen_info, int mask)
218 Client *c;
219 XWindowChanges wc;
220 int i;
222 g_return_if_fail (screen_info != NULL);
224 TRACE ("entering clientRedrawAllFrames");
225 myScreenGrabPointer (screen_info, EnterWindowMask, None, myDisplayGetCurrentTime (screen_info->display_info));
227 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, i++)
229 unsigned long configure_flags = 0L;
231 if (mask & UPDATE_BUTTON_GRABS)
233 clientUngrabButtons (c);
234 clientGrabButtons (c);
235 clientGrabMouseButton (c);
237 if (mask & UPDATE_CACHE)
239 clientUpdateIconPix (c);
241 if (mask & UPDATE_GRAVITY)
243 clientGravitate (c, REMOVE);
244 clientGravitate (c, APPLY);
245 setNetFrameExtents (screen_info->display_info,
246 c->window,
247 frameTop (c),
248 frameLeft (c),
249 frameRight (c),
250 frameBottom (c));
251 configure_flags |= CFG_FORCE_REDRAW;
252 mask &= ~UPDATE_FRAME;
254 if (mask & UPDATE_MAXIMIZE)
256 unsigned long maximization_flags = 0L;
258 /* Recompute size and position of maximized windows */
259 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT))
261 maximization_flags |= FLAG_TEST (c->flags,
262 CLIENT_FLAG_MAXIMIZED_HORIZ) ? WIN_STATE_MAXIMIZED_HORIZ : 0;
263 maximization_flags |= FLAG_TEST (c->flags,
264 CLIENT_FLAG_MAXIMIZED_VERT) ? WIN_STATE_MAXIMIZED_VERT : 0;
266 /* Force an update by clearing the internal flags */
267 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
268 clientToggleMaximized (c, maximization_flags, FALSE);
270 configure_flags |= CFG_FORCE_REDRAW;
271 mask &= ~UPDATE_FRAME;
274 if (configure_flags != 0L)
276 wc.x = c->x;
277 wc.y = c->y;
278 wc.width = c->width;
279 wc.height = c->height;
280 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, configure_flags);
282 if (mask & UPDATE_FRAME)
284 frameDraw (c, TRUE);
288 myScreenUngrabPointer (screen_info);
291 void
292 clientGrabButtons (Client * c)
294 ScreenInfo *screen_info;
296 g_return_if_fail (c != NULL);
297 TRACE ("entering clientGrabButtons");
298 TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
300 screen_info = c->screen_info;
301 if (screen_info->params->easy_click)
303 grabButton(clientGetXDisplay (c), AnyButton, screen_info->params->easy_click, c->window);
307 void
308 clientUngrabButtons (Client * c)
310 g_return_if_fail (c != NULL);
311 TRACE ("entering clientUngrabButtons");
312 TRACE ("grabbing buttons for client \"%s\" (0x%lx)", c->name, c->window);
314 XUngrabButton (clientGetXDisplay (c), AnyButton, AnyModifier, c->window);
317 static gboolean
318 urgent_cb (gpointer data)
320 Client *c;
322 TRACE ("entering urgent_cb");
324 c = (Client *) data;
325 if (c != clientGetFocus ())
327 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
328 frameDraw (c, FALSE);
330 return (TRUE);
333 void
334 clientUpdateUrgency (Client *c)
336 g_return_if_fail (c != NULL);
338 TRACE ("entering clientUpdateUrgency");
340 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
341 if (c->blink_timeout_id)
343 g_source_remove (c->blink_timeout_id);
344 frameDraw (c, FALSE);
346 FLAG_UNSET (c->wm_flags, WM_FLAG_URGENT);
348 c->blink_timeout_id = 0;
349 if ((c->wmhints) && (c->wmhints->flags & XUrgencyHint))
351 FLAG_SET (c->wm_flags, WM_FLAG_URGENT);
352 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
354 c->blink_timeout_id =
355 g_timeout_add_full (G_PRIORITY_DEFAULT,
356 CLIENT_BLINK_TIMEOUT,
357 (GtkFunction) urgent_cb,
358 (gpointer) c, NULL);
361 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE)
362 && !FLAG_TEST (c->wm_flags, WM_FLAG_URGENT)
363 && (c != clientGetFocus ()))
365 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE);
366 frameDraw (c, FALSE);
370 void
371 clientCoordGravitate (Client * c, int mode, int *x, int *y)
373 int dx, dy;
375 g_return_if_fail (c != NULL);
376 TRACE ("entering clientCoordGravitate");
378 c->gravity = c->size->flags & PWinGravity ? c->size->win_gravity : NorthWestGravity;
379 switch (c->gravity)
381 case CenterGravity:
382 dx = (c->border_width * 2) - ((frameLeft (c) +
383 frameRight (c)) / 2);
384 dy = (c->border_width * 2) - ((frameTop (c) +
385 frameBottom (c)) / 2);
386 break;
387 case NorthGravity:
388 dx = (c->border_width * 2) - ((frameLeft (c) +
389 frameRight (c)) / 2);
390 dy = frameTop (c);
391 break;
392 case SouthGravity:
393 dx = (c->border_width * 2) - ((frameLeft (c) +
394 frameRight (c)) / 2);
395 dy = (c->border_width * 2) - frameBottom (c);
396 break;
397 case EastGravity:
398 dx = (c->border_width * 2) - frameRight (c);
399 dy = (c->border_width * 2) - ((frameTop (c) +
400 frameBottom (c)) / 2);
401 break;
402 case WestGravity:
403 dx = frameLeft (c);
404 dy = (c->border_width * 2) - ((frameTop (c) +
405 frameBottom (c)) / 2);
406 break;
407 case NorthWestGravity:
408 dx = frameLeft (c);
409 dy = frameTop (c);
410 break;
411 case NorthEastGravity:
412 dx = (c->border_width * 2) - frameRight (c);
413 dy = frameTop (c);
414 break;
415 case SouthWestGravity:
416 dx = frameLeft (c);
417 dy = (c->border_width * 2) - frameBottom (c);
418 break;
419 case SouthEastGravity:
420 dx = (c->border_width * 2) - frameRight (c);
421 dy = (c->border_width * 2) - frameBottom (c);
422 break;
423 default:
424 dx = 0;
425 dy = 0;
426 break;
428 *x = *x + (dx * mode);
429 *y = *y + (dy * mode);
432 void
433 clientGravitate (Client * c, int mode)
435 int x, y;
437 g_return_if_fail (c != NULL);
438 TRACE ("entering clientGravitate");
440 x = c->x;
441 y = c->y;
442 clientCoordGravitate (c, mode, &x, &y);
443 c->x = x;
444 c->y = y;
447 static void
448 clientComputeWidth (Client * c, int *w)
450 int w2;
452 g_return_if_fail (c != NULL);
453 g_return_if_fail (w != NULL);
454 TRACE ("entering clientComputeWidth");
456 /* Bypass resize increment and max sizes for fullscreen */
457 if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
458 && !(FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
459 && (c->screen_info->params->borderless_maximize)))
461 if ((c->size->flags & PResizeInc) && (c->size->width_inc))
463 w2 = (*w - c->size->min_width) / c->size->width_inc;
464 *w = c->size->min_width + (w2 * c->size->width_inc);
466 if (c->size->flags & PMaxSize)
468 if (*w > c->size->max_width)
470 *w = c->size->max_width;
475 if (c->size->flags & PMinSize)
477 if (*w < c->size->min_width)
479 *w = c->size->min_width;
482 if (*w < 1)
484 *w = 1;
488 static void
489 clientSetWidth (Client * c, int w)
491 int temp;
493 g_return_if_fail (c != NULL);
494 TRACE ("entering clientSetWidth");
495 TRACE ("setting width %i for client \"%s\" (0x%lx)", w, c->name, c->window);
497 temp = w;
498 clientComputeWidth (c, &temp);
499 c->width = temp;
502 static void
503 clientComputeHeight (Client * c, int *h)
505 int h2;
507 g_return_if_fail (c != NULL);
508 TRACE ("entering clientComputeHeight");
510 /* Bypass resize increment and max sizes for fullscreen */
511 if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
512 && !(FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
513 && (c->screen_info->params->borderless_maximize)))
515 if ((c->size->flags & PResizeInc) && (c->size->height_inc))
517 h2 = (*h - c->size->min_height) / c->size->height_inc;
518 *h = c->size->min_height + (h2 * c->size->height_inc);
520 if (c->size->flags & PMaxSize)
522 if (*h > c->size->max_height)
524 *h = c->size->max_height;
529 if (c->size->flags & PMinSize)
531 if (*h < c->size->min_height)
533 *h = c->size->min_height;
536 if (*h < 1)
538 *h = 1;
542 static void
543 clientSetHeight (Client * c, int h)
545 int temp;
547 g_return_if_fail (c != NULL);
548 TRACE ("entering clientSetHeight");
549 TRACE ("setting height %i for client \"%s\" (0x%lx)", h, c->name, c->window);
551 temp = h;
552 clientComputeHeight (c, &temp);
553 c->height = temp;
556 /* clientConstrainRatio - adjust the given width and height to account for
557 the constraints imposed by size hints
559 The aspect ratio stuff, is borrowed from uwm's CheckConsistency routine.
562 #define MAKE_MULT(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
563 static void
564 clientConstrainRatio (Client * c, int *w, int *h, int corner)
567 g_return_if_fail (c != NULL);
568 TRACE ("entering clientConstrainRatio");
569 TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
571 if (c->size->flags & PAspect)
573 int xinc, yinc, minx, miny, maxx, maxy, delta;
575 xinc = c->size->width_inc;
576 yinc = c->size->height_inc;
577 minx = c->size->min_aspect.x;
578 miny = c->size->min_aspect.y;
579 maxx = c->size->max_aspect.x;
580 maxy = c->size->max_aspect.y;
582 if ((minx * *h > miny * *w) && (miny) &&
583 ((corner == CORNER_COUNT + SIDE_TOP) || (corner == CORNER_COUNT + SIDE_BOTTOM)))
585 /* Change width to match */
586 delta = MAKE_MULT (minx * *h / miny - *w, xinc);
587 if (!(c->size->flags & PMaxSize) ||
588 (*w + delta <= c->size->max_width))
590 *w += delta;
593 if ((minx * *h > miny * *w) && (minx))
595 delta = MAKE_MULT (*h - *w * miny / minx, yinc);
596 if (!(c->size->flags & PMinSize) ||
597 (*h - delta >= c->size->min_height))
599 *h -= delta;
601 else
603 delta = MAKE_MULT (minx * *h / miny - *w, xinc);
604 if (!(c->size->flags & PMaxSize) ||
605 (*w + delta <= c->size->max_width))
606 *w += delta;
610 if ((maxx * *h < maxy * *w) && (maxx) &&
611 ((corner == CORNER_COUNT + SIDE_LEFT) || (corner == CORNER_COUNT + SIDE_RIGHT)))
613 delta = MAKE_MULT (*w * maxy / maxx - *h, yinc);
614 if (!(c->size->flags & PMaxSize) ||
615 (*h + delta <= c->size->max_height))
617 *h += delta;
620 if ((maxx * *h < maxy * *w) && (maxy))
622 delta = MAKE_MULT (*w - maxx * *h / maxy, xinc);
623 if (!(c->size->flags & PMinSize) ||
624 (*w - delta >= c->size->min_width))
626 *w -= delta;
628 else
630 delta = MAKE_MULT (*w * maxy / maxx - *h, yinc);
631 if (!(c->size->flags & PMaxSize) ||
632 (*h + delta <= c->size->max_height))
634 *h += delta;
641 #define WIN_MOVED (mask & (CWX | CWY))
642 #define WIN_RESIZED (mask & (CWWidth | CWHeight))
644 static void
645 clientConfigureWindows (Client * c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
647 unsigned long change_mask;
648 XWindowChanges change_values;
650 change_mask = (mask & (CWX | CWY | CWWidth | CWHeight));
651 if (flags & CFG_FORCE_REDRAW)
653 change_mask |= (CWX | CWY);
656 if (change_mask & (CWX | CWY | CWWidth | CWHeight))
658 change_values.x = frameX (c);
659 change_values.y = frameY (c);
660 change_values.width = frameWidth (c);
661 change_values.height = frameHeight (c);
662 XConfigureWindow (clientGetXDisplay (c), c->frame, change_mask, &change_values);
664 if (WIN_RESIZED || (flags & CFG_FORCE_REDRAW))
666 frameDraw (c, (flags & CFG_FORCE_REDRAW));
669 change_values.x = frameLeft (c);
670 change_values.y = frameTop (c);
671 change_values.width = c->width;
672 change_values.height = c->height;
673 XConfigureWindow (clientGetXDisplay (c), c->window, change_mask, &change_values);
677 void
678 clientConfigure (Client * c, XWindowChanges * wc, unsigned long mask, unsigned short flags)
680 XConfigureEvent ce;
681 int px, py, pwidth, pheight;
683 g_return_if_fail (c != NULL);
684 g_return_if_fail (c->window != None);
686 TRACE ("entering clientConfigure");
687 TRACE ("configuring client \"%s\" (0x%lx) %s, type %u", c->name,
688 c->window, flags & CFG_CONSTRAINED ? "constrained" : "not contrained", c->type);
690 if (mask & CWX)
692 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
694 c->x = wc->x;
697 if (mask & CWY)
699 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING))
701 c->y = wc->y;
704 if (mask & CWWidth)
706 clientSetWidth (c, wc->width);
708 if (mask & CWHeight)
710 clientSetHeight (c, wc->height);
712 if (mask & CWBorderWidth)
714 c->border_width = wc->border_width;
716 if (mask & CWStackMode)
718 switch (wc->stack_mode)
721 * Limitation: we don't support neither
722 * TopIf, BottomIf nor Opposite ...
724 case Above:
725 TRACE ("Above");
726 if (mask & CWSibling)
728 clientRaise (c, wc->sibling);
730 else
732 clientRaise (c, None);
734 break;
735 case Below:
736 TRACE ("Below");
737 if (mask & CWSibling)
739 clientLower (c, wc->sibling);
741 else
743 clientLower (c, None);
746 break;
747 case Opposite:
748 case TopIf:
749 case BottomIf:
750 default:
751 break;
754 mask &= ~(CWStackMode | CWSibling);
756 /* Keep control over what the application does. However, some broken apps try
757 to achieve fullscreen by using static gravity and a (0,0) position, the
758 second part of the test is for this case.
760 if (((flags & (CFG_CONSTRAINED | CFG_REQUEST)) == (CFG_CONSTRAINED | CFG_REQUEST))
761 && CONSTRAINED_WINDOW (c)
762 && !((c->gravity == StaticGravity) && (c->x == 0) && (c->y == 0)))
764 px = c->x;
765 py = c->y;
766 pwidth = c->width;
767 pheight = c->height;
769 /* Keep fully visible only on resize */
770 clientConstrainPos (c, (mask & (CWWidth | CWHeight)));
772 if (c->x != px)
774 mask |= CWX;
776 if (c->y != py)
778 mask |= CWY;
781 if (c->width != pwidth)
783 mask |= CWWidth;
785 if (c->height != pheight)
787 mask |= CWHeight;
791 clientConfigureWindows (c, wc, mask, flags);
794 We reparent to client window. According to the ICCCM spec, the
795 WM must send a senthetic event when the window is moved and not resized.
797 But, since we reparent the window, we must also send a synthetic
798 configure event when the window is moved and resized.
800 See this thread for the rational:
801 http://www.mail-archive.com/wm-spec-list@gnome.org/msg00379.html
803 And specifically this post from Carsten Haitzler:
804 http://www.mail-archive.com/wm-spec-list@gnome.org/msg00382.html
807 if ((WIN_MOVED) || (flags & CFG_NOTIFY) ||
808 ((flags & CFG_REQUEST) && !(WIN_MOVED || WIN_RESIZED)))
810 DBG ("Sending ConfigureNotify");
811 ce.type = ConfigureNotify;
812 ce.display = clientGetXDisplay (c);
813 ce.event = c->window;
814 ce.window = c->window;
815 ce.x = c->x;
816 ce.y = c->y;
817 ce.width = c->width;
818 ce.height = c->height;
819 ce.border_width = 0;
820 ce.above = c->frame;
821 ce.override_redirect = FALSE;
822 XSendEvent (clientGetXDisplay (c), c->window, FALSE,
823 StructureNotifyMask, (XEvent *) & ce);
825 #undef WIN_MOVED
826 #undef WIN_RESIZED
829 void
830 clientGetMWMHints (Client * c, gboolean update)
832 ScreenInfo *screen_info;
833 DisplayInfo *display_info;
834 PropMwmHints *mwm_hints;
835 XWindowChanges wc;
837 g_return_if_fail (c != NULL);
838 g_return_if_fail (c->window != None);
840 TRACE ("entering clientGetMWMHints client \"%s\" (0x%lx)", c->name,
841 c->window);
843 screen_info = c->screen_info;
844 display_info = screen_info->display_info;
846 mwm_hints = getMotifHints (display_info, c->window);
847 if (mwm_hints)
849 if ((mwm_hints->flags & MWM_HINTS_DECORATIONS))
851 if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_SHAPE))
853 if (mwm_hints->decorations & MWM_DECOR_ALL)
855 FLAG_SET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
857 else
859 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_HAS_MENU);
860 FLAG_SET (c->xfwm_flags, (mwm_hints-> decorations & (MWM_DECOR_TITLE | MWM_DECOR_BORDER))
861 ? XFWM_FLAG_HAS_BORDER : 0);
862 FLAG_SET (c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MENU))
863 ? XFWM_FLAG_HAS_MENU : 0);
865 FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
866 FLAG_UNSET(c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
867 FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MINIMIZE)) ? XFWM_FLAG_HAS_HIDE : 0);
868 FLAG_SET(c->xfwm_flags, (mwm_hints->decorations & (MWM_DECOR_MAXIMIZE)) ? XFWM_FLAG_HAS_MAXIMIZE : 0);
873 /* The following is from Metacity : */
874 if (mwm_hints->flags & MWM_HINTS_FUNCTIONS)
876 if (!(mwm_hints->functions & MWM_FUNC_ALL))
878 FLAG_UNSET (c->xfwm_flags,
879 XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
880 XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
881 XFWM_FLAG_HAS_RESIZE);
883 else
885 FLAG_SET (c->xfwm_flags,
886 XFWM_FLAG_HAS_CLOSE | XFWM_FLAG_HAS_HIDE |
887 XFWM_FLAG_HAS_MAXIMIZE | XFWM_FLAG_HAS_MOVE |
888 XFWM_FLAG_HAS_RESIZE);
891 if (mwm_hints->functions & MWM_FUNC_CLOSE)
893 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE);
895 if (mwm_hints->functions & MWM_FUNC_MINIMIZE)
897 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_HIDE);
899 if (mwm_hints->functions & MWM_FUNC_MAXIMIZE)
901 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE);
903 if (mwm_hints->functions & MWM_FUNC_RESIZE)
905 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_RESIZE);
907 if (mwm_hints->functions & MWM_FUNC_MOVE)
909 FLAG_TOGGLE (c->xfwm_flags, XFWM_FLAG_HAS_MOVE);
912 g_free (mwm_hints);
915 if (update)
917 if (FLAG_TEST_ALL(c->xfwm_flags, XFWM_FLAG_HAS_BORDER | XFWM_FLAG_LEGACY_FULLSCREEN)
918 && !FLAG_TEST(c->flags, CLIENT_FLAG_FULLSCREEN))
920 /* legacy app changed its decoration, put it back on regular layer */
921 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_LEGACY_FULLSCREEN);
922 clientSetLayer (c, WIN_LAYER_NORMAL);
924 wc.x = c->x;
925 wc.y = c->y;
926 wc.width = c->width;
927 wc.height = c->height;
928 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_FORCE_REDRAW);
930 /* MWM hints can add or remove decorations, update NET_FRAME_EXTENTS accordingly */
931 setNetFrameExtents (display_info,
932 c->window,
933 frameTop (c),
934 frameLeft (c),
935 frameRight (c),
936 frameBottom (c));
940 void
941 clientGetWMNormalHints (Client * c, gboolean update)
943 XWindowChanges wc;
944 unsigned long previous_value;
945 long dummy;
947 g_return_if_fail (c != NULL);
948 g_return_if_fail (c->window != None);
950 TRACE ("entering clientGetWMNormalHints client \"%s\" (0x%lx)", c->name,
951 c->window);
953 if (!c->size)
955 c->size = XAllocSizeHints ();
957 g_assert (c->size);
959 dummy = 0;
960 if (!XGetWMNormalHints (clientGetXDisplay (c), c->window, c->size, &dummy))
962 c->size->flags = 0;
965 previous_value = FLAG_TEST (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
966 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
968 wc.x = c->x;
969 wc.y = c->y;
970 wc.width = c->width;
971 wc.height = c->height;
973 if (!(c->size->flags & PMaxSize))
975 c->size->max_width = G_MAXINT;
976 c->size->max_height = G_MAXINT;
977 c->size->flags |= PMaxSize;
980 if (!(c->size->flags & PBaseSize))
982 c->size->base_width = 0;
983 c->size->base_height = 0;
986 if (!(c->size->flags & PMinSize))
988 if ((c->size->flags & PBaseSize))
990 c->size->min_width = c->size->base_width;
991 c->size->min_height = c->size->base_height;
993 else
995 c->size->min_width = 1;
996 c->size->min_height = 1;
998 c->size->flags |= PMinSize;
1001 if (c->size->flags & PResizeInc)
1003 if (c->size->width_inc < 1)
1005 c->size->width_inc = 1;
1007 if (c->size->height_inc < 1)
1009 c->size->height_inc = 1;
1012 else
1014 c->size->width_inc = 1;
1015 c->size->height_inc = 1;
1018 if (c->size->flags & PAspect)
1020 if (c->size->min_aspect.x < 1)
1022 c->size->min_aspect.x = 1;
1024 if (c->size->min_aspect.y < 1)
1026 c->size->min_aspect.y = 1;
1028 if (c->size->max_aspect.x < 1)
1030 c->size->max_aspect.x = 1;
1032 if (c->size->max_aspect.y < 1)
1034 c->size->max_aspect.y = 1;
1037 else
1039 c->size->min_aspect.x = 1;
1040 c->size->min_aspect.y = 1;
1041 c->size->max_aspect.x = G_MAXINT;
1042 c->size->max_aspect.y = G_MAXINT;
1045 if (c->size->min_width < 1)
1047 c->size->min_width = 1;
1049 if (c->size->min_height < 1)
1051 c->size->min_height = 1;
1053 if (c->size->max_width < 1)
1055 c->size->max_width = 1;
1057 if (c->size->max_height < 1)
1059 c->size->max_height = 1;
1061 if (wc.width > c->size->max_width)
1063 wc.width = c->size->max_width;
1065 if (wc.height > c->size->max_height)
1067 wc.height = c->size->max_height;
1069 if (wc.width < c->size->min_width)
1071 wc.width = c->size->min_width;
1073 if (wc.height < c->size->min_height)
1075 wc.height = c->size->min_height;
1078 if ((c->size->min_width < c->size->max_width) ||
1079 (c->size->min_height < c->size->max_height))
1081 FLAG_SET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1084 if (update)
1086 if ((c->width != wc.width) || (c->height != wc.height))
1088 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_CONSTRAINED);
1090 else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE) != previous_value)
1092 frameQueueDraw (c);
1095 else
1097 c->width = wc.width;
1098 c->height = wc.height;
1102 void
1103 clientGetWMProtocols (Client * c)
1105 ScreenInfo *screen_info;
1106 DisplayInfo *display_info;
1107 unsigned int wm_protocols_flags;
1109 g_return_if_fail (c != NULL);
1110 g_return_if_fail (c->window != None);
1112 TRACE ("entering clientGetWMProtocols client \"%s\" (0x%lx)", c->name,
1113 c->window);
1115 screen_info = c->screen_info;
1116 display_info = screen_info->display_info;
1118 wm_protocols_flags = getWMProtocols (display_info, c->window);
1119 FLAG_SET (c->wm_flags,
1120 (wm_protocols_flags & WM_PROTOCOLS_DELETE_WINDOW) ?
1121 WM_FLAG_DELETE : 0);
1122 FLAG_SET (c->wm_flags,
1123 (wm_protocols_flags & WM_PROTOCOLS_TAKE_FOCUS) ?
1124 WM_FLAG_TAKEFOCUS : 0);
1125 /* KDE extension */
1126 FLAG_SET (c->wm_flags,
1127 (wm_protocols_flags & WM_PROTOCOLS_CONTEXT_HELP) ?
1128 WM_FLAG_CONTEXT_HELP : 0);
1131 #ifdef HAVE_XSYNC
1132 static void
1133 clientIncrementXSyncValue (Client *c)
1135 XSyncValue add;
1136 int overflow;
1138 g_return_if_fail (c != NULL);
1139 g_return_if_fail (c->xsync_counter != None);
1141 TRACE ("entering clientIncrementXSyncValue");
1143 XSyncIntToValue (&add, 1);
1144 XSyncValueAdd (&c->xsync_value, c->xsync_value, add, &overflow);
1147 static gboolean
1148 clientCreateXSyncAlarm (Client *c)
1150 ScreenInfo *screen_info;
1151 DisplayInfo *display_info;
1152 XSyncAlarmAttributes values;
1154 g_return_val_if_fail (c != NULL, FALSE);
1155 g_return_val_if_fail (c->xsync_counter != None, FALSE);
1157 TRACE ("entering clientCreateXSyncAlarm");
1159 screen_info = c->screen_info;
1160 display_info = screen_info->display_info;
1162 XSyncIntToValue (&c->xsync_value, 0);
1163 XSyncSetCounter (display_info->dpy, c->xsync_counter, c->xsync_value);
1164 XSyncIntToValue (&values.trigger.wait_value, 1);
1165 XSyncIntToValue (&values.delta, 1);
1167 values.trigger.counter = c->xsync_counter;
1168 values.trigger.value_type = XSyncAbsolute;
1169 values.trigger.test_type = XSyncPositiveComparison;
1170 values.events = True;
1172 c->xsync_alarm = XSyncCreateAlarm (display_info->dpy,
1173 XSyncCACounter |
1174 XSyncCADelta |
1175 XSyncCAEvents |
1176 XSyncCATestType |
1177 XSyncCAValue |
1178 XSyncCAValueType,
1179 &values);
1180 return (c->xsync_alarm != None);
1183 static void
1184 clientDestroyXSyncAlarm (Client *c)
1186 ScreenInfo *screen_info;
1187 DisplayInfo *display_info;
1189 g_return_if_fail (c != NULL);
1190 g_return_if_fail (c->xsync_alarm != None);
1192 TRACE ("entering clientClearXSyncAlarm");
1194 screen_info = c->screen_info;
1195 display_info = screen_info->display_info;
1197 XSyncDestroyAlarm (display_info->dpy, c->xsync_alarm);
1198 c->xsync_alarm = None;
1201 static void
1202 clientXSyncClearTimeout (Client * c)
1204 g_return_if_fail (c != NULL);
1206 TRACE ("entering clientXSyncClearTimeout");
1208 if (c->xsync_timeout_id)
1210 g_source_remove (c->xsync_timeout_id);
1211 c->xsync_timeout_id = 0;
1215 static gboolean
1216 clientXSyncTimeout (gpointer data)
1218 Client *c;
1219 XWindowChanges wc;
1221 TRACE ("entering clientXSyncTimeout");
1223 c = (Client *) data;
1224 if (c)
1226 TRACE ("XSync timeout for client \"%s\" (0x%lx)", c->name, c->window);
1227 clientXSyncClearTimeout (c);
1228 c->xsync_waiting = FALSE;
1229 c->xsync_enabled = FALSE;
1231 wc.x = c->x;
1232 wc.y = c->y;
1233 wc.width = c->width;
1234 wc.height = c->height;
1235 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, NO_CFG_FLAG);
1237 return (TRUE);
1240 static void
1241 clientXSyncResetTimeout (Client * c)
1243 g_return_if_fail (c != NULL);
1245 TRACE ("entering clientXSyncResetTimeout");
1247 clientXSyncClearTimeout (c);
1248 c->xsync_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
1249 CLIENT_XSYNC_TIMEOUT,
1250 (GtkFunction) clientXSyncTimeout,
1251 (gpointer) c, NULL);
1254 void
1255 clientXSyncRequest (Client * c)
1257 ScreenInfo *screen_info;
1258 DisplayInfo *display_info;
1260 g_return_if_fail (c != NULL);
1261 g_return_if_fail (c->window != None);
1263 TRACE ("entering clientXSyncRequest");
1265 screen_info = c->screen_info;
1266 display_info = screen_info->display_info;
1268 clientIncrementXSyncValue (c);
1269 sendXSyncRequest (display_info, c->window, c->xsync_value);
1270 clientXSyncResetTimeout (c);
1271 c->xsync_waiting = TRUE;
1274 static gboolean
1275 clientXSyncEnable (Client * c)
1277 ScreenInfo *screen_info;
1278 DisplayInfo *display_info;
1280 g_return_val_if_fail (c != NULL, FALSE);
1282 TRACE ("entering clientXSyncEnable");
1284 screen_info = c->screen_info;
1285 display_info = screen_info->display_info;
1287 c->xsync_enabled = FALSE;
1288 if (display_info->have_xsync)
1290 if ((c->xsync_counter) && (c->xsync_alarm))
1292 c->xsync_enabled = TRUE;
1295 return (c->xsync_enabled);
1297 #endif /* HAVE_XSYNC */
1299 static void
1300 clientFree (Client * c)
1302 g_return_if_fail (c != NULL);
1304 TRACE ("entering clientFree");
1305 TRACE ("freeing client \"%s\" (0x%lx)", c->name, c->window);
1307 clientClearFocus (c);
1308 if (clientGetLastRaise (c->screen_info) == c)
1310 clientClearLastRaise (c->screen_info);
1312 if (clientGetLastUngrab () == c)
1314 clientClearLastUngrab ();
1316 if (clientGetDelayedFocus () == c)
1318 clientClearDelayedFocus ();
1320 if (c->blink_timeout_id)
1322 g_source_remove (c->blink_timeout_id);
1324 if (c->icon_timeout_id)
1326 g_source_remove (c->icon_timeout_id);
1328 if (c->frame_timeout_id)
1330 g_source_remove (c->frame_timeout_id);
1332 if (c->name)
1334 g_free (c->name);
1336 #ifdef HAVE_XSYNC
1337 if (c->xsync_alarm != None)
1339 clientDestroyXSyncAlarm (c);
1341 if (c->xsync_timeout_id)
1343 g_source_remove (c->xsync_timeout_id);
1345 #endif /* HAVE_XSYNC */
1346 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
1347 if (c->startup_id)
1349 g_free (c->startup_id);
1351 #endif /* HAVE_LIBSTARTUP_NOTIFICATION */
1352 if (c->size)
1354 XFree (c->size);
1356 if (c->wmhints)
1358 XFree (c->wmhints);
1360 if ((c->ncmap > 0) && (c->cmap_windows))
1362 XFree (c->cmap_windows);
1364 if (c->class.res_name)
1366 XFree (c->class.res_name);
1368 if (c->class.res_class)
1370 XFree (c->class.res_class);
1373 g_free (c);
1376 static void
1377 clientGetWinState (Client * c)
1379 g_return_if_fail (c != NULL);
1381 TRACE ("entering clientGetWinState");
1383 if (c->win_state & WIN_STATE_STICKY)
1385 if (!clientIsValidTransientOrModal (c))
1387 FLAG_SET (c->flags, CLIENT_FLAG_STICKY);
1390 if (c->win_state & WIN_STATE_SHADED)
1392 FLAG_SET (c->flags, CLIENT_FLAG_SHADED);
1394 if (c->win_state & WIN_STATE_MAXIMIZED_HORIZ)
1396 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1398 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ);
1401 if (c->win_state & WIN_STATE_MAXIMIZED_VERT)
1403 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1405 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_VERT);
1408 if (c->win_state & WIN_STATE_MAXIMIZED)
1410 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1412 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED);
1417 static void
1418 clientApplyInitialState (Client * c)
1420 g_return_if_fail (c != NULL);
1422 TRACE ("entering clientApplyInitialState");
1424 /* We check that afterwards to make sure all states are now known */
1425 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
1427 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1429 unsigned long mode = 0;
1431 TRACE ("Applying client's initial state: maximized");
1432 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
1434 TRACE ("initial state: maximized horiz.");
1435 mode |= WIN_STATE_MAXIMIZED_HORIZ;
1437 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
1439 TRACE ("initial state: maximized vert.");
1440 mode |= WIN_STATE_MAXIMIZED_VERT;
1442 /* Unset fullscreen mode so that clientToggleMaximized() really change the state */
1443 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
1444 clientToggleMaximized (c, mode, FALSE);
1447 if (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
1449 if (!clientIsValidTransientOrModal (c))
1451 TRACE ("Applying client's initial state: fullscreen");
1452 clientUpdateFullscreenState (c);
1455 if (FLAG_TEST_AND_NOT (c->flags, CLIENT_FLAG_ABOVE, CLIENT_FLAG_BELOW))
1457 TRACE ("Applying client's initial state: above");
1458 clientUpdateAboveState (c);
1460 if (FLAG_TEST_AND_NOT (c->flags, CLIENT_FLAG_BELOW, CLIENT_FLAG_ABOVE))
1462 TRACE ("Applying client's initial state: below");
1463 clientUpdateBelowState (c);
1465 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY) &&
1466 FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK))
1468 if (!clientIsValidTransientOrModal (c))
1470 TRACE ("Applying client's initial state: sticky");
1471 clientStick (c, TRUE);
1474 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
1476 TRACE ("Applying client's initial state: shaded");
1477 clientShade (c);
1481 void
1482 clientUpdateWinState (Client * c, XClientMessageEvent * ev)
1484 unsigned long action;
1485 Atom add_remove;
1487 g_return_if_fail (c != NULL);
1488 TRACE ("entering clientUpdateWinState");
1489 TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1491 action = ((XEvent *) ev)->xclient.data.l[0];
1492 add_remove = ((XEvent *) ev)->xclient.data.l[1];
1494 if (action & WIN_STATE_SHADED)
1496 TRACE ("client \"%s\" (0x%lx) has received a win_state/shade event",
1497 c->name, c->window);
1498 if (add_remove == WIN_STATE_SHADED)
1500 clientShade (c);
1502 else
1504 clientUnshade (c);
1507 else if ((action & WIN_STATE_STICKY)
1508 && FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK))
1510 TRACE ("client \"%s\" (0x%lx) has received a win_state/stick event",
1511 c->name, c->window);
1512 if (!clientIsValidTransientOrModal (c))
1514 if (add_remove == WIN_STATE_STICKY)
1516 clientStick (c, TRUE);
1518 else
1520 clientUnstick (c, TRUE);
1522 frameDraw (c, FALSE);
1525 else if ((action & WIN_STATE_MAXIMIZED)
1526 && FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MAXIMIZE))
1528 TRACE ("client \"%s\" (0x%lx) has received a win_state/maximize event",
1529 c->name, c->window);
1530 clientToggleMaximized (c, add_remove, TRUE);
1534 static gboolean
1535 clientCheckShape (Client * c)
1537 ScreenInfo *screen_info;
1538 DisplayInfo *display_info;
1539 int xws, yws, xbs, ybs;
1540 unsigned wws, hws, wbs, hbs;
1541 int boundingShaped, clipShaped;
1543 g_return_val_if_fail (c != NULL, FALSE);
1545 screen_info = c->screen_info;
1546 display_info = screen_info->display_info;
1548 if (display_info->have_shape)
1550 XShapeQueryExtents (display_info->dpy, c->window, &boundingShaped, &xws, &yws, &wws,
1551 &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs);
1552 return (boundingShaped != 0);
1554 return FALSE;
1557 static void
1558 clientGetUserTime (Client * c)
1560 ScreenInfo *screen_info;
1561 DisplayInfo *display_info;
1563 g_return_if_fail (c != NULL);
1564 g_return_if_fail (c->window != None);
1566 screen_info = c->screen_info;
1567 display_info = screen_info->display_info;
1569 if (getNetWMUserTime (display_info, c->window, &c->user_time))
1571 FLAG_SET (c->flags, CLIENT_FLAG_HAS_USER_TIME);
1572 myDisplaySetLastUserTime (display_info, c->user_time);
1576 static void
1577 clientUpdateIconPix (Client * c)
1579 ScreenInfo *screen_info;
1580 DisplayInfo *display_info;
1581 gint size;
1582 GdkPixbuf *icon;
1583 int i;
1585 g_return_if_fail (c != NULL);
1586 g_return_if_fail (c->window != None);
1588 TRACE ("entering clientUpdateIconPix for \"%s\" (0x%lx)", c->name, c->window);
1590 screen_info = c->screen_info;
1591 display_info = screen_info->display_info;
1593 for (i = 0; i < STATE_TOGGLED; i++)
1595 xfwmPixmapFree (&c->appmenu[i]);
1598 if (xfwmPixmapNone(&screen_info->buttons[MENU_BUTTON][ACTIVE]))
1600 /* The current theme has no menu button */
1601 return;
1604 for (i = 0; i < STATE_TOGGLED; i++)
1606 if (!xfwmPixmapNone(&screen_info->buttons[MENU_BUTTON][i]))
1608 xfwmPixmapDuplicate (&screen_info->buttons[MENU_BUTTON][i], &c->appmenu[i]);
1611 size = MIN (screen_info->buttons[MENU_BUTTON][ACTIVE].width,
1612 screen_info->buttons[MENU_BUTTON][ACTIVE].height);
1614 if (size > 1)
1616 icon = getAppIcon (display_info, c->window, size, size);
1618 for (i = 0; i < STATE_TOGGLED; i++)
1620 if (!xfwmPixmapNone(&c->appmenu[i]))
1622 xfwmPixmapRenderGdkPixbuf (&c->appmenu[i], icon);
1625 g_object_unref (icon);
1629 static gboolean
1630 update_icon_idle_cb (gpointer data)
1632 Client *c;
1634 TRACE ("entering update_icon_idle_cb");
1636 c = (Client *) data;
1637 g_return_val_if_fail (c, FALSE);
1639 clientUpdateIconPix (c);
1640 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
1642 frameDraw (c, FALSE);
1644 c->icon_timeout_id = 0;
1646 return FALSE;
1649 void
1650 clientUpdateIcon (Client * c)
1652 g_return_if_fail (c);
1654 TRACE ("entering clientUpdateIcon for \"%s\" (0x%lx)", c->name, c->window);
1656 if (c->icon_timeout_id == 0)
1658 c->icon_timeout_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1659 update_icon_idle_cb, c, NULL);
1663 Client *
1664 clientFrame (DisplayInfo *display_info, Window w, gboolean recapture)
1666 ScreenInfo *screen_info;
1667 XWindowAttributes attr;
1668 XWindowChanges wc;
1669 XSetWindowAttributes attributes;
1670 Client *c = NULL;
1671 gboolean shaped;
1672 gboolean grabbed;
1673 unsigned long valuemask;
1674 int i;
1676 g_return_val_if_fail (w != None, NULL);
1677 g_return_val_if_fail (display_info != NULL, NULL);
1679 TRACE ("entering clientFrame");
1680 TRACE ("framing client (0x%lx)", w);
1682 gdk_error_trap_push ();
1683 myDisplayGrabServer (display_info);
1685 if (!XGetWindowAttributes (display_info->dpy, w, &attr))
1687 TRACE ("Cannot get window attributes");
1688 myDisplayUngrabServer (display_info);
1689 gdk_error_trap_pop ();
1690 return NULL;
1693 screen_info = myDisplayGetScreenFromRoot (display_info, attr.root);
1694 if (!screen_info)
1696 TRACE ("Cannot determine screen info from windows");
1697 myDisplayUngrabServer (display_info);
1698 gdk_error_trap_pop ();
1699 return NULL;
1702 if (w == screen_info->xfwm4_win)
1704 TRACE ("Not managing our own event window");
1705 compositorAddWindow (display_info, w, NULL);
1706 myDisplayUngrabServer (display_info);
1707 gdk_error_trap_pop ();
1708 return NULL;
1711 #ifdef ENABLE_KDE_SYSTRAY_PROXY
1712 if (checkKdeSystrayWindow (display_info, w))
1714 TRACE ("Detected KDE systray windows");
1715 if (screen_info->systray != None)
1717 sendSystrayReqDock (display_info, w, screen_info->systray);
1718 myDisplayUngrabServer (display_info);
1719 gdk_error_trap_pop ();
1720 return NULL;
1722 TRACE ("No systray found for this screen");
1724 #endif /* ENABLE_KDE_SYSTRAY_PROXY */
1726 if (attr.override_redirect)
1728 TRACE ("Override redirect window 0x%lx", w);
1729 compositorAddWindow (display_info, w, NULL);
1730 myDisplayUngrabServer (display_info);
1731 gdk_error_trap_pop ();
1732 return NULL;
1735 c = g_new0 (Client, 1);
1736 if (!c)
1738 TRACE ("Cannot allocate memory for the window structure");
1739 myDisplayUngrabServer (display_info);
1740 gdk_error_trap_pop ();
1741 return NULL;
1744 c->window = w;
1745 c->screen_info = screen_info;
1746 c->serial = screen_info->client_serial++;
1748 getWindowName (display_info, c->window, &c->name);
1749 TRACE ("name \"%s\"", c->name);
1750 getTransientFor (display_info, screen_info->xroot, c->window, &c->transient_for);
1752 /* Initialize structure */
1753 c->size = NULL;
1754 c->flags = 0L;
1755 c->wm_flags = 0L;
1756 c->xfwm_flags = CLIENT_FLAG_INITIAL_VALUES;
1757 c->x = attr.x;
1758 c->y = attr.y;
1759 c->width = attr.width;
1760 c->height = attr.height;
1762 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
1763 c->startup_id = NULL;
1764 #endif /* HAVE_LIBSTARTUP_NOTIFICATION */
1766 #ifdef HAVE_XSYNC
1767 c->xsync_waiting = FALSE;
1768 c->xsync_enabled = FALSE;
1769 c->xsync_counter = None;
1770 c->xsync_alarm = None;
1771 c->xsync_timeout_id = 0;
1772 if (display_info->have_xsync)
1774 getXSyncCounter (display_info, c->window, &c->xsync_counter);
1775 if ((c->xsync_counter) && clientCreateXSyncAlarm (c))
1777 c->xsync_enabled = TRUE;
1780 #endif /* HAVE_XSYNC */
1782 clientGetWMNormalHints (c, FALSE);
1784 c->size->x = c->x;
1785 c->size->y = c->y;
1786 c->size->width = c->width;
1787 c->size->height = c->height;
1788 c->previous_width = -1;
1789 c->previous_height = -1;
1790 c->border_width = attr.border_width;
1791 c->cmap = attr.colormap;
1793 shaped = clientCheckShape(c);
1794 if (shaped)
1796 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_HAS_BORDER);
1797 FLAG_SET (c->flags, CLIENT_FLAG_HAS_SHAPE);
1800 if (((c->size->flags & (PMinSize | PMaxSize)) != (PMinSize | PMaxSize))
1801 || (((c->size->flags & (PMinSize | PMaxSize)) ==
1802 (PMinSize | PMaxSize))
1803 && ((c->size->min_width < c->size->max_width)
1804 || (c->size->min_height < c->size->max_height))))
1806 FLAG_SET (c->xfwm_flags, XFWM_FLAG_IS_RESIZABLE);
1809 for (i = 0; i < BUTTON_COUNT; i++)
1811 c->button_status[i] = BUTTON_STATE_NORMAL;
1814 if (!XGetWMColormapWindows (display_info->dpy, c->window, &c->cmap_windows, &c->ncmap))
1816 c->ncmap = 0;
1819 /* Opacity for compositing manager */
1820 c->opacity = NET_WM_OPAQUE;
1821 getOpacity (display_info, c->window, &c->opacity);
1822 c->opacity_applied = c->opacity;
1823 c->opacity_flags = 0;
1825 c->opacity_locked = getOpacityLock (display_info, c->window);
1827 /* Timout for asynchronous icon update */
1828 c->icon_timeout_id = 0;
1829 /* Timout for asynchronous frame update */
1830 c->frame_timeout_id = 0;
1831 /* Timeout for blinking on urgency */
1832 c->blink_timeout_id = 0;
1834 c->class.res_name = NULL;
1835 c->class.res_class = NULL;
1836 XGetClassHint (display_info->dpy, w, &c->class);
1837 c->wmhints = XGetWMHints (display_info->dpy, c->window);
1838 c->group_leader = None;
1839 if (c->wmhints)
1841 if (c->wmhints->flags & WindowGroupHint)
1843 c->group_leader = c->wmhints->window_group;
1846 c->client_leader = getClientLeader (display_info, c->window);
1848 TRACE ("\"%s\" (0x%lx) initial map_state = %s",
1849 c->name, c->window,
1850 (attr.map_state == IsUnmapped) ?
1851 "IsUnmapped" :
1852 (attr.map_state == IsViewable) ?
1853 "IsViewable" :
1854 (attr.map_state == IsUnviewable) ?
1855 "IsUnviewable" :
1856 "(unknown)");
1857 if (attr.map_state != IsUnmapped)
1859 /* Reparent will send us unmap/map events */
1860 FLAG_SET (c->xfwm_flags, XFWM_FLAG_MAP_PENDING);
1862 c->ignore_unmap = 0;
1863 c->type = UNSET;
1864 c->type_atom = None;
1866 FLAG_SET (c->flags, START_ICONIC (c) ? CLIENT_FLAG_ICONIFIED : 0);
1867 FLAG_SET (c->wm_flags, HINTS_ACCEPT_INPUT (c->wmhints) ? WM_FLAG_INPUT : 0);
1869 clientGetWMProtocols (c);
1870 clientGetMWMHints (c, FALSE);
1871 getHint (display_info, w, WIN_HINTS, (long *) &c->win_hints);
1872 getHint (display_info, w, WIN_STATE, (long *) &c->win_state);
1873 if (!getHint (display_info, w, WIN_LAYER, (long *) &c->win_layer))
1875 c->win_layer = WIN_LAYER_NORMAL;
1877 c->fullscreen_old_layer = c->win_layer;
1879 /* net_wm_user_time standard */
1880 clientGetUserTime (c);
1882 /* Apply startup notification properties if available */
1883 sn_client_startup_properties (c);
1885 /* Reload from session */
1886 if (sessionMatchWinToSM (c))
1888 FLAG_SET (c->xfwm_flags, XFWM_FLAG_SESSION_MANAGED);
1891 /* Beware, order of calls is important here ! */
1892 clientGetWinState (c);
1893 clientGetNetState (c);
1894 clientGetNetWmType (c);
1895 clientGetInitialNetWmDesktop (c);
1896 /* workarea will be updated when shown, no need to worry here */
1897 clientGetNetStruts (c);
1899 /* Fullscreen for older legacy apps */
1900 if ((c->x <= 0) && (c->y <= 0) &&
1901 (c->width >= screen_info->width) &&
1902 (c->height >= screen_info->height) &&
1903 !FLAG_TEST(c->xfwm_flags, XFWM_FLAG_HAS_BORDER) &&
1904 !FLAG_TEST (c->flags, CLIENT_FLAG_BELOW | CLIENT_FLAG_ABOVE | CLIENT_FLAG_FULLSCREEN) &&
1905 (c->win_layer == WIN_LAYER_NORMAL) &&
1906 (c->type == WINDOW_NORMAL))
1908 FLAG_SET (c->xfwm_flags, XFWM_FLAG_LEGACY_FULLSCREEN);
1911 /* Once we know the type of window, we can initialize window position */
1912 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SESSION_MANAGED))
1914 if ((attr.map_state != IsUnmapped))
1916 clientGravitate (c, APPLY);
1918 else
1920 clientInitPosition (c);
1925 Initialize "old" fields once the position is ensured, to avoid
1926 initially maximized or fullscreen windows being placed offscreen
1927 once de-maximized
1929 c->old_x = c->x;
1930 c->old_y = c->y;
1931 c->old_width = c->width;
1932 c->old_height = c->height;
1933 c->fullscreen_old_x = c->x;
1934 c->fullscreen_old_y = c->y;
1935 c->fullscreen_old_width = c->width;
1936 c->fullscreen_old_height = c->height;
1939 We must call clientApplyInitialState() after having placed the
1940 window so that the inital position values are correctly set if the
1941 inital state is maximize or fullscreen
1943 clientApplyInitialState (c);
1945 valuemask = CWEventMask|CWBitGravity|CWWinGravity;
1946 attributes.event_mask = (FRAME_EVENT_MASK | POINTER_EVENT_MASK);
1947 attributes.win_gravity = StaticGravity;
1948 attributes.bit_gravity = StaticGravity;
1950 #ifdef HAVE_RENDER
1951 if (display_info->have_render)
1953 c->visual = attr.visual;
1954 c->depth = attr.depth;
1955 attributes.colormap = attr.colormap;
1956 valuemask |= CWColormap;
1958 else
1960 c->visual = screen_info->visual;
1961 c->depth = screen_info->depth;
1964 if (c->depth == 32)
1966 attributes.background_pixmap = None;
1967 attributes.border_pixel = 0;
1968 attributes.background_pixel = 0;
1969 valuemask |= CWBackPixmap|CWBackPixel|CWBorderPixel;
1971 #else /* HAVE_RENDER */
1972 /* We don't support multiple depth/visual w/out render */
1973 c->visual = screen_info->visual;
1974 c->depth = screen_info->depth;
1975 #endif /* HAVE_RENDER */
1977 c->frame =
1978 XCreateWindow (display_info->dpy, screen_info->xroot, 0, 0, 1, 1, 0,
1979 c->depth, InputOutput, c->visual, valuemask, &attributes);
1981 XSelectInput (display_info->dpy, c->window, 0);
1982 XSetWindowBorderWidth (display_info->dpy, c->window, 0);
1983 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
1985 XUnmapWindow (display_info->dpy, c->window);
1987 XReparentWindow (display_info->dpy, c->window, c->frame, frameLeft (c), frameTop (c));
1988 valuemask = CWEventMask;
1989 attributes.event_mask = (CLIENT_EVENT_MASK);
1990 XChangeWindowAttributes (display_info->dpy, c->window, valuemask, &attributes);
1991 XSelectInput (display_info->dpy, c->window, CLIENT_EVENT_MASK);
1992 if (display_info->have_shape)
1994 XShapeSelectInput (display_info->dpy, c->window, ShapeNotifyMask);
1997 clientAddToList (c);
1998 clientSetNetActions (c);
1999 clientGrabButtons(c);
2001 /* Initialize per client menu button pixmap */
2003 for (i = 0; i < STATE_TOGGLED; i++)
2005 xfwmPixmapInit (screen_info, &c->appmenu[i]);
2008 for (i = 0; i < SIDE_TOP; i++) /* Keep SIDE_TOP for later */
2010 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
2011 &c->sides[i], NoEventMask,
2012 myDisplayGetCursorResize(screen_info->display_info, CORNER_COUNT + i));
2015 for (i = 0; i < CORNER_COUNT; i++)
2017 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
2018 &c->corners[i], NoEventMask,
2019 myDisplayGetCursorResize(screen_info->display_info, i));
2022 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
2023 &c->title, NoEventMask, None);
2025 /* create the top side window AFTER the title window since they overlap
2026 and the top side window should be on top */
2028 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
2029 &c->sides[SIDE_TOP], NoEventMask,
2030 myDisplayGetCursorResize(screen_info->display_info,
2031 CORNER_COUNT + SIDE_TOP));
2033 for (i = 0; i < BUTTON_COUNT; i++)
2035 xfwmWindowCreate (screen_info, c->visual, c->depth, c->frame,
2036 &c->buttons[i], BUTTON_EVENT_MASK, None);
2038 clientUpdateIconPix (c);
2040 /* Put the window on top to avoid XShape, that speeds up hw accelerated
2041 GL apps dramatically */
2042 XRaiseWindow (display_info->dpy, c->window);
2044 TRACE ("now calling configure for the new window \"%s\" (0x%lx)", c->name, c->window);
2045 wc.x = c->x;
2046 wc.y = c->y;
2047 wc.width = c->width;
2048 wc.height = c->height;
2049 clientConfigure (c, &wc, CWX | CWY | CWHeight | CWWidth, CFG_NOTIFY | CFG_FORCE_REDRAW);
2051 /* Notify the compositor about this new window */
2052 compositorAddWindow (display_info, c->frame, c);
2054 grabbed = FALSE;
2055 if (!FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
2057 if ((c->win_workspace == screen_info->current_ws) ||
2058 FLAG_TEST(c->flags, CLIENT_FLAG_STICKY))
2060 if (recapture)
2062 clientRaise (c, None);
2063 clientShow (c, TRUE);
2064 clientSortRing(c);
2066 else
2068 clientFocusNew(c);
2069 grabbed = TRUE;
2072 else
2074 clientRaise (c, None);
2075 clientInitFocusFlag (c);
2078 else
2080 clientRaise (c, None);
2081 setWMState (display_info, c->window, IconicState);
2082 clientSetNetState (c);
2085 if (!grabbed)
2087 clientGrabMouseButton (c);
2089 setNetFrameExtents (display_info, c->window, frameTop (c), frameLeft (c),
2090 frameRight (c), frameBottom (c));
2092 /* Window is reparented now, so we can safely release the grab
2093 * on the server
2095 myDisplayUngrabServer (display_info);
2096 gdk_error_trap_pop ();
2098 DBG ("client \"%s\" (0x%lx) is now managed", c->name, c->window);
2099 DBG ("client_count=%d", screen_info->client_count);
2101 return c;
2104 void
2105 clientUnframe (Client * c, gboolean remap)
2107 ScreenInfo *screen_info;
2108 DisplayInfo *display_info;
2109 XEvent ev;
2110 int i;
2111 gboolean reparented;
2113 TRACE ("entering clientUnframe");
2114 TRACE ("unframing client \"%s\" (0x%lx) [%s]",
2115 c->name, c->window, remap ? "remap" : "no remap");
2117 g_return_if_fail (c != NULL);
2119 screen_info = c->screen_info;
2120 display_info = screen_info->display_info;
2122 clientRemoveFromList (c);
2123 compositorSetClient (display_info, c->frame, NULL);
2125 myDisplayGrabServer (display_info);
2126 gdk_error_trap_push ();
2127 clientUngrabButtons (c);
2128 XUnmapWindow (display_info->dpy, c->frame);
2129 clientGravitate (c, REMOVE);
2130 XSelectInput (display_info->dpy, c->window, NoEventMask);
2131 reparented = XCheckTypedWindowEvent (display_info->dpy, c->window, ReparentNotify, &ev);
2133 if (remap || !reparented)
2135 XReparentWindow (display_info->dpy, c->window, c->screen_info->xroot, c->x, c->y);
2136 XSetWindowBorderWidth (display_info->dpy, c->window, c->border_width);
2137 if (remap)
2139 compositorAddWindow (display_info, c->window, NULL);
2140 XMapWindow (display_info->dpy, c->window);
2142 else
2144 XUnmapWindow (display_info->dpy, c->window);
2145 setWMState (display_info, c->window, WithdrawnState);
2149 if (!remap)
2151 XDeleteProperty (display_info->dpy, c->window,
2152 display_info->atoms[NET_WM_STATE]);
2153 XDeleteProperty (display_info->dpy, c->window,
2154 display_info->atoms[WIN_STATE]);
2155 XDeleteProperty (display_info->dpy, c->window,
2156 display_info->atoms[NET_WM_DESKTOP]);
2157 XDeleteProperty (display_info->dpy, c->window,
2158 display_info->atoms[WIN_WORKSPACE]);
2159 XDeleteProperty (display_info->dpy, c->window,
2160 display_info->atoms[WIN_LAYER]);
2161 XDeleteProperty (display_info->dpy, c->window,
2162 display_info->atoms[NET_WM_ALLOWED_ACTIONS]);
2165 xfwmWindowDelete (&c->title);
2167 for (i = 0; i < SIDE_COUNT; i++)
2169 xfwmWindowDelete (&c->sides[i]);
2171 for (i = 0; i < CORNER_COUNT; i++)
2173 xfwmWindowDelete (&c->corners[i]);
2175 for (i = 0; i < STATE_TOGGLED; i++)
2177 xfwmPixmapFree (&c->appmenu[i]);
2179 for (i = 0; i < BUTTON_COUNT; i++)
2181 xfwmWindowDelete (&c->buttons[i]);
2183 if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STRUT))
2185 workspaceUpdateArea (c->screen_info);
2187 XDestroyWindow (display_info->dpy, c->frame);
2189 myDisplayUngrabServer (display_info);
2190 gdk_error_trap_pop ();
2191 clientFree (c);
2194 void
2195 clientFrameAll (ScreenInfo *screen_info)
2197 DisplayInfo *display_info;
2198 XWindowAttributes attr;
2199 xfwmWindow shield;
2200 Window w1, w2, *wins;
2201 unsigned int count, i;
2203 TRACE ("entering clientFrameAll");
2205 display_info = screen_info->display_info;
2206 clientSetFocus (screen_info, NULL, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
2207 xfwmWindowTemp (screen_info,
2208 NULL, 0,
2209 screen_info->xroot,
2210 &shield,
2211 0, 0,
2212 screen_info->width,
2213 screen_info->height,
2214 EnterWindowMask,
2215 FALSE);
2217 XSync (display_info->dpy, FALSE);
2218 myDisplayGrabServer (display_info);
2219 XQueryTree (display_info->dpy, screen_info->xroot, &w1, &w2, &wins, &count);
2220 for (i = 0; i < count; i++)
2222 XGetWindowAttributes (display_info->dpy, wins[i], &attr);
2223 if ((attr.map_state == IsViewable) && (attr.root == screen_info->xroot))
2225 Client *c = clientFrame (display_info, wins[i], TRUE);
2226 if ((c) && ((screen_info->params->raise_on_click) || (screen_info->params->click_to_focus)))
2228 clientGrabMouseButton (c);
2231 else
2233 compositorAddWindow (display_info, wins[i], NULL);
2236 if (wins)
2238 XFree (wins);
2240 clientFocusTop (screen_info, WIN_LAYER_NORMAL, myDisplayGetCurrentTime (display_info));
2241 xfwmWindowDelete (&shield);
2242 myDisplayUngrabServer (display_info);
2243 XSync (display_info->dpy, FALSE);
2246 void
2247 clientUnframeAll (ScreenInfo *screen_info)
2249 DisplayInfo *display_info;
2250 Client *c;
2251 Window w1, w2, *wins;
2252 unsigned int count, i;
2254 TRACE ("entering clientUnframeAll");
2256 display_info = screen_info->display_info;
2257 clientSetFocus (screen_info, NULL, myDisplayGetCurrentTime (display_info), FOCUS_IGNORE_MODAL);
2258 XSync (display_info->dpy, FALSE);
2259 myDisplayGrabServer (display_info);
2260 XQueryTree (display_info->dpy, screen_info->xroot, &w1, &w2, &wins, &count);
2261 for (i = 0; i < count; i++)
2263 c = myScreenGetClientFromWindow (screen_info, wins[i], SEARCH_FRAME);
2264 if (c)
2266 clientUnframe (c, TRUE);
2269 myDisplayUngrabServer (display_info);
2270 XSync(display_info->dpy, FALSE);
2271 if (wins)
2273 XFree (wins);
2277 Client *
2278 clientGetFromWindow (Client *c, Window w, unsigned short mode)
2280 int b;
2282 g_return_val_if_fail (w != None, NULL);
2283 g_return_val_if_fail (c != NULL, NULL);
2284 TRACE ("entering clientGetFromWindow");
2286 if (mode & SEARCH_WINDOW)
2288 if (c->window == w)
2290 TRACE ("found \"%s\" (mode WINDOW)", c->name);
2291 return (c);
2295 if (mode & SEARCH_FRAME)
2297 if (c->frame == w)
2299 TRACE ("found \"%s\" (mode FRAME)", c->name);
2300 return (c);
2304 if (mode & SEARCH_BUTTON)
2306 for (b = 0; b < BUTTON_COUNT; b++)
2308 if (MYWINDOW_XWINDOW(c->buttons[b]) == w)
2310 TRACE ("found \"%s\" (mode BUTTON)", c->name);
2311 return (c);
2316 TRACE ("no client found");
2318 return NULL;
2321 static void
2322 clientSetWorkspaceSingle (Client * c, int ws)
2324 ScreenInfo *screen_info;
2325 DisplayInfo *display_info;
2327 g_return_if_fail (c != NULL);
2329 TRACE ("entering clientSetWorkspaceSingle");
2331 screen_info = c->screen_info;
2332 display_info = screen_info->display_info;
2334 if (ws > screen_info->workspace_count - 1)
2336 ws = screen_info->workspace_count - 1;
2337 TRACE ("value off limits, using %i instead", ws);
2340 if (c->win_workspace != ws)
2342 TRACE ("setting client \"%s\" (0x%lx) to current_ws %d", c->name, c->window, ws);
2343 c->win_workspace = ws;
2344 setHint (display_info, c->window, WIN_WORKSPACE, ws);
2345 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2347 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2349 else
2351 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ws);
2354 FLAG_SET (c->xfwm_flags, XFWM_FLAG_WORKSPACE_SET);
2357 void
2358 clientSetWorkspace (Client * c, int ws, gboolean manage_mapping)
2360 Client *c2;
2361 GList *list_of_windows;
2362 GList *index;
2363 int previous_ws;
2365 g_return_if_fail (c != NULL);
2367 TRACE ("entering clientSetWorkspace");
2369 list_of_windows = clientListTransientOrModal (c);
2370 for (index = list_of_windows; index; index = g_list_next (index))
2372 c2 = (Client *) index->data;
2374 if (c2->win_workspace != ws)
2376 TRACE ("setting client \"%s\" (0x%lx) to current_ws %d", c->name, c->window, ws);
2378 previous_ws = c2->win_workspace;
2379 clientSetWorkspaceSingle (c2, ws);
2381 if (manage_mapping && !clientIsValidTransientOrModal (c2) && !FLAG_TEST (c2->flags, CLIENT_FLAG_ICONIFIED))
2383 if (previous_ws == c2->screen_info->current_ws)
2385 clientHide (c2, c2->screen_info->current_ws, FALSE);
2387 if (FLAG_TEST (c2->flags, CLIENT_FLAG_STICKY) || (ws == c2->screen_info->current_ws))
2389 clientShow (c2, FALSE);
2394 g_list_free (list_of_windows);
2397 static void
2398 clientShowSingle (Client * c, gboolean deiconify)
2400 ScreenInfo *screen_info;
2401 DisplayInfo *display_info;
2403 g_return_if_fail (c != NULL);
2405 screen_info = c->screen_info;
2406 display_info = screen_info->display_info;
2408 if ((c->win_workspace == screen_info->current_ws) || FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2410 TRACE ("showing client \"%s\" (0x%lx)", c->name, c->window);
2411 FLAG_SET (c->xfwm_flags, XFWM_FLAG_VISIBLE);
2412 XMapWindow (display_info->dpy, c->frame);
2413 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2415 XMapWindow (display_info->dpy, c->window);
2417 /* Adjust to urgency state as the window is visible */
2418 clientUpdateUrgency (c);
2420 if (deiconify)
2422 FLAG_UNSET (c->flags, CLIENT_FLAG_ICONIFIED);
2423 setWMState (display_info, c->window, NormalState);
2425 clientSetNetState (c);
2428 void
2429 clientShow (Client * c, gboolean deiconify)
2431 Client *c2;
2432 GList *list_of_windows;
2433 GList *index;
2435 g_return_if_fail (c != NULL);
2436 TRACE ("entering clientShow \"%s\" (0x%lx)", c->name, c->window);
2438 list_of_windows = clientListTransientOrModal (c);
2439 for (index = g_list_last (list_of_windows); index; index = g_list_previous (index))
2441 c2 = (Client *) index->data;
2442 clientSetWorkspaceSingle (c2, c->win_workspace);
2443 /* Ignore request before if the window is not yet managed */
2444 if (!FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_MANAGED))
2446 continue;
2448 clientShowSingle (c2, deiconify);
2450 g_list_free (list_of_windows);
2452 /* Update working area as windows have been shown */
2453 workspaceUpdateArea (c->screen_info);
2456 static void
2457 clientHideSingle (Client * c, gboolean iconify)
2459 ScreenInfo *screen_info;
2460 DisplayInfo *display_info;
2462 g_return_if_fail (c != NULL);
2464 screen_info = c->screen_info;
2465 display_info = screen_info->display_info;
2467 TRACE ("hiding client \"%s\" (0x%lx)", c->name, c->window);
2468 clientPassFocus(c->screen_info, c, c);
2469 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2471 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_VISIBLE);
2472 c->ignore_unmap++;
2473 /* Adjust to urgency state as the window is not visible */
2474 clientUpdateUrgency (c);
2476 XUnmapWindow (display_info->dpy, c->window);
2477 XUnmapWindow (display_info->dpy, c->frame);
2478 if (iconify)
2480 FLAG_SET (c->flags, CLIENT_FLAG_ICONIFIED);
2481 setWMState (display_info, c->window, IconicState);
2483 clientSetNetState (c);
2486 void
2487 clientHide (Client * c, int ws, gboolean iconify)
2489 Client *c2;
2490 GList *list_of_windows;
2491 GList *index;
2493 g_return_if_fail (c != NULL);
2494 TRACE ("entering clientHide \"%s\" (0x%lx)", c->name, c->window);
2496 list_of_windows = clientListTransientOrModal (c);
2497 for (index = list_of_windows; index; index = g_list_next (index))
2499 c2 = (Client *) index->data;
2501 /* Ignore request before if the window is not yet managed */
2502 if (!FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_MANAGED))
2504 continue;
2507 /* ws is used when transitioning between desktops, to avoid
2508 hiding a transient for group that will be shown again on the new
2509 workspace (transient for groups can be transients for multiple
2510 ancesors splitted across workspaces...)
2512 if (clientIsTransientOrModal (c2) &&
2513 clientTransientOrModalHasAncestor (c2, ws))
2515 /* Other ancestors for that transient are still on screen, so don't
2516 hide it...
2518 continue;
2521 if (FLAG_TEST (c2->flags, CLIENT_FLAG_STICKY) && !iconify)
2523 continue;
2525 clientHideSingle (c2, iconify);
2527 g_list_free (list_of_windows);
2529 /* Update working area as windows have been hidden */
2530 workspaceUpdateArea (c->screen_info);
2533 void
2534 clientHideAll (Client * c, int ws)
2536 ScreenInfo *screen_info;
2537 Client *c2;
2538 int i;
2540 g_return_if_fail (c != NULL);
2542 TRACE ("entering clientHideAll");
2544 screen_info = c->screen_info;
2545 for (c2 = c->next, i = 0; (c2) && (i < screen_info->client_count); c2 = c2->next, i++)
2547 if (CLIENT_CAN_HIDE_WINDOW (c2)
2548 && !clientIsValidTransientOrModal (c2) && (c2 != c))
2550 if (((!c) && (c2->win_workspace == ws))
2551 || ((c) && !clientIsTransientOrModalFor (c, c2)
2552 && (c2->win_workspace == c->win_workspace)))
2554 clientHide (c2, ws, TRUE);
2560 void
2561 clientClearAllShowDesktop (ScreenInfo *screen_info)
2563 TRACE ("entering clientClearShowDesktop");
2565 if (screen_info->show_desktop)
2567 GList *index = NULL;
2569 for (index = screen_info->windows_stack; index; index = g_list_next (index))
2571 Client *c = (Client *) index->data;
2572 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2574 screen_info->show_desktop = FALSE;
2575 sendRootMessage (screen_info, NET_SHOWING_DESKTOP, screen_info->show_desktop,
2576 myDisplayGetCurrentTime (screen_info->display_info));
2580 void
2581 clientToggleShowDesktop (ScreenInfo *screen_info)
2583 GList *index;
2585 TRACE ("entering clientToggleShowDesktop");
2587 clientSetFocus (screen_info, NULL,
2588 myDisplayGetCurrentTime (screen_info->display_info),
2589 FOCUS_IGNORE_MODAL);
2590 if (screen_info->show_desktop)
2592 for (index = screen_info->windows_stack; index; index = g_list_next (index))
2594 Client *c = (Client *) index->data;
2595 if ((c->type & WINDOW_REGULAR_FOCUSABLE)
2596 && !FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED | CLIENT_FLAG_SKIP_TASKBAR))
2598 FLAG_SET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2599 clientHide (c, c->win_workspace, TRUE);
2602 clientFocusTop (screen_info, WIN_LAYER_DESKTOP, myDisplayGetCurrentTime (screen_info->display_info));
2604 else
2606 for (index = g_list_last(screen_info->windows_stack); index; index = g_list_previous (index))
2608 Client *c = (Client *) index->data;
2609 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN))
2611 clientShow (c, TRUE);
2613 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_WAS_SHOWN);
2615 clientFocusTop (screen_info, WIN_LAYER_NORMAL, myDisplayGetCurrentTime (screen_info->display_info));
2619 void
2620 clientActivate (Client * c, Time timestamp)
2622 ScreenInfo *screen_info;
2624 g_return_if_fail (c != NULL);
2625 TRACE ("entering clientActivate \"%s\" (0x%lx)", c->name, c->window);
2627 screen_info = c->screen_info;
2628 if ((screen_info->current_ws == c->win_workspace) || (screen_info->params->activate_action != ACTIVATE_ACTION_NONE))
2630 if (screen_info->current_ws != c->win_workspace)
2632 if (screen_info->params->activate_action == ACTIVATE_ACTION_BRING)
2634 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2636 else
2638 workspaceSwitch (screen_info, c->win_workspace, NULL, FALSE, timestamp);
2641 clientShow (c, TRUE);
2642 clientClearAllShowDesktop (screen_info);
2643 clientSetFocus (screen_info, c, timestamp, NO_FOCUS_FLAG);
2644 clientRaise (c, None);
2646 else
2648 TRACE ("Setting WM_STATE_DEMANDS_ATTENTION flag on \"%s\" (0x%lx)", c->name, c->window);
2649 FLAG_SET (c->flags, CLIENT_FLAG_DEMANDS_ATTENTION);
2650 clientSetNetState (c);
2654 void
2655 clientClose (Client * c)
2657 ScreenInfo *screen_info;
2658 DisplayInfo *display_info;
2660 g_return_if_fail (c != NULL);
2662 TRACE ("entering clientClose");
2663 TRACE ("closing client \"%s\" (0x%lx)", c->name, c->window);
2665 screen_info = c->screen_info;
2666 display_info = screen_info->display_info;
2668 if (FLAG_TEST (c->wm_flags, WM_FLAG_DELETE))
2670 sendClientMessage (screen_info, c->window, WM_DELETE_WINDOW,
2671 myDisplayGetCurrentTime (display_info));
2673 else
2675 clientKill (c);
2679 void
2680 clientKill (Client * c)
2682 g_return_if_fail (c != NULL);
2683 TRACE ("entering clientKill");
2684 TRACE ("killing client \"%s\" (0x%lx)", c->name, c->window);
2686 XKillClient (clientGetXDisplay (c), c->window);
2689 void
2690 clientEnterContextMenuState (Client * c)
2692 ScreenInfo *screen_info;
2693 DisplayInfo *display_info;
2695 g_return_if_fail (c != NULL);
2697 TRACE ("entering clientEnterContextMenuState");
2698 TRACE ("Showing the what's this help for client \"%s\" (0x%lx)", c->name, c->window);
2700 screen_info = c->screen_info;
2701 display_info = screen_info->display_info;
2703 if (FLAG_TEST (c->wm_flags, WM_FLAG_CONTEXT_HELP))
2705 sendClientMessage (c->screen_info, c->window, NET_WM_CONTEXT_HELP,
2706 myDisplayGetCurrentTime (display_info));
2710 void
2711 clientSetLayer (Client * c, int l)
2713 ScreenInfo *screen_info;
2714 DisplayInfo *display_info;
2715 GList *list_of_windows = NULL;
2716 GList *index = NULL;
2717 Client *c2 = NULL;
2719 g_return_if_fail (c != NULL);
2720 TRACE ("entering clientSetLayer");
2722 screen_info = c->screen_info;
2723 display_info = screen_info->display_info;
2725 list_of_windows = clientListTransientOrModal (c);
2726 for (index = list_of_windows; index; index = g_list_next (index))
2728 c2 = (Client *) index->data;
2729 if (c2->win_layer != l)
2731 TRACE ("setting client \"%s\" (0x%lx) layer to %d", c2->name,
2732 c2->window, l);
2733 c2->win_layer = l;
2734 setHint (display_info, c2->window, WIN_LAYER, l);
2737 g_list_free (list_of_windows);
2738 if (clientGetLastRaise (c->screen_info) == c)
2740 clientClearLastRaise (c->screen_info);
2742 clientRaise (c, None);
2745 void
2746 clientShade (Client * c)
2748 XWindowChanges wc;
2749 ScreenInfo *screen_info;
2750 DisplayInfo *display_info;
2751 unsigned long mask;
2753 g_return_if_fail (c != NULL);
2754 TRACE ("entering clientToggleShaded");
2755 TRACE ("shading client \"%s\" (0x%lx)", c->name, c->window);
2757 if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
2758 || FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
2760 TRACE ("cowardly refusing to shade \"%s\" (0x%lx) because it has no border", c->name, c->window);
2761 return;
2763 else if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2765 TRACE ("\"%s\" (0x%lx) is already shaded", c->name, c->window);
2766 return;
2769 screen_info = c->screen_info;
2770 display_info = screen_info->display_info;
2772 c->win_state |= WIN_STATE_SHADED;
2773 FLAG_SET (c->flags, CLIENT_FLAG_SHADED);
2774 clientSetNetState (c);
2775 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
2777 mask = (CWWidth | CWHeight);
2778 if (clientConstrainPos (c, FALSE))
2780 wc.x = c->x;
2781 wc.y = c->y;
2782 mask |= (CWX | CWY);
2785 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2787 c->ignore_unmap++;
2790 * Shading unmaps the client window. We therefore have to transfer focus to its frame
2791 * so that focus doesn't return to root. clientSetFocus() will take care of focusing
2792 * the window frame since the SHADED flag is now set.
2794 if (c == clientGetFocus ())
2796 clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
2798 XUnmapWindow (display_info->dpy, c->window);
2800 wc.width = c->width;
2801 wc.height = c->height;
2802 clientConfigure (c, &wc, mask, CFG_FORCE_REDRAW);
2806 void
2807 clientUnshade (Client * c)
2809 XWindowChanges wc;
2810 ScreenInfo *screen_info;
2811 DisplayInfo *display_info;
2813 g_return_if_fail (c != NULL);
2814 TRACE ("entering clientToggleShaded");
2815 TRACE ("shading/unshading client \"%s\" (0x%lx)", c->name, c->window);
2817 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2819 TRACE ("\"%s\" (0x%lx) is not shaded", c->name, c->window);
2820 return;
2823 screen_info = c->screen_info;
2824 display_info = screen_info->display_info;
2826 c->win_state &= ~WIN_STATE_SHADED;
2827 FLAG_UNSET (c->flags, CLIENT_FLAG_SHADED);
2828 clientSetNetState (c);
2829 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
2831 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_VISIBLE))
2833 XMapWindow (display_info->dpy, c->window);
2836 * Unshading will show the client window, so we need to focus it when unshading.
2838 if (c == clientGetFocus ())
2840 clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
2843 wc.width = c->width;
2844 wc.height = c->height;
2845 clientConfigure (c, &wc, CWWidth | CWHeight, CFG_FORCE_REDRAW);
2849 void
2850 clientToggleShaded (Client * c)
2852 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
2854 clientUnshade (c);
2856 else
2858 clientShade (c);
2862 void
2863 clientStick (Client * c, gboolean include_transients)
2865 ScreenInfo *screen_info;
2866 DisplayInfo *display_info;
2867 Client *c2;
2868 GList *list_of_windows;
2869 GList *index;
2871 g_return_if_fail (c != NULL);
2872 TRACE ("entering clientStick");
2874 screen_info = c->screen_info;
2875 display_info = screen_info->display_info;
2877 if (include_transients)
2879 list_of_windows = clientListTransientOrModal (c);
2880 for (index = list_of_windows; index; index = g_list_next (index))
2882 c2 = (Client *) index->data;
2883 TRACE ("sticking client \"%s\" (0x%lx)", c2->name, c2->window);
2884 c2->win_state |= WIN_STATE_STICKY;
2885 FLAG_SET (c2->flags, CLIENT_FLAG_STICKY);
2886 setHint (display_info, c2->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2887 clientSetNetState (c2);
2889 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2890 g_list_free (list_of_windows);
2892 else
2894 TRACE ("sticking client \"%s\" (0x%lx)", c->name, c->window);
2895 c->win_state |= WIN_STATE_STICKY;
2896 FLAG_SET (c->flags, CLIENT_FLAG_STICKY);
2897 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) ALL_WORKSPACES);
2898 clientSetNetState (c);
2899 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2903 void
2904 clientUnstick (Client * c, gboolean include_transients)
2906 ScreenInfo *screen_info;
2907 DisplayInfo *display_info;
2908 Client *c2;
2909 GList *list_of_windows;
2910 GList *index;
2912 g_return_if_fail (c != NULL);
2913 TRACE ("entering clientUnstick");
2914 TRACE ("unsticking client \"%s\" (0x%lx)", c->name, c->window);
2916 screen_info = c->screen_info;
2917 display_info = screen_info->display_info;
2919 if (include_transients)
2921 list_of_windows = clientListTransientOrModal (c);
2922 for (index = list_of_windows; index; index = g_list_next (index))
2924 c2 = (Client *) index->data;
2925 c2->win_state &= ~WIN_STATE_STICKY;
2926 FLAG_UNSET (c2->flags, CLIENT_FLAG_STICKY);
2927 setHint (display_info, c2->window, NET_WM_DESKTOP, (unsigned long) screen_info->current_ws);
2928 clientSetNetState (c2);
2930 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2931 g_list_free (list_of_windows);
2933 else
2935 c->win_state &= ~WIN_STATE_STICKY;
2936 FLAG_UNSET (c->flags, CLIENT_FLAG_STICKY);
2937 setHint (display_info, c->window, NET_WM_DESKTOP, (unsigned long) screen_info->current_ws);
2938 clientSetNetState (c);
2939 clientSetWorkspace (c, screen_info->current_ws, TRUE);
2943 void
2944 clientToggleSticky (Client * c, gboolean include_transients)
2946 g_return_if_fail (c != NULL);
2947 TRACE ("entering clientToggleSticky");
2948 TRACE ("sticking/unsticking client \"%s\" (0x%lx)", c->name, c->window);
2950 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
2952 clientUnstick (c, include_transients);
2954 else
2956 clientStick (c, include_transients);
2960 void clientToggleFullscreen (Client * c)
2962 g_return_if_fail (c != NULL);
2963 TRACE ("entering clientToggleFullscreen");
2964 TRACE ("toggle fullscreen client \"%s\" (0x%lx)", c->name, c->window);
2966 /* Can we switch to full screen, does it make any sense? */
2967 if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN) && (c->size->flags & PMaxSize))
2969 GdkRectangle rect;
2970 gint monitor_nbr;
2971 int cx, cy;
2973 cx = frameX (c) + (frameWidth (c) / 2);
2974 cy = frameY (c) + (frameHeight (c) / 2);
2976 monitor_nbr = find_monitor_at_point (c->screen_info->gscr, cx, cy);
2977 gdk_screen_get_monitor_geometry (c->screen_info->gscr, monitor_nbr, &rect);
2979 if ((c->size->max_width < rect.width) || (c->size->max_height < rect.height))
2981 return;
2985 if (!clientIsValidTransientOrModal (c) && (c->type == WINDOW_NORMAL))
2987 FLAG_TOGGLE (c->flags, CLIENT_FLAG_FULLSCREEN);
2988 clientUpdateFullscreenState (c);
2992 void clientToggleAbove (Client * c)
2994 g_return_if_fail (c != NULL);
2995 TRACE ("entering clientToggleAbove");
2996 TRACE ("toggle above client \"%s\" (0x%lx)", c->name, c->window);
2998 if (!clientIsValidTransientOrModal (c) &&
2999 !FLAG_TEST (c->flags, CLIENT_FLAG_BELOW | CLIENT_FLAG_FULLSCREEN))
3001 FLAG_TOGGLE (c->flags, CLIENT_FLAG_ABOVE);
3002 clientUpdateAboveState (c);
3006 void clientToggleBelow (Client * c)
3008 g_return_if_fail (c != NULL);
3009 TRACE ("entering clientToggleBelow");
3010 TRACE ("toggle below client \"%s\" (0x%lx)", c->name, c->window);
3012 if (!FLAG_TEST (c->flags, CLIENT_FLAG_ABOVE))
3014 FLAG_TOGGLE (c->flags, CLIENT_FLAG_BELOW);
3015 clientUpdateAboveState (c);
3019 void
3020 clientRemoveMaximizeFlag (Client * c)
3022 g_return_if_fail (c != NULL);
3023 TRACE ("entering clientRemoveMaximizeFlag");
3024 TRACE ("Removing maximize flag on client \"%s\" (0x%lx)", c->name,
3025 c->window);
3027 c->win_state &= ~WIN_STATE_MAXIMIZED;
3028 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3029 frameDraw (c, FALSE);
3030 clientSetNetState (c);
3033 static void
3034 clientNewMaxState (Client * c, XWindowChanges *wc, int mode)
3037 * We treat differently full maximization from vertical or horizontal maximization.
3038 * This is for usability concerns, otherwise maximization acts like a toggle,
3039 * switching from horizontal to vertical instead of switching to full maximization.
3041 * The full size is not computed yet, as full maximization removes borders
3042 * while either horizontal or vertical maximization still shows decorations...
3045 if ((mode & WIN_STATE_MAXIMIZED) == WIN_STATE_MAXIMIZED)
3047 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
3049 c->win_state |= WIN_STATE_MAXIMIZED;
3050 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED);
3051 return;
3055 if (mode & WIN_STATE_MAXIMIZED_HORIZ)
3057 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
3059 c->win_state |= WIN_STATE_MAXIMIZED_HORIZ;
3060 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ);
3061 return;
3065 if (mode & WIN_STATE_MAXIMIZED_VERT)
3067 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
3069 c->win_state |= WIN_STATE_MAXIMIZED_VERT;
3070 FLAG_SET (c->flags, CLIENT_FLAG_MAXIMIZED_VERT);
3071 return;
3075 c->win_state &= ~WIN_STATE_MAXIMIZED;
3076 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED);
3077 wc->x = c->old_x;
3078 wc->y = c->old_y;
3079 wc->width = c->old_width;
3080 wc->height = c->old_height;
3083 static void
3084 clientNewMaxSize (Client * c, XWindowChanges *wc)
3086 ScreenInfo *screen_info;
3087 GdkRectangle rect;
3088 int cx, cy, full_x, full_y, full_w, full_h;
3089 int tmp_x, tmp_y, tmp_w, tmp_h;
3090 gint monitor_nbr;
3092 tmp_x = frameX (c);
3093 tmp_y = frameY (c);
3094 tmp_h = frameHeight (c);
3095 tmp_w = frameWidth (c);
3097 cx = tmp_x + (tmp_w / 2);
3098 cy = tmp_y + (tmp_h / 2);
3100 screen_info = c->screen_info;
3102 monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
3103 gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);
3105 full_x = MAX (screen_info->params->xfwm_margins[STRUTS_LEFT], rect.x);
3106 full_y = MAX (screen_info->params->xfwm_margins[STRUTS_TOP], rect.y);
3107 full_w = MIN (screen_info->width - screen_info->params->xfwm_margins[STRUTS_RIGHT],
3108 rect.x + rect.width) - full_x;
3109 full_h = MIN (screen_info->height - screen_info->params->xfwm_margins[STRUTS_BOTTOM],
3110 rect.y + rect.height) - full_y;
3112 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED))
3114 /* Adjust size to the largest size available, not covering struts */
3115 clientMaxSpace (screen_info, &full_x, &full_y, &full_w, &full_h);
3116 wc->x = full_x + frameLeft (c);
3117 wc->y = full_y + frameTop (c);
3118 wc->width = full_w - frameLeft (c) - frameRight (c);
3119 wc->height = full_h - frameTop (c) - frameBottom (c);
3121 return;
3124 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ))
3126 /* Adjust size to the widest size available, for the current vertical position/height */
3127 clientMaxSpace (screen_info, &full_x, &tmp_y, &full_w, &tmp_h);
3128 wc->x = full_x + frameLeft (c);
3129 wc->width = full_w - frameLeft (c) - frameRight (c);
3131 return;
3134 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_VERT))
3136 /* Adjust size to the tallest size available, for the current horizontal position/width */
3137 clientMaxSpace (screen_info, &tmp_x, &full_y, &tmp_w, &full_h);
3138 wc->y = full_y + frameTop (c);
3139 wc->height = full_h - frameTop (c) - frameBottom (c);
3141 return;
3145 void
3146 clientToggleMaximized (Client * c, int mode, gboolean restore_position)
3148 DisplayInfo *display_info;
3149 ScreenInfo *screen_info;
3151 XWindowChanges wc;
3153 g_return_if_fail (c != NULL);
3154 TRACE ("entering clientToggleMaximized");
3155 TRACE ("maximzing/unmaximizing client \"%s\" (0x%lx)", c->name, c->window);
3157 if (!CLIENT_CAN_MAXIMIZE_WINDOW (c))
3159 return;
3162 screen_info = c->screen_info;
3163 display_info = screen_info->display_info;
3165 wc.x = c->x;
3166 wc.y = c->y;
3167 wc.width = c->width;
3168 wc.height = c->height;
3170 if (!FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED) && (restore_position))
3172 c->old_x = c->x;
3173 c->old_y = c->y;
3174 c->old_width = c->width;
3175 c->old_height = c->height;
3178 /* 1) Compute the new state */
3179 clientNewMaxState (c, &wc, mode);
3181 /* 2) Compute the new size, based on the state */
3182 clientNewMaxSize (c, &wc);
3184 /* 3) Update window state fields */
3185 clientSetNetState (c);
3187 /* 4) Update size and position fields */
3188 c->x = wc.x;
3189 c->y = wc.y;
3190 c->height = wc.height;
3191 c->width = wc.width;
3193 /* Maximizing may remove decoration on the side, update NET_FRAME_EXTENTS accordingly */
3194 setNetFrameExtents (display_info,
3195 c->window,
3196 frameTop (c),
3197 frameLeft (c),
3198 frameRight (c),
3199 frameBottom (c));
3201 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED) && (restore_position))
3204 For some reason, the configure can generate EnterNotify events
3205 on lower windows, causing a nasty race cond with apps trying to
3206 grab focus in focus follow mouse mode. Grab the pointer to
3207 avoid these effects
3209 myScreenGrabPointer (c->screen_info, EnterWindowMask, None, myDisplayGetCurrentTime (display_info));
3210 clientConfigure (c, &wc, CWWidth | CWHeight | CWX | CWY, CFG_FORCE_REDRAW);
3211 myScreenUngrabPointer (c->screen_info);
3215 void
3216 clientFill (Client * c, int fill_type)
3218 ScreenInfo *screen_info;
3219 DisplayInfo *display_info;
3220 Client *east_neighbour;
3221 Client *west_neighbour;
3222 Client *north_neighbour;
3223 Client *south_neighbour;
3224 Client *c2;
3225 GdkRectangle rect;
3226 XWindowChanges wc;
3227 unsigned short mask;
3228 int i, cx, cy, full_x, full_y, full_w, full_h;
3229 int tmp_x, tmp_y, tmp_w, tmp_h;
3230 gint monitor_nbr;
3232 g_return_if_fail (c != NULL);
3234 if (!CLIENT_CAN_FILL_WINDOW (c))
3236 return;
3239 screen_info = c->screen_info;
3240 display_info = screen_info->display_info;
3241 mask = 0;
3242 east_neighbour = NULL;
3243 west_neighbour = NULL;
3244 north_neighbour = NULL;
3245 south_neighbour = NULL;
3247 for (c2 = screen_info->clients, i = 0; i < screen_info->client_count; c2 = c2->next, i++)
3250 /* Filter out all windows which are not visible, or not on the same layer
3251 * as well as the client window itself
3253 if ((c != c2) && FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE) && (c2->win_layer == c->win_layer))
3255 /* Fill horizontally */
3256 if (fill_type & CLIENT_FILL_HORIZ)
3259 * check if the neigbour client (c2) is located
3260 * east or west of our client.
3262 if (!(((frameY(c) + frameHeight(c)) < (frameY(c2) - frameTop(c2))) || ((frameY(c2) + frameHeight(c2)) < (frameY(c) - frameTop(c)))))
3264 if ((frameX(c2) + frameWidth(c2)) < frameX(c))
3266 if (east_neighbour)
3268 /* Check if c2 is closer to the client
3269 * then the east neighbour already found
3271 if ((frameX(east_neighbour) + frameWidth(east_neighbour)) < (frameX(c2) + frameWidth(c2)))
3273 east_neighbour = c2;
3276 else
3278 east_neighbour = c2;
3281 if ((frameX(c) + frameWidth(c)) < frameX(c2))
3283 /* Check if c2 is closer to the client
3284 * then the west neighbour already found
3286 if (west_neighbour)
3288 if (frameX(c2) < frameX(west_neighbour))
3290 west_neighbour = c2;
3293 else
3295 west_neighbour = c2;
3301 /* Fill vertically */
3302 if (fill_type & CLIENT_FILL_VERT)
3304 /* check if the neigbour client (c2) is located
3305 * north or south of our client.
3307 if (!(((frameX(c) + frameWidth(c)) < frameX(c2)) || ((frameX(c2) + frameWidth(c2)) < frameX(c))))
3309 if ((frameY(c2) + frameHeight(c2)) < frameY(c))
3311 if (north_neighbour)
3313 /* Check if c2 is closer to the client
3314 * then the north neighbour already found
3316 if ((frameY(north_neighbour) + frameHeight(north_neighbour)) < (frameY(c2) + frameHeight(c2)))
3318 north_neighbour = c2;
3321 else
3323 north_neighbour = c2;
3326 if ((frameY(c) + frameHeight(c)) < frameY(c2))
3328 if (south_neighbour)
3330 /* Check if c2 is closer to the client
3331 * then the south neighbour already found
3333 if (frameY(c2) < frameY(south_neighbour))
3335 south_neighbour = c2;
3338 else
3340 south_neighbour = c2;
3348 /* Compute the largest size available, based on struts, margins and Xinerama layout */
3349 tmp_x = frameX (c);
3350 tmp_y = frameY (c);
3351 tmp_h = frameHeight (c);
3352 tmp_w = frameWidth (c);
3354 cx = tmp_x + (tmp_w / 2);
3355 cy = tmp_y + (tmp_h / 2);
3357 monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
3358 gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);
3360 full_x = MAX (screen_info->params->xfwm_margins[STRUTS_LEFT], rect.x);
3361 full_y = MAX (screen_info->params->xfwm_margins[STRUTS_TOP], rect.y);
3362 full_w = MIN (screen_info->width - screen_info->params->xfwm_margins[STRUTS_RIGHT],
3363 rect.x + rect.width) - full_x;
3364 full_h = MIN (screen_info->height - screen_info->params->xfwm_margins[STRUTS_BOTTOM],
3365 rect.y + rect.height) - full_y;
3367 if ((fill_type & CLIENT_FILL) == CLIENT_FILL)
3369 mask = CWX | CWY | CWHeight | CWWidth;
3370 /* Adjust size to the largest size available, not covering struts */
3371 clientMaxSpace (screen_info, &full_x, &full_y, &full_w, &full_h);
3373 else if (fill_type & CLIENT_FILL_VERT)
3375 mask = CWY | CWHeight;
3376 /* Adjust size to the tallest size available, for the current horizontal position/width */
3377 clientMaxSpace (screen_info, &tmp_x, &full_y, &tmp_w, &full_h);
3379 else if (fill_type & CLIENT_FILL_HORIZ)
3381 mask = CWX | CWWidth;
3382 /* Adjust size to the widest size available, for the current vertical position/height */
3383 clientMaxSpace (screen_info, &full_x, &tmp_y, &full_w, &tmp_h);
3386 /* If there are neighbours, resize to their borders.
3387 * If not, resize to the largest size available taht you just have computed.
3390 if (east_neighbour)
3392 wc.x = frameX(east_neighbour) + frameWidth(east_neighbour) + frameLeft(c);
3394 else
3396 wc.x = full_x + frameLeft(c);
3399 if (west_neighbour)
3401 wc.width = full_x + frameX(west_neighbour) - frameRight(c) - wc.x;
3403 else
3405 wc.width = full_x + full_w - frameRight(c) - wc.x;
3408 if (north_neighbour)
3410 wc.y = frameY(north_neighbour) + frameHeight(north_neighbour) + frameTop(c);
3412 else
3414 wc.y = full_y + frameTop(c);
3417 if (south_neighbour)
3419 wc.height = full_y + frameY(south_neighbour) - frameBottom(c) - wc.y;
3421 else
3423 wc.height = full_y + full_h - frameBottom(c) - wc.y;
3426 TRACE ("Fill size request: (%d,%d) %dx%d", wc.x, wc.y, wc.width, wc.height);
3427 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MANAGED))
3430 For some reason, the configure can generate EnterNotify events
3431 on lower windows, causing a nasty race cond with apps trying to
3432 grab focus in focus follow mouse mode. Grab the pointer to
3433 avoid these effects
3435 myScreenGrabPointer (c->screen_info, EnterWindowMask, None, myDisplayGetCurrentTime (display_info));
3436 clientConfigure(c, &wc, mask, NO_CFG_FLAG);
3437 myScreenUngrabPointer (c->screen_info);
3441 void
3442 clientUpdateOpacity (ScreenInfo *screen_info, Client *focus)
3444 DisplayInfo *display_info;
3445 Client *c;
3446 int i;
3448 display_info = screen_info->display_info;
3449 if (!compositorIsUsable (display_info))
3451 return;
3454 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, ++i)
3456 gboolean o = FLAG_TEST(c->type, WINDOW_TYPE_DONT_PLACE | WINDOW_TYPE_DONT_FOCUS)
3457 || (focus == c)
3458 || (focus && ((focus->transient_for == c->window) || (focus->window == c->transient_for)))
3459 || (focus && (clientIsModalFor (c, focus) || clientIsModalFor (focus, c)));
3461 clientSetOpacity (c, c->opacity, OPACITY_INACTIVE, o ? 0 : OPACITY_INACTIVE);
3465 void
3466 clientSetOpacity (Client *c, guint opacity, guint clear, guint xor)
3468 ScreenInfo *screen_info;
3469 DisplayInfo *display_info;
3470 guint applied;
3472 screen_info = c->screen_info;
3473 display_info = screen_info->display_info;
3475 if (!compositorIsUsable (display_info))
3477 return;
3480 c->opacity_flags = (c->opacity_flags & ~clear) ^ xor;
3482 if (c->opacity_locked)
3484 applied = c->opacity;
3486 else
3488 long long multiplier = 1, divisor = 1;
3490 c->opacity = applied = opacity;
3492 if (FLAG_TEST (c->opacity_flags, OPACITY_MOVE))
3494 multiplier *= c->screen_info->params->move_opacity;
3495 divisor *= 100;
3497 if (FLAG_TEST (c->opacity_flags, OPACITY_RESIZE))
3499 multiplier *= c->screen_info->params->resize_opacity;
3500 divisor *= 100;
3502 if (FLAG_TEST (c->opacity_flags, OPACITY_INACTIVE))
3504 multiplier *= c->screen_info->params->inactive_opacity;
3505 divisor *= 100;
3508 applied = (guint) ((long long) applied * multiplier / divisor);
3511 if (applied != c->opacity_applied)
3513 c->opacity_applied = applied;
3514 compositorWindowSetOpacity (display_info, c->frame, applied);
3518 void
3519 clientDecOpacity (Client * c)
3521 ScreenInfo *screen_info;
3522 DisplayInfo *display_info;
3524 screen_info = c->screen_info;
3525 display_info = screen_info->display_info;
3527 if (!compositorIsUsable (display_info))
3529 return;
3532 if ((c->opacity > OPACITY_SET_MIN) && !(c->opacity_locked ))
3534 clientSetOpacity (c, c->opacity - OPACITY_SET_STEP, 0, 0);
3538 void
3539 clientIncOpacity (Client * c)
3541 ScreenInfo *screen_info;
3542 DisplayInfo *display_info;
3544 screen_info = c->screen_info;
3545 display_info = screen_info->display_info;
3547 if (!compositorIsUsable (display_info))
3549 return;
3552 if ((c->opacity < NET_WM_OPAQUE) && !(c->opacity_locked ))
3554 guint opacity = c->opacity + OPACITY_SET_STEP;
3556 if (opacity < OPACITY_SET_MIN)
3558 opacity = NET_WM_OPAQUE;
3560 clientSetOpacity (c, opacity, 0, 0);
3564 /* Xrandr stuff: on screen size change, make sure all clients are still visible */
3565 void
3566 clientScreenResize(ScreenInfo *screen_info)
3568 Client *c = NULL;
3569 GList *index, *list_of_windows;
3570 XWindowChanges wc;
3572 list_of_windows = clientGetStackList (screen_info);
3574 if (!list_of_windows)
3576 return;
3579 /* Revalidate client struts */
3580 for (index = list_of_windows; index; index = g_list_next (index))
3582 c = (Client *) index->data;
3583 if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_STRUT))
3585 clientValidateNetStrut (c);
3589 myScreenGrabPointer (screen_info, EnterWindowMask, None, myDisplayGetCurrentTime (screen_info->display_info));
3590 for (index = list_of_windows; index; index = g_list_next (index))
3592 unsigned long maximization_flags = 0L;
3594 c = (Client *) index->data;
3595 if (!CONSTRAINED_WINDOW (c))
3597 continue;
3600 /* Recompute size and position of maximized windows */
3601 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT))
3603 /* Too bad, the flags used internally are different from the WIN_STATE_* bits */
3604 maximization_flags |= FLAG_TEST (c->flags,
3605 CLIENT_FLAG_MAXIMIZED_HORIZ) ? WIN_STATE_MAXIMIZED_HORIZ : 0;
3606 maximization_flags |= FLAG_TEST (c->flags,
3607 CLIENT_FLAG_MAXIMIZED_VERT) ? WIN_STATE_MAXIMIZED_VERT : 0;
3609 /* Force an update by clearing the internal flags */
3610 FLAG_UNSET (c->flags, CLIENT_FLAG_MAXIMIZED_HORIZ | CLIENT_FLAG_MAXIMIZED_VERT);
3611 clientToggleMaximized (c, maximization_flags, FALSE);
3613 wc.x = c->x;
3614 wc.y = c->y;
3615 wc.width = c->width;
3616 wc.height = c->height;
3617 clientConfigure (c, &wc, CWX | CWY | CWWidth | CWHeight, CFG_NOTIFY);
3619 else
3621 wc.x = c->x;
3622 wc.y = c->y;
3623 clientConfigure (c, &wc, CWX | CWY, CFG_CONSTRAINED | CFG_REQUEST);
3626 myScreenUngrabPointer (screen_info);
3628 g_list_free (list_of_windows);
3631 static void
3632 clientDrawOutline (Client * c)
3634 TRACE ("entering clientDrawOutline");
3636 XDrawRectangle (clientGetXDisplay (c), c->screen_info->xroot, c->screen_info->box_gc, frameX (c), frameY (c),
3637 frameWidth (c) - 1, frameHeight (c) - 1);
3638 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
3639 &&!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN | CLIENT_FLAG_SHADED))
3641 XDrawRectangle (clientGetXDisplay (c), c->screen_info->xroot, c->screen_info->box_gc, c->x, c->y, c->width - 1,
3642 c->height - 1);
3646 static void
3647 clientSnapPosition (Client * c, int prev_x, int prev_y)
3649 ScreenInfo *screen_info;
3650 Client *c2;
3651 int cx, cy, i, delta;
3652 int disp_x, disp_y, disp_max_x, disp_max_y;
3653 int frame_x, frame_y, frame_height, frame_width;
3654 int frame_top, frame_left, frame_right, frame_bottom;
3655 int frame_x2, frame_y2;
3656 int best_frame_x, best_frame_y;
3657 int best_delta_x, best_delta_y;
3658 int c_frame_x1, c_frame_x2, c_frame_y1, c_frame_y2;
3659 GdkRectangle rect;
3660 gint monitor_nbr;
3662 g_return_if_fail (c != NULL);
3663 TRACE ("entering clientSnapPosition");
3664 TRACE ("Snapping client \"%s\" (0x%lx)", c->name, c->window);
3666 screen_info = c->screen_info;
3667 best_delta_x = screen_info->params->snap_width + 1;
3668 best_delta_y = screen_info->params->snap_width + 1;
3670 frame_x = frameX (c);
3671 frame_y = frameY (c);
3672 frame_height = frameHeight (c);
3673 frame_width = frameWidth (c);
3674 frame_top = frameTop (c);
3675 frame_left = frameLeft (c);
3676 frame_right = frameRight (c);
3677 frame_bottom = frameBottom (c);
3679 cx = frame_x + (frame_width / 2);
3680 cy = frame_y + (frame_height / 2);
3682 frame_x2 = frame_x + frame_width;
3683 frame_y2 = frame_y + frame_height;
3684 best_frame_x = frame_x;
3685 best_frame_y = frame_y;
3687 monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
3688 gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);
3690 disp_x = rect.x;
3691 disp_y = rect.y;
3692 disp_max_x = rect.x + rect.width;
3693 disp_max_y = rect.y + rect.height;
3695 if (screen_info->params->snap_to_border)
3697 if (abs (disp_x - frame_x) < abs (disp_max_x - frame_x2))
3699 if (!screen_info->params->snap_resist || ((frame_x <= disp_x) && (c->x < prev_x)))
3701 best_delta_x = abs (disp_x - frame_x);
3702 best_frame_x = disp_x;
3705 else
3707 if (!screen_info->params->snap_resist || ((frame_x2 >= disp_max_x) && (c->x > prev_x)))
3709 best_delta_x = abs (disp_max_x - frame_x2);
3710 best_frame_x = disp_max_x - frame_width;
3714 if (abs (disp_y - frame_y) < abs (disp_max_y - frame_y2))
3716 if (!screen_info->params->snap_resist || ((frame_y <= disp_y) && (c->y < prev_y)))
3718 best_delta_y = abs (disp_y - frame_y);
3719 best_frame_y = disp_y;
3722 else
3724 if (!screen_info->params->snap_resist || ((frame_y2 >= disp_max_y) && (c->y > prev_y)))
3726 best_delta_y = abs (disp_max_y - frame_y2);
3727 best_frame_y = disp_max_y - frame_height;
3732 for (c2 = screen_info->clients, i = 0; i < screen_info->client_count; c2 = c2->next, i++)
3734 if (FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE) && (c2 != c) &&
3735 (((screen_info->params->snap_to_windows) && (c2->win_layer == c->win_layer))
3736 || ((screen_info->params->snap_to_border)
3737 && FLAG_TEST (c2->flags, CLIENT_FLAG_HAS_STRUT)
3738 && FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE))))
3740 c_frame_x1 = frameX (c2);
3741 c_frame_x2 = c_frame_x1 + frameWidth (c2);
3742 c_frame_y1 = frameY (c2);
3743 c_frame_y2 = c_frame_y1 + frameHeight (c2);
3745 if ((c_frame_y1 <= frame_y2) && (c_frame_y2 >= frame_y))
3747 delta = abs (c_frame_x2 - frame_x);
3748 if (delta < best_delta_x)
3750 if (!screen_info->params->snap_resist || ((frame_x <= c_frame_x2) && (c->x < prev_x)))
3752 best_delta_x = delta;
3753 best_frame_x = c_frame_x2;
3757 delta = abs (c_frame_x1 - frame_x2);
3758 if (delta < best_delta_x)
3760 if (!screen_info->params->snap_resist || ((frame_x2 >= c_frame_x1) && (c->x > prev_x)))
3762 best_delta_x = delta;
3763 best_frame_x = c_frame_x1 - frame_width;
3768 if ((c_frame_x1 <= frame_x2) && (c_frame_x2 >= frame_x))
3770 delta = abs (c_frame_y2 - frame_y);
3771 if (delta < best_delta_y)
3773 if (!screen_info->params->snap_resist || ((frame_y <= c_frame_y2) && (c->y < prev_y)))
3775 best_delta_y = delta;
3776 best_frame_y = c_frame_y2;
3780 delta = abs (c_frame_y1 - frame_y2);
3781 if (delta < best_delta_y)
3783 if (!screen_info->params->snap_resist || ((frame_y2 >= c_frame_y1) && (c->y > prev_y)))
3785 best_delta_y = delta;
3786 best_frame_y = c_frame_y1 - frame_height;
3793 if (best_delta_x <= screen_info->params->snap_width)
3795 c->x = best_frame_x + frame_left;
3797 if (best_delta_y <= screen_info->params->snap_width)
3799 c->y = best_frame_y + frame_top;
3803 static eventFilterStatus
3804 clientButtonReleaseFilter (XEvent * xevent, gpointer data)
3806 MoveResizeData *passdata = (MoveResizeData *) data;
3808 TRACE ("entering clientButtonReleaseFilter");
3810 if ((xevent->type == ButtonRelease) &&
3811 (xevent->xbutton.button == passdata->button))
3813 gtk_main_quit ();
3814 return EVENT_FILTER_STOP;
3817 return EVENT_FILTER_CONTINUE;
3820 static eventFilterStatus
3821 clientMoveEventFilter (XEvent * xevent, gpointer data)
3823 static int edge_scroll_x = 0;
3824 static int edge_scroll_y = 0;
3825 static gboolean toggled_maximize = FALSE;
3826 static Time lastresist = (Time) 0;
3827 unsigned long configure_flags;
3828 ScreenInfo *screen_info;
3829 DisplayInfo *display_info;
3830 eventFilterStatus status = EVENT_FILTER_STOP;
3831 MoveResizeData *passdata = (MoveResizeData *) data;
3832 Client *c = NULL;
3833 gboolean moving = TRUE;
3834 gboolean warp_pointer = FALSE;
3835 XWindowChanges wc;
3836 int prev_x, prev_y;
3838 TRACE ("entering clientMoveEventFilter");
3840 c = passdata->c;
3841 prev_x=c->x;
3842 prev_y=c->y;
3843 screen_info = c->screen_info;
3844 display_info = screen_info->display_info;
3845 configure_flags = NO_CFG_FLAG;
3847 /* Update the display time */
3848 myDisplayUpdateCurrentTime (display_info, xevent);
3850 if (xevent->type == KeyPress)
3852 while (XCheckMaskEvent (display_info->dpy, KeyPressMask, xevent))
3854 /* Update the display time */
3855 myDisplayUpdateCurrentTime (display_info, xevent);
3858 if ((passdata->use_keys) && !FLAG_TEST_ALL(c->flags, CLIENT_FLAG_MAXIMIZED))
3860 int key_move = 16;
3861 unsigned int edge;
3863 if ((screen_info->params->snap_to_border) || (screen_info->params->snap_to_windows))
3865 key_move = MAX (16, screen_info->params->snap_width + 1);
3868 if (!passdata->grab && screen_info->params->box_move)
3870 myDisplayGrabServer (display_info);
3871 passdata->grab = TRUE;
3872 clientDrawOutline (c);
3874 if (screen_info->params->box_move)
3876 clientDrawOutline (c);
3878 if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_LEFT].keycode)
3880 c->x = c->x - key_move;
3882 else if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_RIGHT].keycode)
3884 c->x = c->x + key_move;
3886 else if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_UP].keycode)
3888 c->y = c->y - key_move;
3890 else if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_DOWN].keycode)
3892 c->y = c->y + key_move;
3895 clientSnapPosition (c, prev_x, prev_y);
3896 edge = clientConstrainPos (c, FALSE);
3897 if ((edge) && (screen_info->params->wrap_windows))
3899 int maxx, maxy, maxw, maxh;
3901 maxx = 0;
3902 maxy = 0;
3903 maxw = screen_info->width;
3904 maxh = screen_info->height;
3905 clientMaxSpace (screen_info, &maxx, &maxy, &maxw, &maxh);
3907 if (edge & CLIENT_CONSTRAINED_TOP)
3909 if (workspaceMove (screen_info, -1, 0, c, xevent->xkey.time))
3911 c->y = maxy + maxh;
3914 else if (edge & CLIENT_CONSTRAINED_BOTTOM)
3916 if (workspaceMove (screen_info, 1, 0, c, xevent->xkey.time))
3918 c->y = maxy + frameTop (c);
3922 if (edge & CLIENT_CONSTRAINED_LEFT)
3924 if (workspaceMove (screen_info, 0, -1, c, xevent->xkey.time))
3926 c->x = maxx + maxw - frameWidth (c) + frameRight (c);
3929 else if (edge & CLIENT_CONSTRAINED_RIGHT)
3931 if (workspaceMove (screen_info, 0, 1, c, xevent->xkey.time))
3933 c->x = maxx + frameLeft (c);
3937 #ifdef SHOW_POSITION
3938 if (passdata->poswin)
3940 poswinSetPosition (passdata->poswin, c);
3942 #endif /* SHOW_POSITION */
3943 if (screen_info->params->box_move)
3945 clientDrawOutline (c);
3947 else
3949 wc.x = c->x;
3950 wc.y = c->y;
3951 clientConfigure (c, &wc, CWX | CWY, configure_flags);
3955 else if (xevent->type == KeyRelease)
3957 if (xevent->xkey.keycode == screen_info->params->keys[KEY_CANCEL].keycode)
3959 moving = FALSE;
3960 passdata->released = passdata->use_keys;
3962 if (screen_info->params->box_move)
3964 clientDrawOutline (c);
3967 c->x = passdata->cancel_x;
3968 c->y = passdata->cancel_y;
3970 if (screen_info->params->box_move)
3972 clientDrawOutline (c);
3974 else
3976 wc.x = c->x;
3977 wc.y = c->y;
3978 clientConfigure (c, &wc, CWX | CWY, configure_flags);
3980 if (screen_info->current_ws != passdata->cancel_workspace)
3982 workspaceSwitch (screen_info, passdata->cancel_workspace, c, FALSE, xevent->xkey.time);
3984 if (toggled_maximize)
3986 toggled_maximize = FALSE;
3987 clientToggleMaximized (c, WIN_STATE_MAXIMIZED, FALSE);
3988 configure_flags = CFG_FORCE_REDRAW;
3989 passdata->move_resized = TRUE;
3992 else if (passdata->use_keys)
3994 if (IsModifierKey (XLookupKeysym (&xevent->xkey, 0)))
3996 moving = FALSE;
4000 else if (xevent->type == ButtonRelease)
4002 if (!passdata->use_keys)
4004 moving = FALSE;
4005 passdata->released = (xevent->xbutton.button == passdata->button);
4008 else if (xevent->type == MotionNotify)
4010 while (XCheckMaskEvent (display_info->dpy, ButtonMotionMask, xevent))
4012 /* Update the display time */
4013 myDisplayUpdateCurrentTime (display_info, xevent);
4015 if (!passdata->grab && screen_info->params->box_move)
4017 myDisplayGrabServer (display_info);
4018 passdata->grab = TRUE;
4019 clientDrawOutline (c);
4021 if (screen_info->params->box_move)
4023 clientDrawOutline (c);
4025 if ((screen_info->workspace_count > 1) && !(passdata->is_transient))
4027 if ((screen_info->params->wrap_windows) && (screen_info->params->wrap_resistance))
4029 int msx, msy, maxx, maxy;
4030 int rx, ry;
4032 msx = xevent->xmotion.x_root;
4033 msy = xevent->xmotion.y_root;
4034 maxx = screen_info->width - 1;
4035 maxy = screen_info->height - 1;
4036 rx = 0;
4037 ry = 0;
4038 warp_pointer = FALSE;
4040 if ((msx == 0) || (msx == maxx))
4042 if ((xevent->xmotion.time - lastresist) > 250) /* ms */
4044 edge_scroll_x = 0;
4046 else
4048 edge_scroll_x++;
4050 if (msx == 0)
4052 rx = 1;
4054 else
4056 rx = -1;
4058 warp_pointer = TRUE;
4059 lastresist = xevent->xmotion.time;
4061 if ((msy == 0) || (msy == maxy))
4063 if ((xevent->xmotion.time - lastresist) > 250) /* ms */
4065 edge_scroll_y = 0;
4067 else
4069 edge_scroll_y++;
4071 if (msy == 0)
4073 ry = 1;
4075 else
4077 ry = -1;
4079 warp_pointer = TRUE;
4080 lastresist = xevent->xmotion.time;
4083 if (edge_scroll_x > screen_info->params->wrap_resistance)
4085 edge_scroll_x = 0;
4086 if ((msx == 0) || (msx == maxx))
4088 if (msx == 0)
4090 if (workspaceMove (screen_info, 0, -1, c, xevent->xmotion.time))
4092 rx = 4 * maxx / 5;
4095 else
4097 if (workspaceMove (screen_info, 0, 1, c, xevent->xmotion.time))
4099 rx = -4 * maxx / 5;
4102 warp_pointer = TRUE;
4104 lastresist = (Time) 0;
4106 if (edge_scroll_y > screen_info->params->wrap_resistance)
4108 edge_scroll_y = 0;
4109 if ((msy == 0) || (msy == maxy))
4111 if (msy == 0)
4113 if (workspaceMove (screen_info, -1, 0, c, xevent->xmotion.time))
4115 ry = 4 * maxy / 5;
4118 else
4120 if (workspaceMove (screen_info, 1, 0, c, xevent->xmotion.time))
4122 ry = -4 * maxy / 5;
4125 warp_pointer = TRUE;
4127 lastresist = (Time) 0;
4130 if (warp_pointer)
4132 XWarpPointer (display_info->dpy, None, None, 0, 0, 0, 0, rx, ry);
4133 XFlush (display_info->dpy);
4134 msx += rx;
4135 msy += ry;
4138 xevent->xmotion.x_root = msx;
4139 xevent->xmotion.y_root = msy;
4143 if (FLAG_TEST_ALL(c->flags, CLIENT_FLAG_MAXIMIZED)
4144 && (screen_info->params->restore_on_move))
4146 if (xevent->xmotion.y_root - passdata->my > 15)
4148 /* to keep the distance from the edges of the window proportional. */
4149 double xratio, yratio;
4151 xratio = (xevent->xmotion.x_root - c->x)/(double)c->width;
4152 yratio = (xevent->xmotion.y_root - c->y)/(double)c->width;
4154 clientToggleMaximized (c, WIN_STATE_MAXIMIZED, FALSE);
4155 passdata->move_resized = TRUE;
4156 passdata->ox = c->x;
4157 passdata->mx = CLAMP(c->x + c->width * xratio, c->x, c->x + c->width);
4158 passdata->oy = c->y;
4159 passdata->my = c->y - frameTop(c) / 2;
4160 configure_flags = CFG_FORCE_REDRAW;
4161 toggled_maximize = TRUE;
4163 else
4165 xevent->xmotion.x_root = c->x - passdata->ox + passdata->mx;
4166 xevent->xmotion.y_root = c->y - passdata->oy + passdata->my;
4170 c->x = passdata->ox + (xevent->xmotion.x_root - passdata->mx);
4171 c->y = passdata->oy + (xevent->xmotion.y_root - passdata->my);
4173 clientSnapPosition (c, prev_x, prev_y);
4174 if (screen_info->params->restore_on_move)
4176 if ((clientConstrainPos (c, FALSE) & CLIENT_CONSTRAINED_TOP) && toggled_maximize)
4178 clientToggleMaximized (c, WIN_STATE_MAXIMIZED, FALSE);
4179 configure_flags = CFG_FORCE_REDRAW;
4180 toggled_maximize = FALSE;
4181 passdata->move_resized = TRUE;
4183 Update "passdata->my" to the current value to
4184 allow "restore on move" to keep working next time
4186 passdata->my = c->y - frameTop(c) / 2;
4189 else
4191 clientConstrainPos(c, FALSE);
4194 #ifdef SHOW_POSITION
4195 if (passdata->poswin)
4197 poswinSetPosition (passdata->poswin, c);
4199 #endif /* SHOW_POSITION */
4200 if (screen_info->params->box_move)
4202 clientDrawOutline (c);
4204 else
4206 int changes = CWX | CWY;
4208 if (passdata->move_resized)
4210 wc.width = c->width;
4211 wc.height = c->height;
4212 changes |= CWWidth | CWHeight;
4213 passdata->move_resized = FALSE;
4216 wc.x = c->x;
4217 wc.y = c->y;
4218 clientConfigure (c, &wc, changes, configure_flags);
4221 else if ((xevent->type == UnmapNotify) && (xevent->xunmap.window == c->window))
4223 moving = FALSE;
4225 else if ((xevent->type == EnterNotify) || (xevent->type == LeaveNotify))
4227 /* Ignore enter/leave events */
4229 else
4231 status = EVENT_FILTER_CONTINUE;
4234 TRACE ("leaving clientMoveEventFilter");
4236 if (!moving)
4238 TRACE ("event loop now finished");
4239 edge_scroll_x = 0;
4240 edge_scroll_y = 0;
4241 toggled_maximize = FALSE;
4242 gtk_main_quit ();
4245 return status;
4248 void
4249 clientMove (Client * c, XEvent * ev)
4251 ScreenInfo *screen_info;
4252 DisplayInfo *display_info;
4253 XWindowChanges wc;
4254 MoveResizeData passdata;
4255 int changes;
4256 gboolean g1, g2;
4258 g_return_if_fail (c != NULL);
4259 TRACE ("entering clientDoMove");
4260 TRACE ("moving client \"%s\" (0x%lx)", c->name, c->window);
4262 screen_info = c->screen_info;
4263 display_info = screen_info->display_info;
4265 changes = CWX | CWY;
4267 passdata.c = c;
4268 passdata.cancel_x = passdata.ox = c->x;
4269 passdata.cancel_y = passdata.oy = c->y;
4270 passdata.cancel_workspace = c->win_workspace;
4271 passdata.use_keys = FALSE;
4272 passdata.grab = FALSE;
4273 passdata.released = FALSE;
4274 passdata.button = ev->xbutton.button;
4275 passdata.is_transient = clientIsValidTransientOrModal (c);
4276 passdata.move_resized = FALSE;
4278 if (ev->type == KeyPress)
4280 passdata.released = passdata.use_keys = TRUE;
4281 passdata.mx = ev->xkey.x_root;
4282 passdata.my = ev->xkey.y_root;
4284 else if (ev->type == ButtonPress)
4286 passdata.mx = ev->xbutton.x_root;
4287 passdata.my = ev->xbutton.y_root;
4289 else
4291 getMouseXY (screen_info, screen_info->xroot, &passdata.mx, &passdata.my);
4294 g1 = myScreenGrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info));
4295 g2 = myScreenGrabPointer (screen_info, ButtonMotionMask | ButtonReleaseMask,
4296 myDisplayGetCursorMove (display_info),
4297 myDisplayGetCurrentTime (display_info));
4298 if (!g1 || !g2)
4300 TRACE ("grab failed in clientMove");
4302 gdk_beep ();
4303 myScreenUngrabKeyboard (screen_info);
4304 myScreenUngrabPointer (screen_info);
4306 return;
4309 passdata.poswin = NULL;
4310 #ifdef SHOW_POSITION
4311 passdata.poswin = poswinCreate(screen_info->gscr);
4312 poswinSetPosition (passdata.poswin, c);
4313 poswinShow (passdata.poswin);
4314 #endif /* SHOW_POSITION */
4316 /* Set window translucent while moving, looks nice */
4317 if ((screen_info->params->move_opacity < 100) && !(screen_info->params->box_move) && !(c->opacity_locked))
4319 clientSetOpacity (c, c->opacity, OPACITY_MOVE, OPACITY_MOVE);
4323 * Need to remove the sidewalk windows while moving otherwise
4324 * the motion events aren't reported on screen edges
4326 placeSidewalks(screen_info, FALSE);
4328 FLAG_SET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
4329 TRACE ("entering move loop");
4330 eventFilterPush (display_info->xfilter, clientMoveEventFilter, &passdata);
4331 if (passdata.use_keys)
4333 XPutBackEvent (display_info->dpy, ev);
4335 gtk_main ();
4336 eventFilterPop (display_info->xfilter);
4337 TRACE ("leaving move loop");
4338 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
4340 /* Put back the sidewalks as they ought to be */
4341 placeSidewalks(screen_info, screen_info->params->wrap_workspaces);
4343 #ifdef SHOW_POSITION
4344 if (passdata.poswin)
4346 poswinDestroy (passdata.poswin);
4348 #endif /* SHOW_POSITION */
4349 if (passdata.grab && screen_info->params->box_move)
4351 clientDrawOutline (c);
4353 /* Set window opacity to its original value */
4354 clientSetOpacity (c, c->opacity, OPACITY_MOVE, 0);
4356 wc.x = c->x;
4357 wc.y = c->y;
4358 if (passdata.move_resized)
4360 wc.width = c->width;
4361 wc.height = c->height;
4362 changes |= CWWidth | CWHeight;
4364 clientConfigure (c, &wc, changes, NO_CFG_FLAG);
4366 myScreenUngrabKeyboard (screen_info);
4367 if (!passdata.released)
4369 /* If this is a drag-move, wait for the button to be released.
4370 * If we don't, we might get release events in the wrong place.
4372 eventFilterPush (display_info->xfilter, clientButtonReleaseFilter, &passdata);
4373 gtk_main ();
4374 eventFilterPop (display_info->xfilter);
4376 myScreenUngrabPointer (screen_info);
4378 if (passdata.grab && screen_info->params->box_move)
4380 myDisplayUngrabServer (display_info);
4384 static void
4385 clientResizeConfigure (Client *c, int px, int py, int pw, int ph)
4387 ScreenInfo *screen_info;
4388 DisplayInfo *display_info;
4389 XWindowChanges wc;
4390 unsigned long value_mask;
4392 screen_info = c->screen_info;
4393 display_info = screen_info->display_info;
4395 value_mask = 0L;
4396 if (c->x != px)
4398 value_mask |= CWX;
4400 if (c->y != py)
4402 value_mask |= CWY;
4404 if (c->width != pw)
4406 value_mask |= CWWidth;
4408 if (c->height != ph)
4410 value_mask |= CWHeight;
4412 if (!value_mask)
4414 return;
4417 #ifdef HAVE_XSYNC
4418 if (!c->xsync_waiting)
4420 if ((display_info->have_xsync) && (c->xsync_enabled) && (c->xsync_counter)
4421 && (value_mask & (CWWidth | CWHeight)))
4423 clientXSyncRequest (c);
4425 #endif /* HAVE_XSYNC */
4426 wc.x = c->x;
4427 wc.y = c->y;
4428 wc.width = c->width;
4429 wc.height = c->height;
4430 clientConfigure (c, &wc, value_mask, NO_CFG_FLAG);
4431 #ifdef HAVE_XSYNC
4433 #endif /* HAVE_XSYNC */
4436 static eventFilterStatus
4437 clientResizeEventFilter (XEvent * xevent, gpointer data)
4439 ScreenInfo *screen_info;
4440 DisplayInfo *display_info;
4441 Client *c;
4442 GdkRectangle rect;
4443 MoveResizeData *passdata;
4444 eventFilterStatus status;
4445 int prev_x, prev_y, prev_width, prev_height;
4446 int cx, cy, disp_x, disp_y, disp_max_x, disp_max_y;
4447 int frame_x, frame_y, frame_height, frame_width;
4448 int frame_top, frame_left, frame_right, frame_bottom;
4449 int move_top, move_bottom, move_left, move_right;
4450 int temp;
4451 gint monitor_nbr;
4452 gint min_visible;
4453 gboolean resizing;
4455 TRACE ("entering clientResizeEventFilter");
4457 passdata = (MoveResizeData *) data;
4458 c = passdata->c;
4459 screen_info = c->screen_info;
4460 display_info = screen_info->display_info;
4461 status = EVENT_FILTER_STOP;
4462 resizing = TRUE;
4464 frame_x = frameX (c);
4465 frame_y = frameY (c);
4466 frame_height = frameHeight (c);
4467 frame_width = frameWidth (c);
4468 frame_top = frameTop (c);
4469 frame_left = frameLeft (c);
4470 frame_right = frameRight (c);
4471 frame_bottom = frameBottom (c);
4472 min_visible = MAX (frame_top, CLIENT_MIN_VISIBLE);
4474 cx = frame_x + (frame_width / 2);
4475 cy = frame_y + (frame_height / 2);
4477 move_top = ((passdata->corner == CORNER_TOP_RIGHT)
4478 || (passdata->corner == CORNER_TOP_LEFT)
4479 || (passdata->corner == CORNER_COUNT + SIDE_TOP)) ?
4480 1 : 0;
4481 move_bottom = ((passdata->corner == CORNER_BOTTOM_RIGHT)
4482 || (passdata->corner == CORNER_BOTTOM_LEFT)
4483 || (passdata->corner == CORNER_COUNT + SIDE_BOTTOM)) ?
4484 1 : 0;
4485 move_right = ((passdata->corner == CORNER_TOP_RIGHT)
4486 || (passdata->corner == CORNER_BOTTOM_RIGHT)
4487 || (passdata->corner == CORNER_COUNT + SIDE_RIGHT)) ?
4488 1 : 0;
4489 move_left = ((passdata->corner == CORNER_TOP_LEFT)
4490 || (passdata->corner == CORNER_BOTTOM_LEFT)
4491 || (passdata->corner == CORNER_COUNT + SIDE_LEFT)) ?
4492 1 : 0;
4494 monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
4495 gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);
4497 disp_x = rect.x;
4498 disp_y = rect.y;
4499 disp_max_x = rect.x + rect.width;
4500 disp_max_y = rect.y + rect.height;
4502 /* Store previous values in case the resize puts the window title off bounds */
4503 prev_x = c->x;
4504 prev_y = c->y;
4505 prev_width = c->width;
4506 prev_height = c->height;
4508 /* Update the display time */
4509 myDisplayUpdateCurrentTime (display_info, xevent);
4511 if (xevent->type == KeyPress)
4513 while (XCheckMaskEvent (display_info->dpy, KeyPressMask, xevent))
4515 /* Update the display time */
4516 myDisplayUpdateCurrentTime (display_info, xevent);
4519 if (passdata->use_keys)
4521 int key_width_inc, key_height_inc;
4522 int corner = -1;
4524 key_width_inc = c->size->width_inc;
4525 key_height_inc = c->size->height_inc;
4527 if (key_width_inc < 10)
4529 key_width_inc = ((int) (10 / key_width_inc)) * key_width_inc;
4531 if (key_height_inc < 10)
4533 key_height_inc = ((int) (10 / key_height_inc)) * key_height_inc;
4535 if (!passdata->grab && screen_info->params->box_resize)
4537 myDisplayGrabServer (display_info);
4538 passdata->grab = TRUE;
4539 clientDrawOutline (c);
4541 if (screen_info->params->box_resize)
4543 clientDrawOutline (c);
4546 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED)
4547 && (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_UP].keycode))
4549 c->height = c->height - key_height_inc;
4550 corner = CORNER_COUNT + SIDE_BOTTOM;
4552 else if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED)
4553 && (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_DOWN].keycode))
4555 c->height = c->height + key_height_inc;
4556 corner = CORNER_COUNT + SIDE_BOTTOM;
4558 else if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_LEFT].keycode)
4560 c->width = c->width - key_width_inc;
4561 corner = CORNER_COUNT + SIDE_RIGHT;
4563 else if (xevent->xkey.keycode == screen_info->params->keys[KEY_MOVE_RIGHT].keycode)
4565 c->width = c->width + key_width_inc;
4566 corner = CORNER_COUNT + SIDE_RIGHT;
4568 if (corner >= 0)
4570 clientConstrainRatio (c, &c->width, &c->height, corner);
4572 if ((c->x + c->width < disp_x + min_visible)
4573 || (c->x + c->width < screen_info->margins [STRUTS_LEFT] + min_visible))
4575 c->width = prev_width;
4577 if ((c->y + c->height < disp_y + min_visible)
4578 || (c->y + c->height < screen_info->margins [STRUTS_TOP] + min_visible))
4580 c->height = prev_height;
4582 if (passdata->poswin)
4584 poswinSetPosition (passdata->poswin, c);
4586 if (screen_info->params->box_resize)
4588 clientDrawOutline (c);
4590 else
4592 clientResizeConfigure (c, prev_x, prev_y, prev_width, prev_height);
4596 else if (xevent->type == KeyRelease)
4598 if (xevent->xkey.keycode == screen_info->params->keys[KEY_CANCEL].keycode)
4600 resizing = FALSE;
4601 passdata->released = passdata->use_keys;
4603 if (screen_info->params->box_resize)
4605 clientDrawOutline (c);
4608 /* restore the pre-resize position & size */
4609 if (move_left)
4611 c->x += c->width - passdata->cancel_x;
4613 if (move_top)
4615 c->y += c->height - passdata->cancel_y;
4617 c->width = passdata->cancel_x;
4618 c->height = passdata->cancel_y;
4619 if (screen_info->params->box_resize)
4621 clientDrawOutline (c);
4623 else
4625 clientResizeConfigure (c, prev_x, prev_y, prev_width, prev_height);
4628 else if (passdata->use_keys)
4630 if (IsModifierKey (XLookupKeysym (&xevent->xkey, 0)))
4632 resizing = FALSE;
4636 else if (xevent->type == MotionNotify)
4638 while (XCheckMaskEvent (display_info->dpy, ButtonMotionMask | PointerMotionMask, xevent))
4640 /* Update the display time */
4641 myDisplayUpdateCurrentTime (display_info, xevent);
4644 if (xevent->type == ButtonRelease)
4646 resizing = FALSE;
4648 if (!passdata->grab && screen_info->params->box_resize)
4650 myDisplayGrabServer (display_info);
4651 passdata->grab = TRUE;
4652 clientDrawOutline (c);
4654 if (screen_info->params->box_resize)
4656 clientDrawOutline (c);
4658 passdata->oldw = c->width;
4659 passdata->oldh = c->height;
4661 if (move_left)
4663 c->width = passdata->ox - (xevent->xmotion.x_root - passdata->mx);
4665 else if (move_right)
4667 c->width = passdata->ox + (xevent->xmotion.x_root - passdata->mx);
4669 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
4671 if (move_top)
4673 c->height = passdata->oy - (xevent->xmotion.y_root - passdata->my);
4675 else if (move_bottom)
4677 c->height = passdata->oy + (xevent->xmotion.y_root - passdata->my);
4680 clientConstrainRatio (c, &c->width, &c->height, passdata->corner);
4682 clientSetWidth (c, c->width);
4683 if (move_left)
4685 c->x = c->x - (c->width - passdata->oldw);
4686 frame_x = frameX (c);
4689 clientSetHeight (c, c->height);
4690 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED) && move_top)
4692 c->y = c->y - (c->height - passdata->oldh);
4693 frame_y = frameY (c);
4696 if (move_top)
4698 if ((c->y > MAX (disp_max_y - min_visible, screen_info->height - screen_info->margins [STRUTS_BOTTOM] - min_visible))
4699 || (!clientCkeckTitle (c) && (frame_y < screen_info->margins [STRUTS_TOP])))
4701 temp = c->y + c->height;
4702 c->y = CLAMP (c->y, screen_info->margins [STRUTS_TOP] + frame_top,
4703 MAX (disp_max_y - min_visible, screen_info->height - screen_info->margins [STRUTS_BOTTOM] - min_visible));
4704 clientSetHeight (c, temp - c->y);
4705 c->y = temp - c->height;
4707 else if (frame_y < 0)
4709 temp = c->y + c->height;
4710 c->y = frame_top;
4711 clientSetHeight (c, temp - c->y);
4712 c->y = temp - c->height;
4715 else if (move_bottom)
4717 if (c->y + c->height < MAX (disp_y + min_visible, screen_info->margins [STRUTS_TOP] + min_visible))
4719 temp = MAX (disp_y + min_visible, screen_info->margins [STRUTS_TOP] + min_visible);
4720 clientSetHeight (c, temp - c->y);
4723 if (move_left)
4725 if (c->x > MIN (disp_max_x - min_visible, screen_info->width - screen_info->margins [STRUTS_RIGHT] - min_visible))
4727 temp = c->x + c->width;
4728 c->x = MIN (disp_max_x - min_visible, screen_info->width - screen_info->margins [STRUTS_RIGHT] - min_visible);
4729 clientSetWidth (c, temp - c->x);
4730 c->x = temp - c->width;
4733 else if (move_right)
4735 if (c->x + c->width < MAX (disp_x + min_visible, screen_info->margins [STRUTS_LEFT] + min_visible))
4737 temp = MAX (disp_x + min_visible, screen_info->margins [STRUTS_LEFT] + min_visible);
4738 clientSetWidth (c, temp - c->x);
4742 if (passdata->poswin)
4744 poswinSetPosition (passdata->poswin, c);
4746 if (screen_info->params->box_resize)
4748 clientDrawOutline (c);
4750 else
4752 clientResizeConfigure (c, prev_x, prev_y, prev_width, prev_height);
4756 else if (xevent->type == ButtonRelease)
4758 if (!passdata->use_keys)
4760 resizing = FALSE;
4761 passdata->released = (xevent->xbutton.button == passdata->button);
4764 else if ((xevent->type == UnmapNotify) && (xevent->xunmap.window == c->window))
4766 resizing = FALSE;
4768 else if ((xevent->type == EnterNotify) || (xevent->type == LeaveNotify))
4770 /* Ignore enter/leave events */
4772 else
4774 status = EVENT_FILTER_CONTINUE;
4777 TRACE ("leaving clientResizeEventFilter");
4779 if (!resizing)
4781 TRACE ("event loop now finished");
4782 gtk_main_quit ();
4785 return status;
4788 void
4789 clientResize (Client * c, int corner, XEvent * ev)
4791 ScreenInfo *screen_info;
4792 DisplayInfo *display_info;
4793 XWindowChanges wc;
4794 MoveResizeData passdata;
4795 int w_orig, h_orig;
4796 gboolean g1, g2;
4798 g_return_if_fail (c != NULL);
4799 TRACE ("entering clientResize");
4800 TRACE ("resizing client \"%s\" (0x%lx)", c->name, c->window);
4802 screen_info = c->screen_info;
4803 display_info = screen_info->display_info;
4805 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
4806 && (screen_info->params->borderless_maximize))
4808 return;
4811 passdata.c = c;
4812 passdata.cancel_x = passdata.ox = c->width;
4813 passdata.cancel_y = passdata.oy = c->height;
4814 passdata.use_keys = FALSE;
4815 passdata.grab = FALSE;
4816 passdata.released = FALSE;
4817 passdata.button = ev->xbutton.button;
4818 passdata.corner = corner;
4819 w_orig = c->width;
4820 h_orig = c->height;
4822 if (ev->type == KeyPress)
4824 passdata.released = passdata.use_keys = TRUE;
4825 passdata.mx = ev->xkey.x_root;
4826 passdata.my = ev->xkey.y_root;
4828 else if (ev->type == ButtonPress)
4830 passdata.mx = ev->xbutton.x_root;
4831 passdata.my = ev->xbutton.y_root;
4833 else
4835 getMouseXY (screen_info, screen_info->xroot, &passdata.mx, &passdata.my);
4838 g1 = myScreenGrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info));
4839 g2 = myScreenGrabPointer (screen_info, ButtonMotionMask | ButtonReleaseMask,
4840 myDisplayGetCursorResize(display_info, passdata.corner),
4841 myDisplayGetCurrentTime (display_info));
4843 if (!g1 || !g2)
4845 TRACE ("grab failed in clientResize");
4847 gdk_beep ();
4848 myScreenUngrabKeyboard (screen_info);
4849 myScreenUngrabPointer (screen_info);
4851 return;
4854 passdata.poswin = NULL;
4855 #ifndef SHOW_POSITION
4856 if ((c->size->width_inc > 1) || (c->size->height_inc > 1))
4857 #endif /* SHOW_POSITION */
4859 passdata.poswin = poswinCreate(screen_info->gscr);
4860 poswinSetPosition (passdata.poswin, c);
4861 poswinShow (passdata.poswin);
4864 #ifdef HAVE_XSYNC
4865 clientXSyncEnable (c);
4866 #endif /* HAVE_XSYNC */
4868 /* Set window translucent while resizing, doesn't looks too nice :( */
4869 if ((screen_info->params->resize_opacity < 100) && !(screen_info->params->box_resize) && !(c->opacity_locked))
4871 clientSetOpacity (c, c->opacity, OPACITY_RESIZE, OPACITY_RESIZE);
4874 FLAG_SET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
4875 TRACE ("entering resize loop");
4876 eventFilterPush (display_info->xfilter, clientResizeEventFilter, &passdata);
4877 if (passdata.use_keys)
4879 XPutBackEvent (display_info->dpy, ev);
4881 gtk_main ();
4882 eventFilterPop (display_info->xfilter);
4883 TRACE ("leaving resize loop");
4884 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_MOVING_RESIZING);
4886 if (passdata.poswin)
4888 poswinDestroy (passdata.poswin);
4890 if (passdata.grab && screen_info->params->box_resize)
4892 clientDrawOutline (c);
4894 /* Set window opacity to its original value */
4895 clientSetOpacity (c, c->opacity, OPACITY_RESIZE, 0);
4897 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED) &&
4898 ((w_orig != c->width) || (h_orig != c->height)))
4900 clientRemoveMaximizeFlag (c);
4903 wc.x = c->x;
4904 wc.y = c->y;
4905 wc.width = c->width;
4906 wc.height = c->height;
4907 clientConfigure (c, &wc, CWX | CWY | CWHeight | CWWidth, NO_CFG_FLAG);
4908 #ifdef HAVE_XSYNC
4909 clientXSyncClearTimeout (c);
4910 c->xsync_waiting = FALSE;
4911 #endif /* HAVE_XSYNC */
4913 myScreenUngrabKeyboard (screen_info);
4914 if (!passdata.released)
4916 /* If this is a drag-resize, wait for the button to be released.
4917 * If we don't, we might get release events in the wrong place.
4919 eventFilterPush (display_info->xfilter, clientButtonReleaseFilter, &passdata);
4920 gtk_main ();
4921 eventFilterPop (display_info->xfilter);
4923 myScreenUngrabPointer (screen_info);
4925 if (passdata.grab && screen_info->params->box_resize)
4927 myDisplayUngrabServer (display_info);
4931 static eventFilterStatus
4932 clientCycleEventFilter (XEvent * xevent, gpointer data)
4934 ScreenInfo *screen_info;
4935 DisplayInfo *display_info;
4936 ClientCycleData *passdata;
4937 Client *c, *removed;
4938 eventFilterStatus status;
4939 KeyCode cycle;
4940 KeyCode cancel;
4941 int modifier;
4942 gboolean key_pressed, cycling, gone;
4944 TRACE ("entering clientCycleEventFilter");
4946 passdata = (ClientCycleData *) data;
4947 if (passdata->c == NULL)
4949 return EVENT_FILTER_CONTINUE;
4950 /* will never be executed */
4951 /* gtk_main_quit (); */
4954 c = passdata->c;
4955 screen_info = c->screen_info;
4956 display_info = screen_info->display_info;
4957 cycle = screen_info->params->keys[KEY_CYCLE_WINDOWS].keycode;
4958 cancel = screen_info->params->keys[KEY_CANCEL].keycode;
4959 modifier = screen_info->params->keys[KEY_CYCLE_WINDOWS].modifier;
4960 key_pressed = ((xevent->type == KeyPress) && ((xevent->xkey.keycode == cycle) ||
4961 (xevent->xkey.keycode == cancel)));
4962 status = EVENT_FILTER_STOP;
4963 cycling = TRUE;
4964 gone = FALSE;
4966 /* Update the display time */
4967 myDisplayUpdateCurrentTime (display_info, xevent);
4969 switch (xevent->type)
4971 case DestroyNotify:
4972 removed = myScreenGetClientFromWindow (screen_info, ((XDestroyWindowEvent *) xevent)->window, SEARCH_WINDOW);
4973 gone |= (c == removed);
4974 c = tabwinRemoveClient(passdata->tabwin, removed);
4975 passdata->c = c;
4976 status = EVENT_FILTER_CONTINUE;
4977 /* Walk through */
4978 case UnmapNotify:
4979 removed = myScreenGetClientFromWindow (screen_info, ((XUnmapEvent *) xevent)->window, SEARCH_WINDOW);
4980 gone |= (c == removed);
4981 c = tabwinRemoveClient(passdata->tabwin, removed);
4982 passdata->c = c;
4983 status = EVENT_FILTER_CONTINUE;
4984 /* Walk through */
4985 case KeyPress:
4986 if (gone || key_pressed)
4988 if (key_pressed)
4990 Client *c2 = NULL;
4992 if (xevent->xkey.keycode == cancel)
4994 c2 = tabwinGetHead (passdata->tabwin);
4995 cycling = FALSE;
4997 /* If KEY_CYCLE_WINDOWS has Shift, then do not reverse */
4998 else if (!(modifier & ShiftMask) && (xevent->xkey.state & ShiftMask))
5000 TRACE ("Cycle: previous");
5001 c2 = tabwinSelectPrev(passdata->tabwin);
5003 else
5005 TRACE ("Cycle: next");
5006 c2 = tabwinSelectNext(passdata->tabwin);
5008 if (c2)
5010 c = c2;
5011 passdata->c = c;
5014 /* If last key press event had not our modifier pressed, finish cycling */
5015 if (!(xevent->xkey.state & modifier))
5017 cycling = FALSE;
5021 if (cycling)
5023 if (c)
5025 wireframeUpdate (c, passdata->wireframe);
5027 else
5029 cycling = FALSE;
5033 break;
5034 case KeyRelease:
5036 int keysym = XLookupKeysym (&xevent->xkey, 0);
5038 if (!(xevent->xkey.state & modifier) ||
5039 (IsModifierKey(keysym) && (keysym != XK_Shift_L) && (keysym != XK_Shift_R)))
5041 cycling = FALSE;
5044 break;
5045 case ButtonPress:
5046 case ButtonRelease:
5047 case EnterNotify:
5048 case LeaveNotify:
5049 case MotionNotify:
5050 break;
5051 default:
5052 status = EVENT_FILTER_CONTINUE;
5053 break;
5056 if (!cycling)
5058 TRACE ("event loop now finished");
5059 gtk_main_quit ();
5062 return status;
5065 void
5066 clientCycle (Client * c, XEvent * ev)
5068 ScreenInfo *screen_info;
5069 DisplayInfo *display_info;
5070 ClientCycleData passdata;
5071 gboolean g1, g2;
5073 g_return_if_fail (c != NULL);
5074 TRACE ("entering clientCycle");
5076 screen_info = c->screen_info;
5077 display_info = screen_info->display_info;
5079 g1 = myScreenGrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info));
5080 g2 = myScreenGrabPointer (screen_info, NoEventMask, None, myDisplayGetCurrentTime (display_info));
5082 if (!g1 || !g2)
5084 TRACE ("grab failed in clientCycle");
5086 gdk_beep ();
5087 myScreenUngrabKeyboard (screen_info);
5088 myScreenUngrabPointer (screen_info);
5090 return;
5093 if (screen_info->params->cycle_hidden)
5095 passdata.cycle_range = INCLUDE_HIDDEN;
5097 else
5099 passdata.cycle_range = 0;
5101 if (!screen_info->params->cycle_minimum)
5103 passdata.cycle_range |= INCLUDE_SKIP_TASKBAR | INCLUDE_SKIP_PAGER;
5105 if (screen_info->params->cycle_workspaces)
5107 passdata.cycle_range |= INCLUDE_ALL_WORKSPACES;
5109 passdata.c = clientGetNext (c, passdata.cycle_range);
5111 /* If there is one single client, and if it's eligible for focus, use it */
5112 if ((passdata.c == NULL) && (c != clientGetFocus()) &&
5113 clientSelectMask (c, passdata.cycle_range, WINDOW_REGULAR_FOCUSABLE))
5115 passdata.c = c;
5118 if (passdata.c)
5120 TRACE ("entering cycle loop");
5121 passdata.wireframe = wireframeCreate (passdata.c);
5122 passdata.tabwin = tabwinCreate (passdata.c->screen_info->gscr, c,
5123 passdata.c, passdata.cycle_range,
5124 screen_info->params->cycle_workspaces);
5125 eventFilterPush (display_info->xfilter, clientCycleEventFilter, &passdata);
5126 gtk_main ();
5127 eventFilterPop (display_info->xfilter);
5128 TRACE ("leaving cycle loop");
5129 tabwinDestroy (passdata.tabwin);
5130 g_free (passdata.tabwin);
5131 wireframeDelete (screen_info, passdata.wireframe);
5132 updateXserverTime (display_info);
5135 if (passdata.c)
5137 Client *focused;
5138 int workspace;
5140 c = passdata.c;
5141 workspace = c->win_workspace;
5142 focused = clientGetFocus ();
5144 if (workspace != screen_info->current_ws)
5146 workspaceSwitch (screen_info, workspace, c, FALSE, myDisplayGetCurrentTime (display_info));
5149 if ((focused) && (passdata.c != focused))
5151 clientClearAllShowDesktop (screen_info);
5152 clientAdjustFullscreenLayer (focused, FALSE);
5155 clientShow (c, TRUE);
5156 clientSetFocus (screen_info, c, myDisplayGetCurrentTime (display_info), NO_FOCUS_FLAG);
5157 clientRaise (c, None);
5160 myScreenUngrabKeyboard (screen_info);
5161 myScreenUngrabPointer (screen_info);
5164 static eventFilterStatus
5165 clientButtonPressEventFilter (XEvent * xevent, gpointer data)
5167 ScreenInfo *screen_info;
5168 DisplayInfo *display_info;
5169 Client *c;
5170 ButtonPressData *passdata;
5171 eventFilterStatus status;
5172 int b;
5173 gboolean pressed;
5175 passdata = (ButtonPressData *) data;
5176 c = passdata->c;
5177 b = passdata->b;
5179 screen_info = c->screen_info;
5180 display_info = screen_info->display_info;
5182 /* Update the display time */
5183 myDisplayUpdateCurrentTime (display_info, xevent);
5185 status = EVENT_FILTER_STOP;
5186 pressed = TRUE;
5188 if (xevent->type == EnterNotify)
5190 c->button_status[b] = BUTTON_STATE_PRESSED;
5191 frameDraw (c, FALSE);
5193 else if (xevent->type == LeaveNotify)
5195 c->button_status[b] = BUTTON_STATE_NORMAL;
5196 frameDraw (c, FALSE);
5198 else if (xevent->type == ButtonRelease)
5200 pressed = FALSE;
5202 else if ((xevent->type == UnmapNotify) && (xevent->xunmap.window == c->window))
5204 pressed = FALSE;
5205 c->button_status[b] = BUTTON_STATE_NORMAL;
5207 else if ((xevent->type == KeyPress) || (xevent->type == KeyRelease))
5210 else
5212 status = EVENT_FILTER_CONTINUE;
5215 if (!pressed)
5217 TRACE ("event loop now finished");
5218 gtk_main_quit ();
5221 return status;
5224 void
5225 clientButtonPress (Client * c, Window w, XButtonEvent * bev)
5227 ScreenInfo *screen_info;
5228 DisplayInfo *display_info;
5229 ButtonPressData passdata;
5230 int b, g1;
5232 g_return_if_fail (c != NULL);
5233 TRACE ("entering clientButtonPress");
5235 for (b = 0; b < BUTTON_COUNT; b++)
5237 if (MYWINDOW_XWINDOW (c->buttons[b]) == w)
5239 break;
5243 screen_info = c->screen_info;
5244 display_info = screen_info->display_info;
5246 g1 = XGrabPointer (display_info->dpy, w, FALSE,
5247 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask,
5248 GrabModeAsync, GrabModeAsync,
5249 screen_info->xroot, None,
5250 myDisplayGetCurrentTime (display_info));
5252 if (g1 != GrabSuccess)
5254 TRACE ("grab failed in clientButtonPress");
5255 gdk_beep ();
5256 if (g1 == GrabSuccess)
5258 XUngrabKeyboard (display_info->dpy, myDisplayGetCurrentTime (display_info));
5260 return;
5263 passdata.c = c;
5264 passdata.b = b;
5266 c->button_status[b] = BUTTON_STATE_PRESSED;
5267 frameDraw (c, FALSE);
5269 TRACE ("entering button press loop");
5270 eventFilterPush (display_info->xfilter, clientButtonPressEventFilter, &passdata);
5271 gtk_main ();
5272 eventFilterPop (display_info->xfilter);
5273 TRACE ("leaving button press loop");
5275 XUngrabPointer (display_info->dpy, myDisplayGetCurrentTime (display_info));
5277 if (c->button_status[b] == BUTTON_STATE_PRESSED)
5280 * Button was pressed at the time, means the pointer was still within
5281 * the button, so return to prelight if available, normal otherwise.
5283 if (!xfwmPixmapNone(clientGetButtonPixmap(c, b, PRELIGHT)))
5285 c->button_status[b] = BUTTON_STATE_PRELIGHT;
5287 else
5289 c->button_status[b] = BUTTON_STATE_NORMAL;
5292 switch (b)
5294 case HIDE_BUTTON:
5295 if (CLIENT_CAN_HIDE_WINDOW (c))
5297 clientHide (c, c->win_workspace, TRUE);
5299 break;
5300 case CLOSE_BUTTON:
5301 clientClose (c);
5302 break;
5303 case MAXIMIZE_BUTTON:
5304 if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
5306 if (bev->button == Button1)
5308 clientToggleMaximized (c, WIN_STATE_MAXIMIZED, TRUE);
5310 else if (bev->button == Button2)
5312 clientToggleMaximized (c, WIN_STATE_MAXIMIZED_VERT, TRUE);
5314 else if (bev->button == Button3)
5316 clientToggleMaximized (c, WIN_STATE_MAXIMIZED_HORIZ, TRUE);
5319 break;
5320 case SHADE_BUTTON:
5321 clientToggleShaded (c);
5322 break;
5323 case STICK_BUTTON:
5324 clientToggleSticky (c, TRUE);
5325 break;
5326 default:
5327 break;
5329 frameDraw (c, FALSE);
5333 xfwmPixmap *
5334 clientGetButtonPixmap (Client * c, int button, int state)
5336 ScreenInfo *screen_info;
5338 screen_info = c->screen_info;
5339 switch (button)
5341 case MENU_BUTTON:
5342 if ((screen_info->params->show_app_icon)
5343 && (!xfwmPixmapNone(&c->appmenu[state])))
5345 return &c->appmenu[state];
5347 break;
5348 case SHADE_BUTTON:
5349 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED)
5350 && (!xfwmPixmapNone(&screen_info->buttons[SHADE_BUTTON][state + STATE_TOGGLED])))
5352 return &screen_info->buttons[SHADE_BUTTON][state + STATE_TOGGLED];
5354 return &screen_info->buttons[SHADE_BUTTON][state];
5355 break;
5356 case STICK_BUTTON:
5357 if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY)
5358 && (!xfwmPixmapNone(&screen_info->buttons[STICK_BUTTON][state + STATE_TOGGLED])))
5360 return &screen_info->buttons[STICK_BUTTON][state + STATE_TOGGLED];
5362 return &screen_info->buttons[STICK_BUTTON][state];
5363 break;
5364 case MAXIMIZE_BUTTON:
5365 if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED)
5366 && (!xfwmPixmapNone(&screen_info->buttons[MAXIMIZE_BUTTON][state + STATE_TOGGLED])))
5368 return &screen_info->buttons[MAXIMIZE_BUTTON][state + STATE_TOGGLED];
5370 return &screen_info->buttons[MAXIMIZE_BUTTON][state];
5371 break;
5372 default:
5373 break;
5375 return &screen_info->buttons[button][state];
5379 clientGetButtonState (Client *c, int button, int state)
5381 ScreenInfo *screen_info;
5383 screen_info = c->screen_info;
5385 if (state == INACTIVE)
5387 return (state);
5390 if ((c->button_status[button] == BUTTON_STATE_PRESSED) &&
5391 clientGetButtonPixmap (c, button, PRESSED))
5393 return (PRESSED);
5396 if ((c->button_status[button] == BUTTON_STATE_PRELIGHT) &&
5397 clientGetButtonPixmap (c, button, PRELIGHT))
5399 return (PRELIGHT);
5402 return (ACTIVE);
5406 Client *
5407 clientGetLeader (Client * c)
5409 TRACE ("entering clientGetLeader");
5410 g_return_val_if_fail (c != NULL, NULL);
5412 if (c->group_leader != None)
5414 return myScreenGetClientFromWindow (c->screen_info, c->group_leader, SEARCH_WINDOW);
5416 else if (c->client_leader != None)
5418 return myScreenGetClientFromWindow (c->screen_info, c->client_leader, SEARCH_WINDOW);
5420 return NULL;
5423 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
5424 char *
5425 clientGetStartupId (Client * c)
5427 ScreenInfo *screen_info;
5428 DisplayInfo *display_info;
5429 gboolean got_startup_id;
5431 g_return_val_if_fail (c != NULL, NULL);
5432 g_return_val_if_fail (c->window != None, NULL);
5434 screen_info = c->screen_info;
5435 display_info = screen_info->display_info;
5436 got_startup_id = FALSE;
5438 if (c->startup_id)
5440 return (c->startup_id);
5443 got_startup_id = getWindowStartupId (display_info, c->window, &c->startup_id);
5445 if (!got_startup_id && (c->client_leader))
5447 got_startup_id = getWindowStartupId (display_info, c->client_leader, &c->startup_id);
5450 if (!got_startup_id && (c->group_leader))
5452 got_startup_id = getWindowStartupId (display_info, c->group_leader, &c->startup_id);
5455 return (c->startup_id);
5457 #endif /* HAVE_LIBSTARTUP_NOTIFICATION */