~ubuntu-dev/ubuntu/lucid/mutter/lucid-201002102012

« back to all changes in this revision

Viewing changes to src/core/frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2009-08-01 09:30:39 UTC
  • Revision ID: james.westby@ubuntu.com-20090801093039-jpu7jwcri465eb0z
Tags: upstream-2.27.1
ImportĀ upstreamĀ versionĀ 2.27.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/* Mutter X window decorations */
 
4
 
 
5
/* 
 
6
 * Copyright (C) 2001 Havoc Pennington
 
7
 * Copyright (C) 2003, 2004 Red Hat, Inc.
 
8
 * Copyright (C) 2005 Elijah Newren
 
9
 * 
 
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.
 
14
 *
 
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.
 
19
 * 
 
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
 
23
 * 02111-1307, USA.
 
24
 */
 
25
 
 
26
#include <config.h>
 
27
#include "frame-private.h"
 
28
#include "bell.h"
 
29
#include "errors.h"
 
30
#include "keybindings-private.h"
 
31
 
 
32
#include <X11/extensions/Xrender.h>
 
33
 
 
34
#define EVENT_MASK (SubstructureRedirectMask |                     \
 
35
                    StructureNotifyMask | SubstructureNotifyMask | \
 
36
                    ExposureMask |                                 \
 
37
                    ButtonPressMask | ButtonReleaseMask |          \
 
38
                    PointerMotionMask | PointerMotionHintMask |    \
 
39
                    EnterWindowMask | LeaveWindowMask |            \
 
40
                    FocusChangeMask |                              \
 
41
                    ColormapChangeMask)
 
42
 
 
43
void
 
44
meta_window_ensure_frame (MetaWindow *window)
 
45
{
 
46
  MetaFrame *frame;
 
47
  XSetWindowAttributes attrs;
 
48
  Visual *visual;
 
49
  gulong create_serial;
 
50
  
 
51
  if (window->frame)
 
52
    return;
 
53
  
 
54
  /* See comment below for why this is required. */
 
55
  meta_display_grab (window->display);
 
56
  
 
57
  frame = g_new (MetaFrame, 1);
 
58
 
 
59
  frame->window = window;
 
60
  frame->xwindow = None;
 
61
 
 
62
  frame->rect = window->rect;
 
63
  frame->child_x = 0;
 
64
  frame->child_y = 0;
 
65
  frame->bottom_height = 0;
 
66
  frame->right_width = 0;
 
67
  frame->current_cursor = 0;
 
68
 
 
69
  frame->mapped = FALSE;
 
70
  frame->need_reapply_frame_shape = TRUE;
 
71
  frame->is_flashing = FALSE;
 
72
  
 
73
  meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n",
 
74
                window->desc,
 
75
                XVisualIDFromVisual (window->xvisual) ==
 
76
                XVisualIDFromVisual (window->screen->default_xvisual) ?
 
77
                "is" : "is not",
 
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);
 
82
  
 
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.
 
87
   *
 
88
   * We look for an ARGB visual if we can find one, otherwise use
 
89
   * the default of NULL.
 
90
   */
 
91
  
 
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.
 
94
   */
 
95
  if (window->depth == 32)
 
96
    visual = window->xvisual;
 
97
  else
 
98
    visual = NULL;
 
99
  
 
100
  frame->xwindow = meta_ui_create_frame_window (window->screen->ui,
 
101
                                                window->display->xdisplay,
 
102
                                                visual,
 
103
                                                frame->rect.x,
 
104
                                                frame->rect.y,
 
105
                                                frame->rect.width,
 
106
                                                frame->rect.height,
 
107
                                                frame->window->screen->number,
 
108
                                                &create_serial);
 
109
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 
110
                                 frame->xwindow,
 
111
                                 create_serial);
 
112
 
 
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);
 
117
  
 
118
  meta_display_register_x_window (window->display, &frame->xwindow, window);
 
119
 
 
120
  /* Now that frame->xwindow is registered with window, we can set its
 
121
   * background.
 
122
   */
 
123
  meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);
 
124
 
 
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
 
131
   * a grab.
 
132
   */
 
133
  meta_error_trap_push (window->display);
 
134
  if (window->mapped)
 
135
    {
 
136
      window->mapped = FALSE; /* the reparent will unmap the window,
 
137
                               * we don't want to take that as a withdraw
 
138
                               */
 
139
      meta_topic (META_DEBUG_WINDOW_STATE,
 
140
                  "Incrementing unmaps_pending on %s for reparent\n", window->desc);
 
141
      window->unmaps_pending += 1;
 
142
    }
 
143
  /* window was reparented to this position */
 
144
  window->rect.x = 0;
 
145
  window->rect.y = 0;
 
146
 
 
147
  meta_stack_tracker_record_remove (window->screen->stack_tracker,
 
148
                                    window->xwindow,
 
149
                                    XNextRequest (window->display->xdisplay));
 
150
  XReparentWindow (window->display->xdisplay,
 
151
                   window->xwindow,
 
152
                   frame->xwindow,
 
153
                   window->rect.x,
 
154
                   window->rect.y);
 
155
  /* FIXME handle this error */
 
156
  meta_error_trap_pop (window->display, FALSE);
 
157
  
 
158
  /* stick frame to the window */
 
159
  window->frame = frame;
 
160
  
 
161
  if (window->title)
 
162
    meta_ui_set_frame_title (window->screen->ui,
 
163
                             window->frame->xwindow,
 
164
                             window->title);
 
165
 
 
166
  /* Move keybindings to frame instead of window */
 
167
  meta_window_grab_keys (window);
 
168
 
 
169
  /* Shape mask */
 
170
  meta_ui_apply_frame_shape (frame->window->screen->ui,
 
171
                             frame->xwindow,
 
172
                             frame->rect.width,
 
173
                             frame->rect.height,
 
174
                             frame->window->has_shape);
 
175
  frame->need_reapply_frame_shape = FALSE;
 
176
  
 
177
  meta_display_ungrab (window->display);
 
178
}
 
179
 
 
180
void
 
181
meta_window_destroy_frame (MetaWindow *window)
 
182
{
 
183
  MetaFrame *frame;
 
184
  
 
185
  if (window->frame == NULL)
 
186
    return;
 
187
 
 
188
  meta_verbose ("Unframing window %s\n", window->desc);
 
189
  
 
190
  frame = window->frame;
 
191
  
 
192
  meta_bell_notify_frame_destroy (frame);
 
193
  
 
194
  /* Unparent the client window; it may be destroyed,
 
195
   * thus the error trap.
 
196
   */
 
197
  meta_error_trap_push (window->display);
 
198
  if (window->mapped)
 
199
    {
 
200
      window->mapped = FALSE; /* Keep track of unmapping it, so we
 
201
                               * can identify a withdraw initiated
 
202
                               * by the client.
 
203
                               */
 
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;
 
207
    }
 
208
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 
209
                                 window->xwindow,
 
210
                                 XNextRequest (window->display->xdisplay));
 
211
  XReparentWindow (window->display->xdisplay,
 
212
                   window->xwindow,
 
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.
 
217
                    */
 
218
                   window->frame->rect.x,
 
219
                   window->frame->rect.y);
 
220
  meta_error_trap_pop (window->display, FALSE);
 
221
 
 
222
  meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow);
 
223
 
 
224
  meta_display_unregister_x_window (window->display,
 
225
                                    frame->xwindow);
 
226
  
 
227
  window->frame = NULL;
 
228
 
 
229
  /* Move keybindings to window instead of frame */
 
230
  meta_window_grab_keys (window);
 
231
  
 
232
  g_free (frame);
 
233
  
 
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);
 
237
}
 
238
 
 
239
 
 
240
MetaFrameFlags
 
241
meta_frame_get_flags (MetaFrame *frame)
 
242
{
 
243
  MetaFrameFlags flags;
 
244
 
 
245
  flags = 0;
 
246
 
 
247
  if (frame->window->border_only)
 
248
    {
 
249
      ; /* FIXME this may disable the _function_ as well as decor
 
250
         * in some cases, which is sort of wrong.
 
251
         */
 
252
    }
 
253
  else
 
254
    {
 
255
      flags |= META_FRAME_ALLOWS_MENU;
 
256
      
 
257
      if (frame->window->has_close_func)
 
258
        flags |= META_FRAME_ALLOWS_DELETE;
 
259
      
 
260
      if (frame->window->has_maximize_func)
 
261
        flags |= META_FRAME_ALLOWS_MAXIMIZE;
 
262
      
 
263
      if (frame->window->has_minimize_func)
 
264
        flags |= META_FRAME_ALLOWS_MINIMIZE;
 
265
      
 
266
      if (frame->window->has_shade_func)
 
267
        flags |= META_FRAME_ALLOWS_SHADE;
 
268
    }  
 
269
  
 
270
  if (META_WINDOW_ALLOWS_MOVE (frame->window))
 
271
    flags |= META_FRAME_ALLOWS_MOVE;
 
272
 
 
273
  if (META_WINDOW_ALLOWS_HORIZONTAL_RESIZE (frame->window))
 
274
    flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
 
275
 
 
276
  if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window))
 
277
    flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
 
278
  
 
279
  if (frame->window->has_focus)
 
280
    flags |= META_FRAME_HAS_FOCUS;
 
281
 
 
282
  if (frame->window->shaded)
 
283
    flags |= META_FRAME_SHADED;
 
284
 
 
285
  if (frame->window->on_all_workspaces)
 
286
    flags |= META_FRAME_STUCK;
 
287
 
 
288
  /* FIXME: Should we have some kind of UI for windows that are just vertically
 
289
   * maximized or just horizontally maximized?
 
290
   */
 
291
  if (META_WINDOW_MAXIMIZED (frame->window))
 
292
    flags |= META_FRAME_MAXIMIZED;
 
293
 
 
294
  if (frame->window->fullscreen)
 
295
    flags |= META_FRAME_FULLSCREEN;
 
296
 
 
297
  if (frame->is_flashing)
 
298
    flags |= META_FRAME_IS_FLASHING;
 
299
 
 
300
  if (frame->window->wm_state_above)
 
301
    flags |= META_FRAME_ABOVE;
 
302
  
 
303
  return flags;
 
304
}
 
305
 
 
306
void
 
307
meta_frame_calc_geometry (MetaFrame         *frame,
 
308
                          MetaFrameGeometry *geomp)
 
309
{
 
310
  MetaFrameGeometry geom;
 
311
  MetaWindow *window;
 
312
 
 
313
  window = frame->window;
 
314
 
 
315
  meta_ui_get_frame_geometry (window->screen->ui,
 
316
                              frame->xwindow,
 
317
                              &geom.top_height,
 
318
                              &geom.bottom_height,
 
319
                              &geom.left_width,
 
320
                              &geom.right_width);
 
321
  
 
322
  *geomp = geom;
 
323
}
 
324
 
 
325
static void
 
326
update_shape (MetaFrame *frame)
 
327
{
 
328
  if (frame->need_reapply_frame_shape)
 
329
    {
 
330
      meta_ui_apply_frame_shape (frame->window->screen->ui,
 
331
                                 frame->xwindow,
 
332
                                 frame->rect.width,
 
333
                                 frame->rect.height,
 
334
                                 frame->window->has_shape);
 
335
      frame->need_reapply_frame_shape = FALSE;
 
336
    }
 
337
}
 
338
 
 
339
void
 
340
meta_frame_sync_to_window (MetaFrame *frame,
 
341
                           int        resize_gravity,
 
342
                           gboolean   need_move,
 
343
                           gboolean   need_resize)
 
344
{
 
345
  if (!(need_move || need_resize))
 
346
    {
 
347
      update_shape (frame);
 
348
      return;
 
349
    }
 
350
 
 
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);
 
357
 
 
358
  /* set bg to none to avoid flicker */
 
359
  if (need_resize)
 
360
    {
 
361
      meta_ui_unflicker_frame_bg (frame->window->screen->ui,
 
362
                                  frame->xwindow,
 
363
                                  frame->rect.width,
 
364
                                  frame->rect.height);
 
365
 
 
366
      /* we need new shape if we're resized */
 
367
      frame->need_reapply_frame_shape = TRUE;
 
368
    }
 
369
 
 
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.
 
375
   */
 
376
  update_shape (frame);
 
377
  
 
378
  meta_ui_move_resize_frame (frame->window->screen->ui,
 
379
                             frame->xwindow,
 
380
                             frame->rect.x,
 
381
                             frame->rect.y,
 
382
                             frame->rect.width,
 
383
                             frame->rect.height);
 
384
 
 
385
  if (need_resize)
 
386
    {
 
387
      meta_ui_reset_frame_bg (frame->window->screen->ui,
 
388
                              frame->xwindow);
 
389
 
 
390
      /* If we're interactively resizing the frame, repaint
 
391
       * it immediately so we don't start to lag.
 
392
       */
 
393
      if (frame->window->display->grab_window ==
 
394
          frame->window)
 
395
        meta_ui_repaint_frame (frame->window->screen->ui,
 
396
                               frame->xwindow);
 
397
    }
 
398
}
 
399
 
 
400
void
 
401
meta_frame_queue_draw (MetaFrame *frame)
 
402
{
 
403
  meta_ui_queue_frame_draw (frame->window->screen->ui,
 
404
                            frame->xwindow);
 
405
}
 
406
 
 
407
void
 
408
meta_frame_set_screen_cursor (MetaFrame *frame,
 
409
                              MetaCursor cursor)
 
410
{
 
411
  Cursor xcursor;
 
412
  if (cursor == frame->current_cursor)
 
413
    return;
 
414
  frame->current_cursor = cursor;
 
415
  if (cursor == META_CURSOR_DEFAULT)
 
416
    XUndefineCursor (frame->window->display->xdisplay, frame->xwindow);
 
417
  else
 
418
    { 
 
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);
 
423
    }
 
424
}
 
425
 
 
426
Window
 
427
meta_frame_get_xwindow (MetaFrame *frame)
 
428
{
 
429
  return frame->xwindow;
 
430
}