1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
/* Mutter X window decorations */
6
* Copyright (C) 2001 Havoc Pennington
7
* Copyright (C) 2003, 2004 Red Hat, Inc.
8
* Copyright (C) 2005 Elijah Newren
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public License as
12
* published by the Free Software Foundation; either version 2 of the
13
* License, or (at your option) any later version.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27
#include "frame-private.h"
30
#include "keybindings-private.h"
32
#include <X11/extensions/Xrender.h>
34
#define EVENT_MASK (SubstructureRedirectMask | \
35
StructureNotifyMask | SubstructureNotifyMask | \
37
ButtonPressMask | ButtonReleaseMask | \
38
PointerMotionMask | PointerMotionHintMask | \
39
EnterWindowMask | LeaveWindowMask | \
44
meta_window_ensure_frame (MetaWindow *window)
47
XSetWindowAttributes attrs;
54
/* See comment below for why this is required. */
55
meta_display_grab (window->display);
57
frame = g_new (MetaFrame, 1);
59
frame->window = window;
60
frame->xwindow = None;
62
frame->rect = window->rect;
65
frame->bottom_height = 0;
66
frame->right_width = 0;
67
frame->current_cursor = 0;
69
frame->mapped = FALSE;
70
frame->need_reapply_frame_shape = TRUE;
71
frame->is_flashing = FALSE;
73
meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n",
75
XVisualIDFromVisual (window->xvisual) ==
76
XVisualIDFromVisual (window->screen->default_xvisual) ?
78
window->depth, window->screen->default_depth);
79
meta_verbose ("Frame geometry %d,%d %dx%d\n",
80
frame->rect.x, frame->rect.y,
81
frame->rect.width, frame->rect.height);
83
/* Default depth/visual handles clients with weird visuals; they can
84
* always be children of the root depth/visual obviously, but
85
* e.g. DRI games can't be children of a parent that has the same
86
* visual as the client. NULL means default visual.
88
* We look for an ARGB visual if we can find one, otherwise use
89
* the default of NULL.
92
/* Special case for depth 32 windows (assumed to be ARGB),
93
* we use the window's visual. Otherwise we just use the system visual.
95
if (window->depth == 32)
96
visual = window->xvisual;
100
frame->xwindow = meta_ui_create_frame_window (window->screen->ui,
101
window->display->xdisplay,
107
frame->window->screen->number,
109
meta_stack_tracker_record_add (window->screen->stack_tracker,
113
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
114
attrs.event_mask = EVENT_MASK;
115
XChangeWindowAttributes (window->display->xdisplay,
116
frame->xwindow, CWEventMask, &attrs);
118
meta_display_register_x_window (window->display, &frame->xwindow, window);
120
/* Now that frame->xwindow is registered with window, we can set its
123
meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);
125
/* Reparent the client window; it may be destroyed,
126
* thus the error trap. We'll get a destroy notify later
127
* and free everything. Comment in FVWM source code says
128
* we need a server grab or the child can get its MapNotify
129
* before we've finished reparenting and getting the decoration
130
* window onscreen, so ensure_frame must be called with
133
meta_error_trap_push (window->display);
136
window->mapped = FALSE; /* the reparent will unmap the window,
137
* we don't want to take that as a withdraw
139
meta_topic (META_DEBUG_WINDOW_STATE,
140
"Incrementing unmaps_pending on %s for reparent\n", window->desc);
141
window->unmaps_pending += 1;
143
/* window was reparented to this position */
147
meta_stack_tracker_record_remove (window->screen->stack_tracker,
149
XNextRequest (window->display->xdisplay));
150
XReparentWindow (window->display->xdisplay,
155
/* FIXME handle this error */
156
meta_error_trap_pop (window->display, FALSE);
158
/* stick frame to the window */
159
window->frame = frame;
162
meta_ui_set_frame_title (window->screen->ui,
163
window->frame->xwindow,
166
/* Move keybindings to frame instead of window */
167
meta_window_grab_keys (window);
170
meta_ui_apply_frame_shape (frame->window->screen->ui,
174
frame->window->has_shape);
175
frame->need_reapply_frame_shape = FALSE;
177
meta_display_ungrab (window->display);
181
meta_window_destroy_frame (MetaWindow *window)
185
if (window->frame == NULL)
188
meta_verbose ("Unframing window %s\n", window->desc);
190
frame = window->frame;
192
meta_bell_notify_frame_destroy (frame);
194
/* Unparent the client window; it may be destroyed,
195
* thus the error trap.
197
meta_error_trap_push (window->display);
200
window->mapped = FALSE; /* Keep track of unmapping it, so we
201
* can identify a withdraw initiated
204
meta_topic (META_DEBUG_WINDOW_STATE,
205
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
206
window->unmaps_pending += 1;
208
meta_stack_tracker_record_add (window->screen->stack_tracker,
210
XNextRequest (window->display->xdisplay));
211
XReparentWindow (window->display->xdisplay,
213
window->screen->xroot,
214
/* Using anything other than meta_window_get_position()
215
* coordinates here means we'll need to ensure a configure
216
* notify event is sent; see bug 399552.
218
window->frame->rect.x,
219
window->frame->rect.y);
220
meta_error_trap_pop (window->display, FALSE);
222
meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow);
224
meta_display_unregister_x_window (window->display,
227
window->frame = NULL;
229
/* Move keybindings to window instead of frame */
230
meta_window_grab_keys (window);
234
/* Put our state back where it should be */
235
meta_window_queue (window, META_QUEUE_CALC_SHOWING);
236
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
241
meta_frame_get_flags (MetaFrame *frame)
243
MetaFrameFlags flags;
247
if (frame->window->border_only)
249
; /* FIXME this may disable the _function_ as well as decor
250
* in some cases, which is sort of wrong.
255
flags |= META_FRAME_ALLOWS_MENU;
257
if (frame->window->has_close_func)
258
flags |= META_FRAME_ALLOWS_DELETE;
260
if (frame->window->has_maximize_func)
261
flags |= META_FRAME_ALLOWS_MAXIMIZE;
263
if (frame->window->has_minimize_func)
264
flags |= META_FRAME_ALLOWS_MINIMIZE;
266
if (frame->window->has_shade_func)
267
flags |= META_FRAME_ALLOWS_SHADE;
270
if (META_WINDOW_ALLOWS_MOVE (frame->window))
271
flags |= META_FRAME_ALLOWS_MOVE;
273
if (META_WINDOW_ALLOWS_HORIZONTAL_RESIZE (frame->window))
274
flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
276
if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window))
277
flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
279
if (frame->window->has_focus)
280
flags |= META_FRAME_HAS_FOCUS;
282
if (frame->window->shaded)
283
flags |= META_FRAME_SHADED;
285
if (frame->window->on_all_workspaces)
286
flags |= META_FRAME_STUCK;
288
/* FIXME: Should we have some kind of UI for windows that are just vertically
289
* maximized or just horizontally maximized?
291
if (META_WINDOW_MAXIMIZED (frame->window))
292
flags |= META_FRAME_MAXIMIZED;
294
if (frame->window->fullscreen)
295
flags |= META_FRAME_FULLSCREEN;
297
if (frame->is_flashing)
298
flags |= META_FRAME_IS_FLASHING;
300
if (frame->window->wm_state_above)
301
flags |= META_FRAME_ABOVE;
307
meta_frame_calc_geometry (MetaFrame *frame,
308
MetaFrameGeometry *geomp)
310
MetaFrameGeometry geom;
313
window = frame->window;
315
meta_ui_get_frame_geometry (window->screen->ui,
326
update_shape (MetaFrame *frame)
328
if (frame->need_reapply_frame_shape)
330
meta_ui_apply_frame_shape (frame->window->screen->ui,
334
frame->window->has_shape);
335
frame->need_reapply_frame_shape = FALSE;
340
meta_frame_sync_to_window (MetaFrame *frame,
343
gboolean need_resize)
345
if (!(need_move || need_resize))
347
update_shape (frame);
351
meta_topic (META_DEBUG_GEOMETRY,
352
"Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n",
353
frame->rect.x, frame->rect.y,
354
frame->rect.width, frame->rect.height,
355
frame->rect.x + frame->rect.width,
356
frame->rect.y + frame->rect.height);
358
/* set bg to none to avoid flicker */
361
meta_ui_unflicker_frame_bg (frame->window->screen->ui,
366
/* we need new shape if we're resized */
367
frame->need_reapply_frame_shape = TRUE;
370
/* Done before the window resize, because doing it before means
371
* part of the window being resized becomes unshaped, which may
372
* be sort of hard to see with bg = None. If we did it after
373
* window resize, part of the window being resized would become
374
* shaped, which might be more visible.
376
update_shape (frame);
378
meta_ui_move_resize_frame (frame->window->screen->ui,
387
meta_ui_reset_frame_bg (frame->window->screen->ui,
390
/* If we're interactively resizing the frame, repaint
391
* it immediately so we don't start to lag.
393
if (frame->window->display->grab_window ==
395
meta_ui_repaint_frame (frame->window->screen->ui,
401
meta_frame_queue_draw (MetaFrame *frame)
403
meta_ui_queue_frame_draw (frame->window->screen->ui,
408
meta_frame_set_screen_cursor (MetaFrame *frame,
412
if (cursor == frame->current_cursor)
414
frame->current_cursor = cursor;
415
if (cursor == META_CURSOR_DEFAULT)
416
XUndefineCursor (frame->window->display->xdisplay, frame->xwindow);
419
xcursor = meta_display_create_x_cursor (frame->window->display, cursor);
420
XDefineCursor (frame->window->display->xdisplay, frame->xwindow, xcursor);
421
XFlush (frame->window->display->xdisplay);
422
XFreeCursor (frame->window->display->xdisplay, xcursor);
427
meta_frame_get_xwindow (MetaFrame *frame)
429
return frame->xwindow;