window.c 300 KB
Newer Older
1
2
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

3
/* Mutter X managed windows */
rhp's avatar
...  
rhp committed
4

5
/*
6
 * Copyright (C) 2001 Havoc Pennington, Anders Carlsson
7
8
 * Copyright (C) 2002, 2003 Red Hat, Inc.
 * Copyright (C) 2003 Rob Adams
9
 * Copyright (C) 2004-2006 Elijah Newren
10
 *
rhp's avatar
...  
rhp committed
11
12
13
14
15
16
17
18
19
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
20
 *
rhp's avatar
...  
rhp committed
21
22
23
24
25
26
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

27
#include <config.h>
28
#include "window-private.h"
29
#include "boxes-private.h"
30
#include "edge-resistance.h"
rhp's avatar
...  
rhp committed
31
#include "util.h"
32
#include "frame-private.h"
rhp's avatar
...    
rhp committed
33
#include "errors.h"
34
#include "workspace-private.h"
rhp's avatar
...    
rhp committed
35
#include "stack.h"
36
#include "keybindings-private.h"
rhp's avatar
...    
rhp committed
37
#include "ui.h"
rhp's avatar
...    
rhp committed
38
#include "place.h"
rhp's avatar
...    
rhp committed
39
#include "session.h"
40
#include "prefs.h"
41
#include "resizepopup.h"
42
#include "xprops.h"
43
#include "group.h"
44
#include "window-props.h"
45
#include "constraints.h"
46
#include "mutter-enum-types.h"
rhp's avatar
...    
rhp committed
47

rhp's avatar
...    
rhp committed
48
#include <X11/Xatom.h>
49
#include <X11/Xlibint.h> /* For display->resource_mask */
50
#include <string.h>
rhp's avatar
...    
rhp committed
51

52
53
54
55
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif

56
57
#include <X11/extensions/Xcomposite.h>

58
59
static int destroying_windows_disallowed = 0;

rhp's avatar
...    
rhp committed
60
61

static void     update_sm_hints           (MetaWindow     *window);
62
static void     update_net_frame_extents  (MetaWindow     *window);
rhp's avatar
...    
rhp committed
63
static void     recalc_window_type        (MetaWindow     *window);
rhp's avatar
...    
rhp committed
64
static void     recalc_window_features    (MetaWindow     *window);
65
static void     invalidate_work_areas     (MetaWindow     *window);
66
static void     recalc_window_type        (MetaWindow     *window);
67
static void     set_wm_state              (MetaWindow     *window,
rhp's avatar
...    
rhp committed
68
                                           int             state);
69
static void     set_net_wm_state          (MetaWindow     *window);
70

rhp's avatar
...    
rhp committed
71
72
73
74
75
76
static void     send_configure_notify     (MetaWindow     *window);
static gboolean process_property_notify   (MetaWindow     *window,
                                           XPropertyEvent *event);
static void     meta_window_show          (MetaWindow     *window);
static void     meta_window_hide          (MetaWindow     *window);

77
78
79
static gboolean meta_window_same_client (MetaWindow *window,
                                         MetaWindow *other_window);

80
static void     meta_window_save_rect         (MetaWindow    *window);
81
82
static void     save_user_window_placement    (MetaWindow    *window);
static void     force_save_user_window_placement (MetaWindow    *window);
83

Havoc Pennington's avatar
Havoc Pennington committed
84
85
86
87
88
89
90
static void meta_window_move_resize_internal (MetaWindow         *window,
                                              MetaMoveResizeFlags flags,
                                              int                 resize_gravity,
                                              int                 root_x_nw,
                                              int                 root_y_nw,
                                              int                 w,
                                              int                 h);
rhp's avatar
...    
rhp committed
91

92
93
94
static void     ensure_mru_position_after (MetaWindow *window,
                                           MetaWindow *after_this_one);

rhp's avatar
...    
rhp committed
95

96
static void meta_window_move_resize_now (MetaWindow  *window);
rhp's avatar
...    
rhp committed
97

98
static void meta_window_unqueue (MetaWindow *window, guint queuebits);
99

100
101
102
103
104
105
106
107
108
109
110
111
112
static void     update_move           (MetaWindow   *window,
                                       gboolean      snap,
                                       int           x,
                                       int           y);
static gboolean update_move_timeout   (gpointer data);
static void     update_resize         (MetaWindow   *window,
                                       gboolean      snap,
                                       int           x,
                                       int           y,
                                       gboolean      force);
static gboolean update_resize_timeout (gpointer data);


113
static void meta_window_flush_calc_showing   (MetaWindow *window);
rhp's avatar
...    
rhp committed
114

115
116
117
static gboolean queue_calc_showing_func (MetaWindow *window,
                                         void       *data);

rhp's avatar
...    
rhp committed
118
119
120
static void meta_window_apply_session_info (MetaWindow                  *window,
                                            const MetaWindowSessionInfo *info);

121
122
123
static void unmaximize_window_before_freeing (MetaWindow        *window);
static void unminimize_window_and_all_transient_parents (MetaWindow *window);

124
125
126
/* Idle handlers for the three queues (run with meta_later_add()). The
 * "data" parameter in each case will be a GINT_TO_POINTER of the
 * index into the queue arrays to use.
127
128
129
130
131
132
133
 *
 * TODO: Possibly there is still some code duplication among these, which we
 * need to sort out at some point.
 */
static gboolean idle_calc_showing (gpointer data);
static gboolean idle_move_resize (gpointer data);
static gboolean idle_update_icon (gpointer data);
134

Owen Taylor's avatar
Owen Taylor committed
135
136
G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT);

137
138
139
140
141
enum {
  PROP_0,

  PROP_TITLE,
  PROP_ICON,
142
  PROP_MINI_ICON,
143
  PROP_DECORATED,
144
  PROP_FULLSCREEN,
145
146
  PROP_MAXIMIZED_HORIZONTALLY,
  PROP_MAXIMIZED_VERTICALLY,
147
  PROP_WINDOW_TYPE,
148
  PROP_USER_TIME,
149
  PROP_DEMANDS_ATTENTION,
Tomas Frydrych's avatar
Tomas Frydrych committed
150
151
  PROP_URGENT,
  PROP_MUTTER_HINTS
152
153
};

154
155
156
enum
{
  WORKSPACE_CHANGED,
Tomas Frydrych's avatar
Tomas Frydrych committed
157
  FOCUS,
Tomas Frydrych's avatar
Tomas Frydrych committed
158
  RAISED,
159
  UNMANAGED,
160
161
162
163
164
165

  LAST_SIGNAL
};

static guint window_signals[LAST_SIGNAL] = { 0 };

Owen Taylor's avatar
Owen Taylor committed
166
167
168
169
static void
meta_window_finalize (GObject *object)
{
  MetaWindow *window = META_WINDOW (object);
170

Owen Taylor's avatar
Owen Taylor committed
171
172
173
174
175
176
177
  if (window->icon)
    g_object_unref (G_OBJECT (window->icon));

  if (window->mini_icon)
    g_object_unref (G_OBJECT (window->mini_icon));

  meta_icon_cache_free (&window->icon_cache);
178

Owen Taylor's avatar
Owen Taylor committed
179
180
181
182
183
184
185
186
187
188
189
  g_free (window->sm_client_id);
  g_free (window->wm_client_machine);
  g_free (window->startup_id);
  g_free (window->role);
  g_free (window->res_class);
  g_free (window->res_name);
  g_free (window->title);
  g_free (window->icon_name);
  g_free (window->desc);
}

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
static void
meta_window_get_property(GObject         *object,
                         guint            prop_id,
                         GValue          *value,
                         GParamSpec      *pspec)
{
  MetaWindow *win = META_WINDOW (object);

  switch (prop_id)
    {
    case PROP_TITLE:
      g_value_set_string (value, win->title);
      break;
    case PROP_ICON:
      g_value_set_object (value, win->icon);
      break;
    case PROP_MINI_ICON:
      g_value_set_object (value, win->mini_icon);
208
      break;
209
210
211
    case PROP_DECORATED:
      g_value_set_boolean (value, win->decorated);
      break;
212
213
214
    case PROP_FULLSCREEN:
      g_value_set_boolean (value, win->fullscreen);
      break;
215
216
217
218
219
220
    case PROP_MAXIMIZED_HORIZONTALLY:
      g_value_set_boolean (value, win->maximized_horizontally);
      break;
    case PROP_MAXIMIZED_VERTICALLY:
      g_value_set_boolean (value, win->maximized_vertically);
      break;
221
222
223
    case PROP_WINDOW_TYPE:
      g_value_set_enum (value, win->type);
      break;
224
225
226
    case PROP_USER_TIME:
      g_value_set_uint (value, win->net_wm_user_time);
      break;
227
228
229
    case PROP_DEMANDS_ATTENTION:
      g_value_set_boolean (value, win->wm_state_demands_attention);
      break;
230
231
232
    case PROP_URGENT:
      g_value_set_boolean (value, win->wm_hints_urgent);
      break;
Tomas Frydrych's avatar
Tomas Frydrych committed
233
234
235
    case PROP_MUTTER_HINTS:
      g_value_set_string (value, win->mutter_hints);
      break;
236
237
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
238
      break;
239
240
241
242
243
244
245
246
247
248
249
250
251
    }
}

static void
meta_window_set_property(GObject         *object,
                         guint            prop_id,
                         const GValue    *value,
                         GParamSpec      *pspec)
{
  switch (prop_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
252
      break;
253
254
255
    }
}

Owen Taylor's avatar
Owen Taylor committed
256
257
258
259
260
261
static void
meta_window_class_init (MetaWindowClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->finalize = meta_window_finalize;
262

263
264
  object_class->get_property = meta_window_get_property;
  object_class->set_property = meta_window_set_property;
265

266
267
268
269
270
271
  g_object_class_install_property (object_class,
                                   PROP_TITLE,
                                   g_param_spec_string ("title",
                                                        "Title",
                                                        "The title of the window",
                                                        NULL,
272
                                                        G_PARAM_READABLE));
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  g_object_class_install_property (object_class,
                                   PROP_ICON,
                                   g_param_spec_object ("icon",
                                                        "Icon",
                                                        "32 pixel sized icon",
                                                        GDK_TYPE_PIXBUF,
                                                        G_PARAM_READABLE));

  g_object_class_install_property (object_class,
                                   PROP_MINI_ICON,
                                   g_param_spec_object ("mini-icon",
                                                        "Mini Icon",
                                                        "16 pixel sized icon",
                                                        GDK_TYPE_PIXBUF,
287
                                                        G_PARAM_READABLE));
288

289
290
291
292
  g_object_class_install_property (object_class,
                                   PROP_DECORATED,
                                   g_param_spec_boolean ("decorated",
                                                         "Decorated",
293
                                                         "Whether window is decorated",
294
295
296
                                                         TRUE,
                                                         G_PARAM_READABLE));

297
298
299
300
  g_object_class_install_property (object_class,
                                   PROP_FULLSCREEN,
                                   g_param_spec_boolean ("fullscreen",
                                                         "Fullscreen",
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
                                                         "Whether window is fullscreened",
                                                         FALSE,
                                                         G_PARAM_READABLE));

  g_object_class_install_property (object_class,
                                   PROP_MAXIMIZED_HORIZONTALLY,
                                   g_param_spec_boolean ("maximized-horizontally",
                                                         "Maximized horizontally",
                                                         "Whether window is maximized horizontally",
                                                         FALSE,
                                                         G_PARAM_READABLE));

  g_object_class_install_property (object_class,
                                   PROP_MAXIMIZED_VERTICALLY,
                                   g_param_spec_boolean ("maximized-vertically",
                                                         "Maximizing vertically",
                                                         "Whether window is maximized vertically",
318
319
320
                                                         FALSE,
                                                         G_PARAM_READABLE));

321
322
323
324
325
326
327
328
329
  g_object_class_install_property (object_class,
                                   PROP_WINDOW_TYPE,
                                   g_param_spec_enum ("window-type",
                                                      "Window Type",
                                                      "The type of the window",
                                                      MUTTER_TYPE_WINDOW_TYPE,
                                                      META_WINDOW_NORMAL,
                                                      G_PARAM_READABLE));

330
331
332
333
334
335
336
337
338
339
  g_object_class_install_property (object_class,
                                   PROP_USER_TIME,
                                   g_param_spec_uint ("user-time",
                                                      "User time",
                                                      "Timestamp of last user interaction",
                                                      0,
                                                      G_MAXUINT,
                                                      0,
                                                      G_PARAM_READABLE));

340
341
342
343
344
345
346
347
  g_object_class_install_property (object_class,
                                   PROP_DEMANDS_ATTENTION,
                                   g_param_spec_boolean ("demands-attention",
                                                         "Demands Attention",
                                                         "Whether the window has _NET_WM_STATE_DEMANDS_ATTENTION set",
                                                         FALSE,
                                                         G_PARAM_READABLE));

348
349
350
351
352
353
354
355
  g_object_class_install_property (object_class,
                                   PROP_URGENT,
                                   g_param_spec_boolean ("urgent",
                                                         "Urgent",
                                                         "Whether the urgent flag of WM_HINTS is set",
                                                         FALSE,
                                                         G_PARAM_READABLE));

Tomas Frydrych's avatar
Tomas Frydrych committed
356
357
358
359
360
361
362
  g_object_class_install_property (object_class,
                                   PROP_MUTTER_HINTS,
                                   g_param_spec_string ("mutter-hints",
                                                        "_MUTTER_HINTS",
                                                        "Contents of the _MUTTER_HINTS property of this window",
                                                        NULL,
                                                        G_PARAM_READABLE));
363
364
365
366
367
368
369
370
371
  window_signals[WORKSPACE_CHANGED] =
    g_signal_new ("workspace-changed",
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (MetaWindowClass, workspace_changed),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__INT,
                  G_TYPE_NONE, 1,
                  G_TYPE_INT);
Tomas Frydrych's avatar
Tomas Frydrych committed
372
373
374
375
376
377
378
379
380

  window_signals[FOCUS] =
    g_signal_new ("focus",
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (MetaWindowClass, focus),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Tomas Frydrych's avatar
Tomas Frydrych committed
381
382
383
384
385
386
387
388
389

  window_signals[RAISED] =
    g_signal_new ("raised",
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (MetaWindowClass, raised),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
390
391
392
393
394
395
396
397
398

  window_signals[UNMANAGED] =
    g_signal_new ("unmanaged",
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (MetaWindowClass, unmanaged),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
Owen Taylor's avatar
Owen Taylor committed
399
400
401
402
403
404
405
}

static void
meta_window_init (MetaWindow *self)
{
}

406
#ifdef WITH_VERBOSE_MODE
407
408
409
410
411
412
static const char*
wm_state_to_string (int state)
{
  switch (state)
    {
    case NormalState:
413
      return "NormalState";
414
415
416
417
418
419
420
421
    case IconicState:
      return "IconicState";
    case WithdrawnState:
      return "WithdrawnState";
    }

  return "Unknown";
}
422
#endif
423

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
static gboolean
is_desktop_or_dock_foreach (MetaWindow *window,
                            void       *data)
{
  gboolean *result = data;

  *result =
    window->type == META_WINDOW_DESKTOP ||
    window->type == META_WINDOW_DOCK;
  if (*result)
    return FALSE; /* stop as soon as we find one */
  else
    return TRUE;
}

/* window is the window that's newly mapped provoking
 * the possible change
 */
static void
maybe_leave_show_desktop_mode (MetaWindow *window)
{
  gboolean is_desktop_or_dock;

447
  if (!window->screen->active_workspace->showing_desktop)
448
449
450
451
452
453
454
455
    return;

  /* If the window is a transient for the dock or desktop, don't
   * leave show desktop mode when the window opens. That's
   * so you can e.g. hide all windows, manipulate a file on
   * the desktop via a dialog, then unshow windows again.
   */
  is_desktop_or_dock = FALSE;
456
457
  is_desktop_or_dock_foreach (window,
                              &is_desktop_or_dock);
458
459
460
461
462
463

  meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
                                &is_desktop_or_dock);

  if (!is_desktop_or_dock)
    {
464
465
      meta_screen_minimize_all_on_active_workspace_except (window->screen,
                                                           window);
466
      meta_screen_unshow_desktop (window->screen);
467
468
469
    }
}

rhp's avatar
...  
rhp committed
470
MetaWindow*
471
472
473
meta_window_new (MetaDisplay *display,
                 Window       xwindow,
                 gboolean     must_be_viewable)
rhp's avatar
...  
rhp committed
474
475
{
  XWindowAttributes attrs;
Havoc Pennington's avatar
Havoc Pennington committed
476
  MetaWindow *window;
477

Havoc Pennington's avatar
Havoc Pennington committed
478
479
480
481
  meta_display_grab (display);
  meta_error_trap_push (display); /* Push a trap over all of window
                                   * creation, to reduce XSync() calls
                                   */
482

Havoc Pennington's avatar
Havoc Pennington committed
483
  meta_error_trap_push_with_return (display);
484
485

  if (XGetWindowAttributes (display->xdisplay,xwindow, &attrs))
486
   {
487
      if(meta_error_trap_pop_with_return (display) != Success)
488
489
490
       {
          meta_verbose ("Failed to get attributes for window 0x%lx\n",
                        xwindow);
491
          meta_error_trap_pop (display);
492
493
494
495
          meta_display_ungrab (display);
          return NULL;
       }
      window = meta_window_new_with_attrs (display, xwindow,
496
497
498
                                           must_be_viewable,
                                           META_COMP_EFFECT_CREATE,
                                           &attrs);
499
500
501
   }
  else
   {
502
         meta_error_trap_pop_with_return (display);
503
504
         meta_verbose ("Failed to get attributes for window 0x%lx\n",
                        xwindow);
505
         meta_error_trap_pop (display);
506
507
508
         meta_display_ungrab (display);
         return NULL;
   }
509
510


511
  meta_error_trap_pop (display);
Havoc Pennington's avatar
Havoc Pennington committed
512
513
514
515
516
517
518
519
520
  meta_display_ungrab (display);

  return window;
}

MetaWindow*
meta_window_new_with_attrs (MetaDisplay       *display,
                            Window             xwindow,
                            gboolean           must_be_viewable,
521
                            MetaCompEffect     effect,
Havoc Pennington's avatar
Havoc Pennington committed
522
523
524
                            XWindowAttributes *attrs)
{
  MetaWindow *window;
rhp's avatar
...  
rhp committed
525
  GSList *tmp;
rhp's avatar
...    
rhp committed
526
  MetaWorkspace *space;
rhp's avatar
...    
rhp committed
527
  gulong existing_wm_state;
528
  gulong event_mask;
529
  MetaMoveResizeFlags flags;
530
  gboolean has_shape;
531
  MetaScreen *screen;
Havoc Pennington's avatar
Havoc Pennington committed
532
533

  g_assert (attrs != NULL);
534

rhp's avatar
...    
rhp committed
535
  meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
rhp's avatar
...    
rhp committed
536

537
  if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
538
539
540
541
542
    {
      meta_verbose ("Not managing no_focus_window 0x%lx\n",
                    xwindow);
      return NULL;
    }
Havoc Pennington's avatar
Havoc Pennington committed
543

544
545
  screen = NULL;
  for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
Havoc Pennington's avatar
Havoc Pennington committed
546
    {
547
548
549
550
551
552
553
      MetaScreen *scr = tmp->data;

      if (scr->xroot == attrs->root)
        {
          screen = tmp->data;
          break;
        }
Havoc Pennington's avatar
Havoc Pennington committed
554
    }
555

556
  g_assert (screen);
557

558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  /* A black list of override redirect windows that we don't need to manage: */
  if (attrs->override_redirect &&
      (xwindow == screen->no_focus_window ||
       xwindow == screen->flash_window ||
       xwindow == screen->wm_sn_selection_window ||
       attrs->class == InputOnly ||
       /* any windows created via meta_create_offscreen_window: */
       (attrs->x == -100 && attrs->y == -100
	&& attrs->width == 1 && attrs->height == 1) ||
       xwindow == screen->wm_cm_selection_window ||
       xwindow == screen->guard_window ||
       (display->compositor &&
        xwindow == XCompositeGetOverlayWindow (display->xdisplay,
					       screen->xroot)
       )
      )
     ) {
    meta_verbose ("Not managing our own windows\n");
    return NULL;
  }

rhp's avatar
...    
rhp committed
579
580
  /* Grab server */
  meta_display_grab (display);
581
582
583
  meta_error_trap_push (display); /* Push a trap over all of window
                                   * creation, to reduce XSync() calls
                                   */
rhp's avatar
...    
rhp committed
584

Havoc Pennington's avatar
Havoc Pennington committed
585
  meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
586
                must_be_viewable,
Havoc Pennington's avatar
Havoc Pennington committed
587
588
                attrs->map_state,
                (attrs->map_state == IsUnmapped) ?
589
                "IsUnmapped" :
Havoc Pennington's avatar
Havoc Pennington committed
590
                (attrs->map_state == IsViewable) ?
591
                "IsViewable" :
Havoc Pennington's avatar
Havoc Pennington committed
592
                (attrs->map_state == IsUnviewable) ?
593
594
                "IsUnviewable" :
                "(unknown)");
595

rhp's avatar
...    
rhp committed
596
  existing_wm_state = WithdrawnState;
Havoc Pennington's avatar
Havoc Pennington committed
597
  if (must_be_viewable && attrs->map_state != IsViewable)
rhp's avatar
...    
rhp committed
598
    {
rhp's avatar
...    
rhp committed
599
600
601
      /* Only manage if WM_STATE is IconicState or NormalState */
      gulong state;

Havoc Pennington's avatar
Havoc Pennington committed
602
603
      /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
      if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
604
605
                                                   display->atom_WM_STATE,
                                                   display->atom_WM_STATE,
Havoc Pennington's avatar
Havoc Pennington committed
606
                                                   &state) &&
rhp's avatar
...    
rhp committed
607
608
609
            (state == IconicState || state == NormalState)))
        {
          meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
610
          meta_error_trap_pop (display);
rhp's avatar
...    
rhp committed
611
612
613
614
          meta_display_ungrab (display);
          return NULL;
        }

rhp's avatar
...    
rhp committed
615
      existing_wm_state = state;
616
617
      meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
                    wm_state_to_string (existing_wm_state));
rhp's avatar
...    
rhp committed
618
    }
619

620
  meta_error_trap_push_with_return (display);
621

622
623
624
625
626
627
628
629
630
  /*
   * XAddToSaveSet can only be called on windows created by a different client.
   * with Mutter we want to be able to create manageable windows from within
   * the process (such as a dummy desktop window), so we do not want this
   * call failing to prevent the window from being managed -- wrap it in its
   * own error trap (we use the _with_return() version here to ensure that
   * XSync() is done on the pop, otherwise the error will not get caught).
   */
  meta_error_trap_push_with_return (display);
rhp's avatar
...    
rhp committed
631
  XAddToSaveSet (display->xdisplay, xwindow);
632
  meta_error_trap_pop_with_return (display);
rhp's avatar
...    
rhp committed
633

634
635
636
  event_mask =
    PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
    FocusChangeMask | ColormapChangeMask;
637
638
  if (attrs->override_redirect)
    event_mask |= StructureNotifyMask;
639

640
641
642
643
644
  /* If the window is from this client (a menu, say) we need to augment
   * the event mask, not replace it. For windows from other clients,
   * attrs->your_event_mask will be empty at this point.
   */
  XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664

  has_shape = FALSE;
#ifdef HAVE_SHAPE
  if (META_DISPLAY_HAS_SHAPE (display))
    {
      int x_bounding, y_bounding, x_clip, y_clip;
      unsigned w_bounding, h_bounding, w_clip, h_clip;
      int bounding_shaped, clip_shaped;

      XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);

      XShapeQueryExtents (display->xdisplay, xwindow,
                          &bounding_shaped, &x_bounding, &y_bounding,
                          &w_bounding, &h_bounding,
                          &clip_shaped, &x_clip, &y_clip,
                          &w_clip, &h_clip);

      has_shape = bounding_shaped != FALSE;

      meta_topic (META_DEBUG_SHAPES,
665
                  "Window has_shape = %d extents %d,%d %u x %u\n",
666
667
668
669
                  has_shape, x_bounding, y_bounding,
                  w_bounding, h_bounding);
    }
#endif
rhp's avatar
...    
rhp committed
670
671

  /* Get rid of any borders */
Havoc Pennington's avatar
Havoc Pennington committed
672
  if (attrs->border_width != 0)
rhp's avatar
...    
rhp committed
673
    XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
rhp's avatar
...    
rhp committed
674
675

  /* Get rid of weird gravities */
Havoc Pennington's avatar
Havoc Pennington committed
676
  if (attrs->win_gravity != NorthWestGravity)
rhp's avatar
...    
rhp committed
677
678
    {
      XSetWindowAttributes set_attrs;
679

rhp's avatar
...    
rhp committed
680
      set_attrs.win_gravity = NorthWestGravity;
681

rhp's avatar
...    
rhp committed
682
683
684
685
686
      XChangeWindowAttributes (display->xdisplay,
                               xwindow,
                               CWWinGravity,
                               &set_attrs);
    }
687

688
  if (meta_error_trap_pop_with_return (display) != Success)
rhp's avatar
...  
rhp committed
689
690
691
    {
      meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
                    xwindow);
692
      meta_error_trap_pop (display);
rhp's avatar
...    
rhp committed
693
      meta_display_ungrab (display);
rhp's avatar
...  
rhp committed
694
695
      return NULL;
    }
rhp's avatar
...    
rhp committed
696

697

Owen Taylor's avatar
Owen Taylor committed
698
  window = g_object_new (META_TYPE_WINDOW, NULL);
rhp's avatar
...  
rhp committed
699

700
  window->constructing = TRUE;
701

702
  window->dialog_pid = -1;
703

rhp's avatar
...  
rhp committed
704
  window->xwindow = xwindow;
705

rhp's avatar
...    
rhp committed
706
707
708
709
  /* this is in window->screen->display, but that's too annoying to
   * type
   */
  window->display = display;
710
  window->workspace = NULL;
711
712

#ifdef HAVE_XSYNC
713
714
715
716
  window->sync_request_counter = None;
  window->sync_request_serial = 0;
  window->sync_request_time.tv_sec = 0;
  window->sync_request_time.tv_usec = 0;
717
#endif
718

719
  window->screen = screen;
rhp's avatar
...    
rhp committed
720

721
  window->desc = g_strdup_printf ("0x%lx", window->xwindow);
722

723
724
  window->override_redirect = attrs->override_redirect;

rhp's avatar
...    
rhp committed
725
726
  /* avoid tons of stack updates */
  meta_stack_freeze (window->screen->stack);
727
728

  window->has_shape = has_shape;
729

Havoc Pennington's avatar
Havoc Pennington committed
730
731
732
733
  window->rect.x = attrs->x;
  window->rect.y = attrs->y;
  window->rect.width = attrs->width;
  window->rect.height = attrs->height;
rhp's avatar
...    
rhp committed
734

rhp's avatar
...    
rhp committed
735
  /* And border width, size_hints are the "request" */
Havoc Pennington's avatar
Havoc Pennington committed
736
737
738
739
740
  window->border_width = attrs->border_width;
  window->size_hints.x = attrs->x;
  window->size_hints.y = attrs->y;
  window->size_hints.width = attrs->width;
  window->size_hints.height = attrs->height;
741
742
  /* initialize the remaining size_hints as if size_hints.flags were zero */
  meta_set_normal_hints (window, NULL);
rhp's avatar
...    
rhp committed
743
744
745

  /* And this is our unmaximized size */
  window->saved_rect = window->rect;
Havoc Pennington's avatar
Havoc Pennington committed
746
  window->user_rect = window->rect;
747

Havoc Pennington's avatar
Havoc Pennington committed
748
749
750
  window->depth = attrs->depth;
  window->xvisual = attrs->visual;
  window->colormap = attrs->colormap;
751

rhp's avatar
...    
rhp committed
752
  window->title = NULL;
rhp's avatar
...    
rhp committed
753
754
  window->icon_name = NULL;
  window->icon = NULL;
755
  window->mini_icon = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
756
757
758
  meta_icon_cache_init (&window->icon_cache);
  window->wm_hints_pixmap = None;
  window->wm_hints_mask = None;
759
  window->wm_hints_urgent = FALSE;
rhp's avatar
...    
rhp committed
760
761

  window->frame = NULL;
rhp's avatar
...    
rhp committed
762
  window->has_focus = FALSE;
rhp's avatar
...    
rhp committed
763

764
765
766
767
  window->maximized_horizontally = FALSE;
  window->maximized_vertically = FALSE;
  window->maximize_horizontally_after_placement = FALSE;
  window->maximize_vertically_after_placement = FALSE;
768
  window->minimize_after_placement = FALSE;
769
  window->fullscreen = FALSE;
770
  window->fullscreen_after_placement = FALSE;
771
  window->fullscreen_monitors[0] = -1;
772
  window->require_fully_onscreen = TRUE;
773
  window->require_on_single_monitor = TRUE;
774
  window->require_titlebar_visible = TRUE;
rhp's avatar
...    
rhp committed
775
  window->on_all_workspaces = FALSE;
776
  window->tile_mode = META_TILE_NONE;
rhp's avatar
...    
rhp committed
777
  window->shaded = FALSE;
rhp's avatar
...    
rhp committed
778
779
  window->initially_iconic = FALSE;
  window->minimized = FALSE;
780
  window->tab_unminimized = FALSE;
rhp's avatar
...    
rhp committed
781
  window->iconic = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
782
  window->mapped = attrs->map_state != IsUnmapped;
783
784
785
  window->hidden = FALSE;
  window->visible_to_compositor = FALSE;
  window->pending_compositor_effect = effect;
786
787
  /* if already mapped, no need to worry about focus-on-first-time-showing */
  window->showing_for_first_time = !window->mapped;
788
789
790
  /* if already mapped we don't want to do the placement thing;
   * override-redirect windows are placed by the app */
  window->placed = ((window->mapped && !window->hidden) || window->override_redirect);
rhp's avatar
...    
rhp committed
791
  if (window->placed)
792
793
794
    meta_topic (META_DEBUG_PLACEMENT,
                "Not placing window 0x%lx since it's already mapped\n",
                xwindow);
795
  window->force_save_user_rect = TRUE;
796
  window->denied_focus_and_not_transient = FALSE;
rhp's avatar
...    
rhp committed
797
  window->unmanaging = FALSE;
798
  window->is_in_queues = 0;
rhp's avatar
...    
rhp committed
799
800
  window->keys_grabbed = FALSE;
  window->grab_on_frame = FALSE;
rhp's avatar
...    
rhp committed
801
  window->all_keys_grabbed = FALSE;
rhp's avatar
...    
rhp committed
802
  window->withdrawn = FALSE;
rhp's avatar
...    
rhp committed
803
  window->initial_workspace_set = FALSE;
804
805
  window->initial_timestamp_set = FALSE;
  window->net_wm_user_time_set = FALSE;
806
  window->user_time_window = None;
807
808
809
810
  window->take_focus = FALSE;
  window->delete_window = FALSE;
  window->net_wm_ping = FALSE;
  window->input = TRUE;
rhp's avatar
...    
rhp committed
811
  window->calc_placement = FALSE;
812
  window->shaken_loose = FALSE;
813
  window->have_focus_click_grab = FALSE;
814
  window->disable_sync = FALSE;
815

rhp's avatar
...    
rhp committed
816
  window->unmaps_pending = 0;
817

rhp's avatar
...    
rhp committed
818
  window->mwm_decorated = TRUE;
819
  window->mwm_border_only = FALSE;
rhp's avatar
...    
rhp committed
820
821
822
823
824
  window->mwm_has_close_func = TRUE;
  window->mwm_has_minimize_func = TRUE;
  window->mwm_has_maximize_func = TRUE;
  window->mwm_has_move_func = TRUE;
  window->mwm_has_resize_func = TRUE;
825

rhp's avatar
...    
rhp committed
826
827
828
829
  window->decorated = TRUE;
  window->has_close_func = TRUE;
  window->has_minimize_func = TRUE;
  window->has_maximize_func = TRUE;
rhp's avatar
...    
rhp committed
830
831
832
  window->has_move_func = TRUE;
  window->has_resize_func = TRUE;

rhp's avatar
...    
rhp committed
833
  window->has_shade_func = TRUE;
834
835

  window->has_fullscreen_func = TRUE;
836
837

  window->always_sticky = FALSE;
838

rhp's avatar
...    
rhp committed
839
  window->wm_state_modal = FALSE;
840
841
  window->skip_taskbar = FALSE;
  window->skip_pager = FALSE;
rhp's avatar
...    
rhp committed
842
843
  window->wm_state_skip_taskbar = FALSE;
  window->wm_state_skip_pager = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
844
845
  window->wm_state_above = FALSE;
  window->wm_state_below = FALSE;
846
  window->wm_state_demands_attention = FALSE;
847

rhp's avatar
...    
rhp committed
848
849
850
851
  window->res_class = NULL;
  window->res_name = NULL;
  window->role = NULL;
  window->sm_client_id = NULL;
852
  window->wm_client_machine = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
853
  window->startup_id = NULL;
854

855
  window->net_wm_pid = -1;
856

rhp's avatar
...    
rhp committed
857
858
  window->xtransient_for = None;
  window->xclient_leader = None;
859
  window->transient_parent_is_root_window = FALSE;
860

rhp's avatar
...    
rhp committed
861
862
  window->type = META_WINDOW_NORMAL;
  window->type_atom = None;
rhp's avatar
...    
rhp committed
863

864
  window->struts = NULL;
865

866
867
868
869
  window->using_net_wm_name              = FALSE;
  window->using_net_wm_visible_name      = FALSE;
  window->using_net_wm_icon_name         = FALSE;
  window->using_net_wm_visible_icon_name = FALSE;
870
871

  window->need_reread_icon = TRUE;
872

873
874
  window->layer = META_LAYER_LAST; /* invalid value */
  window->stack_position = -1;
rhp's avatar
...    
rhp committed
875
  window->initial_workspace = 0; /* not used */
876
  window->initial_timestamp = 0; /* not used */
877
878

  window->compositor_private = NULL;
879

880
881
882
883
884
885
886
887
888
889
  if (window->override_redirect)
    {
      window->decorated = FALSE;
      window->always_sticky = TRUE;
      window->has_close_func = FALSE;
      window->has_shade_func = FALSE;
      window->has_move_func = FALSE;
      window->has_resize_func = FALSE;
    }

rhp's avatar
...    
rhp committed
890
  meta_display_register_x_window (display, &window->xwindow, window);
Havoc Pennington's avatar
Havoc Pennington committed
891

892
893
894
895
  /* Assign this #MetaWindow a sequence number which can be used
   * for sorting.
   */
  window->stable_sequence = ++display->window_sequence_counter;
Havoc Pennington's avatar
Havoc Pennington committed
896
897
898
899
900
901

  /* assign the window to its group, or create a new group if needed
   */
  window->group = NULL;
  window->xgroup_leader = None;
  meta_window_compute_group (window);
902

903
  meta_window_load_initial_properties (window);
904

905
  if (!window->override_redirect)
906
907
908
909
910
    {
      update_sm_hints (window); /* must come after transient_for */

      meta_window_update_role (window);
    }
Tomas Frydrych's avatar
Tomas Frydrych committed
911

912
  meta_window_update_net_wm_type (window);
Tomas Frydrych's avatar
Tomas Frydrych committed
913

914
915
  if (!window->override_redirect)
    meta_window_update_icon_now (window);
916

rhp's avatar
...    
rhp committed
917
918
  if (window->initially_iconic)
    {
rhp's avatar
...    
rhp committed
919
920
921
      /* WM_HINTS said minimized */
      window->minimized = TRUE;
      meta_verbose ("Window %s asked to start out minimized\n", window->desc);
rhp's avatar
...    
rhp committed
922
    }
rhp's avatar
...    
rhp committed
923
924
925
926
927
928
929
930
931
932
933
934
935

  if (existing_wm_state == IconicState)
    {
      /* WM_STATE said minimized */
      window->minimized = TRUE;
      meta_verbose ("Window %s had preexisting WM_STATE = IconicState, minimizing\n",
                    window->desc);

      /* Assume window was previously placed, though perhaps it's
       * been iconic its whole life, we have no way of knowing.
       */
      window->placed = TRUE;
    }
Havoc Pennington's avatar
Havoc Pennington committed
936
937
938
939
940

  /* Apply any window attributes such as initial workspace
   * based on startup notification
   */
  meta_screen_apply_startup_properties (window->screen, window);
941
942
943
944
945
946
947

  /* Try to get a "launch timestamp" for the window.  If the window is
   * a transient, we'd like to be able to get a last-usage timestamp
   * from the parent window.  If the window has no parent, there isn't
   * much we can do...except record the current time so that any children
   * can use this time as a fallback.
   */
948
  if (!window->override_redirect && !window->net_wm_user_time_set) {
949
950
951
952
953
    MetaWindow *parent = NULL;
    if (window->xtransient_for)
      parent = meta_display_lookup_x_window (window->display,
                                             window->xtransient_for);

954
955
956
    /* First, maybe the app was launched with startup notification using an
     * obsolete version of the spec; use that timestamp if it exists.
     */
957
    if (window->initial_timestamp_set)
958
959
960
      /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
       * being recorded as a fallback for potential transients
       */
961
962
963
964
      window->net_wm_user_time = window->initial_timestamp;
    else if (parent != NULL)
      meta_window_set_user_time(window, parent->net_wm_user_time);
    else
965
966
967
      /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
       * being recorded as a fallback for potential transients
       */
968
969
970
      window->net_wm_user_time =
        meta_display_get_current_time_roundtrip (window->display);
  }
971

rhp's avatar
...    
rhp committed
972
973
  if (window->decorated)
    meta_window_ensure_frame (window);
rhp's avatar
...    
rhp committed
974

rhp's avatar
...    
rhp committed
975
  meta_window_grab_keys (window);
976
  if (window->type != META_WINDOW_DOCK && !window->override_redirect)
977
978
979
980
    {
      meta_display_grab_window_buttons (window->display, window->xwindow);
      meta_display_grab_focus_window_button (window->display, window);
    }
981
982

  if (window->type == META_WINDOW_DESKTOP ||
983
984
      window->type == META_WINDOW_DOCK ||
      window->override_redirect)
985
986
987
988
989
990
991
992
    {
      /* Change the default, but don't enforce this if the user
       * focuses the dock/desktop and unsticks it using key shortcuts.
       * Need to set this before adding to the workspaces so the MRU
       * lists will be updated.
       */
      window->on_all_workspaces = TRUE;
    }
993

rhp's avatar
...    
rhp committed
994
995
996
997
  /* For the workspace, first honor hints,
   * if that fails put transients with parents,
   * otherwise put window on active space
   */
998

rhp's avatar
...    
rhp committed
999
1000
  if (window->initial_workspace_set)
    {
1001
      if (window->initial_workspace == (int) 0xFFFFFFFF)
1002
        {
1003
1004
1005
          meta_topic (META_DEBUG_PLACEMENT,
                      "Window %s is initially on all spaces\n",
                      window->desc);
1006

1007
1008
1009
	  /* need to set on_all_workspaces first so that it will be
	   * added to all the MRU lists
	   */
Rob Adams's avatar
Rob Adams committed
1010
          window->on_all_workspaces = TRUE;
1011
          meta_workspace_add_window (window->screen->active_workspace, window);
1012
1013
1014
        }
      else
        {
1015
1016
1017
1018
          meta_topic (META_DEBUG_PLACEMENT,
                      "Window %s is initially on space %d\n",
                      window->desc, window->initial_workspace);

1019
          space =
1020
1021
            meta_screen_get_workspace_by_index (window->screen,
                                                window->initial_workspace);
1022

1023
1024
1025
          if (space)
            meta_workspace_add_window (space, window);
        }
rhp's avatar
...    
rhp committed
1026
    }
1027

1028
1029
1030
1031
1032
1033
1034
  /* override-redirect windows are subtly different from other windows
   * with window->on_all_workspaces == TRUE. Other windows are part of
   * some workspace (so they can return to that if the flag is turned off),
   * but appear on other workspaces. override-redirect windows are part
   * of no workspace.
   */
  if (!window->override_redirect)
rhp's avatar
...    
rhp committed
1035
    {
1036
1037
1038
1039
1040
      if (window->workspace == NULL &&
          window->xtransient_for != None)
        {
          /* Try putting dialog on parent's workspace */
          MetaWindow *parent;
rhp's avatar
...    
rhp committed
1041

1042
1043
          parent = meta_display_lookup_x_window (window->display,
                                                 window->xtransient_for);
rhp's avatar
...    
rhp committed
1044

1045
1046
1047
1048
1049
          if (parent && parent->workspace)
            {
              meta_topic (META_DEBUG_PLACEMENT,
                          "Putting window %s on same workspace as parent %s\n",
                          window->desc, parent->desc);
1050

1051
1052
              if (parent->on_all_workspaces)
                window->on_all_workspaces = TRUE;
1053

1054
1055
1056
1057
              /* this will implicitly add to the appropriate MRU lists
               */
              meta_workspace_add_window (parent->workspace, window);
            }
rhp's avatar
...    
rhp committed
1058
        }
1059

1060
1061
1062
1063
1064
      if (window->workspace == NULL)
        {
          meta_topic (META_DEBUG_PLACEMENT,
                      "Putting window %s on active workspace\n",
                      window->desc);
1065

1066
          space = window->screen->active_workspace;
rhp's avatar
...    
rhp committed
1067

Owen W. Taylor's avatar