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

« back to all changes in this revision

Viewing changes to src/core/display.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 display handler */
 
4
 
 
5
/* 
 
6
 * Copyright (C) 2001 Havoc Pennington
 
7
 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
 
8
 * Copyright (C) 2003, 2004 Rob Adams
 
9
 * Copyright (C) 2004-2006 Elijah Newren
 
10
 * 
 
11
 * This program is free software; you can redistribute it and/or
 
12
 * modify it under the terms of the GNU General Public License as
 
13
 * published by the Free Software Foundation; either version 2 of the
 
14
 * License, or (at your option) any later version.
 
15
 *
 
16
 * This program is distributed in the hope that it will be useful, but
 
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
19
 * General Public License for more details.
 
20
 * 
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
24
 * 02111-1307, USA.
 
25
 */
 
26
 
 
27
/**
 
28
 * \file display.c Handles operations on an X display.
 
29
 *
 
30
 * The display is represented as a MetaDisplay struct.
 
31
 */
 
32
 
 
33
#include <config.h>
 
34
#include "display-private.h"
 
35
#include "util.h"
 
36
#include "main.h"
 
37
#include "screen-private.h"
 
38
#include "window-private.h"
 
39
#include "window-props.h"
 
40
#include "group-props.h"
 
41
#include "frame-private.h"
 
42
#include "errors.h"
 
43
#include "keybindings-private.h"
 
44
#include "prefs.h"
 
45
#include "resizepopup.h"
 
46
#include "xprops.h"
 
47
#include "workspace-private.h"
 
48
#include "bell.h"
 
49
#include "compositor.h"
 
50
#include <X11/Xatom.h>
 
51
#include <X11/cursorfont.h>
 
52
#ifdef HAVE_SOLARIS_XINERAMA
 
53
#include <X11/extensions/xinerama.h>
 
54
#endif
 
55
#ifdef HAVE_XFREE_XINERAMA
 
56
#include <X11/extensions/Xinerama.h>
 
57
#endif
 
58
#ifdef HAVE_RANDR
 
59
#include <X11/extensions/Xrandr.h>
 
60
#endif
 
61
#ifdef HAVE_SHAPE
 
62
#include <X11/extensions/shape.h>
 
63
#endif
 
64
#ifdef HAVE_XKB
 
65
#include <X11/XKBlib.h>
 
66
#endif
 
67
#ifdef HAVE_XCURSOR
 
68
#include <X11/Xcursor/Xcursor.h>
 
69
#endif
 
70
#include <X11/extensions/Xrender.h>
 
71
#include <X11/extensions/Xcomposite.h>
 
72
#include <X11/extensions/Xdamage.h>
 
73
#include <X11/extensions/Xfixes.h>
 
74
#include <string.h>
 
75
 
 
76
#define GRAB_OP_IS_WINDOW_SWITCH(g)                     \
 
77
        (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL  ||  \
 
78
         g == META_GRAB_OP_KEYBOARD_TABBING_DOCK    ||  \
 
79
         g == META_GRAB_OP_KEYBOARD_TABBING_GROUP   ||  \
 
80
         g == META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL ||  \
 
81
         g == META_GRAB_OP_KEYBOARD_ESCAPING_DOCK   ||  \
 
82
         g == META_GRAB_OP_KEYBOARD_ESCAPING_GROUP)
 
83
 
 
84
/**
 
85
 * \defgroup pings Pings
 
86
 *
 
87
 * Sometimes we want to see whether a window is responding,
 
88
 * so we send it a "ping" message and see whether it sends us back a "pong"
 
89
 * message within a reasonable time. Here we have a system which lets us
 
90
 * nominate one function to be called if we get the pong in time and another
 
91
 * function if we don't. The system is rather more complicated than it needs
 
92
 * to be, since we only ever use it to destroy windows which are asked to
 
93
 * close themselves and don't do so within a reasonable amount of time, and
 
94
 * therefore we always use the same callbacks. It's possible that we might
 
95
 * use it for other things in future, or on the other hand we might decide
 
96
 * that we're never going to do so and simplify it a bit.
 
97
 */
 
98
 
 
99
/**
 
100
 * Describes a ping on a window. When we send a ping to a window, we build
 
101
 * one of these structs, and it eventually gets passed to the timeout function
 
102
 * or to the function which handles the response from the window. If the window
 
103
 * does or doesn't respond to the ping, we use this information to deal with
 
104
 * these facts; we have a handler function for each.
 
105
 *
 
106
 * \ingroup pings
 
107
 */
 
108
typedef struct 
 
109
{
 
110
  MetaDisplay *display;
 
111
  Window       xwindow;
 
112
  guint32      timestamp;
 
113
  MetaWindowPingFunc ping_reply_func;
 
114
  MetaWindowPingFunc ping_timeout_func;
 
115
  void        *user_data;
 
116
  guint        ping_timeout_id;
 
117
} MetaPingData;
 
118
 
 
119
typedef struct 
 
120
{
 
121
  MetaDisplay *display;
 
122
  Window xwindow;
 
123
} MetaAutoRaiseData;
 
124
 
 
125
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
 
126
 
 
127
/* Signals */
 
128
enum
 
129
{
 
130
  OVERLAY_KEY,
 
131
  LAST_SIGNAL
 
132
};
 
133
 
 
134
static guint display_signals [LAST_SIGNAL] = { 0 };
 
135
 
 
136
/**
 
137
 * The display we're managing.  This is a singleton object.  (Historically,
 
138
 * this was a list of displays, but there was never any way to add more
 
139
 * than one element to it.)  The goofy name is because we don't want it
 
140
 * to shadow the parameter in its object methods.
 
141
 */
 
142
static MetaDisplay *the_display = NULL;
 
143
 
 
144
static void   meta_spew_event           (MetaDisplay    *display,
 
145
                                         XEvent         *event);
 
146
 
 
147
static gboolean event_callback          (XEvent         *event,
 
148
                                         gpointer        data);
 
149
static Window event_get_modified_window (MetaDisplay    *display,
 
150
                                         XEvent         *event);
 
151
static guint32 event_get_time           (MetaDisplay    *display,
 
152
                                         XEvent         *event);
 
153
static void    process_request_frame_extents (MetaDisplay    *display,
 
154
                                              XEvent         *event);
 
155
static void    process_pong_message     (MetaDisplay    *display,
 
156
                                         XEvent         *event);
 
157
static void    process_selection_request (MetaDisplay   *display,
 
158
                                          XEvent        *event);
 
159
static void    process_selection_clear   (MetaDisplay   *display,
 
160
                                          XEvent        *event);
 
161
 
 
162
static void    update_window_grab_modifiers (MetaDisplay *display);
 
163
 
 
164
static void    prefs_changed_callback    (MetaPreference pref,
 
165
                                          void          *data);
 
166
 
 
167
static void    sanity_check_timestamps   (MetaDisplay *display,
 
168
                                          guint32      known_good_timestamp);
 
169
 
 
170
MetaGroup*     get_focussed_group (MetaDisplay *display);
 
171
 
 
172
static void
 
173
meta_display_class_init (MetaDisplayClass *klass)
 
174
{
 
175
  display_signals[OVERLAY_KEY] =
 
176
    g_signal_new ("overlay-key",
 
177
                  G_TYPE_FROM_CLASS (klass),
 
178
                  G_SIGNAL_RUN_LAST,
 
179
                  0,
 
180
                  NULL, NULL,
 
181
                  g_cclosure_marshal_VOID__VOID,
 
182
                  G_TYPE_NONE, 0);  
 
183
}
 
184
 
 
185
/**
 
186
 * Destructor for MetaPingData structs. Will destroy the
 
187
 * event source for the struct as well.
 
188
 *
 
189
 * \ingroup pings
 
190
 */
 
191
static void
 
192
ping_data_free (MetaPingData *ping_data)
 
193
{
 
194
  /* Remove the timeout */
 
195
  if (ping_data->ping_timeout_id != 0)
 
196
    g_source_remove (ping_data->ping_timeout_id);
 
197
 
 
198
  g_free (ping_data);
 
199
}
 
200
 
 
201
/**
 
202
 * Frees every pending ping structure for the given X window on the
 
203
 * given display. This means that we also destroy the timeouts.
 
204
 *
 
205
 * \param display The display the window appears on
 
206
 * \param xwindow The X ID of the window whose pings we should remove
 
207
 *
 
208
 * \ingroup pings
 
209
 *
 
210
 */
 
211
static void
 
212
remove_pending_pings_for_window (MetaDisplay *display, Window xwindow)
 
213
{
 
214
  GSList *tmp;
 
215
  GSList *dead;
 
216
 
 
217
  /* could obviously be more efficient, don't care */
 
218
  
 
219
  /* build list to be removed */
 
220
  dead = NULL;
 
221
  for (tmp = display->pending_pings; tmp; tmp = tmp->next)
 
222
    {
 
223
      MetaPingData *ping_data = tmp->data;
 
224
 
 
225
      if (ping_data->xwindow == xwindow)
 
226
        dead = g_slist_prepend (dead, ping_data);
 
227
    }
 
228
 
 
229
  /* remove what we found */
 
230
  for (tmp = dead; tmp; tmp = tmp->next)
 
231
    {
 
232
      MetaPingData *ping_data = tmp->data;
 
233
 
 
234
      display->pending_pings = g_slist_remove (display->pending_pings, ping_data);
 
235
      ping_data_free (ping_data);
 
236
    }
 
237
 
 
238
  g_slist_free (dead);
 
239
}
 
240
 
 
241
 
 
242
#ifdef HAVE_STARTUP_NOTIFICATION
 
243
static void
 
244
sn_error_trap_push (SnDisplay *sn_display,
 
245
                    Display   *xdisplay)
 
246
{
 
247
  MetaDisplay *display;
 
248
  display = meta_display_for_x_display (xdisplay);
 
249
  if (display != NULL)
 
250
    meta_error_trap_push (display);
 
251
}
 
252
 
 
253
static void
 
254
sn_error_trap_pop (SnDisplay *sn_display,
 
255
                   Display   *xdisplay)
 
256
{
 
257
  MetaDisplay *display;
 
258
  display = meta_display_for_x_display (xdisplay);
 
259
  if (display != NULL)
 
260
    meta_error_trap_pop (display, FALSE);
 
261
}
 
262
#endif
 
263
 
 
264
static void
 
265
enable_compositor (MetaDisplay *display,
 
266
                   gboolean     composite_windows)
 
267
{
 
268
  GSList *list;
 
269
 
 
270
  if (!META_DISPLAY_HAS_COMPOSITE (display) ||
 
271
      !META_DISPLAY_HAS_DAMAGE (display) ||
 
272
      !META_DISPLAY_HAS_XFIXES (display) ||
 
273
      !META_DISPLAY_HAS_RENDER (display))
 
274
    {
 
275
      meta_warning (_("Missing %s extension required for compositing"),
 
276
                    !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" :
 
277
                    !META_DISPLAY_HAS_DAMAGE (display) ? "damage" :
 
278
                    !META_DISPLAY_HAS_XFIXES (display) ? "xfixes" : "render");
 
279
      return;
 
280
    }
 
281
 
 
282
  if (!display->compositor)
 
283
      display->compositor = meta_compositor_new (display);
 
284
 
 
285
  if (!display->compositor)
 
286
    return;
 
287
  
 
288
  for (list = display->screens; list != NULL; list = list->next)
 
289
    {
 
290
      MetaScreen *screen = list->data;
 
291
      
 
292
      meta_compositor_manage_screen (screen->display->compositor,
 
293
                                     screen);
 
294
 
 
295
      if (composite_windows)
 
296
        meta_screen_composite_all_windows (screen);
 
297
    }
 
298
}
 
299
 
 
300
static void
 
301
disable_compositor (MetaDisplay *display)
 
302
{
 
303
  GSList *list;
 
304
  
 
305
  if (!display->compositor)
 
306
    return;
 
307
  
 
308
  for (list = display->screens; list != NULL; list = list->next)
 
309
    {
 
310
      MetaScreen *screen = list->data;
 
311
      
 
312
      meta_compositor_unmanage_screen (screen->display->compositor,
 
313
                                       screen);
 
314
    }
 
315
  
 
316
  meta_compositor_destroy (display->compositor);
 
317
  display->compositor = NULL;
 
318
}
 
319
 
 
320
static void
 
321
meta_display_init (MetaDisplay *disp)
 
322
{
 
323
  /* Some stuff could go in here that's currently in _open,
 
324
   * but it doesn't really matter. */
 
325
}
 
326
 
 
327
/**
 
328
 * Opens a new display, sets it up, initialises all the X extensions
 
329
 * we will need, and adds it to the list of displays.
 
330
 *
 
331
 * \return True if the display was opened successfully, and False
 
332
 * otherwise-- that is, if the display doesn't exist or it already
 
333
 * has a window manager.
 
334
 *
 
335
 * \ingroup main
 
336
 */
 
337
gboolean
 
338
meta_display_open (void)
 
339
{
 
340
  Display *xdisplay;
 
341
  GSList *screens;
 
342
  GSList *tmp;
 
343
  int i;
 
344
  guint32 timestamp;
 
345
 
 
346
  /* A list of all atom names, so that we can intern them in one go. */
 
347
  char *atom_names[] = {
 
348
#define item(x) #x,
 
349
#include "atomnames.h"
 
350
#undef item
 
351
  };
 
352
  Atom atoms[G_N_ELEMENTS(atom_names)];
 
353
  
 
354
  meta_verbose ("Opening display '%s'\n", XDisplayName (NULL));
 
355
 
 
356
  xdisplay = meta_ui_get_display ();
 
357
  
 
358
  if (xdisplay == NULL)
 
359
    {
 
360
      meta_warning (_("Failed to open X Window System display '%s'\n"),
 
361
                    XDisplayName (NULL));
 
362
      return FALSE;
 
363
    }
 
364
 
 
365
  if (meta_is_syncing ())
 
366
    XSynchronize (xdisplay, True);
 
367
  
 
368
  g_assert (the_display == NULL);
 
369
  the_display = g_object_new (META_TYPE_DISPLAY, NULL);
 
370
 
 
371
  the_display->closing = 0;
 
372
  
 
373
  /* here we use XDisplayName which is what the user
 
374
   * probably put in, vs. DisplayString(display) which is
 
375
   * canonicalized by XOpenDisplay()
 
376
   */
 
377
  the_display->name = g_strdup (XDisplayName (NULL));
 
378
  the_display->xdisplay = xdisplay;
 
379
  the_display->error_trap_synced_at_last_pop = TRUE;
 
380
  the_display->error_traps = 0;
 
381
  the_display->error_trap_handler = NULL;
 
382
  the_display->server_grab_count = 0;
 
383
  the_display->display_opening = TRUE;
 
384
 
 
385
  the_display->pending_pings = NULL;
 
386
  the_display->autoraise_timeout_id = 0;
 
387
  the_display->autoraise_window = NULL;
 
388
  the_display->focus_window = NULL;
 
389
  the_display->expected_focus_window = NULL;
 
390
  the_display->grab_old_window_stacking = NULL;
 
391
 
 
392
  the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
 
393
  the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
 
394
                                                  terminal has the focus */
 
395
 
 
396
#ifdef HAVE_XSYNC
 
397
  the_display->grab_sync_request_alarm = None;
 
398
#endif
 
399
  
 
400
  /* FIXME copy the checks from GDK probably */
 
401
  the_display->static_gravity_works = g_getenv ("MUTTER_USE_STATIC_GRAVITY") != NULL;
 
402
  
 
403
  meta_bell_init (the_display);
 
404
 
 
405
  meta_display_init_keys (the_display);
 
406
 
 
407
  update_window_grab_modifiers (the_display);
 
408
 
 
409
  meta_prefs_add_listener (prefs_changed_callback, the_display);
 
410
 
 
411
  meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names));
 
412
  XInternAtoms (the_display->xdisplay, atom_names, G_N_ELEMENTS (atom_names),
 
413
                False, atoms);
 
414
  {
 
415
    int i = 0;    
 
416
#define item(x) the_display->atom_##x = atoms[i++];
 
417
#include "atomnames.h"
 
418
#undef item
 
419
  }
 
420
 
 
421
  the_display->prop_hooks = NULL;
 
422
  meta_display_init_window_prop_hooks (the_display);
 
423
  the_display->group_prop_hooks = NULL;
 
424
  meta_display_init_group_prop_hooks (the_display);
 
425
  
 
426
  /* Offscreen unmapped window used for _NET_SUPPORTING_WM_CHECK,
 
427
   * created in screen_new
 
428
   */
 
429
  the_display->leader_window = None;
 
430
  the_display->timestamp_pinging_window = None;
 
431
 
 
432
  the_display->xinerama_cache_invalidated = TRUE;
 
433
 
 
434
  the_display->groups_by_leader = NULL;
 
435
 
 
436
  the_display->window_with_menu = NULL;
 
437
  the_display->window_menu = NULL;
 
438
  
 
439
  the_display->screens = NULL;
 
440
  the_display->active_screen = NULL;
 
441
  
 
442
#ifdef HAVE_STARTUP_NOTIFICATION
 
443
  the_display->sn_display = sn_display_new (the_display->xdisplay,
 
444
                                        sn_error_trap_push,
 
445
                                        sn_error_trap_pop);
 
446
#endif
 
447
  
 
448
  the_display->events = NULL;
 
449
 
 
450
  /* Get events */
 
451
  meta_ui_add_event_func (the_display->xdisplay,
 
452
                          event_callback,
 
453
                          the_display);
 
454
  
 
455
  the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash,
 
456
                                          meta_unsigned_long_equal);
 
457
  
 
458
  i = 0;
 
459
  while (i < N_IGNORED_SERIALS)
 
460
    {
 
461
      the_display->ignored_serials[i] = 0;
 
462
      ++i;
 
463
    }
 
464
  the_display->ungrab_should_not_cause_focus_window = None;
 
465
  
 
466
  the_display->current_time = CurrentTime;
 
467
  the_display->sentinel_counter = 0;
 
468
 
 
469
  the_display->grab_resize_timeout_id = 0;
 
470
  the_display->grab_have_keyboard = FALSE;
 
471
  
 
472
#ifdef HAVE_XKB  
 
473
  the_display->last_bell_time = 0;
 
474
#endif
 
475
 
 
476
  the_display->grab_op = META_GRAB_OP_NONE;
 
477
  the_display->grab_window = NULL;
 
478
  the_display->grab_screen = NULL;
 
479
  the_display->grab_resize_popup = NULL;
 
480
 
 
481
  the_display->grab_edge_resistance_data = NULL;
 
482
 
 
483
#ifdef HAVE_XSYNC
 
484
  {
 
485
    int major, minor;
 
486
 
 
487
    the_display->have_xsync = FALSE;
 
488
    
 
489
    the_display->xsync_error_base = 0;
 
490
    the_display->xsync_event_base = 0;
 
491
 
 
492
    /* I don't think we really have to fill these in */
 
493
    major = SYNC_MAJOR_VERSION;
 
494
    minor = SYNC_MINOR_VERSION;
 
495
    
 
496
    if (!XSyncQueryExtension (the_display->xdisplay,
 
497
                              &the_display->xsync_event_base,
 
498
                              &the_display->xsync_error_base) ||
 
499
        !XSyncInitialize (the_display->xdisplay,
 
500
                          &major, &minor))
 
501
      {
 
502
        the_display->xsync_error_base = 0;
 
503
        the_display->xsync_event_base = 0;
 
504
      }
 
505
    else
 
506
      the_display->have_xsync = TRUE;
 
507
    
 
508
    meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n",
 
509
                  major, minor,
 
510
                  the_display->xsync_error_base,
 
511
                  the_display->xsync_event_base);
 
512
  }
 
513
#else  /* HAVE_XSYNC */
 
514
  meta_verbose ("Not compiled with Xsync support\n");
 
515
#endif /* !HAVE_XSYNC */
 
516
 
 
517
 
 
518
#ifdef HAVE_SHAPE
 
519
  {
 
520
    the_display->have_shape = FALSE;
 
521
    
 
522
    the_display->shape_error_base = 0;
 
523
    the_display->shape_event_base = 0;
 
524
    
 
525
    if (!XShapeQueryExtension (the_display->xdisplay,
 
526
                               &the_display->shape_event_base,
 
527
                               &the_display->shape_error_base))
 
528
      {
 
529
        the_display->shape_error_base = 0;
 
530
        the_display->shape_event_base = 0;
 
531
      }
 
532
    else
 
533
      the_display->have_shape = TRUE;
 
534
    
 
535
    meta_verbose ("Attempted to init Shape, found error base %d event base %d\n",
 
536
                  the_display->shape_error_base,
 
537
                  the_display->shape_event_base);
 
538
  }
 
539
#else  /* HAVE_SHAPE */
 
540
  meta_verbose ("Not compiled with Shape support\n");
 
541
#endif /* !HAVE_SHAPE */
 
542
 
 
543
  {
 
544
    the_display->have_render = FALSE;
 
545
    
 
546
    the_display->render_error_base = 0;
 
547
    the_display->render_event_base = 0;
 
548
    
 
549
    if (!XRenderQueryExtension (the_display->xdisplay,
 
550
                                &the_display->render_event_base,
 
551
                                &the_display->render_error_base))
 
552
      {
 
553
        the_display->render_error_base = 0;
 
554
        the_display->render_event_base = 0;
 
555
      }
 
556
    else
 
557
      the_display->have_render = TRUE;
 
558
    
 
559
    meta_verbose ("Attempted to init Render, found error base %d event base %d\n",
 
560
                  the_display->render_error_base,
 
561
                  the_display->render_event_base);
 
562
  }
 
563
 
 
564
  {
 
565
    the_display->have_composite = FALSE;
 
566
 
 
567
    the_display->composite_error_base = 0;
 
568
    the_display->composite_event_base = 0;
 
569
 
 
570
    if (!XCompositeQueryExtension (the_display->xdisplay,
 
571
                                   &the_display->composite_event_base,
 
572
                                   &the_display->composite_error_base))
 
573
      {
 
574
        the_display->composite_error_base = 0;
 
575
        the_display->composite_event_base = 0;
 
576
      } 
 
577
    else
 
578
      {
 
579
        the_display->composite_major_version = 0;
 
580
        the_display->composite_minor_version = 0;
 
581
        if (XCompositeQueryVersion (the_display->xdisplay,
 
582
                                    &the_display->composite_major_version,
 
583
                                    &the_display->composite_minor_version))
 
584
          {
 
585
            the_display->have_composite = TRUE;
 
586
          }
 
587
        else
 
588
          {
 
589
            the_display->composite_major_version = 0;
 
590
            the_display->composite_minor_version = 0;
 
591
          }
 
592
      }
 
593
 
 
594
    meta_verbose ("Attempted to init Composite, found error base %d event base %d "
 
595
                  "extn ver %d %d\n",
 
596
                  the_display->composite_error_base, 
 
597
                  the_display->composite_event_base,
 
598
                  the_display->composite_major_version,
 
599
                  the_display->composite_minor_version);
 
600
 
 
601
    the_display->have_damage = FALSE;
 
602
 
 
603
    the_display->damage_error_base = 0;
 
604
    the_display->damage_event_base = 0;
 
605
 
 
606
    if (!XDamageQueryExtension (the_display->xdisplay,
 
607
                                &the_display->damage_event_base,
 
608
                                &the_display->damage_error_base))
 
609
      {
 
610
        the_display->damage_error_base = 0;
 
611
        the_display->damage_event_base = 0;
 
612
      } 
 
613
    else
 
614
      the_display->have_damage = TRUE;
 
615
 
 
616
    meta_verbose ("Attempted to init Damage, found error base %d event base %d\n",
 
617
                  the_display->damage_error_base, 
 
618
                  the_display->damage_event_base);
 
619
 
 
620
    the_display->have_xfixes = FALSE;
 
621
 
 
622
    the_display->xfixes_error_base = 0;
 
623
    the_display->xfixes_event_base = 0;
 
624
 
 
625
    if (!XFixesQueryExtension (the_display->xdisplay,
 
626
                               &the_display->xfixes_event_base,
 
627
                               &the_display->xfixes_error_base))
 
628
      {
 
629
        the_display->xfixes_error_base = 0;
 
630
        the_display->xfixes_event_base = 0;
 
631
      } 
 
632
    else
 
633
      the_display->have_xfixes = TRUE;
 
634
 
 
635
    meta_verbose ("Attempted to init XFixes, found error base %d event base %d\n",
 
636
                  the_display->xfixes_error_base, 
 
637
                  the_display->xfixes_event_base);
 
638
  }
 
639
      
 
640
#ifdef HAVE_XCURSOR
 
641
  {
 
642
    XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ());
 
643
    XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ());
 
644
  }
 
645
#else /* HAVE_XCURSOR */
 
646
  meta_verbose ("Not compiled with Xcursor support\n");
 
647
#endif /* !HAVE_XCURSOR */
 
648
 
 
649
  /* Create the leader window here. Set its properties and
 
650
   * use the timestamp from one of the PropertyNotify events
 
651
   * that will follow.
 
652
   */
 
653
  {
 
654
    gulong data[1];
 
655
    XEvent event;
 
656
 
 
657
    /* We only care about the PropertyChangeMask in the next 30 or so lines of
 
658
     * code.  Note that gdk will at some point unset the PropertyChangeMask for
 
659
     * this window, so we can't rely on it still being set later.  See bug
 
660
     * 354213 for details.
 
661
     */
 
662
    the_display->leader_window =
 
663
      meta_create_offscreen_window (the_display->xdisplay,
 
664
                                    DefaultRootWindow (the_display->xdisplay),
 
665
                                    PropertyChangeMask);
 
666
 
 
667
    meta_prop_set_utf8_string_hint (the_display,
 
668
                                    the_display->leader_window,
 
669
                                    the_display->atom__NET_WM_NAME,
 
670
                                    "Mutter");
 
671
    
 
672
    meta_prop_set_utf8_string_hint (the_display,
 
673
                                    the_display->leader_window,
 
674
                                    the_display->atom__MUTTER_VERSION,
 
675
                                    VERSION);
 
676
 
 
677
    data[0] = the_display->leader_window;
 
678
    XChangeProperty (the_display->xdisplay,
 
679
                     the_display->leader_window,
 
680
                     the_display->atom__NET_SUPPORTING_WM_CHECK,
 
681
                     XA_WINDOW,
 
682
                     32, PropModeReplace, (guchar*) data, 1);
 
683
 
 
684
    XWindowEvent (the_display->xdisplay,
 
685
                  the_display->leader_window,
 
686
                  PropertyChangeMask,
 
687
                  &event);
 
688
 
 
689
    timestamp = event.xproperty.time;
 
690
 
 
691
    /* Make it painfully clear that we can't rely on PropertyNotify events on
 
692
     * this window, as per bug 354213.
 
693
     */
 
694
    XSelectInput(the_display->xdisplay,
 
695
                 the_display->leader_window,
 
696
                 NoEventMask);
 
697
  }
 
698
 
 
699
  /* Make a little window used only for pinging the server for timestamps; note
 
700
   * that meta_create_offscreen_window already selects for PropertyChangeMask.
 
701
   */
 
702
  the_display->timestamp_pinging_window =
 
703
    meta_create_offscreen_window (the_display->xdisplay,
 
704
                                  DefaultRootWindow (the_display->xdisplay),
 
705
                                  PropertyChangeMask);
 
706
 
 
707
  the_display->last_focus_time = timestamp;
 
708
  the_display->last_user_time = timestamp;
 
709
  the_display->compositor = NULL;
 
710
  
 
711
  screens = NULL;
 
712
  
 
713
  i = 0;
 
714
  while (i < ScreenCount (xdisplay))
 
715
    {
 
716
      MetaScreen *screen;
 
717
 
 
718
      screen = meta_screen_new (the_display, i, timestamp);
 
719
 
 
720
      if (screen)
 
721
        screens = g_slist_prepend (screens, screen);
 
722
      ++i;
 
723
    }
 
724
  
 
725
  the_display->screens = screens;
 
726
  
 
727
  if (screens == NULL)
 
728
    {
 
729
      /* This would typically happen because all the screens already
 
730
       * have window managers.
 
731
       */
 
732
      meta_display_close (the_display, timestamp);
 
733
      return FALSE;
 
734
    }
 
735
 
 
736
  /* We don't composite the windows here because they will be composited 
 
737
     faster with the call to meta_screen_manage_all_windows further down 
 
738
     the code */
 
739
  if (1) /* meta_prefs_get_compositing_manager ()) FIXME */
 
740
    enable_compositor (the_display, FALSE);
 
741
   
 
742
  meta_display_grab (the_display);
 
743
  
 
744
  /* Now manage all existing windows */
 
745
  tmp = the_display->screens;
 
746
  while (tmp != NULL)
 
747
    {
 
748
      MetaScreen *screen = tmp->data;
 
749
        
 
750
      meta_screen_manage_all_windows (screen);
 
751
 
 
752
      tmp = tmp->next;
 
753
    }
 
754
 
 
755
  {
 
756
    Window focus;
 
757
    int ret_to;
 
758
 
 
759
    /* kinda bogus because GetInputFocus has no possible errors */
 
760
    meta_error_trap_push (the_display);
 
761
 
 
762
    /* FIXME: This is totally broken; see comment 9 of bug 88194 about this */
 
763
    focus = None;
 
764
    ret_to = RevertToPointerRoot;
 
765
    XGetInputFocus (the_display->xdisplay, &focus, &ret_to);
 
766
 
 
767
    /* Force a new FocusIn (does this work?) */
 
768
 
 
769
    /* Use the same timestamp that was passed to meta_screen_new(),
 
770
     * as it is the most recent timestamp.
 
771
     */
 
772
    if (focus == None || focus == PointerRoot)
 
773
      /* Just focus the no_focus_window on the first screen */
 
774
      meta_display_focus_the_no_focus_window (the_display,
 
775
                                              the_display->screens->data,
 
776
                                              timestamp);
 
777
    else
 
778
      {
 
779
        MetaWindow * window;
 
780
        window  = meta_display_lookup_x_window (the_display, focus);
 
781
        if (window)
 
782
          meta_display_set_input_focus_window (the_display, window, FALSE, timestamp);
 
783
        else
 
784
          /* Just focus the no_focus_window on the first screen */
 
785
          meta_display_focus_the_no_focus_window (the_display,
 
786
                                                  the_display->screens->data,
 
787
                                                  timestamp);
 
788
      }
 
789
 
 
790
    meta_error_trap_pop (the_display, FALSE);
 
791
  }
 
792
  
 
793
  meta_display_ungrab (the_display);  
 
794
 
 
795
  /* Done opening new display */
 
796
  the_display->display_opening = FALSE;
 
797
 
 
798
  return TRUE;
 
799
}
 
800
 
 
801
static gint
 
802
ptrcmp (gconstpointer a, gconstpointer b)
 
803
{
 
804
  if (a < b)
 
805
    return -1;
 
806
  else if (a > b)
 
807
    return 1;
 
808
  else
 
809
    return 0;
 
810
}
 
811
 
 
812
/**
 
813
 * meta_display_list_windows:
 
814
 * @display: a #MetaDisplay
 
815
 * @flags: options for listing
 
816
 *
 
817
 * Lists windows for the display, the @flags parameter for
 
818
 * now determines whether override-redirect windows will be
 
819
 * included.
 
820
 *
 
821
 * Return value: (transfer container): the list of windows.
 
822
 */
 
823
GSList*
 
824
meta_display_list_windows (MetaDisplay          *display,
 
825
                           MetaListWindowsFlags  flags)
 
826
{
 
827
  GSList *winlist;
 
828
  GSList *tmp;
 
829
  GSList *prev;
 
830
  GHashTableIter iter;
 
831
  gpointer key, value;
 
832
 
 
833
  winlist = NULL;
 
834
 
 
835
  g_hash_table_iter_init (&iter, display->window_ids);
 
836
  while (g_hash_table_iter_next (&iter, &key, &value))
 
837
    {
 
838
      MetaWindow *window = value;
 
839
 
 
840
      if (!window->override_redirect ||
 
841
          (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0)
 
842
        winlist = g_slist_prepend (winlist, window);
 
843
    }
 
844
 
 
845
  /* Uniquify the list, since both frame windows and plain
 
846
   * windows are in the hash
 
847
   */
 
848
  winlist = g_slist_sort (winlist, ptrcmp);
 
849
 
 
850
  prev = NULL;
 
851
  tmp = winlist;
 
852
  while (tmp != NULL)
 
853
    {
 
854
      GSList *next;
 
855
 
 
856
      next = tmp->next;
 
857
      
 
858
      if (next &&
 
859
          next->data == tmp->data)
 
860
        {
 
861
          /* Delete tmp from list */
 
862
 
 
863
          if (prev)
 
864
            prev->next = next;
 
865
 
 
866
          if (tmp == winlist)
 
867
            winlist = next;
 
868
          
 
869
          g_slist_free_1 (tmp);
 
870
 
 
871
          /* leave prev unchanged */
 
872
        }
 
873
      else
 
874
        {
 
875
          prev = tmp;
 
876
        }
 
877
      
 
878
      tmp = next;
 
879
    }
 
880
 
 
881
  return winlist;
 
882
}
 
883
 
 
884
void
 
885
meta_display_close (MetaDisplay *display,
 
886
                    guint32      timestamp)
 
887
{
 
888
  GSList *tmp;
 
889
 
 
890
  g_assert (display != NULL);
 
891
 
 
892
  if (display->closing != 0)
 
893
    {
 
894
      /* The display's already been closed. */
 
895
      return;
 
896
    }
 
897
 
 
898
  if (display->error_traps > 0)
 
899
    meta_bug ("Display closed with error traps pending\n");
 
900
 
 
901
  display->closing += 1;
 
902
 
 
903
  meta_prefs_remove_listener (prefs_changed_callback, display);
 
904
  
 
905
  meta_display_remove_autoraise_callback (display);
 
906
 
 
907
  if (display->grab_old_window_stacking)
 
908
    g_list_free (display->grab_old_window_stacking);
 
909
  
 
910
  /* Stop caring about events */
 
911
  meta_ui_remove_event_func (display->xdisplay,
 
912
                             event_callback,
 
913
                             display);
 
914
  
 
915
  /* Free all screens */
 
916
  tmp = display->screens;
 
917
  while (tmp != NULL)
 
918
    {
 
919
      MetaScreen *screen = tmp->data;
 
920
      meta_screen_free (screen, timestamp);
 
921
      tmp = tmp->next;
 
922
    }
 
923
 
 
924
  g_slist_free (display->screens);
 
925
  display->screens = NULL;
 
926
 
 
927
#ifdef HAVE_STARTUP_NOTIFICATION
 
928
  if (display->sn_display)
 
929
    {
 
930
      sn_display_unref (display->sn_display);
 
931
      display->sn_display = NULL;
 
932
    }
 
933
#endif
 
934
  
 
935
  /* Must be after all calls to meta_window_unmanage() since they
 
936
   * unregister windows
 
937
   */
 
938
  g_hash_table_destroy (display->window_ids);
 
939
 
 
940
  if (display->leader_window != None)
 
941
    XDestroyWindow (display->xdisplay, display->leader_window);
 
942
 
 
943
  XFlush (display->xdisplay);
 
944
 
 
945
  meta_display_free_window_prop_hooks (display);
 
946
  meta_display_free_group_prop_hooks (display);
 
947
  
 
948
  g_free (display->name);
 
949
 
 
950
  meta_display_shutdown_keys (display);
 
951
 
 
952
  if (display->compositor)
 
953
    meta_compositor_destroy (display->compositor);
 
954
  
 
955
  g_object_unref (display);
 
956
 
 
957
  meta_quit (META_EXIT_SUCCESS);
 
958
}
 
959
 
 
960
/**
 
961
 * meta_display_screen_for_root:
 
962
 * @display: a #MetaDisplay
 
963
 *
 
964
 * Return the #MetaScreen corresponding to a specified X root window ID.
 
965
 *
 
966
 * Return Value: (transfer none): the screen for the specified root window ID, or %NULL
 
967
 */
 
968
MetaScreen*
 
969
meta_display_screen_for_root (MetaDisplay *display,
 
970
                              Window       xroot)
 
971
{
 
972
  GSList *tmp;
 
973
 
 
974
  tmp = display->screens;
 
975
  while (tmp != NULL)
 
976
    {
 
977
      MetaScreen *screen = tmp->data;
 
978
 
 
979
      if (xroot == screen->xroot)
 
980
        return screen;
 
981
 
 
982
      tmp = tmp->next;
 
983
    }
 
984
 
 
985
  return NULL;
 
986
}
 
987
 
 
988
MetaScreen*
 
989
meta_display_screen_for_xwindow (MetaDisplay *display,
 
990
                                 Window       xwindow)
 
991
{
 
992
  XWindowAttributes attr;
 
993
  int result;
 
994
  
 
995
  meta_error_trap_push (display);
 
996
  attr.screen = NULL;
 
997
  result = XGetWindowAttributes (display->xdisplay, xwindow, &attr);
 
998
  meta_error_trap_pop (display, TRUE);
 
999
 
 
1000
  /* Note, XGetWindowAttributes is on all kinds of crack
 
1001
   * and returns 1 on success 0 on failure, rather than Success
 
1002
   * on success.
 
1003
   */
 
1004
  if (result == 0 || attr.screen == NULL)
 
1005
    return NULL;
 
1006
  
 
1007
  return meta_display_screen_for_x_screen (display, attr.screen);
 
1008
}
 
1009
 
 
1010
MetaScreen*
 
1011
meta_display_screen_for_x_screen (MetaDisplay *display,
 
1012
                                  Screen      *xscreen)
 
1013
{
 
1014
  GSList *tmp;
 
1015
 
 
1016
  tmp = display->screens;
 
1017
  while (tmp != NULL)
 
1018
    {
 
1019
      MetaScreen *screen = tmp->data;
 
1020
 
 
1021
      if (xscreen == screen->xscreen)
 
1022
        return screen;
 
1023
 
 
1024
      tmp = tmp->next;
 
1025
    }
 
1026
 
 
1027
  return NULL;
 
1028
}
 
1029
 
 
1030
/* Grab/ungrab routines taken from fvwm */
 
1031
void
 
1032
meta_display_grab (MetaDisplay *display)
 
1033
{
 
1034
  if (display->server_grab_count == 0)
 
1035
    {
 
1036
      XGrabServer (display->xdisplay);
 
1037
    }
 
1038
  display->server_grab_count += 1;
 
1039
  meta_verbose ("Grabbing display, grab count now %d\n",
 
1040
                display->server_grab_count);
 
1041
}
 
1042
 
 
1043
void
 
1044
meta_display_ungrab (MetaDisplay *display)
 
1045
{
 
1046
  if (display->server_grab_count == 0)
 
1047
    meta_bug ("Ungrabbed non-grabbed server\n");
 
1048
  
 
1049
  display->server_grab_count -= 1;
 
1050
  if (display->server_grab_count == 0)
 
1051
    {
 
1052
      /* FIXME we want to purge all pending "queued" stuff
 
1053
       * at this point, such as window hide/show
 
1054
       */
 
1055
      XUngrabServer (display->xdisplay);
 
1056
      XFlush (display->xdisplay);
 
1057
    }
 
1058
 
 
1059
  meta_verbose ("Ungrabbing display, grab count now %d\n",
 
1060
                display->server_grab_count);
 
1061
}
 
1062
 
 
1063
/**
 
1064
 * Returns the singleton MetaDisplay if "xdisplay" matches the X display it's
 
1065
 * managing; otherwise gives a warning and returns NULL.  When we were claiming
 
1066
 * to be able to manage multiple displays, this was supposed to find the
 
1067
 * display out of the list which matched that display.  Now it's merely an
 
1068
 * extra sanity check.
 
1069
 *
 
1070
 * \param xdisplay  An X display
 
1071
 * \return  The singleton X display, or NULL if "xdisplay" isn't the one
 
1072
 *          we're managing.
 
1073
 */
 
1074
MetaDisplay*
 
1075
meta_display_for_x_display (Display *xdisplay)
 
1076
{
 
1077
  if (the_display->xdisplay == xdisplay)
 
1078
    return the_display;
 
1079
 
 
1080
  meta_warning ("Could not find display for X display %p, probably going to crash\n",
 
1081
                xdisplay);
 
1082
  
 
1083
  return NULL;
 
1084
}
 
1085
 
 
1086
/**
 
1087
 * Accessor for the singleton MetaDisplay.
 
1088
 *
 
1089
 * \return  The only MetaDisplay there is.  This can be NULL, but only
 
1090
 *          during startup.
 
1091
 */
 
1092
MetaDisplay*
 
1093
meta_get_display (void)
 
1094
{
 
1095
  return the_display;
 
1096
}
 
1097
 
 
1098
#ifdef WITH_VERBOSE_MODE
 
1099
static gboolean dump_events = TRUE;
 
1100
#endif
 
1101
 
 
1102
static gboolean
 
1103
grab_op_is_mouse_only (MetaGrabOp op)
 
1104
{
 
1105
  switch (op)
 
1106
    {
 
1107
    case META_GRAB_OP_MOVING:
 
1108
    case META_GRAB_OP_RESIZING_SE:
 
1109
    case META_GRAB_OP_RESIZING_S:      
 
1110
    case META_GRAB_OP_RESIZING_SW:      
 
1111
    case META_GRAB_OP_RESIZING_N:
 
1112
    case META_GRAB_OP_RESIZING_NE:
 
1113
    case META_GRAB_OP_RESIZING_NW:
 
1114
    case META_GRAB_OP_RESIZING_W:
 
1115
    case META_GRAB_OP_RESIZING_E:
 
1116
      return TRUE;
 
1117
 
 
1118
    default:
 
1119
      return FALSE;
 
1120
    }
 
1121
}
 
1122
 
 
1123
static gboolean
 
1124
grab_op_is_mouse (MetaGrabOp op)
 
1125
{
 
1126
  switch (op)
 
1127
    {
 
1128
    case META_GRAB_OP_MOVING:
 
1129
    case META_GRAB_OP_RESIZING_SE:
 
1130
    case META_GRAB_OP_RESIZING_S:      
 
1131
    case META_GRAB_OP_RESIZING_SW:      
 
1132
    case META_GRAB_OP_RESIZING_N:
 
1133
    case META_GRAB_OP_RESIZING_NE:
 
1134
    case META_GRAB_OP_RESIZING_NW:
 
1135
    case META_GRAB_OP_RESIZING_W:
 
1136
    case META_GRAB_OP_RESIZING_E:
 
1137
    case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
 
1138
    case META_GRAB_OP_KEYBOARD_RESIZING_S:
 
1139
    case META_GRAB_OP_KEYBOARD_RESIZING_N:
 
1140
    case META_GRAB_OP_KEYBOARD_RESIZING_W:
 
1141
    case META_GRAB_OP_KEYBOARD_RESIZING_E:
 
1142
    case META_GRAB_OP_KEYBOARD_RESIZING_SE:
 
1143
    case META_GRAB_OP_KEYBOARD_RESIZING_NE:
 
1144
    case META_GRAB_OP_KEYBOARD_RESIZING_SW:
 
1145
    case META_GRAB_OP_KEYBOARD_RESIZING_NW:
 
1146
    case META_GRAB_OP_KEYBOARD_MOVING:
 
1147
      return TRUE;
 
1148
 
 
1149
    default:
 
1150
      return FALSE;
 
1151
    }
 
1152
}
 
1153
 
 
1154
static gboolean
 
1155
grab_op_is_keyboard (MetaGrabOp op)
 
1156
{
 
1157
  switch (op)
 
1158
    {
 
1159
    case META_GRAB_OP_KEYBOARD_MOVING:
 
1160
    case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
 
1161
    case META_GRAB_OP_KEYBOARD_RESIZING_S:
 
1162
    case META_GRAB_OP_KEYBOARD_RESIZING_N:
 
1163
    case META_GRAB_OP_KEYBOARD_RESIZING_W:
 
1164
    case META_GRAB_OP_KEYBOARD_RESIZING_E:
 
1165
    case META_GRAB_OP_KEYBOARD_RESIZING_SE:
 
1166
    case META_GRAB_OP_KEYBOARD_RESIZING_NE:
 
1167
    case META_GRAB_OP_KEYBOARD_RESIZING_SW:
 
1168
    case META_GRAB_OP_KEYBOARD_RESIZING_NW:
 
1169
    case META_GRAB_OP_KEYBOARD_TABBING_NORMAL:
 
1170
    case META_GRAB_OP_KEYBOARD_TABBING_DOCK:
 
1171
    case META_GRAB_OP_KEYBOARD_TABBING_GROUP:
 
1172
    case META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL:
 
1173
    case META_GRAB_OP_KEYBOARD_ESCAPING_DOCK:
 
1174
    case META_GRAB_OP_KEYBOARD_ESCAPING_GROUP:
 
1175
    case META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING:
 
1176
      return TRUE;
 
1177
 
 
1178
    default:
 
1179
      return FALSE;
 
1180
    }
 
1181
}
 
1182
 
 
1183
gboolean
 
1184
meta_grab_op_is_resizing (MetaGrabOp op)
 
1185
{
 
1186
  switch (op)
 
1187
    {
 
1188
    case META_GRAB_OP_RESIZING_SE:
 
1189
    case META_GRAB_OP_RESIZING_S:      
 
1190
    case META_GRAB_OP_RESIZING_SW:      
 
1191
    case META_GRAB_OP_RESIZING_N:
 
1192
    case META_GRAB_OP_RESIZING_NE:
 
1193
    case META_GRAB_OP_RESIZING_NW:
 
1194
    case META_GRAB_OP_RESIZING_W:
 
1195
    case META_GRAB_OP_RESIZING_E:
 
1196
    case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
 
1197
    case META_GRAB_OP_KEYBOARD_RESIZING_S:
 
1198
    case META_GRAB_OP_KEYBOARD_RESIZING_N:
 
1199
    case META_GRAB_OP_KEYBOARD_RESIZING_W:
 
1200
    case META_GRAB_OP_KEYBOARD_RESIZING_E:
 
1201
    case META_GRAB_OP_KEYBOARD_RESIZING_SE:
 
1202
    case META_GRAB_OP_KEYBOARD_RESIZING_NE:
 
1203
    case META_GRAB_OP_KEYBOARD_RESIZING_SW:
 
1204
    case META_GRAB_OP_KEYBOARD_RESIZING_NW:
 
1205
      return TRUE;
 
1206
 
 
1207
    default:
 
1208
      return FALSE;
 
1209
    }
 
1210
}
 
1211
 
 
1212
gboolean
 
1213
meta_grab_op_is_moving (MetaGrabOp op)
 
1214
{
 
1215
  switch (op)
 
1216
    {
 
1217
    case META_GRAB_OP_MOVING:
 
1218
    case META_GRAB_OP_KEYBOARD_MOVING:
 
1219
      return TRUE;
 
1220
      
 
1221
    default:
 
1222
      return FALSE;
 
1223
    }
 
1224
}
 
1225
 
 
1226
/* Get time of current event, or CurrentTime if none. */
 
1227
guint32
 
1228
meta_display_get_current_time (MetaDisplay *display)
 
1229
{
 
1230
  return display->current_time;
 
1231
}
 
1232
 
 
1233
/* Get a timestamp, even if it means a roundtrip */
 
1234
guint32
 
1235
meta_display_get_current_time_roundtrip (MetaDisplay *display)
 
1236
{
 
1237
  guint32 timestamp;
 
1238
  
 
1239
  timestamp = meta_display_get_current_time (display);
 
1240
  if (timestamp == CurrentTime)
 
1241
    {
 
1242
      XEvent property_event;
 
1243
 
 
1244
      /* Using the property XA_PRIMARY because it's safe; nothing
 
1245
       * would use it as a property. The type doesn't matter.
 
1246
       */
 
1247
      XChangeProperty (display->xdisplay,
 
1248
                       display->timestamp_pinging_window,
 
1249
                       XA_PRIMARY, XA_STRING, 8,
 
1250
                       PropModeAppend, NULL, 0);
 
1251
      XWindowEvent (display->xdisplay,
 
1252
                    display->timestamp_pinging_window,
 
1253
                    PropertyChangeMask,
 
1254
                    &property_event);
 
1255
      timestamp = property_event.xproperty.time;
 
1256
    }
 
1257
 
 
1258
  sanity_check_timestamps (display, timestamp);
 
1259
 
 
1260
  return timestamp;
 
1261
}
 
1262
 
 
1263
static void
 
1264
add_ignored_serial (MetaDisplay  *display,
 
1265
                    unsigned long serial)
 
1266
{
 
1267
  int i;
 
1268
 
 
1269
  /* don't add the same serial more than once */
 
1270
  if (display->ignored_serials[N_IGNORED_SERIALS-1] == serial)
 
1271
    return;
 
1272
  
 
1273
  /* shift serials to the left */
 
1274
  i = 0;
 
1275
  while (i < (N_IGNORED_SERIALS - 1))
 
1276
    {
 
1277
      display->ignored_serials[i] = display->ignored_serials[i+1];
 
1278
      ++i;
 
1279
    }
 
1280
  /* put new one on the end */
 
1281
  display->ignored_serials[i] = serial;
 
1282
}
 
1283
 
 
1284
static gboolean
 
1285
serial_is_ignored (MetaDisplay  *display,
 
1286
                   unsigned long serial)
 
1287
{
 
1288
  int i;
 
1289
 
 
1290
  i = 0;
 
1291
  while (i < N_IGNORED_SERIALS)
 
1292
    {
 
1293
      if (display->ignored_serials[i] == serial)
 
1294
        return TRUE;
 
1295
      ++i;
 
1296
    }
 
1297
  return FALSE;
 
1298
}
 
1299
 
 
1300
static void
 
1301
reset_ignores (MetaDisplay *display)
 
1302
{
 
1303
  int i;
 
1304
 
 
1305
  i = 0;
 
1306
  while (i < N_IGNORED_SERIALS)
 
1307
    {
 
1308
      display->ignored_serials[i] = 0;
 
1309
      ++i;
 
1310
    }
 
1311
 
 
1312
  display->ungrab_should_not_cause_focus_window = None;
 
1313
}
 
1314
 
 
1315
static gboolean 
 
1316
window_raise_with_delay_callback (void *data)
 
1317
{
 
1318
  MetaWindow *window;
 
1319
  MetaAutoRaiseData *auto_raise;
 
1320
 
 
1321
  auto_raise = data;
 
1322
 
 
1323
  meta_topic (META_DEBUG_FOCUS, 
 
1324
              "In autoraise callback for window 0x%lx\n", 
 
1325
              auto_raise->xwindow);
 
1326
 
 
1327
  auto_raise->display->autoraise_timeout_id = 0;
 
1328
  auto_raise->display->autoraise_window = NULL;
 
1329
 
 
1330
  window  = meta_display_lookup_x_window (auto_raise->display, 
 
1331
                                          auto_raise->xwindow);
 
1332
  
 
1333
  if (window == NULL) 
 
1334
    return FALSE;
 
1335
 
 
1336
  /* If we aren't already on top, check whether the pointer is inside
 
1337
   * the window and raise the window if so.
 
1338
   */      
 
1339
  if (meta_stack_get_top (window->screen->stack) != window) 
 
1340
    {
 
1341
      int x, y, root_x, root_y;
 
1342
      Window root, child;
 
1343
      unsigned int mask;
 
1344
      gboolean same_screen;
 
1345
      gboolean point_in_window;
 
1346
 
 
1347
      meta_error_trap_push (window->display);
 
1348
      same_screen = XQueryPointer (window->display->xdisplay,
 
1349
                                   window->xwindow,
 
1350
                                   &root, &child,
 
1351
                                   &root_x, &root_y, &x, &y, &mask);
 
1352
      meta_error_trap_pop (window->display, TRUE);
 
1353
 
 
1354
      point_in_window = 
 
1355
        (window->frame && POINT_IN_RECT (root_x, root_y, window->frame->rect)) ||
 
1356
        (window->frame == NULL && POINT_IN_RECT (root_x, root_y, window->rect));
 
1357
      if (same_screen && point_in_window)
 
1358
        meta_window_raise (window);
 
1359
      else
 
1360
        meta_topic (META_DEBUG_FOCUS, 
 
1361
                    "Pointer not inside window, not raising %s\n", 
 
1362
                    window->desc);
 
1363
    }
 
1364
 
 
1365
  return FALSE;
 
1366
}
 
1367
 
 
1368
void
 
1369
meta_display_queue_autoraise_callback (MetaDisplay *display,
 
1370
                                       MetaWindow  *window)
 
1371
{
 
1372
  MetaAutoRaiseData *auto_raise_data;
 
1373
 
 
1374
  meta_topic (META_DEBUG_FOCUS, 
 
1375
              "Queuing an autoraise timeout for %s with delay %d\n", 
 
1376
              window->desc, 
 
1377
              meta_prefs_get_auto_raise_delay ());
 
1378
  
 
1379
  auto_raise_data = g_new (MetaAutoRaiseData, 1);
 
1380
  auto_raise_data->display = window->display;
 
1381
  auto_raise_data->xwindow = window->xwindow;
 
1382
  
 
1383
  if (display->autoraise_timeout_id != 0)
 
1384
    g_source_remove (display->autoraise_timeout_id);
 
1385
 
 
1386
  display->autoraise_timeout_id = 
 
1387
    g_timeout_add_full (G_PRIORITY_DEFAULT,
 
1388
                        meta_prefs_get_auto_raise_delay (),
 
1389
                        window_raise_with_delay_callback,
 
1390
                        auto_raise_data,
 
1391
                        g_free);
 
1392
  display->autoraise_window = window;
 
1393
}
 
1394
 
 
1395
#if 0
 
1396
static void
 
1397
handle_net_restack_window (MetaDisplay* display,
 
1398
                           XEvent *event)
 
1399
{
 
1400
  MetaWindow *window;
 
1401
 
 
1402
  window = meta_display_lookup_x_window (display,
 
1403
                                         event->xclient.window);
 
1404
 
 
1405
  if (window)
 
1406
    {
 
1407
      /* FIXME: The EWMH includes a sibling for the restack request, but we
 
1408
       * (stupidly) don't currently support these types of raises.
 
1409
       *
 
1410
       * Also, unconditionally following these is REALLY stupid--we should
 
1411
       * combine this code with the stuff in
 
1412
       * meta_window_configure_request() which is smart about whether to
 
1413
       * follow the request or do something else (though not smart enough
 
1414
       * and is also too stupid to handle the sibling stuff).
 
1415
       */
 
1416
      switch (event->xclient.data.l[2])
 
1417
        {
 
1418
        case Above:
 
1419
          meta_window_raise (window);
 
1420
          break;
 
1421
        case Below:
 
1422
          meta_window_lower (window);
 
1423
          break;
 
1424
        case TopIf:
 
1425
        case BottomIf:
 
1426
        case Opposite:
 
1427
          break;          
 
1428
        }
 
1429
    }
 
1430
}
 
1431
#endif
 
1432
 
 
1433
/**
 
1434
 * This is the most important function in the whole program. It is the heart,
 
1435
 * it is the nexus, it is the Grand Central Station of Mutter's world.
 
1436
 * When we create a MetaDisplay, we ask GDK to pass *all* events for *all*
 
1437
 * windows to this function. So every time anything happens that we might
 
1438
 * want to know about, this function gets called. You see why it gets a bit
 
1439
 * busy around here. Most of this function is a ginormous switch statement
 
1440
 * dealing with all the kinds of events that might turn up.
 
1441
 *
 
1442
 * \param event The event that just happened
 
1443
 * \param data  The MetaDisplay that events are coming from, cast to a gpointer
 
1444
 *              so that it can be sent to a callback
 
1445
 *
 
1446
 * \ingroup main
 
1447
 */
 
1448
static gboolean
 
1449
event_callback (XEvent   *event,
 
1450
                gpointer  data)
 
1451
{
 
1452
  MetaWindow *window;
 
1453
  MetaWindow *property_for_window;
 
1454
  MetaDisplay *display;
 
1455
  Window modified;
 
1456
  gboolean frame_was_receiver;
 
1457
  gboolean filter_out_event;
 
1458
 
 
1459
  display = data;
 
1460
  
 
1461
#ifdef WITH_VERBOSE_MODE
 
1462
  if (dump_events)
 
1463
    meta_spew_event (display, event);
 
1464
#endif
 
1465
 
 
1466
#ifdef HAVE_STARTUP_NOTIFICATION
 
1467
  sn_display_process_event (display->sn_display, event);
 
1468
#endif
 
1469
  
 
1470
  filter_out_event = FALSE;
 
1471
  display->current_time = event_get_time (display, event);
 
1472
  display->xinerama_cache_invalidated = TRUE;
 
1473
  
 
1474
  modified = event_get_modified_window (display, event);
 
1475
  
 
1476
  if (event->type == UnmapNotify)
 
1477
    {
 
1478
      if (meta_ui_window_should_not_cause_focus (display->xdisplay,
 
1479
                                                 modified))
 
1480
        {
 
1481
          add_ignored_serial (display, event->xany.serial);
 
1482
          meta_topic (META_DEBUG_FOCUS,
 
1483
                      "Adding EnterNotify serial %lu to ignored focus serials\n",
 
1484
                      event->xany.serial);
 
1485
        }
 
1486
    }
 
1487
  else if (event->type == LeaveNotify &&
 
1488
           event->xcrossing.mode == NotifyUngrab &&
 
1489
           modified == display->ungrab_should_not_cause_focus_window)
 
1490
    {
 
1491
      add_ignored_serial (display, event->xany.serial);
 
1492
      meta_topic (META_DEBUG_FOCUS,
 
1493
                  "Adding LeaveNotify serial %lu to ignored focus serials\n",
 
1494
                  event->xany.serial);
 
1495
    }
 
1496
 
 
1497
  if (modified != None)
 
1498
    window = meta_display_lookup_x_window (display, modified);
 
1499
  else
 
1500
    window = NULL;
 
1501
 
 
1502
  /* We only want to respond to _NET_WM_USER_TIME property notify
 
1503
   * events on _NET_WM_USER_TIME_WINDOW windows; in particular,
 
1504
   * responding to UnmapNotify events is kind of bad.
 
1505
   */
 
1506
  property_for_window = NULL;
 
1507
  if (window && modified == window->user_time_window)
 
1508
    {
 
1509
      property_for_window = window;
 
1510
      window = NULL;
 
1511
    }
 
1512
    
 
1513
 
 
1514
  frame_was_receiver = FALSE;
 
1515
  if (window &&
 
1516
      window->frame &&
 
1517
      modified == window->frame->xwindow)
 
1518
    {
 
1519
      /* Note that if the frame and the client both have an
 
1520
       * XGrabButton (as is normal with our setup), the event
 
1521
       * goes to the frame.
 
1522
       */
 
1523
      frame_was_receiver = TRUE;
 
1524
      meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n",
 
1525
                  window->desc);
 
1526
    }
 
1527
 
 
1528
#ifdef HAVE_XSYNC
 
1529
  if (META_DISPLAY_HAS_XSYNC (display) && 
 
1530
      event->type == (display->xsync_event_base + XSyncAlarmNotify) &&
 
1531
      ((XSyncAlarmNotifyEvent*)event)->alarm == display->grab_sync_request_alarm)
 
1532
    {
 
1533
      filter_out_event = TRUE; /* GTK doesn't want to see this really */
 
1534
      
 
1535
      if (display->grab_op != META_GRAB_OP_NONE &&
 
1536
          display->grab_window != NULL &&
 
1537
          grab_op_is_mouse (display->grab_op))
 
1538
        meta_window_handle_mouse_grab_op_event (display->grab_window, event);
 
1539
    }
 
1540
#endif /* HAVE_XSYNC */
 
1541
 
 
1542
#ifdef HAVE_SHAPE
 
1543
  if (META_DISPLAY_HAS_SHAPE (display) && 
 
1544
      event->type == (display->shape_event_base + ShapeNotify))
 
1545
    {
 
1546
      filter_out_event = TRUE; /* GTK doesn't want to see this really */
 
1547
      
 
1548
      if (window && !frame_was_receiver)
 
1549
        {
 
1550
          XShapeEvent *sev = (XShapeEvent*) event;
 
1551
 
 
1552
          if (sev->kind == ShapeBounding)
 
1553
            {
 
1554
              if (sev->shaped && !window->has_shape)
 
1555
                {
 
1556
                  window->has_shape = TRUE;                  
 
1557
                  meta_topic (META_DEBUG_SHAPES,
 
1558
                              "Window %s now has a shape\n",
 
1559
                              window->desc);
 
1560
                }
 
1561
              else if (!sev->shaped && window->has_shape)
 
1562
                {
 
1563
                  window->has_shape = FALSE;
 
1564
                  meta_topic (META_DEBUG_SHAPES,
 
1565
                              "Window %s no longer has a shape\n",
 
1566
                              window->desc);
 
1567
                }
 
1568
              else
 
1569
                {
 
1570
                  meta_topic (META_DEBUG_SHAPES,
 
1571
                              "Window %s shape changed\n",
 
1572
                              window->desc);
 
1573
                }
 
1574
 
 
1575
              if (window->frame)
 
1576
                {
 
1577
                  window->frame->need_reapply_frame_shape = TRUE;
 
1578
                  meta_warning("from event callback\n");                  
 
1579
                  meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 
1580
                }
 
1581
            }
 
1582
        }
 
1583
      else
 
1584
        {
 
1585
          meta_topic (META_DEBUG_SHAPES,
 
1586
                      "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n",
 
1587
                      window ? window->desc : "(none)",
 
1588
                      frame_was_receiver);
 
1589
        }
 
1590
    }
 
1591
#endif /* HAVE_SHAPE */
 
1592
 
 
1593
  if (window && ((event->type == KeyPress) || (event->type == ButtonPress)))
 
1594
    {
 
1595
      if (CurrentTime == display->current_time)
 
1596
        {
 
1597
          /* We can't use missing (i.e. invalid) timestamps to set user time,
 
1598
           * nor do we want to use them to sanity check other timestamps.
 
1599
           * See bug 313490 for more details.
 
1600
           */
 
1601
          meta_warning ("Event has no timestamp! You may be using a broken "
 
1602
                        "program such as xse.  Please ask the authors of that "
 
1603
                        "program to fix it.\n");
 
1604
        }
 
1605
      else
 
1606
        {
 
1607
          meta_window_set_user_time (window, display->current_time);
 
1608
          sanity_check_timestamps (display, display->current_time);
 
1609
        }
 
1610
    }
 
1611
  
 
1612
  switch (event->type)
 
1613
    {
 
1614
    case KeyPress:
 
1615
    case KeyRelease:
 
1616
      meta_display_process_key_event (display, window, event);
 
1617
      break;
 
1618
    case ButtonPress:
 
1619
      if (event->xbutton.button == 4 || event->xbutton.button == 5)
 
1620
        {
 
1621
          if (display->compositor && window)
 
1622
            {
 
1623
              return meta_compositor_process_event (display->compositor,
 
1624
                                                    event,
 
1625
                                                    window);
 
1626
            }
 
1627
          else
 
1628
            return FALSE;
 
1629
        }
 
1630
      else if ((window &&
 
1631
           grab_op_is_mouse (display->grab_op) &&
 
1632
           display->grab_button != (int) event->xbutton.button &&
 
1633
           display->grab_window == window) ||
 
1634
          grab_op_is_keyboard (display->grab_op))
 
1635
        {
 
1636
          meta_topic (META_DEBUG_WINDOW_OPS,
 
1637
                      "Ending grab op %u on window %s due to button press\n",
 
1638
                      display->grab_op,
 
1639
                      (display->grab_window ?
 
1640
                       display->grab_window->desc : 
 
1641
                       "none"));
 
1642
          if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
 
1643
            {
 
1644
              MetaScreen *screen;
 
1645
              meta_topic (META_DEBUG_WINDOW_OPS, 
 
1646
                          "Syncing to old stack positions.\n");
 
1647
              screen = 
 
1648
                meta_display_screen_for_root (display, event->xany.window);
 
1649
 
 
1650
              if (screen!=NULL)
 
1651
                meta_stack_set_positions (screen->stack,
 
1652
                                          display->grab_old_window_stacking);
 
1653
            }
 
1654
          meta_display_end_grab_op (display,
 
1655
                                    event->xbutton.time);
 
1656
        }
 
1657
      else if (window && display->grab_op == META_GRAB_OP_NONE)
 
1658
        {
 
1659
          gboolean begin_move = FALSE;
 
1660
          unsigned int grab_mask;
 
1661
          gboolean unmodified;
 
1662
 
 
1663
          grab_mask = display->window_grab_modifiers;
 
1664
          if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
 
1665
            grab_mask |= ControlMask;
 
1666
 
 
1667
          /* Two possible sources of an unmodified event; one is a
 
1668
           * client that's letting button presses pass through to the
 
1669
           * frame, the other is our focus_window_grab on unmodified
 
1670
           * button 1.  So for all such events we focus the window.
 
1671
           */
 
1672
          unmodified = (event->xbutton.state & grab_mask) == 0;
 
1673
          
 
1674
          if (unmodified ||
 
1675
              event->xbutton.button == 1)
 
1676
            {
 
1677
              /* don't focus if frame received, will be lowered in
 
1678
               * frames.c or special-cased if the click was on a
 
1679
               * minimize/close button.
 
1680
               */
 
1681
              if (!frame_was_receiver)
 
1682
                {
 
1683
                  if (meta_prefs_get_raise_on_click ()) 
 
1684
                    meta_window_raise (window);
 
1685
                  else
 
1686
                    meta_topic (META_DEBUG_FOCUS,
 
1687
                                "Not raising window on click due to don't-raise-on-click option\n");
 
1688
 
 
1689
                  /* Don't focus panels--they must explicitly request focus.
 
1690
                   * See bug 160470
 
1691
                   */
 
1692
                  if (window->type != META_WINDOW_DOCK)
 
1693
                    {
 
1694
                      meta_topic (META_DEBUG_FOCUS,
 
1695
                                  "Focusing %s due to unmodified button %u press (display.c)\n",
 
1696
                                  window->desc, event->xbutton.button);
 
1697
                      meta_window_focus (window, event->xbutton.time);
 
1698
                    }
 
1699
                  else
 
1700
                    /* However, do allow terminals to lose focus due to new
 
1701
                     * window mappings after the user clicks on a panel.
 
1702
                     */
 
1703
                    display->allow_terminal_deactivation = TRUE;
 
1704
                }
 
1705
              
 
1706
              /* you can move on alt-click but not on
 
1707
               * the click-to-focus
 
1708
               */
 
1709
              if (!unmodified)
 
1710
                begin_move = TRUE;
 
1711
            }
 
1712
          else if (!unmodified && event->xbutton.button == meta_prefs_get_mouse_button_resize())
 
1713
            {
 
1714
              if (window->has_resize_func)
 
1715
                {
 
1716
                  gboolean north, south;
 
1717
                  gboolean west, east;
 
1718
                  int root_x, root_y;
 
1719
                  MetaGrabOp op;
 
1720
 
 
1721
                  meta_window_get_position (window, &root_x, &root_y);
 
1722
 
 
1723
                  west = event->xbutton.x_root <  (root_x + 1 * window->rect.width  / 3);
 
1724
                  east = event->xbutton.x_root >  (root_x + 2 * window->rect.width  / 3);
 
1725
                  north = event->xbutton.y_root < (root_y + 1 * window->rect.height / 3);
 
1726
                  south = event->xbutton.y_root > (root_y + 2 * window->rect.height / 3);
 
1727
 
 
1728
                  if (north && west)
 
1729
                    op = META_GRAB_OP_RESIZING_NW;
 
1730
                  else if (north && east)
 
1731
                    op = META_GRAB_OP_RESIZING_NE;
 
1732
                  else if (south && west)
 
1733
                    op = META_GRAB_OP_RESIZING_SW;
 
1734
                  else if (south && east)
 
1735
                    op = META_GRAB_OP_RESIZING_SE;
 
1736
                  else if (north)
 
1737
                    op = META_GRAB_OP_RESIZING_N;
 
1738
                  else if (west)
 
1739
                    op = META_GRAB_OP_RESIZING_W;
 
1740
                  else if (east)
 
1741
                    op = META_GRAB_OP_RESIZING_E;
 
1742
                  else if (south)
 
1743
                    op = META_GRAB_OP_RESIZING_S;
 
1744
                  else /* Middle region is no-op to avoid user triggering wrong action */
 
1745
                    op = META_GRAB_OP_NONE;
 
1746
                  
 
1747
                  if (op != META_GRAB_OP_NONE)
 
1748
                    meta_display_begin_grab_op (display,
 
1749
                                                window->screen,
 
1750
                                                window,
 
1751
                                                op,
 
1752
                                                TRUE,
 
1753
                                                FALSE,
 
1754
                                                event->xbutton.button,
 
1755
                                                0,
 
1756
                                                event->xbutton.time,
 
1757
                                                event->xbutton.x_root,
 
1758
                                                event->xbutton.y_root);
 
1759
                }
 
1760
            }
 
1761
          else if (event->xbutton.button == meta_prefs_get_mouse_button_menu())
 
1762
            {
 
1763
              if (meta_prefs_get_raise_on_click ())
 
1764
                meta_window_raise (window);
 
1765
              meta_window_show_menu (window,
 
1766
                                     event->xbutton.x_root,
 
1767
                                     event->xbutton.y_root,
 
1768
                                     event->xbutton.button,
 
1769
                                     event->xbutton.time);
 
1770
            }
 
1771
 
 
1772
          if (!frame_was_receiver && unmodified)
 
1773
            {
 
1774
              /* This is from our synchronous grab since
 
1775
               * it has no modifiers and was on the client window
 
1776
               */
 
1777
              int mode;
 
1778
              
 
1779
              /* When clicking a different app in click-to-focus
 
1780
               * in application-based mode, and the different
 
1781
               * app is not a dock or desktop, eat the focus click.
 
1782
               */
 
1783
              if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK &&
 
1784
                  meta_prefs_get_application_based () &&
 
1785
                  !window->has_focus &&
 
1786
                  window->type != META_WINDOW_DOCK &&
 
1787
                  window->type != META_WINDOW_DESKTOP &&
 
1788
                  (display->focus_window == NULL ||
 
1789
                   !meta_window_same_application (window,
 
1790
                                                  display->focus_window)))
 
1791
                mode = AsyncPointer; /* eat focus click */
 
1792
              else
 
1793
                mode = ReplayPointer; /* give event back */
 
1794
 
 
1795
              meta_verbose ("Allowing events mode %s time %u\n",
 
1796
                            mode == AsyncPointer ? "AsyncPointer" : "ReplayPointer",
 
1797
                            (unsigned int)event->xbutton.time);
 
1798
              
 
1799
              XAllowEvents (display->xdisplay,
 
1800
                            mode, event->xbutton.time);
 
1801
            }
 
1802
 
 
1803
          if (begin_move && window->has_move_func)
 
1804
            {
 
1805
              meta_display_begin_grab_op (display,
 
1806
                                          window->screen,
 
1807
                                          window,
 
1808
                                          META_GRAB_OP_MOVING,
 
1809
                                          TRUE,
 
1810
                                          FALSE,
 
1811
                                          event->xbutton.button,
 
1812
                                          0,
 
1813
                                          event->xbutton.time,
 
1814
                                          event->xbutton.x_root,
 
1815
                                          event->xbutton.y_root);
 
1816
            }
 
1817
        }
 
1818
      break;
 
1819
    case ButtonRelease:
 
1820
      if (display->grab_window == window &&
 
1821
          grab_op_is_mouse (display->grab_op))
 
1822
        meta_window_handle_mouse_grab_op_event (window, event);
 
1823
      break;
 
1824
    case MotionNotify:
 
1825
      if (display->grab_window == window &&
 
1826
          grab_op_is_mouse (display->grab_op))
 
1827
        meta_window_handle_mouse_grab_op_event (window, event);
 
1828
      break;
 
1829
    case EnterNotify:
 
1830
      if (display->grab_window == window &&
 
1831
          grab_op_is_mouse (display->grab_op))
 
1832
        {
 
1833
          meta_window_handle_mouse_grab_op_event (window, event);
 
1834
          break;
 
1835
        }
 
1836
 
 
1837
      /* If the mouse switches screens, active the default window on the new
 
1838
       * screen; this will make keybindings and workspace-launched items
 
1839
       * actually appear on the right screen.
 
1840
       */
 
1841
      {
 
1842
        MetaScreen *new_screen = 
 
1843
          meta_display_screen_for_root (display, event->xcrossing.root);
 
1844
 
 
1845
        if (new_screen != NULL && display->active_screen != new_screen)
 
1846
          meta_workspace_focus_default_window (new_screen->active_workspace, 
 
1847
                                               NULL,
 
1848
                                               event->xcrossing.time);
 
1849
      }
 
1850
 
 
1851
      /* Check if we've entered a window; do this even if window->has_focus to
 
1852
       * avoid races.
 
1853
       */
 
1854
      if (window && !serial_is_ignored (display, event->xany.serial) &&
 
1855
               event->xcrossing.mode != NotifyGrab && 
 
1856
               event->xcrossing.mode != NotifyUngrab &&
 
1857
               event->xcrossing.detail != NotifyInferior &&
 
1858
               meta_display_focus_sentinel_clear (display))
 
1859
        {
 
1860
          switch (meta_prefs_get_focus_mode ())
 
1861
            {
 
1862
            case META_FOCUS_MODE_SLOPPY:
 
1863
            case META_FOCUS_MODE_MOUSE:
 
1864
              display->mouse_mode = TRUE;
 
1865
              if (window->type != META_WINDOW_DOCK &&
 
1866
                  window->type != META_WINDOW_DESKTOP)
 
1867
                {
 
1868
                  meta_topic (META_DEBUG_FOCUS,
 
1869
                              "Focusing %s due to enter notify with serial %lu "
 
1870
                              "at time %lu, and setting display->mouse_mode to "
 
1871
                              "TRUE.\n",
 
1872
                              window->desc, 
 
1873
                              event->xany.serial,
 
1874
                              event->xcrossing.time);
 
1875
 
 
1876
                  meta_window_focus (window, event->xcrossing.time);
 
1877
 
 
1878
                  /* stop ignoring stuff */
 
1879
                  reset_ignores (display);
 
1880
                  
 
1881
                  if (meta_prefs_get_auto_raise ()) 
 
1882
                    {
 
1883
                      meta_display_queue_autoraise_callback (display, window);
 
1884
                    }
 
1885
                  else
 
1886
                    {
 
1887
                      meta_topic (META_DEBUG_FOCUS,
 
1888
                                  "Auto raise is disabled\n");                
 
1889
                    }
 
1890
                }
 
1891
              /* In mouse focus mode, we defocus when the mouse *enters*
 
1892
               * the DESKTOP window, instead of defocusing on LeaveNotify.
 
1893
               * This is because having the mouse enter override-redirect
 
1894
               * child windows unfortunately causes LeaveNotify events that
 
1895
               * we can't distinguish from the mouse actually leaving the
 
1896
               * toplevel window as we expect.  But, since we filter out
 
1897
               * EnterNotify events on override-redirect windows, this
 
1898
               * alternative mechanism works great.
 
1899
               */
 
1900
              if (window->type == META_WINDOW_DESKTOP &&
 
1901
                  meta_prefs_get_focus_mode() == META_FOCUS_MODE_MOUSE &&
 
1902
                  display->expected_focus_window != NULL)
 
1903
                {
 
1904
                  meta_topic (META_DEBUG_FOCUS,
 
1905
                              "Unsetting focus from %s due to mouse entering "
 
1906
                              "the DESKTOP window\n",
 
1907
                              display->expected_focus_window->desc);
 
1908
                  meta_display_focus_the_no_focus_window (display, 
 
1909
                                                          window->screen,
 
1910
                                                          event->xcrossing.time);
 
1911
                }
 
1912
              break;
 
1913
            case META_FOCUS_MODE_CLICK:
 
1914
              break;
 
1915
            }
 
1916
          
 
1917
          if (window->type == META_WINDOW_DOCK)
 
1918
            meta_window_raise (window);
 
1919
        }
 
1920
      break;
 
1921
    case LeaveNotify:
 
1922
      if (display->grab_window == window &&
 
1923
          grab_op_is_mouse (display->grab_op))
 
1924
        meta_window_handle_mouse_grab_op_event (window, event);
 
1925
      else if (window != NULL)
 
1926
        {
 
1927
          if (window->type == META_WINDOW_DOCK &&
 
1928
              event->xcrossing.mode != NotifyGrab &&
 
1929
              event->xcrossing.mode != NotifyUngrab &&
 
1930
              !window->has_focus)
 
1931
            meta_window_lower (window);
 
1932
        }
 
1933
      break;
 
1934
    case FocusIn:
 
1935
    case FocusOut:
 
1936
      if (window)
 
1937
        {
 
1938
          meta_window_notify_focus (window, event);
 
1939
        }
 
1940
      else if (meta_display_xwindow_is_a_no_focus_window (display,
 
1941
                                                          event->xany.window))
 
1942
        {
 
1943
          meta_topic (META_DEBUG_FOCUS,
 
1944
                      "Focus %s event received on no_focus_window 0x%lx "
 
1945
                      "mode %s detail %s\n",
 
1946
                      event->type == FocusIn ? "in" :
 
1947
                      event->type == FocusOut ? "out" :
 
1948
                      "???",
 
1949
                      event->xany.window,
 
1950
                      meta_event_mode_to_string (event->xfocus.mode),
 
1951
                      meta_event_detail_to_string (event->xfocus.detail));
 
1952
        }
 
1953
      else
 
1954
        {
 
1955
          MetaScreen *screen =
 
1956
                meta_display_screen_for_root(display,
 
1957
                                             event->xany.window);
 
1958
          if (screen == NULL)
 
1959
            break;
 
1960
 
 
1961
          meta_topic (META_DEBUG_FOCUS,
 
1962
                      "Focus %s event received on root window 0x%lx "
 
1963
                      "mode %s detail %s\n",
 
1964
                      event->type == FocusIn ? "in" :
 
1965
                      event->type == FocusOut ? "out" :
 
1966
                      "???",
 
1967
                      event->xany.window,
 
1968
                      meta_event_mode_to_string (event->xfocus.mode),
 
1969
                      meta_event_detail_to_string (event->xfocus.detail));
 
1970
          
 
1971
          if (event->type == FocusIn &&
 
1972
              event->xfocus.detail == NotifyDetailNone)
 
1973
            {
 
1974
              meta_topic (META_DEBUG_FOCUS, 
 
1975
                          "Focus got set to None, probably due to "
 
1976
                          "brain-damage in the X protocol (see bug "
 
1977
                          "125492).  Setting the default focus window.\n");
 
1978
              meta_workspace_focus_default_window (screen->active_workspace,
 
1979
                                                   NULL,
 
1980
                                                   meta_display_get_current_time_roundtrip (display));
 
1981
            }
 
1982
          else if (event->type == FocusIn &&
 
1983
              event->xfocus.mode == NotifyNormal &&
 
1984
              event->xfocus.detail == NotifyInferior)
 
1985
            {
 
1986
              meta_topic (META_DEBUG_FOCUS,
 
1987
                          "Focus got set to root window, probably due to "
 
1988
                          "gnome-session logout dialog usage (see bug "
 
1989
                          "153220).  Setting the default focus window.\n");
 
1990
              meta_workspace_focus_default_window (screen->active_workspace,
 
1991
                                                   NULL,
 
1992
                                                   meta_display_get_current_time_roundtrip (display));
 
1993
            }
 
1994
 
 
1995
        }
 
1996
      break;
 
1997
    case KeymapNotify:
 
1998
      break;
 
1999
    case Expose:
 
2000
      break;
 
2001
    case GraphicsExpose:
 
2002
      break;
 
2003
    case NoExpose:
 
2004
      break;
 
2005
    case VisibilityNotify:
 
2006
      break;
 
2007
    case CreateNotify:
 
2008
      {
 
2009
        MetaScreen *screen;
 
2010
 
 
2011
        screen = meta_display_screen_for_root (display,
 
2012
                                               event->xcreatewindow.parent);
 
2013
        if (screen)
 
2014
          meta_stack_tracker_create_event (screen->stack_tracker,
 
2015
                                           &event->xcreatewindow);
 
2016
      }
 
2017
      break;
 
2018
      
 
2019
    case DestroyNotify:
 
2020
      {
 
2021
        MetaScreen *screen;
 
2022
 
 
2023
        screen = meta_display_screen_for_root (display,
 
2024
                                               event->xdestroywindow.event);
 
2025
        if (screen)
 
2026
          meta_stack_tracker_destroy_event (screen->stack_tracker,
 
2027
                                            &event->xdestroywindow);
 
2028
      }
 
2029
      if (window)
 
2030
        {
 
2031
          /* FIXME: It sucks that DestroyNotify events don't come with
 
2032
           * a timestamp; could we do something better here?  Maybe X
 
2033
           * will change one day?
 
2034
           */
 
2035
          guint32 timestamp;
 
2036
          timestamp = meta_display_get_current_time_roundtrip (display);
 
2037
 
 
2038
          if (display->grab_op != META_GRAB_OP_NONE &&
 
2039
              display->grab_window == window)
 
2040
            meta_display_end_grab_op (display, timestamp);
 
2041
          
 
2042
          if (frame_was_receiver)
 
2043
            {
 
2044
              meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n",
 
2045
                            window->frame->xwindow);
 
2046
              meta_error_trap_push (display);
 
2047
              meta_window_destroy_frame (window->frame->window);
 
2048
              meta_error_trap_pop (display, FALSE);
 
2049
            }
 
2050
          else
 
2051
            {
 
2052
              /* Unmanage destroyed window */
 
2053
              meta_window_unmanage (window, timestamp);
 
2054
              window = NULL;
 
2055
            }
 
2056
        }
 
2057
      break;
 
2058
    case UnmapNotify:
 
2059
      if (window)
 
2060
        {
 
2061
          /* FIXME: It sucks that UnmapNotify events don't come with
 
2062
           * a timestamp; could we do something better here?  Maybe X
 
2063
           * will change one day?
 
2064
           */
 
2065
          guint32 timestamp;
 
2066
          timestamp = meta_display_get_current_time_roundtrip (display);
 
2067
 
 
2068
          if (display->grab_op != META_GRAB_OP_NONE &&
 
2069
              display->grab_window == window &&
 
2070
              ((window->frame == NULL) || !window->frame->mapped))
 
2071
            meta_display_end_grab_op (display, timestamp);
 
2072
      
 
2073
          if (!frame_was_receiver)
 
2074
            {
 
2075
              if (window->unmaps_pending == 0)
 
2076
                {
 
2077
                  meta_topic (META_DEBUG_WINDOW_STATE,
 
2078
                              "Window %s withdrawn\n",
 
2079
                              window->desc);
 
2080
 
 
2081
                  /* Unmanage withdrawn window */                 
 
2082
                  window->withdrawn = TRUE;
 
2083
                  meta_window_unmanage (window, timestamp);
 
2084
                  window = NULL;
 
2085
                }
 
2086
              else
 
2087
                {
 
2088
                  window->unmaps_pending -= 1;
 
2089
                  meta_topic (META_DEBUG_WINDOW_STATE,
 
2090
                              "Received pending unmap, %d now pending\n",
 
2091
                              window->unmaps_pending);
 
2092
                }
 
2093
            }
 
2094
 
 
2095
          /* Unfocus on UnmapNotify, do this after the possible
 
2096
           * window_free above so that window_free can see if window->has_focus
 
2097
           * and move focus to another window
 
2098
           */
 
2099
          if (window)
 
2100
            meta_window_notify_focus (window, event);
 
2101
        }
 
2102
      break;
 
2103
    case MapNotify:
 
2104
      /* NB: override redirect windows wont cause a map request so we
 
2105
       * watch out for map notifies against any root windows too if a
 
2106
       * compositor is enabled: */
 
2107
      if (display->compositor && window == NULL
 
2108
          && meta_display_screen_for_root (display, event->xmap.event))
 
2109
        {
 
2110
          window = meta_window_new (display, event->xmap.window,
 
2111
                                    FALSE);
 
2112
        }
 
2113
      break;
 
2114
    case MapRequest:
 
2115
      if (window == NULL)
 
2116
        {
 
2117
          window = meta_window_new (display, event->xmaprequest.window,
 
2118
                                    FALSE);
 
2119
        }
 
2120
      /* if frame was receiver it's some malicious send event or something */
 
2121
      else if (!frame_was_receiver && window)        
 
2122
        {
 
2123
          meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n",
 
2124
                        window->desc, window->mapped, window->minimized);
 
2125
          if (window->minimized)
 
2126
            {
 
2127
              meta_window_unminimize (window);
 
2128
              if (window->workspace != window->screen->active_workspace)
 
2129
                {
 
2130
                  meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n",
 
2131
                                window->mapped, window->minimized);
 
2132
                  meta_window_change_workspace (window,
 
2133
                                                window->screen->active_workspace);
 
2134
                }
 
2135
            }
 
2136
        }
 
2137
      break;
 
2138
    case ReparentNotify:
 
2139
      {
 
2140
        MetaScreen *screen;
 
2141
 
 
2142
        screen = meta_display_screen_for_root (display,
 
2143
                                               event->xconfigure.event);
 
2144
        if (screen)
 
2145
          {
 
2146
            if (screen)
 
2147
              meta_stack_tracker_reparent_event (screen->stack_tracker,
 
2148
                                                 &event->xreparent);
 
2149
          }
 
2150
      }
 
2151
      break;
 
2152
    case ConfigureNotify:
 
2153
      if (event->xconfigure.event != event->xconfigure.window)
 
2154
        {
 
2155
          MetaScreen *screen;
 
2156
 
 
2157
          screen = meta_display_screen_for_root (display,
 
2158
                                                 event->xconfigure.event);
 
2159
          if (screen)
 
2160
            meta_stack_tracker_configure_event (screen->stack_tracker,
 
2161
                                                &event->xconfigure);
 
2162
        }
 
2163
      if (window && window->override_redirect)
 
2164
        meta_window_configure_notify (window, &event->xconfigure);
 
2165
      else
 
2166
        /* Handle screen resize */
 
2167
        {
 
2168
          MetaScreen *screen;
 
2169
 
 
2170
          screen = meta_display_screen_for_root (display,
 
2171
                                                 event->xconfigure.window);
 
2172
 
 
2173
          if (screen != NULL)
 
2174
            {
 
2175
#ifdef HAVE_RANDR
 
2176
              /* do the resize the official way */
 
2177
              XRRUpdateConfiguration (event);
 
2178
#else
 
2179
              /* poke around in Xlib */
 
2180
              screen->xscreen->width   = event->xconfigure.width;
 
2181
              screen->xscreen->height  = event->xconfigure.height;
 
2182
#endif
 
2183
              
 
2184
              meta_screen_resize (screen, 
 
2185
                                  event->xconfigure.width,
 
2186
                                  event->xconfigure.height);
 
2187
            }
 
2188
        }
 
2189
      break;
 
2190
    case ConfigureRequest:
 
2191
      /* This comment and code is found in both twm and fvwm */
 
2192
      /*
 
2193
       * According to the July 27, 1988 ICCCM draft, we should ignore size and
 
2194
       * position fields in the WM_NORMAL_HINTS property when we map a window.
 
2195
       * Instead, we'll read the current geometry.  Therefore, we should respond
 
2196
       * to configuration requests for windows which have never been mapped.
 
2197
       */
 
2198
      if (window == NULL)
 
2199
        {
 
2200
          unsigned int xwcm;
 
2201
          XWindowChanges xwc;
 
2202
          
 
2203
          xwcm = event->xconfigurerequest.value_mask &
 
2204
            (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
 
2205
 
 
2206
          xwc.x = event->xconfigurerequest.x;
 
2207
          xwc.y = event->xconfigurerequest.y;
 
2208
          xwc.width = event->xconfigurerequest.width;
 
2209
          xwc.height = event->xconfigurerequest.height;
 
2210
          xwc.border_width = event->xconfigurerequest.border_width;
 
2211
 
 
2212
          meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n",
 
2213
                        xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
 
2214
          meta_error_trap_push (display);
 
2215
          XConfigureWindow (display->xdisplay, event->xconfigurerequest.window,
 
2216
                            xwcm, &xwc);
 
2217
          meta_error_trap_pop (display, FALSE);
 
2218
        }
 
2219
      else
 
2220
        {
 
2221
          if (!frame_was_receiver)
 
2222
            meta_window_configure_request (window, event);
 
2223
        }
 
2224
      break;
 
2225
    case GravityNotify:
 
2226
      break;
 
2227
    case ResizeRequest:
 
2228
      break;
 
2229
    case CirculateNotify:
 
2230
      break;
 
2231
    case CirculateRequest:
 
2232
      break;
 
2233
    case PropertyNotify:
 
2234
      {
 
2235
        MetaGroup *group;
 
2236
        MetaScreen *screen;
 
2237
        
 
2238
        if (window && !frame_was_receiver)
 
2239
          meta_window_property_notify (window, event);
 
2240
        else if (property_for_window && !frame_was_receiver)
 
2241
          meta_window_property_notify (property_for_window, event);
 
2242
 
 
2243
        group = meta_display_lookup_group (display,
 
2244
                                           event->xproperty.window);
 
2245
        if (group != NULL)
 
2246
          meta_group_property_notify (group, event);
 
2247
        
 
2248
        screen = NULL;
 
2249
        if (window == NULL &&
 
2250
            group == NULL) /* window/group != NULL means it wasn't a root window */
 
2251
          screen = meta_display_screen_for_root (display,
 
2252
                                                 event->xproperty.window);
 
2253
            
 
2254
        if (screen != NULL)
 
2255
          {
 
2256
            if (event->xproperty.atom ==
 
2257
                display->atom__NET_DESKTOP_LAYOUT)
 
2258
              meta_screen_update_workspace_layout (screen);
 
2259
            else if (event->xproperty.atom ==
 
2260
                     display->atom__NET_DESKTOP_NAMES)
 
2261
              meta_screen_update_workspace_names (screen);
 
2262
#if 0
 
2263
            else if (event->xproperty.atom ==
 
2264
                     display->atom__NET_RESTACK_WINDOW)
 
2265
              handle_net_restack_window (display, event);
 
2266
#endif
 
2267
 
 
2268
            /* we just use this property as a sentinel to avoid
 
2269
             * certain race conditions.  See the comment for the
 
2270
             * sentinel_counter variable declaration in display.h
 
2271
             */
 
2272
            if (event->xproperty.atom ==
 
2273
                display->atom__MUTTER_SENTINEL)
 
2274
              {
 
2275
                meta_display_decrement_focus_sentinel (display);
 
2276
              }
 
2277
          }
 
2278
      }
 
2279
      break;
 
2280
    case SelectionClear:
 
2281
      /* do this here instead of at end of function
 
2282
       * so we can return
 
2283
       */
 
2284
 
 
2285
      /* FIXME: Clearing display->current_time here makes no sense to
 
2286
       * me; who put this here and why?
 
2287
       */
 
2288
      display->current_time = CurrentTime;
 
2289
 
 
2290
      process_selection_clear (display, event);
 
2291
      /* Note that processing that may have resulted in
 
2292
       * closing the display... so return right away.
 
2293
       */
 
2294
      return FALSE;
 
2295
    case SelectionRequest:
 
2296
      process_selection_request (display, event);
 
2297
      break;
 
2298
    case SelectionNotify:
 
2299
      break;
 
2300
    case ColormapNotify:
 
2301
      if (window && !frame_was_receiver)
 
2302
        window->colormap = event->xcolormap.colormap;
 
2303
      break;
 
2304
    case ClientMessage:
 
2305
      if (window)
 
2306
        {
 
2307
          if (!frame_was_receiver)
 
2308
            meta_window_client_message (window, event);
 
2309
        }
 
2310
      else
 
2311
        {
 
2312
          MetaScreen *screen;
 
2313
 
 
2314
          screen = meta_display_screen_for_root (display,
 
2315
                                                 event->xclient.window);
 
2316
          
 
2317
          if (screen)
 
2318
            {
 
2319
              if (event->xclient.message_type ==
 
2320
                  display->atom__NET_CURRENT_DESKTOP)
 
2321
                {
 
2322
                  int space;
 
2323
                  MetaWorkspace *workspace;
 
2324
                  guint32 time;
 
2325
              
 
2326
                  space = event->xclient.data.l[0];
 
2327
                  time = event->xclient.data.l[1];
 
2328
              
 
2329
                  meta_verbose ("Request to change current workspace to %d with "
 
2330
                                "specified timestamp of %u\n",
 
2331
                                space, time);
 
2332
 
 
2333
                  workspace =
 
2334
                    meta_screen_get_workspace_by_index (screen,
 
2335
                                                        space);
 
2336
 
 
2337
                  /* Handle clients using the older version of the spec... */
 
2338
                  if (time == 0 && workspace)
 
2339
                    {
 
2340
                      meta_warning ("Received a NET_CURRENT_DESKTOP message "
 
2341
                                    "from a broken (outdated) client who sent "
 
2342
                                    "a 0 timestamp\n");
 
2343
                      time = meta_display_get_current_time_roundtrip (display);
 
2344
                    }
 
2345
 
 
2346
                  if (workspace)
 
2347
                    meta_workspace_activate (workspace, time);
 
2348
                  else
 
2349
                    meta_verbose ("Don't know about workspace %d\n", space);
 
2350
                }
 
2351
              else if (event->xclient.message_type ==
 
2352
                       display->atom__NET_NUMBER_OF_DESKTOPS)
 
2353
                {
 
2354
                  int num_spaces;
 
2355
              
 
2356
                  num_spaces = event->xclient.data.l[0];
 
2357
              
 
2358
                  meta_verbose ("Request to set number of workspaces to %d\n",
 
2359
                                num_spaces);
 
2360
 
 
2361
                  meta_prefs_set_num_workspaces (num_spaces);
 
2362
                }
 
2363
              else if (event->xclient.message_type ==
 
2364
                       display->atom__NET_SHOWING_DESKTOP)
 
2365
                {
 
2366
                  gboolean showing_desktop;
 
2367
                  guint32  timestamp;
 
2368
                  
 
2369
                  showing_desktop = event->xclient.data.l[0] != 0;
 
2370
                  /* FIXME: Braindead protocol doesn't have a timestamp */
 
2371
                  timestamp = meta_display_get_current_time_roundtrip (display);
 
2372
                  meta_verbose ("Request to %s desktop\n",
 
2373
                                showing_desktop ? "show" : "hide");
 
2374
                  
 
2375
                  if (showing_desktop)
 
2376
                    meta_screen_show_desktop (screen, timestamp);
 
2377
                  else
 
2378
                    {
 
2379
                      meta_screen_unshow_desktop (screen);
 
2380
                      meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp);
 
2381
                    }
 
2382
                }
 
2383
              else if (event->xclient.message_type ==
 
2384
                       display->atom__MUTTER_RESTART_MESSAGE)
 
2385
                {
 
2386
                  meta_verbose ("Received restart request\n");
 
2387
                  meta_restart ();
 
2388
                }
 
2389
              else if (event->xclient.message_type ==
 
2390
                       display->atom__MUTTER_RELOAD_THEME_MESSAGE)
 
2391
                {
 
2392
                  meta_verbose ("Received reload theme request\n");
 
2393
                  meta_ui_set_current_theme (meta_prefs_get_theme (),
 
2394
                                             TRUE);
 
2395
                  meta_display_retheme_all ();
 
2396
                }
 
2397
              else if (event->xclient.message_type ==
 
2398
                       display->atom__MUTTER_SET_KEYBINDINGS_MESSAGE)
 
2399
                {
 
2400
                  meta_verbose ("Received set keybindings request = %d\n",
 
2401
                                (int) event->xclient.data.l[0]);
 
2402
                  meta_set_keybindings_disabled (!event->xclient.data.l[0]);
 
2403
                }
 
2404
              else if (event->xclient.message_type ==
 
2405
                       display->atom__MUTTER_TOGGLE_VERBOSE)
 
2406
                {
 
2407
                  meta_verbose ("Received toggle verbose message\n");
 
2408
                  meta_set_verbose (!meta_is_verbose ());
 
2409
                }
 
2410
              else if (event->xclient.message_type ==
 
2411
                       display->atom_WM_PROTOCOLS) 
 
2412
                {
 
2413
                  meta_verbose ("Received WM_PROTOCOLS message\n");
 
2414
                  
 
2415
                  if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING)
 
2416
                    {
 
2417
                      process_pong_message (display, event);
 
2418
 
 
2419
                      /* We don't want ping reply events going into
 
2420
                       * the GTK+ event loop because gtk+ will treat
 
2421
                       * them as ping requests and send more replies.
 
2422
                       */
 
2423
                      filter_out_event = TRUE;
 
2424
                    }
 
2425
                }
 
2426
            }
 
2427
 
 
2428
          if (event->xclient.message_type ==
 
2429
              display->atom__NET_REQUEST_FRAME_EXTENTS)
 
2430
            {
 
2431
              meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n");
 
2432
              process_request_frame_extents (display, event);
 
2433
            }
 
2434
        }
 
2435
      break;
 
2436
    case MappingNotify:
 
2437
      {
 
2438
        gboolean ignore_current;
 
2439
 
 
2440
        ignore_current = FALSE;
 
2441
        
 
2442
        /* Check whether the next event is an identical MappingNotify
 
2443
         * event.  If it is, ignore the current event, we'll update
 
2444
         * when we get the next one.
 
2445
         */
 
2446
        if (XPending (display->xdisplay))
 
2447
          {
 
2448
            XEvent next_event;
 
2449
            
 
2450
            XPeekEvent (display->xdisplay, &next_event);
 
2451
            
 
2452
            if (next_event.type == MappingNotify &&
 
2453
                next_event.xmapping.request == event->xmapping.request)
 
2454
              ignore_current = TRUE;
 
2455
          }
 
2456
 
 
2457
        if (!ignore_current)
 
2458
          {
 
2459
            /* Let XLib know that there is a new keyboard mapping.
 
2460
             */
 
2461
            XRefreshKeyboardMapping (&event->xmapping);
 
2462
            meta_display_process_mapping_event (display, event);
 
2463
          }
 
2464
      }
 
2465
      break;
 
2466
    default:
 
2467
#ifdef HAVE_XKB
 
2468
      if (event->type == display->xkb_base_event_type) 
 
2469
        {
 
2470
          XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
 
2471
          
 
2472
          switch (xkb_ev->xkb_type)
 
2473
            {
 
2474
            case XkbBellNotify:
 
2475
              if (XSERVER_TIME_IS_BEFORE(display->last_bell_time,
 
2476
                                         xkb_ev->time - 1000))
 
2477
                {
 
2478
                  display->last_bell_time = xkb_ev->time;
 
2479
                  meta_bell_notify (display, xkb_ev);
 
2480
                }
 
2481
              break;
 
2482
            }
 
2483
        }
 
2484
#endif
 
2485
      break;
 
2486
    }
 
2487
 
 
2488
  if (display->compositor)
 
2489
    {
 
2490
      if (meta_compositor_process_event (display->compositor,
 
2491
                                         event,
 
2492
                                         window))
 
2493
        filter_out_event = TRUE;
 
2494
    }
 
2495
  
 
2496
  display->current_time = CurrentTime;
 
2497
  return filter_out_event;
 
2498
}
 
2499
 
 
2500
/* Return the window this has to do with, if any, rather
 
2501
 * than the frame or root window that was selecting
 
2502
 * for substructure
 
2503
 */
 
2504
static Window
 
2505
event_get_modified_window (MetaDisplay *display,
 
2506
                           XEvent *event)
 
2507
{
 
2508
  switch (event->type)
 
2509
    {
 
2510
    case KeyPress:
 
2511
    case KeyRelease:
 
2512
    case ButtonPress:
 
2513
    case ButtonRelease:
 
2514
    case MotionNotify:
 
2515
    case FocusIn:
 
2516
    case FocusOut:
 
2517
    case KeymapNotify:
 
2518
    case Expose:
 
2519
    case GraphicsExpose:
 
2520
    case NoExpose:
 
2521
    case VisibilityNotify:
 
2522
    case ResizeRequest:
 
2523
    case PropertyNotify:
 
2524
    case SelectionClear:
 
2525
    case SelectionRequest:
 
2526
    case SelectionNotify:
 
2527
    case ColormapNotify:
 
2528
    case ClientMessage:
 
2529
    case EnterNotify:
 
2530
    case LeaveNotify:
 
2531
      return event->xany.window;
 
2532
      
 
2533
    case CreateNotify:
 
2534
      return event->xcreatewindow.window;
 
2535
      
 
2536
    case DestroyNotify:
 
2537
      return event->xdestroywindow.window;
 
2538
 
 
2539
    case UnmapNotify:
 
2540
      return event->xunmap.window;
 
2541
 
 
2542
    case MapNotify:
 
2543
      return event->xmap.window;
 
2544
 
 
2545
    case MapRequest:
 
2546
      return event->xmaprequest.window;
 
2547
 
 
2548
    case ReparentNotify:
 
2549
     return event->xreparent.window;
 
2550
      
 
2551
    case ConfigureNotify:
 
2552
      return event->xconfigure.window;
 
2553
      
 
2554
    case ConfigureRequest:
 
2555
      return event->xconfigurerequest.window;
 
2556
 
 
2557
    case GravityNotify:
 
2558
      return event->xgravity.window;
 
2559
 
 
2560
    case CirculateNotify:
 
2561
      return event->xcirculate.window;
 
2562
 
 
2563
    case CirculateRequest:
 
2564
      return event->xcirculaterequest.window;
 
2565
 
 
2566
    case MappingNotify:
 
2567
      return None;
 
2568
 
 
2569
    default:
 
2570
#ifdef HAVE_SHAPE
 
2571
      if (META_DISPLAY_HAS_SHAPE (display) && 
 
2572
          event->type == (display->shape_event_base + ShapeNotify))
 
2573
        {
 
2574
          XShapeEvent *sev = (XShapeEvent*) event;
 
2575
          return sev->window;
 
2576
        }
 
2577
#endif
 
2578
 
 
2579
      return None;
 
2580
    }
 
2581
}
 
2582
 
 
2583
static guint32
 
2584
event_get_time (MetaDisplay *display,
 
2585
                XEvent      *event)
 
2586
{
 
2587
  switch (event->type)
 
2588
    {
 
2589
    case KeyPress:
 
2590
    case KeyRelease:
 
2591
      return event->xkey.time;
 
2592
      
 
2593
    case ButtonPress:
 
2594
    case ButtonRelease:
 
2595
      return event->xbutton.time;
 
2596
      
 
2597
    case MotionNotify:
 
2598
      return event->xmotion.time;
 
2599
 
 
2600
    case PropertyNotify:
 
2601
      return event->xproperty.time;
 
2602
 
 
2603
    case SelectionClear:
 
2604
    case SelectionRequest:
 
2605
    case SelectionNotify:
 
2606
      return event->xselection.time;
 
2607
 
 
2608
    case EnterNotify:
 
2609
    case LeaveNotify:
 
2610
      return event->xcrossing.time;
 
2611
 
 
2612
    case FocusIn:
 
2613
    case FocusOut:
 
2614
    case KeymapNotify:      
 
2615
    case Expose:
 
2616
    case GraphicsExpose:
 
2617
    case NoExpose:
 
2618
    case MapNotify:
 
2619
    case UnmapNotify:
 
2620
    case VisibilityNotify:
 
2621
    case ResizeRequest:
 
2622
    case ColormapNotify:
 
2623
    case ClientMessage:
 
2624
    case CreateNotify:
 
2625
    case DestroyNotify:
 
2626
    case MapRequest:
 
2627
    case ReparentNotify:
 
2628
    case ConfigureNotify:
 
2629
    case ConfigureRequest:
 
2630
    case GravityNotify:
 
2631
    case CirculateNotify:
 
2632
    case CirculateRequest:
 
2633
    case MappingNotify:
 
2634
    default:
 
2635
      return CurrentTime;
 
2636
    }
 
2637
}
 
2638
 
 
2639
#ifdef WITH_VERBOSE_MODE
 
2640
const char*
 
2641
meta_event_detail_to_string (int d)
 
2642
{
 
2643
  const char *detail = "???";
 
2644
  switch (d)
 
2645
    {
 
2646
      /* We are an ancestor in the A<->B focus change relationship */
 
2647
    case NotifyAncestor:
 
2648
      detail = "NotifyAncestor";
 
2649
      break;
 
2650
    case NotifyDetailNone:
 
2651
      detail = "NotifyDetailNone";
 
2652
      break;
 
2653
      /* We are a descendant in the A<->B focus change relationship */
 
2654
    case NotifyInferior:
 
2655
      detail = "NotifyInferior";
 
2656
      break;
 
2657
    case NotifyNonlinear:
 
2658
      detail = "NotifyNonlinear";
 
2659
      break;
 
2660
    case NotifyNonlinearVirtual:
 
2661
      detail = "NotifyNonlinearVirtual";
 
2662
      break;
 
2663
    case NotifyPointer:
 
2664
      detail = "NotifyPointer";
 
2665
      break;
 
2666
    case NotifyPointerRoot:
 
2667
      detail = "NotifyPointerRoot";
 
2668
      break;
 
2669
    case NotifyVirtual:
 
2670
      detail = "NotifyVirtual";
 
2671
      break;
 
2672
    }
 
2673
 
 
2674
  return detail;
 
2675
}
 
2676
#endif /* WITH_VERBOSE_MODE */
 
2677
 
 
2678
#ifdef WITH_VERBOSE_MODE
 
2679
const char*
 
2680
meta_event_mode_to_string (int m)
 
2681
{
 
2682
  const char *mode = "???";
 
2683
  switch (m)
 
2684
    {
 
2685
    case NotifyNormal:
 
2686
      mode = "NotifyNormal";
 
2687
      break;
 
2688
    case NotifyGrab:
 
2689
      mode = "NotifyGrab";
 
2690
      break;
 
2691
    case NotifyUngrab:
 
2692
      mode = "NotifyUngrab";
 
2693
      break;
 
2694
      /* not sure any X implementations are missing this, but
 
2695
       * it seems to be absent from some docs.
 
2696
       */
 
2697
#ifdef NotifyWhileGrabbed
 
2698
    case NotifyWhileGrabbed:
 
2699
      mode = "NotifyWhileGrabbed";
 
2700
      break;
 
2701
#endif
 
2702
    }
 
2703
 
 
2704
  return mode;
 
2705
}
 
2706
#endif /* WITH_VERBOSE_MODE */
 
2707
 
 
2708
#ifdef WITH_VERBOSE_MODE
 
2709
static const char*
 
2710
stack_mode_to_string (int mode)
 
2711
{
 
2712
  switch (mode)
 
2713
    {
 
2714
    case Above:
 
2715
      return "Above";
 
2716
    case Below:
 
2717
      return "Below";
 
2718
    case TopIf:
 
2719
      return "TopIf";
 
2720
    case BottomIf:
 
2721
      return "BottomIf";
 
2722
    case Opposite:
 
2723
      return "Opposite";      
 
2724
    }
 
2725
 
 
2726
  return "Unknown";
 
2727
}
 
2728
#endif /* WITH_VERBOSE_MODE */
 
2729
 
 
2730
#ifdef WITH_VERBOSE_MODE
 
2731
static char*
 
2732
key_event_description (Display *xdisplay,
 
2733
                       XEvent  *event)
 
2734
{
 
2735
  KeySym keysym;
 
2736
  const char *str;
 
2737
  
 
2738
  keysym = XKeycodeToKeysym (xdisplay, event->xkey.keycode, 0);  
 
2739
 
 
2740
  str = XKeysymToString (keysym);
 
2741
  
 
2742
  return g_strdup_printf ("Key '%s' state 0x%x", 
 
2743
                          str ? str : "none", event->xkey.state);
 
2744
}
 
2745
#endif /* WITH_VERBOSE_MODE */
 
2746
 
 
2747
#ifdef HAVE_XSYNC
 
2748
#ifdef WITH_VERBOSE_MODE
 
2749
static gint64
 
2750
sync_value_to_64 (const XSyncValue *value)
 
2751
{
 
2752
  gint64 v;
 
2753
 
 
2754
  v = XSyncValueLow32 (*value);
 
2755
  v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
 
2756
  
 
2757
  return v;
 
2758
}
 
2759
#endif /* WITH_VERBOSE_MODE */
 
2760
 
 
2761
#ifdef WITH_VERBOSE_MODE
 
2762
static const char*
 
2763
alarm_state_to_string (XSyncAlarmState state)
 
2764
{
 
2765
  switch (state)
 
2766
    {
 
2767
    case XSyncAlarmActive:
 
2768
      return "Active";
 
2769
    case XSyncAlarmInactive:
 
2770
      return "Inactive";
 
2771
    case XSyncAlarmDestroyed:
 
2772
      return "Destroyed";
 
2773
    default:
 
2774
      return "(unknown)";
 
2775
    }
 
2776
}
 
2777
#endif /* WITH_VERBOSE_MODE */
 
2778
 
 
2779
#endif /* HAVE_XSYNC */
 
2780
 
 
2781
#ifdef WITH_VERBOSE_MODE
 
2782
static void
 
2783
meta_spew_event (MetaDisplay *display,
 
2784
                 XEvent      *event)
 
2785
{
 
2786
  const char *name = NULL;
 
2787
  char *extra = NULL;
 
2788
  char *winname;
 
2789
  MetaScreen *screen;
 
2790
 
 
2791
  if (!meta_is_verbose())
 
2792
    return;
 
2793
  
 
2794
  /* filter overnumerous events */
 
2795
  if (event->type == Expose || event->type == MotionNotify ||
 
2796
      event->type == NoExpose)
 
2797
    return;
 
2798
      
 
2799
  switch (event->type)
 
2800
    {
 
2801
    case KeyPress:
 
2802
      name = "KeyPress";
 
2803
      extra = key_event_description (display->xdisplay, event);
 
2804
      break;
 
2805
    case KeyRelease:
 
2806
      name = "KeyRelease";
 
2807
      extra = key_event_description (display->xdisplay, event);
 
2808
      break;
 
2809
    case ButtonPress:
 
2810
      name = "ButtonPress";
 
2811
      extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d",
 
2812
                               event->xbutton.button,
 
2813
                               event->xbutton.state,
 
2814
                               event->xbutton.x,
 
2815
                               event->xbutton.y,
 
2816
                               event->xbutton.root,
 
2817
                               event->xbutton.same_screen);
 
2818
      break;
 
2819
    case ButtonRelease:
 
2820
      name = "ButtonRelease";
 
2821
      extra = g_strdup_printf ("button %u state 0x%x x %d y %d root 0x%lx same_screen %d",
 
2822
                               event->xbutton.button,
 
2823
                               event->xbutton.state,
 
2824
                               event->xbutton.x,
 
2825
                               event->xbutton.y,
 
2826
                               event->xbutton.root,
 
2827
                               event->xbutton.same_screen);
 
2828
      break;
 
2829
    case MotionNotify:
 
2830
      name = "MotionNotify";
 
2831
      extra = g_strdup_printf ("win: 0x%lx x: %d y: %d",
 
2832
                               event->xmotion.window,
 
2833
                               event->xmotion.x,
 
2834
                               event->xmotion.y);
 
2835
      break;
 
2836
    case EnterNotify:
 
2837
      name = "EnterNotify";
 
2838
      extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d",
 
2839
                               event->xcrossing.window,
 
2840
                               event->xcrossing.root,
 
2841
                               event->xcrossing.subwindow,
 
2842
                               meta_event_mode_to_string (event->xcrossing.mode),
 
2843
                               meta_event_detail_to_string (event->xcrossing.detail),
 
2844
                               event->xcrossing.focus,
 
2845
                               event->xcrossing.x,
 
2846
                               event->xcrossing.y);
 
2847
      break;
 
2848
    case LeaveNotify:
 
2849
      name = "LeaveNotify";
 
2850
      extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %s detail: %s focus: %d x: %d y: %d",
 
2851
                               event->xcrossing.window,
 
2852
                               event->xcrossing.root,
 
2853
                               event->xcrossing.subwindow,
 
2854
                               meta_event_mode_to_string (event->xcrossing.mode),
 
2855
                               meta_event_detail_to_string (event->xcrossing.detail),
 
2856
                               event->xcrossing.focus,
 
2857
                               event->xcrossing.x,
 
2858
                               event->xcrossing.y);
 
2859
      break;
 
2860
    case FocusIn:
 
2861
      name = "FocusIn";
 
2862
      extra = g_strdup_printf ("detail: %s mode: %s\n",
 
2863
                               meta_event_detail_to_string (event->xfocus.detail),
 
2864
                               meta_event_mode_to_string (event->xfocus.mode));
 
2865
      break;
 
2866
    case FocusOut:
 
2867
      name = "FocusOut";
 
2868
      extra = g_strdup_printf ("detail: %s mode: %s\n",
 
2869
                               meta_event_detail_to_string (event->xfocus.detail),
 
2870
                               meta_event_mode_to_string (event->xfocus.mode));
 
2871
      break;
 
2872
    case KeymapNotify:
 
2873
      name = "KeymapNotify";
 
2874
      break;
 
2875
    case Expose:
 
2876
      name = "Expose";
 
2877
      break;
 
2878
    case GraphicsExpose:
 
2879
      name = "GraphicsExpose";
 
2880
      break;
 
2881
    case NoExpose:
 
2882
      name = "NoExpose";
 
2883
      break;
 
2884
    case VisibilityNotify:
 
2885
      name = "VisibilityNotify";
 
2886
      break;
 
2887
    case CreateNotify:
 
2888
      name = "CreateNotify";
 
2889
      extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
 
2890
                               event->xcreatewindow.parent,
 
2891
                               event->xcreatewindow.window);
 
2892
      break;
 
2893
    case DestroyNotify:
 
2894
      name = "DestroyNotify";
 
2895
      extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
 
2896
                               event->xdestroywindow.event,
 
2897
                               event->xdestroywindow.window);
 
2898
      break;
 
2899
    case UnmapNotify:
 
2900
      name = "UnmapNotify";
 
2901
      extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d",
 
2902
                               event->xunmap.event,
 
2903
                               event->xunmap.window,
 
2904
                               event->xunmap.from_configure);
 
2905
      break;
 
2906
    case MapNotify:
 
2907
      name = "MapNotify";
 
2908
      extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d",
 
2909
                               event->xmap.event,
 
2910
                               event->xmap.window,
 
2911
                               event->xmap.override_redirect);
 
2912
      break;
 
2913
    case MapRequest:
 
2914
      name = "MapRequest";
 
2915
      extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
 
2916
                               event->xmaprequest.window,
 
2917
                               event->xmaprequest.parent);
 
2918
      break;
 
2919
    case ReparentNotify:
 
2920
      name = "ReparentNotify";
 
2921
      extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n",
 
2922
                               event->xreparent.window,
 
2923
                               event->xreparent.parent,
 
2924
                               event->xreparent.event);
 
2925
      break;
 
2926
    case ConfigureNotify:
 
2927
      name = "ConfigureNotify";
 
2928
      extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d",
 
2929
                               event->xconfigure.x,
 
2930
                               event->xconfigure.y,
 
2931
                               event->xconfigure.width,
 
2932
                               event->xconfigure.height,
 
2933
                               event->xconfigure.above,
 
2934
                               event->xconfigure.override_redirect);
 
2935
      break;
 
2936
    case ConfigureRequest:
 
2937
      name = "ConfigureRequest";
 
2938
      extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s",
 
2939
                               event->xconfigurerequest.parent,
 
2940
                               event->xconfigurerequest.window,
 
2941
                               event->xconfigurerequest.x,
 
2942
                               event->xconfigurerequest.value_mask &
 
2943
                               CWX ? "" : "(unset) ",
 
2944
                               event->xconfigurerequest.y,
 
2945
                               event->xconfigurerequest.value_mask &
 
2946
                               CWY ? "" : "(unset) ",
 
2947
                               event->xconfigurerequest.width,
 
2948
                               event->xconfigurerequest.value_mask &
 
2949
                               CWWidth ? "" : "(unset) ",
 
2950
                               event->xconfigurerequest.height,
 
2951
                               event->xconfigurerequest.value_mask &
 
2952
                               CWHeight ? "" : "(unset) ",
 
2953
                               event->xconfigurerequest.border_width,
 
2954
                               event->xconfigurerequest.value_mask &
 
2955
                               CWBorderWidth ? "" : "(unset)",
 
2956
                               event->xconfigurerequest.above,
 
2957
                               event->xconfigurerequest.value_mask &
 
2958
                               CWSibling ? "" : "(unset)",
 
2959
                               stack_mode_to_string (event->xconfigurerequest.detail),
 
2960
                               event->xconfigurerequest.value_mask &
 
2961
                               CWStackMode ? "" : "(unset)");
 
2962
      break;
 
2963
    case GravityNotify:
 
2964
      name = "GravityNotify";
 
2965
      break;
 
2966
    case ResizeRequest:
 
2967
      name = "ResizeRequest";
 
2968
      extra = g_strdup_printf ("width = %d height = %d",
 
2969
                               event->xresizerequest.width,
 
2970
                               event->xresizerequest.height);
 
2971
      break;
 
2972
    case CirculateNotify:
 
2973
      name = "CirculateNotify";
 
2974
      break;
 
2975
    case CirculateRequest:
 
2976
      name = "CirculateRequest";
 
2977
      break;
 
2978
    case PropertyNotify:
 
2979
      {
 
2980
        char *str;
 
2981
        const char *state;
 
2982
            
 
2983
        name = "PropertyNotify";
 
2984
            
 
2985
        meta_error_trap_push (display);
 
2986
        str = XGetAtomName (display->xdisplay,
 
2987
                            event->xproperty.atom);
 
2988
        meta_error_trap_pop (display, TRUE);
 
2989
 
 
2990
        if (event->xproperty.state == PropertyNewValue)
 
2991
          state = "PropertyNewValue";
 
2992
        else if (event->xproperty.state == PropertyDelete)
 
2993
          state = "PropertyDelete";
 
2994
        else
 
2995
          state = "???";
 
2996
            
 
2997
        extra = g_strdup_printf ("atom: %s state: %s",
 
2998
                                 str ? str : "(unknown atom)",
 
2999
                                 state);
 
3000
        meta_XFree (str);
 
3001
      }
 
3002
      break;
 
3003
    case SelectionClear:
 
3004
      name = "SelectionClear";
 
3005
      break;
 
3006
    case SelectionRequest:
 
3007
      name = "SelectionRequest";
 
3008
      break;
 
3009
    case SelectionNotify:
 
3010
      name = "SelectionNotify";
 
3011
      break;
 
3012
    case ColormapNotify:
 
3013
      name = "ColormapNotify";
 
3014
      break;
 
3015
    case ClientMessage:
 
3016
      {
 
3017
        char *str;
 
3018
        name = "ClientMessage";
 
3019
        meta_error_trap_push (display);
 
3020
        str = XGetAtomName (display->xdisplay,
 
3021
                            event->xclient.message_type);
 
3022
        meta_error_trap_pop (display, TRUE);
 
3023
        extra = g_strdup_printf ("type: %s format: %d\n",
 
3024
                                 str ? str : "(unknown atom)",
 
3025
                                 event->xclient.format);
 
3026
        meta_XFree (str);
 
3027
      }
 
3028
      break;
 
3029
    case MappingNotify:
 
3030
      name = "MappingNotify";
 
3031
      break;
 
3032
    default:
 
3033
#ifdef HAVE_XSYNC
 
3034
      if (META_DISPLAY_HAS_XSYNC (display) && 
 
3035
          event->type == (display->xsync_event_base + XSyncAlarmNotify))
 
3036
        {
 
3037
          XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
 
3038
          
 
3039
          name = "XSyncAlarmNotify";
 
3040
          extra =
 
3041
            g_strdup_printf ("alarm: 0x%lx"
 
3042
                             " counter_value: %" G_GINT64_FORMAT
 
3043
                             " alarm_value: %" G_GINT64_FORMAT
 
3044
                             " time: %u alarm state: %s",
 
3045
                             aevent->alarm,
 
3046
                             (gint64) sync_value_to_64 (&aevent->counter_value),
 
3047
                             (gint64) sync_value_to_64 (&aevent->alarm_value),
 
3048
                             (unsigned int)aevent->time,
 
3049
                             alarm_state_to_string (aevent->state));
 
3050
        }
 
3051
      else
 
3052
#endif /* HAVE_XSYNC */
 
3053
#ifdef HAVE_SHAPE
 
3054
        if (META_DISPLAY_HAS_SHAPE (display) && 
 
3055
            event->type == (display->shape_event_base + ShapeNotify))
 
3056
          {
 
3057
            XShapeEvent *sev = (XShapeEvent*) event;
 
3058
 
 
3059
            name = "ShapeNotify";
 
3060
 
 
3061
            extra =
 
3062
              g_strdup_printf ("kind: %s "
 
3063
                               "x: %d y: %d w: %u h: %u "
 
3064
                               "shaped: %d",
 
3065
                               sev->kind == ShapeBounding ?
 
3066
                               "ShapeBounding" :
 
3067
                               (sev->kind == ShapeClip ?
 
3068
                               "ShapeClip" : "(unknown)"),
 
3069
                               sev->x, sev->y, sev->width, sev->height,
 
3070
                               sev->shaped);
 
3071
          }
 
3072
        else
 
3073
#endif /* HAVE_SHAPE */      
 
3074
        {
 
3075
          name = "(Unknown event)";
 
3076
          extra = g_strdup_printf ("type: %d", event->xany.type);
 
3077
        }
 
3078
      break;
 
3079
    }
 
3080
 
 
3081
  screen = meta_display_screen_for_root (display, event->xany.window);
 
3082
      
 
3083
  if (screen)
 
3084
    winname = g_strdup_printf ("root %d", screen->number);
 
3085
  else
 
3086
    winname = g_strdup_printf ("0x%lx", event->xany.window);
 
3087
      
 
3088
  meta_topic (META_DEBUG_EVENTS,
 
3089
              "%s on %s%s %s %sserial %lu\n", name, winname,
 
3090
              extra ? ":" : "", extra ? extra : "",
 
3091
              event->xany.send_event ? "SEND " : "",
 
3092
              event->xany.serial);
 
3093
 
 
3094
  g_free (winname);
 
3095
 
 
3096
  if (extra)
 
3097
    g_free (extra);
 
3098
}
 
3099
#endif /* WITH_VERBOSE_MODE */
 
3100
 
 
3101
MetaWindow*
 
3102
meta_display_lookup_x_window (MetaDisplay *display,
 
3103
                              Window       xwindow)
 
3104
{
 
3105
  return g_hash_table_lookup (display->window_ids, &xwindow);
 
3106
}
 
3107
 
 
3108
void
 
3109
meta_display_register_x_window (MetaDisplay *display,
 
3110
                                Window      *xwindowp,
 
3111
                                MetaWindow  *window)
 
3112
{
 
3113
  g_return_if_fail (g_hash_table_lookup (display->window_ids, xwindowp) == NULL);
 
3114
  
 
3115
  g_hash_table_insert (display->window_ids, xwindowp, window);
 
3116
}
 
3117
 
 
3118
void
 
3119
meta_display_unregister_x_window (MetaDisplay *display,
 
3120
                                  Window       xwindow)
 
3121
{
 
3122
  g_return_if_fail (g_hash_table_lookup (display->window_ids, &xwindow) != NULL);
 
3123
 
 
3124
  g_hash_table_remove (display->window_ids, &xwindow);
 
3125
 
 
3126
  /* Remove any pending pings */
 
3127
  remove_pending_pings_for_window (display, xwindow);
 
3128
}
 
3129
 
 
3130
gboolean
 
3131
meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
 
3132
                                           Window xwindow)
 
3133
{
 
3134
  gboolean is_a_no_focus_window = FALSE;
 
3135
  GSList *temp = display->screens;
 
3136
  while (temp != NULL) {
 
3137
    MetaScreen *screen = temp->data;
 
3138
    if (screen->no_focus_window == xwindow) {
 
3139
      is_a_no_focus_window = TRUE;
 
3140
      break;
 
3141
    }
 
3142
    temp = temp->next;
 
3143
  }
 
3144
 
 
3145
  return is_a_no_focus_window;
 
3146
}
 
3147
 
 
3148
Cursor
 
3149
meta_display_create_x_cursor (MetaDisplay *display,
 
3150
                              MetaCursor cursor)
 
3151
{
 
3152
  Cursor xcursor;
 
3153
  guint glyph;
 
3154
 
 
3155
  switch (cursor)
 
3156
    {
 
3157
    case META_CURSOR_DEFAULT:
 
3158
      glyph = XC_left_ptr;
 
3159
      break;
 
3160
    case META_CURSOR_NORTH_RESIZE:
 
3161
      glyph = XC_top_side;
 
3162
      break;
 
3163
    case META_CURSOR_SOUTH_RESIZE:
 
3164
      glyph = XC_bottom_side;
 
3165
      break;
 
3166
    case META_CURSOR_WEST_RESIZE:
 
3167
      glyph = XC_left_side;
 
3168
      break;
 
3169
    case META_CURSOR_EAST_RESIZE:
 
3170
      glyph = XC_right_side;
 
3171
      break;
 
3172
    case META_CURSOR_SE_RESIZE:
 
3173
      glyph = XC_bottom_right_corner;
 
3174
      break;
 
3175
    case META_CURSOR_SW_RESIZE:
 
3176
      glyph = XC_bottom_left_corner;
 
3177
      break;
 
3178
    case META_CURSOR_NE_RESIZE:
 
3179
      glyph = XC_top_right_corner;
 
3180
      break;
 
3181
    case META_CURSOR_NW_RESIZE:
 
3182
      glyph = XC_top_left_corner;
 
3183
      break;
 
3184
    case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
 
3185
      glyph = XC_fleur;
 
3186
      break;
 
3187
    case META_CURSOR_BUSY:
 
3188
      glyph = XC_watch;
 
3189
      break;
 
3190
      
 
3191
    default:
 
3192
      g_assert_not_reached ();
 
3193
      glyph = 0; /* silence compiler */
 
3194
      break;
 
3195
    }
 
3196
  
 
3197
  xcursor = XCreateFontCursor (display->xdisplay, glyph);
 
3198
 
 
3199
  return xcursor;
 
3200
}
 
3201
 
 
3202
static Cursor
 
3203
xcursor_for_op (MetaDisplay *display,
 
3204
                MetaGrabOp   op)
 
3205
{
 
3206
  MetaCursor cursor = META_CURSOR_DEFAULT;
 
3207
  
 
3208
  switch (op)
 
3209
    {
 
3210
    case META_GRAB_OP_RESIZING_SE:
 
3211
    case META_GRAB_OP_KEYBOARD_RESIZING_SE:
 
3212
      cursor = META_CURSOR_SE_RESIZE;
 
3213
      break;
 
3214
    case META_GRAB_OP_RESIZING_S:
 
3215
    case META_GRAB_OP_KEYBOARD_RESIZING_S:
 
3216
      cursor = META_CURSOR_SOUTH_RESIZE;
 
3217
      break;
 
3218
    case META_GRAB_OP_RESIZING_SW:
 
3219
    case META_GRAB_OP_KEYBOARD_RESIZING_SW:
 
3220
      cursor = META_CURSOR_SW_RESIZE;
 
3221
      break;
 
3222
    case META_GRAB_OP_RESIZING_N:
 
3223
    case META_GRAB_OP_KEYBOARD_RESIZING_N:
 
3224
      cursor = META_CURSOR_NORTH_RESIZE;
 
3225
      break;
 
3226
    case META_GRAB_OP_RESIZING_NE:
 
3227
    case META_GRAB_OP_KEYBOARD_RESIZING_NE:
 
3228
      cursor = META_CURSOR_NE_RESIZE;
 
3229
      break;
 
3230
    case META_GRAB_OP_RESIZING_NW:
 
3231
    case META_GRAB_OP_KEYBOARD_RESIZING_NW:
 
3232
      cursor = META_CURSOR_NW_RESIZE;
 
3233
      break;
 
3234
    case META_GRAB_OP_RESIZING_W:
 
3235
    case META_GRAB_OP_KEYBOARD_RESIZING_W:
 
3236
      cursor = META_CURSOR_WEST_RESIZE;
 
3237
      break;
 
3238
    case META_GRAB_OP_RESIZING_E:
 
3239
    case META_GRAB_OP_KEYBOARD_RESIZING_E:
 
3240
      cursor = META_CURSOR_EAST_RESIZE;
 
3241
      break;
 
3242
    case META_GRAB_OP_MOVING:
 
3243
    case META_GRAB_OP_KEYBOARD_MOVING:
 
3244
    case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
 
3245
      cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW;
 
3246
      break;
 
3247
      
 
3248
    default:
 
3249
      break;
 
3250
    }
 
3251
 
 
3252
  if (cursor == META_CURSOR_DEFAULT)
 
3253
    return None;
 
3254
  return meta_display_create_x_cursor (display, cursor);
 
3255
}
 
3256
 
 
3257
void
 
3258
meta_display_set_grab_op_cursor (MetaDisplay *display,
 
3259
                                 MetaScreen  *screen,
 
3260
                                 MetaGrabOp   op,
 
3261
                                 gboolean     change_pointer,
 
3262
                                 Window       grab_xwindow,
 
3263
                                 guint32      timestamp)
 
3264
{
 
3265
  Cursor cursor;
 
3266
 
 
3267
  cursor = xcursor_for_op (display, op);
 
3268
 
 
3269
#define GRAB_MASK (PointerMotionMask |                          \
 
3270
                   ButtonPressMask | ButtonReleaseMask |        \
 
3271
                   EnterWindowMask | LeaveWindowMask)
 
3272
 
 
3273
  if (change_pointer)
 
3274
    {
 
3275
      meta_error_trap_push_with_return (display);
 
3276
      XChangeActivePointerGrab (display->xdisplay,
 
3277
                                GRAB_MASK,
 
3278
                                cursor,
 
3279
                                timestamp);
 
3280
 
 
3281
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3282
                  "Changed pointer with XChangeActivePointerGrab()\n");
 
3283
 
 
3284
      if (meta_error_trap_pop_with_return (display, FALSE) != Success)
 
3285
        {
 
3286
          meta_topic (META_DEBUG_WINDOW_OPS,
 
3287
                      "Error trapped from XChangeActivePointerGrab()\n");
 
3288
          if (display->grab_have_pointer)
 
3289
            display->grab_have_pointer = FALSE;
 
3290
        }
 
3291
    }
 
3292
  else
 
3293
    {
 
3294
      g_assert (screen != NULL);
 
3295
 
 
3296
      meta_error_trap_push (display);
 
3297
      if (XGrabPointer (display->xdisplay,
 
3298
                        grab_xwindow,
 
3299
                        False,
 
3300
                        GRAB_MASK,
 
3301
                        GrabModeAsync, GrabModeAsync,
 
3302
                        screen->xroot,
 
3303
                        cursor,
 
3304
                        timestamp) == GrabSuccess)
 
3305
        {
 
3306
          display->grab_have_pointer = TRUE;
 
3307
          meta_topic (META_DEBUG_WINDOW_OPS,
 
3308
                      "XGrabPointer() returned GrabSuccess time %u\n",
 
3309
                      timestamp);
 
3310
        }
 
3311
      else
 
3312
        {
 
3313
          meta_topic (META_DEBUG_WINDOW_OPS,
 
3314
                      "XGrabPointer() failed time %u\n",
 
3315
                      timestamp);
 
3316
        }
 
3317
      meta_error_trap_pop (display, TRUE);
 
3318
    }
 
3319
 
 
3320
#undef GRAB_MASK
 
3321
  
 
3322
  if (cursor != None)
 
3323
    XFreeCursor (display->xdisplay, cursor);
 
3324
}
 
3325
 
 
3326
gboolean
 
3327
meta_display_begin_grab_op (MetaDisplay *display,
 
3328
                            MetaScreen  *screen,
 
3329
                            MetaWindow  *window,
 
3330
                            MetaGrabOp   op,
 
3331
                            gboolean     pointer_already_grabbed,
 
3332
                            gboolean     frame_action,
 
3333
                            int          button,
 
3334
                            gulong       modmask,
 
3335
                            guint32      timestamp,
 
3336
                            int          root_x,
 
3337
                            int          root_y)
 
3338
{
 
3339
  Window grab_xwindow;
 
3340
  
 
3341
  meta_topic (META_DEBUG_WINDOW_OPS,
 
3342
              "Doing grab op %u on window %s button %d pointer already grabbed: %d pointer pos %d,%d\n",
 
3343
              op, window ? window->desc : "none", button, pointer_already_grabbed,
 
3344
              root_x, root_y);
 
3345
  
 
3346
  if (display->grab_op != META_GRAB_OP_NONE)
 
3347
    {
 
3348
      if (window)
 
3349
        meta_warning ("Attempt to perform window operation %u on window %s when operation %u on %s already in effect\n",
 
3350
                      op, window->desc, display->grab_op,
 
3351
                      display->grab_window ? display->grab_window->desc : "none");
 
3352
      return FALSE;
 
3353
    }
 
3354
 
 
3355
  if (window &&
 
3356
      (meta_grab_op_is_moving (op) || meta_grab_op_is_resizing (op)))
 
3357
    {
 
3358
      if (meta_prefs_get_raise_on_click ())
 
3359
        meta_window_raise (window);
 
3360
      else
 
3361
        {
 
3362
          display->grab_initial_x = root_x;
 
3363
          display->grab_initial_y = root_y;
 
3364
          display->grab_threshold_movement_reached = FALSE;
 
3365
        }
 
3366
    }
 
3367
 
 
3368
  /* FIXME:
 
3369
   *   If we have no MetaWindow we do our best
 
3370
   *   and try to do the grab on the RootWindow.
 
3371
   *   This will fail if anyone else has any
 
3372
   *   key grab on the RootWindow.
 
3373
   */
 
3374
  if (window)
 
3375
    grab_xwindow = window->frame ? window->frame->xwindow : window->xwindow;
 
3376
  else
 
3377
    grab_xwindow = screen->xroot;
 
3378
 
 
3379
  display->grab_have_pointer = FALSE;
 
3380
  
 
3381
  if (pointer_already_grabbed)
 
3382
    display->grab_have_pointer = TRUE;
 
3383
  
 
3384
  meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow,
 
3385
                                   timestamp);
 
3386
 
 
3387
  if (!display->grab_have_pointer)
 
3388
    {
 
3389
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3390
                  "XGrabPointer() failed\n");
 
3391
      return FALSE;
 
3392
    }
 
3393
 
 
3394
  /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */
 
3395
  if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op))
 
3396
    {
 
3397
      if (window)
 
3398
        display->grab_have_keyboard =
 
3399
                     meta_window_grab_all_keys (window, timestamp);
 
3400
 
 
3401
      else
 
3402
        display->grab_have_keyboard =
 
3403
                     meta_screen_grab_all_keys (screen, timestamp);
 
3404
      
 
3405
      if (!display->grab_have_keyboard)
 
3406
        {
 
3407
          meta_topic (META_DEBUG_WINDOW_OPS,
 
3408
                      "grabbing all keys failed, ungrabbing pointer\n");
 
3409
          XUngrabPointer (display->xdisplay, timestamp);
 
3410
          display->grab_have_pointer = FALSE;
 
3411
          return FALSE;
 
3412
        }
 
3413
    }
 
3414
  
 
3415
  display->grab_op = op;
 
3416
  display->grab_window = window;
 
3417
  display->grab_screen = screen;
 
3418
  display->grab_xwindow = grab_xwindow;
 
3419
  display->grab_button = button;
 
3420
  display->grab_mask = modmask;
 
3421
  display->grab_anchor_root_x = root_x;
 
3422
  display->grab_anchor_root_y = root_y;
 
3423
  display->grab_latest_motion_x = root_x;
 
3424
  display->grab_latest_motion_y = root_y;
 
3425
  display->grab_last_moveresize_time.tv_sec = 0;
 
3426
  display->grab_last_moveresize_time.tv_usec = 0;
 
3427
  display->grab_motion_notify_time = 0;
 
3428
  display->grab_old_window_stacking = NULL;
 
3429
#ifdef HAVE_XSYNC
 
3430
  display->grab_sync_request_alarm = None;
 
3431
  display->grab_last_user_action_was_snap = FALSE;
 
3432
#endif
 
3433
  display->grab_frame_action = frame_action;
 
3434
 
 
3435
  if (display->grab_resize_timeout_id)
 
3436
    {
 
3437
      g_source_remove (display->grab_resize_timeout_id);
 
3438
      display->grab_resize_timeout_id = 0;
 
3439
    }
 
3440
        
 
3441
  if (display->grab_window)
 
3442
    {
 
3443
      meta_window_get_client_root_coords (display->grab_window,
 
3444
                                          &display->grab_initial_window_pos);
 
3445
      display->grab_anchor_window_pos = display->grab_initial_window_pos;
 
3446
 
 
3447
#ifdef HAVE_XSYNC
 
3448
      if ( meta_grab_op_is_resizing (display->grab_op) &&
 
3449
          display->grab_window->sync_request_counter != None)
 
3450
        {
 
3451
          XSyncAlarmAttributes values;
 
3452
          XSyncValue init;
 
3453
 
 
3454
          meta_error_trap_push_with_return (display);
 
3455
 
 
3456
          /* Set the counter to 0, so we know that the application's
 
3457
           * responses to the client messages will always trigger
 
3458
           * a PositiveTransition
 
3459
           */
 
3460
          
 
3461
          XSyncIntToValue (&init, 0);
 
3462
          XSyncSetCounter (display->xdisplay,
 
3463
                           display->grab_window->sync_request_counter, init);
 
3464
          
 
3465
          display->grab_window->sync_request_serial = 0;
 
3466
          display->grab_window->sync_request_time.tv_sec = 0;
 
3467
          display->grab_window->sync_request_time.tv_usec = 0;
 
3468
          
 
3469
          values.trigger.counter = display->grab_window->sync_request_counter;
 
3470
          values.trigger.value_type = XSyncAbsolute;
 
3471
          values.trigger.test_type = XSyncPositiveTransition;
 
3472
          XSyncIntToValue (&values.trigger.wait_value,
 
3473
                           display->grab_window->sync_request_serial + 1);
 
3474
          
 
3475
          /* After triggering, increment test_value by this.
 
3476
           * (NOT wait_value above)
 
3477
           */
 
3478
          XSyncIntToValue (&values.delta, 1);
 
3479
          
 
3480
          /* we want events (on by default anyway) */
 
3481
          values.events = True;
 
3482
          
 
3483
          display->grab_sync_request_alarm = XSyncCreateAlarm (display->xdisplay,
 
3484
                                                         XSyncCACounter |
 
3485
                                                         XSyncCAValueType |
 
3486
                                                         XSyncCAValue |
 
3487
                                                         XSyncCATestType |
 
3488
                                                         XSyncCADelta |
 
3489
                                                         XSyncCAEvents,
 
3490
                                                         &values);
 
3491
 
 
3492
          if (meta_error_trap_pop_with_return (display, FALSE) != Success)
 
3493
            display->grab_sync_request_alarm = None;
 
3494
 
 
3495
          meta_topic (META_DEBUG_RESIZING,
 
3496
                      "Created update alarm 0x%lx\n",
 
3497
                      display->grab_sync_request_alarm);
 
3498
        }
 
3499
#endif
 
3500
    }
 
3501
  
 
3502
  meta_topic (META_DEBUG_WINDOW_OPS,
 
3503
              "Grab op %u on window %s successful\n",
 
3504
              display->grab_op, window ? window->desc : "(null)");
 
3505
 
 
3506
  g_assert (display->grab_window != NULL || display->grab_screen != NULL);
 
3507
  g_assert (display->grab_op != META_GRAB_OP_NONE);
 
3508
 
 
3509
  /* If this is a move or resize, cache the window edges for
 
3510
   * resistance/snapping
 
3511
   */
 
3512
  if (meta_grab_op_is_resizing (display->grab_op) || 
 
3513
      meta_grab_op_is_moving (display->grab_op))
 
3514
    {
 
3515
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3516
                  "Computing edges to resist-movement or snap-to for %s.\n",
 
3517
                  window->desc);
 
3518
      meta_display_compute_resistance_and_snapping_edges (display);
 
3519
    }
 
3520
 
 
3521
  /* Save the old stacking */
 
3522
  if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
 
3523
    {
 
3524
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3525
                  "Saving old stack positions; old pointer was %p.\n",
 
3526
                  display->grab_old_window_stacking);
 
3527
      display->grab_old_window_stacking = 
 
3528
        meta_stack_get_positions (screen->stack);
 
3529
    }
 
3530
 
 
3531
  if (display->grab_window)
 
3532
    {
 
3533
      meta_window_refresh_resize_popup (display->grab_window);
 
3534
    }
 
3535
  
 
3536
  return TRUE;
 
3537
}
 
3538
 
 
3539
void
 
3540
meta_display_end_grab_op (MetaDisplay *display,
 
3541
                          guint32      timestamp)
 
3542
{
 
3543
  meta_topic (META_DEBUG_WINDOW_OPS,
 
3544
              "Ending grab op %u at time %u\n", display->grab_op, timestamp);
 
3545
  
 
3546
  if (display->grab_op == META_GRAB_OP_NONE)
 
3547
    return;
 
3548
 
 
3549
  if (display->grab_window != NULL)
 
3550
    display->grab_window->shaken_loose = FALSE;
 
3551
  
 
3552
  if (display->grab_window != NULL &&
 
3553
      !meta_prefs_get_raise_on_click () &&
 
3554
      (meta_grab_op_is_moving (display->grab_op) ||
 
3555
       meta_grab_op_is_resizing (display->grab_op)))
 
3556
    {
 
3557
      /* Only raise the window in orthogonal raise
 
3558
       * ('do-not-raise-on-click') mode if the user didn't try to move
 
3559
       * or resize the given window by at least a threshold amount.
 
3560
       * For raise on click mode, the window was raised at the
 
3561
       * beginning of the grab_op.
 
3562
       */
 
3563
      if (!display->grab_threshold_movement_reached)
 
3564
        meta_window_raise (display->grab_window);
 
3565
    }
 
3566
 
 
3567
  if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op) ||
 
3568
      display->grab_op == META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING)
 
3569
    {
 
3570
      if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
 
3571
        meta_screen_tab_popup_destroy (display->grab_screen);
 
3572
      else
 
3573
        meta_screen_workspace_popup_destroy (display->grab_screen);
 
3574
 
 
3575
      /* If the ungrab here causes an EnterNotify, ignore it for
 
3576
       * sloppy focus
 
3577
       */
 
3578
      display->ungrab_should_not_cause_focus_window = display->grab_xwindow;
 
3579
    }
 
3580
  
 
3581
  /* If this was a move or resize clear out the edge cache */
 
3582
  if (meta_grab_op_is_resizing (display->grab_op) || 
 
3583
      meta_grab_op_is_moving (display->grab_op))
 
3584
    {
 
3585
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3586
                  "Clearing out the edges for resistance/snapping");
 
3587
      meta_display_cleanup_edges (display);
 
3588
    }
 
3589
 
 
3590
  if (display->grab_old_window_stacking != NULL)
 
3591
    {
 
3592
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3593
                  "Clearing out the old stack position, which was %p.\n",
 
3594
                  display->grab_old_window_stacking);
 
3595
      g_list_free (display->grab_old_window_stacking);
 
3596
      display->grab_old_window_stacking = NULL;
 
3597
    }
 
3598
 
 
3599
  if (display->grab_have_pointer)
 
3600
    {
 
3601
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3602
                  "Ungrabbing pointer with timestamp %u\n", timestamp);
 
3603
      XUngrabPointer (display->xdisplay, timestamp);
 
3604
    }
 
3605
 
 
3606
  if (display->grab_have_keyboard)
 
3607
    {
 
3608
      meta_topic (META_DEBUG_WINDOW_OPS,
 
3609
                  "Ungrabbing all keys timestamp %u\n", timestamp);
 
3610
      if (display->grab_window)
 
3611
        meta_window_ungrab_all_keys (display->grab_window, timestamp);
 
3612
      else
 
3613
        meta_screen_ungrab_all_keys (display->grab_screen, timestamp);
 
3614
    }
 
3615
 
 
3616
#ifdef HAVE_XSYNC
 
3617
  if (display->grab_sync_request_alarm != None)
 
3618
    {
 
3619
      XSyncDestroyAlarm (display->xdisplay,
 
3620
                         display->grab_sync_request_alarm);
 
3621
      display->grab_sync_request_alarm = None;
 
3622
    }
 
3623
#endif /* HAVE_XSYNC */
 
3624
  
 
3625
  display->grab_window = NULL;
 
3626
  display->grab_screen = NULL;
 
3627
  display->grab_xwindow = None;
 
3628
  display->grab_op = META_GRAB_OP_NONE;
 
3629
 
 
3630
  if (display->grab_resize_popup)
 
3631
    {
 
3632
      meta_ui_resize_popup_free (display->grab_resize_popup);
 
3633
      display->grab_resize_popup = NULL;
 
3634
    }
 
3635
 
 
3636
  if (display->grab_resize_timeout_id)
 
3637
    {
 
3638
      g_source_remove (display->grab_resize_timeout_id);
 
3639
      display->grab_resize_timeout_id = 0;
 
3640
    }
 
3641
}
 
3642
 
 
3643
void
 
3644
meta_display_check_threshold_reached (MetaDisplay *display,
 
3645
                                      int          x,
 
3646
                                      int          y)
 
3647
{
 
3648
  /* Don't bother doing the check again if we've already reached the threshold */
 
3649
  if (meta_prefs_get_raise_on_click () ||
 
3650
      display->grab_threshold_movement_reached)
 
3651
    return;
 
3652
 
 
3653
  if (ABS (display->grab_initial_x - x) >= 8 ||
 
3654
      ABS (display->grab_initial_y - y) >= 8)
 
3655
    display->grab_threshold_movement_reached = TRUE;
 
3656
}
 
3657
 
 
3658
static void
 
3659
meta_change_button_grab (MetaDisplay *display,
 
3660
                         Window       xwindow,
 
3661
                         gboolean     grab,
 
3662
                         gboolean     sync,
 
3663
                         int          button,
 
3664
                         int          modmask)
 
3665
{
 
3666
  unsigned int ignored_mask;
 
3667
 
 
3668
  meta_verbose ("%s 0x%lx sync = %d button = %d modmask 0x%x\n",
 
3669
                grab ? "Grabbing" : "Ungrabbing",
 
3670
                xwindow,
 
3671
                sync, button, modmask);
 
3672
  
 
3673
  meta_error_trap_push (display);
 
3674
  
 
3675
  ignored_mask = 0;
 
3676
  while (ignored_mask <= display->ignored_modifier_mask)
 
3677
    {
 
3678
      if (ignored_mask & ~(display->ignored_modifier_mask))
 
3679
        {
 
3680
          /* Not a combination of ignored modifiers
 
3681
           * (it contains some non-ignored modifiers)
 
3682
           */
 
3683
          ++ignored_mask;
 
3684
          continue;
 
3685
        }
 
3686
 
 
3687
      if (meta_is_debugging ())
 
3688
        meta_error_trap_push_with_return (display);
 
3689
 
 
3690
      /* GrabModeSync means freeze until XAllowEvents */
 
3691
      
 
3692
      if (grab)
 
3693
        XGrabButton (display->xdisplay, button, modmask | ignored_mask,
 
3694
                     xwindow, False,
 
3695
                     ButtonPressMask | ButtonReleaseMask |    
 
3696
                     PointerMotionMask | PointerMotionHintMask,
 
3697
                     sync ? GrabModeSync : GrabModeAsync,
 
3698
                     GrabModeAsync,
 
3699
                     False, None);
 
3700
      else
 
3701
        XUngrabButton (display->xdisplay, button, modmask | ignored_mask,
 
3702
                       xwindow);
 
3703
 
 
3704
      if (meta_is_debugging ())
 
3705
        {
 
3706
          int result;
 
3707
          
 
3708
          result = meta_error_trap_pop_with_return (display, FALSE);
 
3709
          
 
3710
          if (result != Success)
 
3711
            meta_verbose ("Failed to %s button %d with mask 0x%x for window 0x%lx error code %d\n",
 
3712
                          grab ? "grab" : "ungrab",
 
3713
                          button, modmask | ignored_mask, xwindow, result);
 
3714
        }
 
3715
      
 
3716
      ++ignored_mask;
 
3717
    }
 
3718
 
 
3719
  meta_error_trap_pop (display, FALSE);
 
3720
}
 
3721
 
 
3722
void
 
3723
meta_display_grab_window_buttons (MetaDisplay *display,
 
3724
                                  Window       xwindow)
 
3725
{  
 
3726
  /* Grab Alt + button1 for moving window.
 
3727
   * Grab Alt + button2 for resizing window.
 
3728
   * Grab Alt + button3 for popping up window menu.
 
3729
   * Grab Alt + Shift + button1 for snap-moving window.
 
3730
   */
 
3731
  meta_verbose ("Grabbing window buttons for 0x%lx\n", xwindow);
 
3732
  
 
3733
  /* FIXME If we ignored errors here instead of spewing, we could
 
3734
   * put one big error trap around the loop and avoid a bunch of
 
3735
   * XSync()
 
3736
   */
 
3737
 
 
3738
  if (display->window_grab_modifiers != 0)
 
3739
    {
 
3740
      gboolean debug = g_getenv ("MUTTER_DEBUG_BUTTON_GRABS") != NULL;
 
3741
      int i;
 
3742
      for (i = 1; i < 4; i++)
 
3743
        {
 
3744
          meta_change_button_grab (display, xwindow,
 
3745
                                   TRUE,
 
3746
                                   FALSE,
 
3747
                                   i, display->window_grab_modifiers);  
 
3748
          
 
3749
          /* This is for debugging, since I end up moving the Xnest
 
3750
           * otherwise ;-)
 
3751
           */
 
3752
          if (debug)
 
3753
            meta_change_button_grab (display, xwindow,
 
3754
                                     TRUE,
 
3755
                                     FALSE,
 
3756
                                     i, ControlMask);
 
3757
        }
 
3758
 
 
3759
      /* In addition to grabbing Alt+Button1 for moving the window,
 
3760
       * grab Alt+Shift+Button1 for snap-moving the window.  See bug
 
3761
       * 112478.  Unfortunately, this doesn't work with
 
3762
       * Shift+Alt+Button1 for some reason; so at least part of the
 
3763
       * order still matters, which sucks (please FIXME).
 
3764
       */
 
3765
      meta_change_button_grab (display, xwindow,
 
3766
                               TRUE,
 
3767
                               FALSE,
 
3768
                               1, display->window_grab_modifiers | ShiftMask);
 
3769
    }
 
3770
}
 
3771
 
 
3772
void
 
3773
meta_display_ungrab_window_buttons  (MetaDisplay *display,
 
3774
                                     Window       xwindow)
 
3775
{
 
3776
  gboolean debug;
 
3777
  int i;
 
3778
 
 
3779
  if (display->window_grab_modifiers == 0)
 
3780
    return;
 
3781
  
 
3782
  debug = g_getenv ("MUTTER_DEBUG_BUTTON_GRABS") != NULL;
 
3783
  i = 1;
 
3784
  while (i < 4)
 
3785
    {
 
3786
      meta_change_button_grab (display, xwindow,
 
3787
                               FALSE, FALSE, i,
 
3788
                               display->window_grab_modifiers);
 
3789
      
 
3790
      if (debug)
 
3791
        meta_change_button_grab (display, xwindow,
 
3792
                                 FALSE, FALSE, i, ControlMask);
 
3793
      
 
3794
      ++i;
 
3795
    }
 
3796
}
 
3797
 
 
3798
/* Grab buttons we only grab while unfocused in click-to-focus mode */
 
3799
#define MAX_FOCUS_BUTTON 4
 
3800
void
 
3801
meta_display_grab_focus_window_button (MetaDisplay *display,
 
3802
                                       MetaWindow  *window)
 
3803
{
 
3804
  /* Grab button 1 for activating unfocused windows */
 
3805
  meta_verbose ("Grabbing unfocused window buttons for %s\n", window->desc);
 
3806
 
 
3807
#if 0
 
3808
  /* FIXME:115072 */
 
3809
  /* Don't grab at all unless in click to focus mode. In click to
 
3810
   * focus, we may sometimes be clever about intercepting and eating
 
3811
   * the focus click. But in mouse focus, we never do that since the
 
3812
   * focus window may not be raised, and who wants to think about
 
3813
   * mouse focus anyway.
 
3814
   */
 
3815
  if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK)
 
3816
    {
 
3817
      meta_verbose (" (well, not grabbing since not in click to focus mode)\n");
 
3818
      return;
 
3819
    }
 
3820
#endif
 
3821
  
 
3822
  if (window->have_focus_click_grab)
 
3823
    {
 
3824
      meta_verbose (" (well, not grabbing since we already have the grab)\n");
 
3825
      return;
 
3826
    }
 
3827
  
 
3828
  /* FIXME If we ignored errors here instead of spewing, we could
 
3829
   * put one big error trap around the loop and avoid a bunch of
 
3830
   * XSync()
 
3831
   */
 
3832
  
 
3833
  {
 
3834
    int i = 1;
 
3835
    while (i < MAX_FOCUS_BUTTON)
 
3836
      {
 
3837
        meta_change_button_grab (display,
 
3838
                                 window->xwindow,
 
3839
                                 TRUE, TRUE,
 
3840
                                 i, 0);
 
3841
        
 
3842
        ++i;
 
3843
      }
 
3844
 
 
3845
    window->have_focus_click_grab = TRUE;
 
3846
  }
 
3847
}
 
3848
 
 
3849
void
 
3850
meta_display_ungrab_focus_window_button (MetaDisplay *display,
 
3851
                                         MetaWindow  *window)
 
3852
{
 
3853
  meta_verbose ("Ungrabbing unfocused window buttons for %s\n", window->desc);
 
3854
 
 
3855
  if (!window->have_focus_click_grab)
 
3856
    return;
 
3857
  
 
3858
  {
 
3859
    int i = 1;
 
3860
    while (i < MAX_FOCUS_BUTTON)
 
3861
      {
 
3862
        meta_change_button_grab (display, window->xwindow,
 
3863
                                 FALSE, FALSE, i, 0);
 
3864
        
 
3865
        ++i;
 
3866
      }
 
3867
 
 
3868
    window->have_focus_click_grab = FALSE;
 
3869
  }
 
3870
}
 
3871
 
 
3872
void
 
3873
meta_display_increment_event_serial (MetaDisplay *display)
 
3874
{
 
3875
  /* We just make some random X request */
 
3876
  XDeleteProperty (display->xdisplay, display->leader_window,
 
3877
                   display->atom__MOTIF_WM_HINTS);
 
3878
}
 
3879
 
 
3880
void
 
3881
meta_display_update_active_window_hint (MetaDisplay *display)
 
3882
{
 
3883
  GSList *tmp;
 
3884
  
 
3885
  gulong data[1];
 
3886
 
 
3887
  if (display->focus_window)
 
3888
    data[0] = display->focus_window->xwindow;
 
3889
  else
 
3890
    data[0] = None;
 
3891
  
 
3892
  tmp = display->screens;
 
3893
  while (tmp != NULL)
 
3894
    {
 
3895
      MetaScreen *screen = tmp->data;
 
3896
      
 
3897
      meta_error_trap_push (display);
 
3898
      XChangeProperty (display->xdisplay, screen->xroot,
 
3899
                       display->atom__NET_ACTIVE_WINDOW,
 
3900
                       XA_WINDOW,
 
3901
                       32, PropModeReplace, (guchar*) data, 1);
 
3902
 
 
3903
      meta_error_trap_pop (display, FALSE);
 
3904
 
 
3905
      tmp = tmp->next;
 
3906
    }
 
3907
}
 
3908
 
 
3909
void
 
3910
meta_display_queue_retheme_all_windows (MetaDisplay *display)
 
3911
{
 
3912
  GSList* windows;
 
3913
  GSList *tmp;
 
3914
 
 
3915
  windows = meta_display_list_windows (display, META_LIST_DEFAULT);
 
3916
  tmp = windows;
 
3917
  while (tmp != NULL)
 
3918
    {
 
3919
      MetaWindow *window = tmp->data;
 
3920
      
 
3921
      meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 
3922
      if (window->frame)
 
3923
        {
 
3924
          window->frame->need_reapply_frame_shape = TRUE;
 
3925
          
 
3926
          meta_frame_queue_draw (window->frame);
 
3927
        }
 
3928
      
 
3929
      tmp = tmp->next;
 
3930
    }
 
3931
 
 
3932
  g_slist_free (windows);
 
3933
}
 
3934
 
 
3935
void
 
3936
meta_display_retheme_all (void)
 
3937
{
 
3938
  meta_display_queue_retheme_all_windows (meta_get_display ());
 
3939
}
 
3940
 
 
3941
void 
 
3942
meta_display_set_cursor_theme (const char *theme, 
 
3943
                               int         size)
 
3944
{
 
3945
#ifdef HAVE_XCURSOR     
 
3946
  GSList *tmp;
 
3947
 
 
3948
  MetaDisplay *display = meta_get_display ();
 
3949
 
 
3950
  XcursorSetTheme (display->xdisplay, theme);
 
3951
  XcursorSetDefaultSize (display->xdisplay, size);
 
3952
 
 
3953
  tmp = display->screens;
 
3954
  while (tmp != NULL)
 
3955
    {
 
3956
      MetaScreen *screen = tmp->data;
 
3957
                  
 
3958
      meta_screen_update_cursor (screen);
 
3959
 
 
3960
      tmp = tmp->next;
 
3961
    }
 
3962
 
 
3963
#endif
 
3964
}
 
3965
 
 
3966
/**
 
3967
 * Stores whether syncing is currently enabled.
 
3968
 */
 
3969
static gboolean is_syncing = FALSE;
 
3970
 
 
3971
/**
 
3972
 * Returns whether X synchronisation is currently enabled.
 
3973
 *
 
3974
 * \return true if we must wait for events whenever we send X requests;
 
3975
 * false otherwise.
 
3976
 *
 
3977
 * \bug This is *only* called by meta_display_open, but by that time
 
3978
 * we have already turned syncing on or off on startup, and we don't
 
3979
 * have any way to do so while Mutter is running, so it's rather
 
3980
 * pointless.
 
3981
 */
 
3982
gboolean
 
3983
meta_is_syncing (void)
 
3984
{
 
3985
  return is_syncing;
 
3986
}
 
3987
 
 
3988
/**
 
3989
 * A handy way to turn on synchronisation on or off for every display.
 
3990
 *
 
3991
 * \bug Of course there is only one display ever anyway, so this can
 
3992
 * be rather hugely simplified.
 
3993
 */
 
3994
void
 
3995
meta_set_syncing (gboolean setting)
 
3996
{
 
3997
  if (setting != is_syncing)
 
3998
    {
 
3999
      is_syncing = setting;
 
4000
 
 
4001
      XSynchronize (meta_get_display ()->xdisplay, is_syncing);
 
4002
    }
 
4003
}
 
4004
 
 
4005
/**
 
4006
 * How long, in milliseconds, we should wait after pinging a window
 
4007
 * before deciding it's not going to get back to us.
 
4008
 */
 
4009
#define PING_TIMEOUT_DELAY 2250
 
4010
 
 
4011
/**
 
4012
 * Does whatever it is we decided to do when a window didn't respond
 
4013
 * to a ping. We also remove the ping from the display's list of
 
4014
 * pending pings. This function is called by the event loop when the timeout
 
4015
 * times out which we created at the start of the ping.
 
4016
 *
 
4017
 * \param data All the information about this ping. It is a MetaPingData
 
4018
 *             cast to a void* in order to be passable to a timeout function.
 
4019
 *             This function will also free this parameter.
 
4020
 *
 
4021
 * \return Always returns false, because this function is called as a
 
4022
 *         timeout and we don't want to run the timer again.
 
4023
 *
 
4024
 * \ingroup pings
 
4025
 */
 
4026
static gboolean
 
4027
meta_display_ping_timeout (gpointer data)
 
4028
{
 
4029
  MetaPingData *ping_data;
 
4030
 
 
4031
  ping_data = data;
 
4032
 
 
4033
  ping_data->ping_timeout_id = 0;
 
4034
 
 
4035
  meta_topic (META_DEBUG_PING,
 
4036
              "Ping %u on window %lx timed out\n",
 
4037
              ping_data->timestamp, ping_data->xwindow);
 
4038
  
 
4039
  (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow,
 
4040
                                    ping_data->timestamp, ping_data->user_data);
 
4041
 
 
4042
  ping_data->display->pending_pings =
 
4043
    g_slist_remove (ping_data->display->pending_pings,
 
4044
                    ping_data);
 
4045
  ping_data_free (ping_data);
 
4046
  
 
4047
  return FALSE;
 
4048
}
 
4049
 
 
4050
/**
 
4051
 * Sends a ping request to a window. The window must respond to
 
4052
 * the request within a certain amount of time. If it does, we
 
4053
 * will call one callback; if the time passes and we haven't had
 
4054
 * a response, we call a different callback. The window must have
 
4055
 * the hint showing that it can respond to a ping; if it doesn't,
 
4056
 * we call the "got a response" callback immediately and return.
 
4057
 * This function returns straight away after setting things up;
 
4058
 * the callbacks will be called from the event loop.
 
4059
 *
 
4060
 * \param display  The MetaDisplay that the window is on
 
4061
 * \param window   The MetaWindow to send the ping to
 
4062
 * \param timestamp The timestamp of the ping. Used for uniqueness.
 
4063
 *                  Cannot be CurrentTime; use a real timestamp!
 
4064
 * \param ping_reply_func The callback to call if we get a response.
 
4065
 * \param ping_timeout_func The callback to call if we don't get a response.
 
4066
 * \param user_data Arbitrary data that will be passed to the callback
 
4067
 *                  function. (In practice it's often a pointer to
 
4068
 *                  the window.)
 
4069
 *
 
4070
 * \bug This should probably be a method on windows, rather than displays
 
4071
 *      for one of their windows.
 
4072
 *
 
4073
 * \ingroup pings
 
4074
 */
 
4075
void
 
4076
meta_display_ping_window (MetaDisplay       *display,
 
4077
                          MetaWindow        *window,
 
4078
                          guint32            timestamp,
 
4079
                          MetaWindowPingFunc ping_reply_func,
 
4080
                          MetaWindowPingFunc ping_timeout_func,
 
4081
                          gpointer           user_data)
 
4082
{
 
4083
  MetaPingData *ping_data;
 
4084
 
 
4085
  if (timestamp == CurrentTime)
 
4086
    {
 
4087
      meta_warning ("Tried to ping a window with CurrentTime! Not allowed.\n");
 
4088
      return;
 
4089
    }
 
4090
 
 
4091
  if (!window->net_wm_ping)
 
4092
    {
 
4093
      if (ping_reply_func)
 
4094
        (* ping_reply_func) (display, window->xwindow, timestamp, user_data);
 
4095
 
 
4096
      return;
 
4097
    }
 
4098
  
 
4099
  ping_data = g_new (MetaPingData, 1);
 
4100
  ping_data->display = display;
 
4101
  ping_data->xwindow = window->xwindow;
 
4102
  ping_data->timestamp = timestamp;
 
4103
  ping_data->ping_reply_func = ping_reply_func;
 
4104
  ping_data->ping_timeout_func = ping_timeout_func;
 
4105
  ping_data->user_data = user_data;
 
4106
  ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY,
 
4107
                                              meta_display_ping_timeout,
 
4108
                                              ping_data);
 
4109
  
 
4110
  display->pending_pings = g_slist_prepend (display->pending_pings, ping_data);
 
4111
 
 
4112
  meta_topic (META_DEBUG_PING,
 
4113
              "Sending ping with timestamp %u to window %s\n",
 
4114
              timestamp, window->desc);
 
4115
  meta_window_send_icccm_message (window,
 
4116
                                  display->atom__NET_WM_PING,
 
4117
                                  timestamp);
 
4118
}
 
4119
 
 
4120
static void
 
4121
process_request_frame_extents (MetaDisplay    *display,
 
4122
                               XEvent         *event)
 
4123
{
 
4124
  /* The X window whose frame extents will be set. */
 
4125
  Window xwindow = event->xclient.window;
 
4126
  unsigned long data[4] = { 0, 0, 0, 0 };
 
4127
 
 
4128
  MotifWmHints *hints = NULL;
 
4129
  gboolean hints_set = FALSE;
 
4130
 
 
4131
  meta_verbose ("Setting frame extents for 0x%lx\n", xwindow);
 
4132
 
 
4133
  /* See if the window is decorated. */
 
4134
  hints_set = meta_prop_get_motif_hints (display,
 
4135
                                         xwindow,
 
4136
                                         display->atom__MOTIF_WM_HINTS,
 
4137
                                         &hints);
 
4138
  if ((hints_set && hints->decorations) || !hints_set)
 
4139
    {
 
4140
      int top = 0;
 
4141
      int bottom = 0;
 
4142
      int left = 0;
 
4143
      int right = 0;
 
4144
 
 
4145
      MetaScreen *screen;
 
4146
 
 
4147
      screen = meta_display_screen_for_xwindow (display,
 
4148
                                                event->xclient.window);
 
4149
      if (screen == NULL)
 
4150
        {
 
4151
          meta_warning ("Received request to set _NET_FRAME_EXTENTS "
 
4152
                        "on 0x%lx which is on a screen we are not managing\n",
 
4153
                        event->xclient.window);
 
4154
          meta_XFree (hints);
 
4155
          return;
 
4156
        }
 
4157
 
 
4158
      /* Return estimated frame extents for a normal window. */
 
4159
      meta_ui_theme_get_frame_borders (screen->ui,
 
4160
                                       META_FRAME_TYPE_NORMAL,
 
4161
                                       0,
 
4162
                                       &top,
 
4163
                                       &bottom,
 
4164
                                       &left,
 
4165
                                       &right);
 
4166
 
 
4167
      data[0] = left;
 
4168
      data[1] = right;
 
4169
      data[2] = top;
 
4170
      data[3] = bottom;
 
4171
    }
 
4172
 
 
4173
  meta_topic (META_DEBUG_GEOMETRY,
 
4174
              "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx "
 
4175
              "to top = %lu, left = %lu, bottom = %lu, right = %lu\n",
 
4176
              xwindow, data[0], data[1], data[2], data[3]);
 
4177
 
 
4178
  meta_error_trap_push (display);
 
4179
  XChangeProperty (display->xdisplay, xwindow,
 
4180
                   display->atom__NET_FRAME_EXTENTS,
 
4181
                   XA_CARDINAL,
 
4182
                   32, PropModeReplace, (guchar*) data, 4);
 
4183
  meta_error_trap_pop (display, FALSE);
 
4184
 
 
4185
  meta_XFree (hints);
 
4186
}
 
4187
 
 
4188
/**
 
4189
 * Process the pong (the response message) from the ping we sent
 
4190
 * to the window. This involves removing the timeout, calling the
 
4191
 * reply handler function, and freeing memory.
 
4192
 *
 
4193
 * \param display  the display we got the pong from
 
4194
 * \param event    the XEvent which is a pong; we can tell which
 
4195
 *                 ping it corresponds to because it bears the
 
4196
 *                 same timestamp.
 
4197
 *
 
4198
 * \ingroup pings
 
4199
 */
 
4200
static void
 
4201
process_pong_message (MetaDisplay    *display,
 
4202
                      XEvent         *event)
 
4203
{
 
4204
  GSList *tmp;
 
4205
  guint32 timestamp = event->xclient.data.l[1];
 
4206
 
 
4207
  meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n",
 
4208
              timestamp);
 
4209
  
 
4210
  for (tmp = display->pending_pings; tmp; tmp = tmp->next)
 
4211
    {
 
4212
      MetaPingData *ping_data = tmp->data;
 
4213
                          
 
4214
      if (timestamp == ping_data->timestamp)
 
4215
        {
 
4216
          meta_topic (META_DEBUG_PING,
 
4217
                      "Matching ping found for pong %u\n", 
 
4218
                      ping_data->timestamp);
 
4219
 
 
4220
          /* Remove the ping data from the list */
 
4221
          display->pending_pings = g_slist_remove (display->pending_pings,
 
4222
                                                   ping_data);
 
4223
 
 
4224
          /* Remove the timeout */
 
4225
          if (ping_data->ping_timeout_id != 0)
 
4226
            {
 
4227
              g_source_remove (ping_data->ping_timeout_id);
 
4228
              ping_data->ping_timeout_id = 0;
 
4229
            }
 
4230
          
 
4231
          /* Call callback */
 
4232
          (* ping_data->ping_reply_func) (display, 
 
4233
                                          ping_data->xwindow,
 
4234
                                          ping_data->timestamp, 
 
4235
                                          ping_data->user_data);
 
4236
                              
 
4237
          ping_data_free (ping_data);
 
4238
 
 
4239
          break;
 
4240
        }
 
4241
    }
 
4242
}
 
4243
 
 
4244
/**
 
4245
 * Finds whether a window has any pings waiting on it.
 
4246
 *
 
4247
 * \param display The MetaDisplay of the window.
 
4248
 * \param window  The MetaWindow whose pings we want to know about.
 
4249
 *
 
4250
 * \return True if there is at least one ping which has been sent
 
4251
 *         to the window without getting a response; false otherwise.
 
4252
 *
 
4253
 * \bug This should probably be a method on windows, rather than displays
 
4254
 *      for one of their windows.
 
4255
 *
 
4256
 * \ingroup pings
 
4257
 */
 
4258
gboolean
 
4259
meta_display_window_has_pending_pings (MetaDisplay *display,
 
4260
                                       MetaWindow  *window)
 
4261
{
 
4262
  GSList *tmp;
 
4263
 
 
4264
  for (tmp = display->pending_pings; tmp; tmp = tmp->next)
 
4265
    {
 
4266
      MetaPingData *ping_data = tmp->data;
 
4267
 
 
4268
      if (ping_data->xwindow == window->xwindow) 
 
4269
        return TRUE;
 
4270
    }
 
4271
 
 
4272
  return FALSE;
 
4273
}
 
4274
 
 
4275
MetaGroup*
 
4276
get_focussed_group (MetaDisplay *display)
 
4277
{
 
4278
  if (display->focus_window)
 
4279
    return display->focus_window->group;
 
4280
  else
 
4281
    return NULL;
 
4282
}
 
4283
 
 
4284
#define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \
 
4285
    || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \
 
4286
    || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))))
 
4287
 
 
4288
static MetaWindow*
 
4289
find_tab_forward (MetaDisplay   *display,
 
4290
                  MetaTabList    type,
 
4291
                  MetaScreen    *screen, 
 
4292
                  MetaWorkspace *workspace,
 
4293
                  GList         *start,
 
4294
                  gboolean       skip_first)
 
4295
{
 
4296
  GList *tmp;
 
4297
 
 
4298
  g_return_val_if_fail (start != NULL, NULL);
 
4299
  g_return_val_if_fail (workspace != NULL, NULL);
 
4300
 
 
4301
  tmp = start;
 
4302
  if (skip_first)
 
4303
    tmp = tmp->next;
 
4304
 
 
4305
  while (tmp != NULL)
 
4306
    {
 
4307
      MetaWindow *window = tmp->data;
 
4308
 
 
4309
      if (window->screen == screen &&
 
4310
          IN_TAB_CHAIN (window, type))
 
4311
        return window;
 
4312
 
 
4313
      tmp = tmp->next;
 
4314
    }
 
4315
 
 
4316
  tmp = workspace->mru_list;
 
4317
  while (tmp != start)
 
4318
    {
 
4319
      MetaWindow *window = tmp->data;
 
4320
 
 
4321
      if (IN_TAB_CHAIN (window, type))
 
4322
        return window;
 
4323
 
 
4324
      tmp = tmp->next;
 
4325
    }  
 
4326
 
 
4327
  return NULL;
 
4328
}
 
4329
 
 
4330
static MetaWindow*
 
4331
find_tab_backward (MetaDisplay   *display,
 
4332
                   MetaTabList    type,
 
4333
                   MetaScreen    *screen, 
 
4334
                   MetaWorkspace *workspace,
 
4335
                   GList         *start,
 
4336
                   gboolean       skip_last)
 
4337
{
 
4338
  GList *tmp;
 
4339
 
 
4340
  g_return_val_if_fail (start != NULL, NULL);
 
4341
  g_return_val_if_fail (workspace != NULL, NULL);
 
4342
 
 
4343
  tmp = start;
 
4344
  if (skip_last)  
 
4345
    tmp = tmp->prev;
 
4346
  while (tmp != NULL)
 
4347
    {
 
4348
      MetaWindow *window = tmp->data;
 
4349
 
 
4350
      if (window->screen == screen &&
 
4351
          IN_TAB_CHAIN (window, type))
 
4352
        return window;
 
4353
 
 
4354
      tmp = tmp->prev;
 
4355
    }
 
4356
 
 
4357
  tmp = g_list_last (workspace->mru_list);
 
4358
  while (tmp != start)
 
4359
    {
 
4360
      MetaWindow *window = tmp->data;
 
4361
 
 
4362
      if (IN_TAB_CHAIN (window, type))
 
4363
        return window;
 
4364
 
 
4365
      tmp = tmp->prev;
 
4366
    }
 
4367
 
 
4368
  return NULL;
 
4369
}
 
4370
 
 
4371
GList*
 
4372
meta_display_get_tab_list (MetaDisplay   *display,
 
4373
                           MetaTabList    type,
 
4374
                           MetaScreen    *screen,
 
4375
                           MetaWorkspace *workspace)
 
4376
{
 
4377
  GList *tab_list;
 
4378
 
 
4379
  g_return_val_if_fail (workspace != NULL, NULL);
 
4380
 
 
4381
  /* Windows sellout mode - MRU order. Collect unminimized windows
 
4382
   * then minimized so minimized windows aren't in the way so much.
 
4383
   */
 
4384
  {
 
4385
    GList *tmp;
 
4386
    
 
4387
    tab_list = NULL;
 
4388
    tmp = workspace->mru_list;
 
4389
    while (tmp != NULL)
 
4390
      {
 
4391
        MetaWindow *window = tmp->data;
 
4392
        
 
4393
        if (!window->minimized &&
 
4394
            window->screen == screen &&
 
4395
            IN_TAB_CHAIN (window, type))
 
4396
          tab_list = g_list_prepend (tab_list, window);
 
4397
        
 
4398
        tmp = tmp->next;
 
4399
      }
 
4400
  }
 
4401
 
 
4402
  {
 
4403
    GList *tmp;
 
4404
    
 
4405
    tmp = workspace->mru_list;
 
4406
    while (tmp != NULL)
 
4407
      {
 
4408
        MetaWindow *window = tmp->data;
 
4409
        
 
4410
        if (window->minimized &&
 
4411
            window->screen == screen &&
 
4412
            IN_TAB_CHAIN (window, type))
 
4413
          tab_list = g_list_prepend (tab_list, window);
 
4414
        
 
4415
        tmp = tmp->next;
 
4416
      }
 
4417
  }
 
4418
 
 
4419
  tab_list = g_list_reverse (tab_list);
 
4420
 
 
4421
  {
 
4422
    GSList *tmp;
 
4423
    MetaWindow *l_window;
 
4424
 
 
4425
    tmp = meta_display_list_windows (display, META_LIST_DEFAULT);
 
4426
 
 
4427
    /* Go through all windows */
 
4428
    while (tmp != NULL)
 
4429
      {
 
4430
        l_window=tmp->data;
 
4431
 
 
4432
        /* Check to see if it demands attention */
 
4433
        if (l_window->wm_state_demands_attention && 
 
4434
            l_window->workspace!=workspace) 
 
4435
          {
 
4436
            /* if it does, add it to the popup */
 
4437
            tab_list = g_list_prepend (tab_list, l_window);
 
4438
          }
 
4439
 
 
4440
        tmp = tmp->next;
 
4441
      } /* End while tmp!=NULL */
 
4442
  }
 
4443
  
 
4444
  return tab_list;
 
4445
}
 
4446
 
 
4447
MetaWindow*
 
4448
meta_display_get_tab_next (MetaDisplay   *display,
 
4449
                           MetaTabList    type,
 
4450
                           MetaScreen    *screen,
 
4451
                           MetaWorkspace *workspace,
 
4452
                           MetaWindow    *window,
 
4453
                           gboolean       backward)
 
4454
{
 
4455
  gboolean skip;
 
4456
  GList *tab_list;
 
4457
  MetaWindow *ret;
 
4458
  tab_list = meta_display_get_tab_list(display,
 
4459
                                       type,
 
4460
                                       screen,
 
4461
                                       workspace);
 
4462
 
 
4463
  if (tab_list == NULL)
 
4464
    return NULL;
 
4465
  
 
4466
  if (window != NULL)
 
4467
    {
 
4468
      g_assert (window->display == display);
 
4469
      
 
4470
      if (backward)
 
4471
        ret = find_tab_backward (display, type, screen, workspace,
 
4472
                                 g_list_find (tab_list,
 
4473
                                              window),
 
4474
                                 TRUE);
 
4475
      else
 
4476
        ret = find_tab_forward (display, type, screen, workspace,
 
4477
                                g_list_find (tab_list,
 
4478
                                             window),
 
4479
                                TRUE);
 
4480
    }
 
4481
  else
 
4482
    {
 
4483
      skip = display->focus_window != NULL && 
 
4484
             IN_TAB_CHAIN (display->focus_window, type);
 
4485
      if (backward)
 
4486
        ret = find_tab_backward (display, type, screen, workspace,
 
4487
                                 tab_list, skip);
 
4488
      else
 
4489
        ret = find_tab_forward (display, type, screen, workspace,
 
4490
                                tab_list, skip);
 
4491
    }
 
4492
 
 
4493
  g_list_free (tab_list);
 
4494
  return ret;
 
4495
}
 
4496
 
 
4497
MetaWindow*
 
4498
meta_display_get_tab_current (MetaDisplay   *display,
 
4499
                              MetaTabList    type,
 
4500
                              MetaScreen    *screen,
 
4501
                              MetaWorkspace *workspace)
 
4502
{
 
4503
  MetaWindow *window;
 
4504
 
 
4505
  window = display->focus_window;
 
4506
  
 
4507
  if (window != NULL &&
 
4508
      window->screen == screen &&
 
4509
      IN_TAB_CHAIN (window, type) &&
 
4510
      (workspace == NULL ||
 
4511
       meta_window_located_on_workspace (window, workspace)))
 
4512
    return window;
 
4513
  else
 
4514
    return NULL;
 
4515
}
 
4516
 
 
4517
int
 
4518
meta_resize_gravity_from_grab_op (MetaGrabOp op)
 
4519
{
 
4520
  int gravity;
 
4521
  
 
4522
  gravity = -1;
 
4523
  switch (op)
 
4524
    {
 
4525
    case META_GRAB_OP_RESIZING_SE:
 
4526
    case META_GRAB_OP_KEYBOARD_RESIZING_SE:
 
4527
      gravity = NorthWestGravity;
 
4528
      break;
 
4529
    case META_GRAB_OP_KEYBOARD_RESIZING_S:
 
4530
    case META_GRAB_OP_RESIZING_S:
 
4531
      gravity = NorthGravity;
 
4532
      break;
 
4533
    case META_GRAB_OP_KEYBOARD_RESIZING_SW:
 
4534
    case META_GRAB_OP_RESIZING_SW:
 
4535
      gravity = NorthEastGravity;
 
4536
      break;
 
4537
    case META_GRAB_OP_KEYBOARD_RESIZING_N:
 
4538
    case META_GRAB_OP_RESIZING_N:
 
4539
      gravity = SouthGravity;
 
4540
      break;
 
4541
    case META_GRAB_OP_KEYBOARD_RESIZING_NE:
 
4542
    case META_GRAB_OP_RESIZING_NE:
 
4543
      gravity = SouthWestGravity;
 
4544
      break;
 
4545
    case META_GRAB_OP_KEYBOARD_RESIZING_NW:
 
4546
    case META_GRAB_OP_RESIZING_NW:
 
4547
      gravity = SouthEastGravity;
 
4548
      break;
 
4549
    case META_GRAB_OP_KEYBOARD_RESIZING_E:
 
4550
    case META_GRAB_OP_RESIZING_E:
 
4551
      gravity = WestGravity;
 
4552
      break;
 
4553
    case META_GRAB_OP_KEYBOARD_RESIZING_W:
 
4554
    case META_GRAB_OP_RESIZING_W:
 
4555
      gravity = EastGravity;
 
4556
      break;
 
4557
    case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
 
4558
      gravity = CenterGravity;
 
4559
      break;
 
4560
    default:
 
4561
      break;
 
4562
    }
 
4563
 
 
4564
  return gravity;
 
4565
}
 
4566
 
 
4567
static MetaScreen*
 
4568
find_screen_for_selection (MetaDisplay *display,
 
4569
                           Window       owner,
 
4570
                           Atom         selection)
 
4571
{  
 
4572
  GSList *tmp;  
 
4573
  
 
4574
  tmp = display->screens;
 
4575
  while (tmp != NULL)
 
4576
    {
 
4577
      MetaScreen *screen = tmp->data;
 
4578
      
 
4579
      if (screen->wm_sn_selection_window == owner &&
 
4580
          screen->wm_sn_atom == selection)
 
4581
        return screen;
 
4582
  
 
4583
      tmp = tmp->next;
 
4584
    }
 
4585
 
 
4586
  return NULL;
 
4587
}
 
4588
 
 
4589
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
 
4590
static gboolean
 
4591
convert_property (MetaDisplay *display,
 
4592
                  MetaScreen  *screen,
 
4593
                  Window       w,
 
4594
                  Atom         target,
 
4595
                  Atom         property)
 
4596
{
 
4597
#define N_TARGETS 4
 
4598
  Atom conversion_targets[N_TARGETS];
 
4599
  long icccm_version[] = { 2, 0 };
 
4600
 
 
4601
  conversion_targets[0] = display->atom_TARGETS;
 
4602
  conversion_targets[1] = display->atom_MULTIPLE;
 
4603
  conversion_targets[2] = display->atom_TIMESTAMP;
 
4604
  conversion_targets[3] = display->atom_VERSION;
 
4605
 
 
4606
  meta_error_trap_push_with_return (display);
 
4607
  if (target == display->atom_TARGETS)
 
4608
    XChangeProperty (display->xdisplay, w, property,
 
4609
                     XA_ATOM, 32, PropModeReplace,
 
4610
                     (unsigned char *)conversion_targets, N_TARGETS);
 
4611
  else if (target == display->atom_TIMESTAMP)
 
4612
    XChangeProperty (display->xdisplay, w, property,
 
4613
                     XA_INTEGER, 32, PropModeReplace,
 
4614
                     (unsigned char *)&screen->wm_sn_timestamp, 1);
 
4615
  else if (target == display->atom_VERSION)
 
4616
    XChangeProperty (display->xdisplay, w, property,
 
4617
                     XA_INTEGER, 32, PropModeReplace,
 
4618
                     (unsigned char *)icccm_version, 2);
 
4619
  else
 
4620
    {
 
4621
      meta_error_trap_pop_with_return (display, FALSE);
 
4622
      return FALSE;
 
4623
    }
 
4624
  
 
4625
  if (meta_error_trap_pop_with_return (display, FALSE) != Success)
 
4626
    return FALSE;
 
4627
 
 
4628
  /* Be sure the PropertyNotify has arrived so we
 
4629
   * can send SelectionNotify
 
4630
   */
 
4631
  /* FIXME the error trap pop synced anyway, right? */
 
4632
  meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC);
 
4633
  XSync (display->xdisplay, False);
 
4634
 
 
4635
  return TRUE;
 
4636
}
 
4637
 
 
4638
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
 
4639
static void
 
4640
process_selection_request (MetaDisplay   *display,
 
4641
                           XEvent        *event)
 
4642
{
 
4643
  XSelectionEvent reply;
 
4644
  MetaScreen *screen;
 
4645
 
 
4646
  screen = find_screen_for_selection (display,
 
4647
                                      event->xselectionrequest.owner,
 
4648
                                      event->xselectionrequest.selection);
 
4649
 
 
4650
  if (screen == NULL)
 
4651
    {
 
4652
      char *str;
 
4653
      
 
4654
      meta_error_trap_push (display);
 
4655
      str = XGetAtomName (display->xdisplay,
 
4656
                          event->xselectionrequest.selection);
 
4657
      meta_error_trap_pop (display, TRUE);
 
4658
      
 
4659
      meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
 
4660
                    str ? str : "(bad atom)", event->xselectionrequest.owner);
 
4661
      
 
4662
      meta_XFree (str);
 
4663
 
 
4664
      return;
 
4665
    }
 
4666
  
 
4667
  reply.type = SelectionNotify;
 
4668
  reply.display = display->xdisplay;
 
4669
  reply.requestor = event->xselectionrequest.requestor;
 
4670
  reply.selection = event->xselectionrequest.selection;
 
4671
  reply.target = event->xselectionrequest.target;
 
4672
  reply.property = None;
 
4673
  reply.time = event->xselectionrequest.time;
 
4674
 
 
4675
  if (event->xselectionrequest.target == display->atom_MULTIPLE)
 
4676
    {
 
4677
      if (event->xselectionrequest.property != None)
 
4678
        {
 
4679
          Atom type, *adata;
 
4680
          int i, format;
 
4681
          unsigned long num, rest;
 
4682
          unsigned char *data;
 
4683
 
 
4684
          meta_error_trap_push_with_return (display);
 
4685
          if (XGetWindowProperty (display->xdisplay,
 
4686
                                  event->xselectionrequest.requestor,
 
4687
                                  event->xselectionrequest.property, 0, 256, False,
 
4688
                                  display->atom_ATOM_PAIR,
 
4689
                                  &type, &format, &num, &rest, &data) != Success)
 
4690
            {
 
4691
              meta_error_trap_pop_with_return (display, TRUE);
 
4692
              return;
 
4693
            }
 
4694
          
 
4695
          if (meta_error_trap_pop_with_return (display, TRUE) == Success)
 
4696
            {              
 
4697
              /* FIXME: to be 100% correct, should deal with rest > 0,
 
4698
               * but since we have 4 possible targets, we will hardly ever
 
4699
               * meet multiple requests with a length > 8
 
4700
               */
 
4701
              adata = (Atom*)data;
 
4702
              i = 0;
 
4703
              while (i < (int) num)
 
4704
                {
 
4705
                  if (!convert_property (display, screen,
 
4706
                                         event->xselectionrequest.requestor,
 
4707
                                         adata[i], adata[i+1]))
 
4708
                    adata[i+1] = None;
 
4709
                  i += 2;
 
4710
                }
 
4711
 
 
4712
              meta_error_trap_push (display);
 
4713
              XChangeProperty (display->xdisplay,
 
4714
                               event->xselectionrequest.requestor,
 
4715
                               event->xselectionrequest.property,
 
4716
                               display->atom_ATOM_PAIR,
 
4717
                               32, PropModeReplace, data, num);
 
4718
              meta_error_trap_pop (display, FALSE);
 
4719
              meta_XFree (data);
 
4720
            }
 
4721
        }
 
4722
    }
 
4723
  else
 
4724
    {
 
4725
      if (event->xselectionrequest.property == None)
 
4726
        event->xselectionrequest.property = event->xselectionrequest.target;
 
4727
      
 
4728
      if (convert_property (display, screen,
 
4729
                            event->xselectionrequest.requestor,
 
4730
                            event->xselectionrequest.target,
 
4731
                            event->xselectionrequest.property))
 
4732
        reply.property = event->xselectionrequest.property;
 
4733
    }
 
4734
 
 
4735
  XSendEvent (display->xdisplay,
 
4736
              event->xselectionrequest.requestor,
 
4737
              False, 0L, (XEvent*)&reply);
 
4738
 
 
4739
  meta_verbose ("Handled selection request\n");
 
4740
}
 
4741
 
 
4742
static void
 
4743
process_selection_clear (MetaDisplay   *display,
 
4744
                         XEvent        *event)
 
4745
{
 
4746
  /* We need to unmanage the screen on which we lost the selection */
 
4747
  MetaScreen *screen;
 
4748
 
 
4749
  screen = find_screen_for_selection (display,
 
4750
                                      event->xselectionclear.window,
 
4751
                                      event->xselectionclear.selection);
 
4752
  
 
4753
 
 
4754
  if (screen != NULL)
 
4755
    {
 
4756
      meta_verbose ("Got selection clear for screen %d on display %s\n",
 
4757
                    screen->number, display->name);
 
4758
      
 
4759
      meta_display_unmanage_screen (display, 
 
4760
                                    screen,
 
4761
                                    event->xselectionclear.time);
 
4762
 
 
4763
      /* display and screen may both be invalid memory... */
 
4764
      
 
4765
      return;
 
4766
    }
 
4767
 
 
4768
  {
 
4769
    char *str;
 
4770
            
 
4771
    meta_error_trap_push (display);
 
4772
    str = XGetAtomName (display->xdisplay,
 
4773
                        event->xselectionclear.selection);
 
4774
    meta_error_trap_pop (display, TRUE);
 
4775
 
 
4776
    meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n",
 
4777
                  str ? str : "(bad atom)", event->xselectionclear.window);
 
4778
 
 
4779
    meta_XFree (str);
 
4780
  }
 
4781
}
 
4782
 
 
4783
void
 
4784
meta_display_unmanage_screen (MetaDisplay *display,
 
4785
                              MetaScreen  *screen,
 
4786
                              guint32      timestamp)
 
4787
{
 
4788
  meta_verbose ("Unmanaging screen %d on display %s\n",
 
4789
                screen->number, display->name);
 
4790
  
 
4791
  g_return_if_fail (g_slist_find (display->screens, screen) != NULL);
 
4792
  
 
4793
  meta_screen_free (screen, timestamp);
 
4794
  display->screens = g_slist_remove (display->screens, screen);
 
4795
 
 
4796
  if (display->screens == NULL)
 
4797
    meta_display_close (display, timestamp);
 
4798
}
 
4799
 
 
4800
void
 
4801
meta_display_unmanage_windows_for_screen (MetaDisplay *display,
 
4802
                                          MetaScreen  *screen,
 
4803
                                          guint32      timestamp)
 
4804
{
 
4805
  GSList *tmp;
 
4806
  GSList *winlist;
 
4807
 
 
4808
  winlist = meta_display_list_windows (display,
 
4809
                                       META_LIST_INCLUDE_OVERRIDE_REDIRECT);
 
4810
  winlist = g_slist_sort (winlist, meta_display_stack_cmp);
 
4811
 
 
4812
  /* Unmanage all windows */
 
4813
  tmp = winlist;
 
4814
  while (tmp != NULL)
 
4815
    {
 
4816
      meta_window_unmanage (tmp->data, timestamp);
 
4817
      
 
4818
      tmp = tmp->next;
 
4819
    }
 
4820
  g_slist_free (winlist);
 
4821
}
 
4822
 
 
4823
int
 
4824
meta_display_stack_cmp (const void *a,
 
4825
                        const void *b)
 
4826
{
 
4827
  MetaWindow *aw = (void*) a;
 
4828
  MetaWindow *bw = (void*) b;
 
4829
 
 
4830
  if (aw->screen == bw->screen)
 
4831
    return meta_stack_windows_cmp (aw->screen->stack, aw, bw);
 
4832
  /* Then assume screens are stacked by number */
 
4833
  else if (aw->screen->number < bw->screen->number)
 
4834
    return -1;
 
4835
  else if (aw->screen->number > bw->screen->number)
 
4836
    return 1;
 
4837
  else
 
4838
    return 0; /* not reached in theory, if windows on same display */
 
4839
}
 
4840
 
 
4841
void
 
4842
meta_display_devirtualize_modifiers (MetaDisplay        *display,
 
4843
                                     MetaVirtualModifier modifiers,
 
4844
                                     unsigned int       *mask)
 
4845
{
 
4846
  *mask = 0;
 
4847
  
 
4848
  if (modifiers & META_VIRTUAL_SHIFT_MASK)
 
4849
    *mask |= ShiftMask;
 
4850
  if (modifiers & META_VIRTUAL_CONTROL_MASK)
 
4851
    *mask |= ControlMask;
 
4852
  if (modifiers & META_VIRTUAL_ALT_MASK)
 
4853
    *mask |= Mod1Mask;
 
4854
  if (modifiers & META_VIRTUAL_META_MASK)
 
4855
    *mask |= display->meta_mask;
 
4856
  if (modifiers & META_VIRTUAL_HYPER_MASK)
 
4857
    *mask |= display->hyper_mask;
 
4858
  if (modifiers & META_VIRTUAL_SUPER_MASK)
 
4859
    *mask |= display->super_mask;
 
4860
  if (modifiers & META_VIRTUAL_MOD2_MASK)
 
4861
    *mask |= Mod2Mask;
 
4862
  if (modifiers & META_VIRTUAL_MOD3_MASK)
 
4863
    *mask |= Mod3Mask;
 
4864
  if (modifiers & META_VIRTUAL_MOD4_MASK)
 
4865
    *mask |= Mod4Mask;
 
4866
  if (modifiers & META_VIRTUAL_MOD5_MASK)
 
4867
    *mask |= Mod5Mask;  
 
4868
}
 
4869
 
 
4870
static void
 
4871
update_window_grab_modifiers (MetaDisplay *display)
 
4872
     
 
4873
{
 
4874
  MetaVirtualModifier virtual_mods;
 
4875
  unsigned int mods;
 
4876
    
 
4877
  virtual_mods = meta_prefs_get_mouse_button_mods ();
 
4878
  meta_display_devirtualize_modifiers (display, virtual_mods,
 
4879
                                       &mods);
 
4880
    
 
4881
  display->window_grab_modifiers = mods;
 
4882
}
 
4883
 
 
4884
static void
 
4885
prefs_changed_callback (MetaPreference pref,
 
4886
                        void          *data)
 
4887
{
 
4888
  MetaDisplay *display = data;
 
4889
  
 
4890
  /* It may not be obvious why we regrab on focus mode
 
4891
   * change; it's because we handle focus clicks a
 
4892
   * bit differently for the different focus modes.
 
4893
   */
 
4894
  if (pref == META_PREF_MOUSE_BUTTON_MODS ||
 
4895
      pref == META_PREF_FOCUS_MODE)
 
4896
    {
 
4897
      MetaDisplay *display = data;
 
4898
      GSList *windows;
 
4899
      GSList *tmp;
 
4900
      
 
4901
      windows = meta_display_list_windows (display, META_LIST_DEFAULT);
 
4902
      
 
4903
      /* Ungrab all */
 
4904
      tmp = windows;
 
4905
      while (tmp != NULL)
 
4906
        {
 
4907
          MetaWindow *w = tmp->data;
 
4908
          meta_display_ungrab_window_buttons (display, w->xwindow);
 
4909
          meta_display_ungrab_focus_window_button (display, w);
 
4910
          tmp = tmp->next;
 
4911
        }
 
4912
 
 
4913
      /* change our modifier */
 
4914
      if (pref == META_PREF_MOUSE_BUTTON_MODS)
 
4915
        update_window_grab_modifiers (display);
 
4916
 
 
4917
      /* Grab all */
 
4918
      tmp = windows;
 
4919
      while (tmp != NULL)
 
4920
        {
 
4921
          MetaWindow *w = tmp->data;
 
4922
          if (w->type != META_WINDOW_DOCK)
 
4923
            {
 
4924
              meta_display_grab_focus_window_button (display, w);
 
4925
              meta_display_grab_window_buttons (display, w->xwindow);
 
4926
            }
 
4927
          tmp = tmp->next;
 
4928
        }
 
4929
 
 
4930
      g_slist_free (windows);
 
4931
    }
 
4932
  else if (pref == META_PREF_AUDIBLE_BELL)
 
4933
    {
 
4934
      meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
 
4935
    }
 
4936
  else if (pref == META_PREF_COMPOSITING_MANAGER)
 
4937
    {
 
4938
      gboolean cm = meta_prefs_get_compositing_manager ();
 
4939
 
 
4940
      if (cm)
 
4941
        enable_compositor (display, TRUE);
 
4942
      else
 
4943
        disable_compositor (display);
 
4944
    }
 
4945
}
 
4946
 
 
4947
void
 
4948
meta_display_increment_focus_sentinel (MetaDisplay *display)
 
4949
{
 
4950
  unsigned long data[1];
 
4951
 
 
4952
  data[0] = meta_display_get_current_time (display);
 
4953
  
 
4954
  XChangeProperty (display->xdisplay,
 
4955
                   ((MetaScreen*) display->screens->data)->xroot,
 
4956
                   display->atom__MUTTER_SENTINEL,
 
4957
                   XA_CARDINAL,
 
4958
                   32, PropModeReplace, (guchar*) data, 1);
 
4959
  
 
4960
  display->sentinel_counter += 1;
 
4961
}
 
4962
 
 
4963
void
 
4964
meta_display_decrement_focus_sentinel (MetaDisplay *display)
 
4965
{
 
4966
  display->sentinel_counter -= 1;
 
4967
 
 
4968
  if (display->sentinel_counter < 0)
 
4969
    display->sentinel_counter = 0;
 
4970
}
 
4971
 
 
4972
gboolean
 
4973
meta_display_focus_sentinel_clear (MetaDisplay *display)
 
4974
{
 
4975
  return (display->sentinel_counter == 0);
 
4976
}
 
4977
 
 
4978
static void
 
4979
sanity_check_timestamps (MetaDisplay *display,
 
4980
                         guint32      timestamp)
 
4981
{
 
4982
  if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time))
 
4983
    {
 
4984
      meta_warning ("last_focus_time (%u) is greater than comparison "
 
4985
                    "timestamp (%u).  This most likely represents a buggy "
 
4986
                    "client sending inaccurate timestamps in messages such as "
 
4987
                    "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
 
4988
                    display->last_focus_time, timestamp);
 
4989
      display->last_focus_time = timestamp;
 
4990
    }
 
4991
  if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time))
 
4992
    {
 
4993
      GSList *windows;
 
4994
      GSList *tmp;
 
4995
 
 
4996
      meta_warning ("last_user_time (%u) is greater than comparison "
 
4997
                    "timestamp (%u).  This most likely represents a buggy "
 
4998
                    "client sending inaccurate timestamps in messages such as "
 
4999
                    "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
 
5000
                    display->last_user_time, timestamp);
 
5001
      display->last_user_time = timestamp;
 
5002
 
 
5003
      windows = meta_display_list_windows (display, META_LIST_DEFAULT);
 
5004
      tmp = windows;
 
5005
      while (tmp != NULL)
 
5006
        {
 
5007
          MetaWindow *window = tmp->data;
 
5008
          
 
5009
          if (XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time))
 
5010
            {
 
5011
              meta_warning ("%s appears to be one of the offending windows "
 
5012
                            "with a timestamp of %u.  Working around...\n",
 
5013
                            window->desc, window->net_wm_user_time);
 
5014
              window->net_wm_user_time = timestamp;
 
5015
            }
 
5016
          
 
5017
          tmp = tmp->next;
 
5018
        }
 
5019
 
 
5020
      g_slist_free (windows);
 
5021
    }
 
5022
}
 
5023
 
 
5024
static gboolean
 
5025
timestamp_too_old (MetaDisplay *display,
 
5026
                   MetaWindow  *window,
 
5027
                   guint32     *timestamp)
 
5028
{
 
5029
  /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow
 
5030
   * us to sanity check the timestamp here and ensure it doesn't correspond to
 
5031
   * a future time (though we would want to rename to 
 
5032
   * timestamp_too_old_or_in_future).
 
5033
   */
 
5034
 
 
5035
  if (*timestamp == CurrentTime)
 
5036
    {
 
5037
      meta_warning ("Got a request to focus %s with a timestamp of 0.  This "
 
5038
                    "shouldn't happen!\n",
 
5039
                    window ? window->desc : "the no_focus_window");
 
5040
      meta_print_backtrace ();
 
5041
      *timestamp = meta_display_get_current_time_roundtrip (display);
 
5042
      return FALSE;
 
5043
    }
 
5044
  else if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_focus_time))
 
5045
    {
 
5046
      if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time))
 
5047
        {
 
5048
          meta_topic (META_DEBUG_FOCUS,
 
5049
                      "Ignoring focus request for %s since %u "
 
5050
                      "is less than %u and %u.\n",
 
5051
                      window ? window->desc : "the no_focus_window",
 
5052
                      *timestamp,
 
5053
                      display->last_user_time,
 
5054
                      display->last_focus_time);
 
5055
          return TRUE;
 
5056
        }
 
5057
      else
 
5058
        {
 
5059
          meta_topic (META_DEBUG_FOCUS,
 
5060
                      "Received focus request for %s which is newer than most "
 
5061
                      "recent user_time, but less recent than "
 
5062
                      "last_focus_time (%u < %u < %u); adjusting "
 
5063
                      "accordingly.  (See bug 167358)\n",
 
5064
                      window ? window->desc : "the no_focus_window",
 
5065
                      display->last_user_time,
 
5066
                      *timestamp,
 
5067
                      display->last_focus_time);
 
5068
          *timestamp = display->last_focus_time;
 
5069
          return FALSE;
 
5070
        }
 
5071
    }
 
5072
 
 
5073
  return FALSE;
 
5074
}
 
5075
 
 
5076
void
 
5077
meta_display_set_input_focus_window (MetaDisplay *display, 
 
5078
                                     MetaWindow  *window,
 
5079
                                     gboolean     focus_frame,
 
5080
                                     guint32      timestamp)
 
5081
{
 
5082
  if (timestamp_too_old (display, window, &timestamp))
 
5083
    return;
 
5084
 
 
5085
  meta_error_trap_push (display);
 
5086
  XSetInputFocus (display->xdisplay,
 
5087
                  focus_frame ? window->frame->xwindow : window->xwindow,
 
5088
                  RevertToPointerRoot,
 
5089
                  timestamp);
 
5090
  meta_error_trap_pop (display, FALSE);
 
5091
 
 
5092
  display->expected_focus_window = window;
 
5093
  display->last_focus_time = timestamp;
 
5094
  display->active_screen = window->screen;
 
5095
 
 
5096
  if (window != display->autoraise_window)
 
5097
    meta_display_remove_autoraise_callback (window->display);
 
5098
}
 
5099
 
 
5100
void
 
5101
meta_display_focus_the_no_focus_window (MetaDisplay *display, 
 
5102
                                        MetaScreen  *screen,
 
5103
                                        guint32      timestamp)
 
5104
{
 
5105
  if (timestamp_too_old (display, NULL, &timestamp))
 
5106
    return;
 
5107
 
 
5108
  XSetInputFocus (display->xdisplay,
 
5109
                  screen->no_focus_window,
 
5110
                  RevertToPointerRoot,
 
5111
                  timestamp);
 
5112
  display->expected_focus_window = NULL;
 
5113
  display->last_focus_time = timestamp;
 
5114
  display->active_screen = screen;
 
5115
 
 
5116
  meta_display_remove_autoraise_callback (display);
 
5117
}
 
5118
 
 
5119
void
 
5120
meta_display_remove_autoraise_callback (MetaDisplay *display)
 
5121
{
 
5122
  if (display->autoraise_timeout_id != 0)
 
5123
    {
 
5124
      g_source_remove (display->autoraise_timeout_id);
 
5125
      display->autoraise_timeout_id = 0;
 
5126
      display->autoraise_window = NULL;
 
5127
    }
 
5128
}
 
5129
 
 
5130
void
 
5131
meta_display_overlay_key_activate (MetaDisplay *display)
 
5132
{
 
5133
  g_signal_emit (display, display_signals[OVERLAY_KEY], 0);
 
5134
}
 
5135
 
 
5136
void
 
5137
meta_display_get_compositor_version (MetaDisplay *display,
 
5138
                                     int         *major,
 
5139
                                     int         *minor)
 
5140
{
 
5141
  *major = display->composite_major_version;
 
5142
  *minor = display->composite_minor_version;
 
5143
}
 
5144
 
 
5145
Display *
 
5146
meta_display_get_xdisplay (MetaDisplay *display)
 
5147
{
 
5148
  return display->xdisplay;
 
5149
}
 
5150
 
 
5151
MetaCompositor *
 
5152
meta_display_get_compositor (MetaDisplay *display)
 
5153
{
 
5154
  return display->compositor;
 
5155
}
 
5156
 
 
5157
GSList *
 
5158
meta_display_get_screens (MetaDisplay *display)
 
5159
{
 
5160
  return display->screens;
 
5161
}
 
5162
 
 
5163
gboolean
 
5164
meta_display_has_shape (MetaDisplay *display)
 
5165
{
 
5166
  return META_DISPLAY_HAS_SHAPE (display);
 
5167
}
 
5168
 
 
5169
/**
 
5170
 * meta_display_get_focus_window:
 
5171
 * @display: a #MetaDisplay
 
5172
 *
 
5173
 * Get the window that, according to events received from X server,
 
5174
 * currently has the input focus. We may have already sent a request
 
5175
 * to the X server to move the focus window elsewhere. (The
 
5176
 * expected_focus_window records where we've last set the input
 
5177
 * focus.)
 
5178
 *
 
5179
 * Return Value: (transfer none): The current focus window
 
5180
 */
 
5181
MetaWindow *
 
5182
meta_display_get_focus_window (MetaDisplay *display)
 
5183
{
 
5184
  return display->focus_window;
 
5185
}
 
5186
 
 
5187
int 
 
5188
meta_display_get_damage_event_base (MetaDisplay *display)
 
5189
{
 
5190
  return display->damage_event_base;
 
5191
}
 
5192
 
 
5193
#ifdef HAVE_SHAPE
 
5194
int
 
5195
meta_display_get_shape_event_base (MetaDisplay *display)
 
5196
{
 
5197
  return display->shape_event_base;
 
5198
}
 
5199
#endif
 
5200
 
 
5201
Atom meta_display_get_atom (MetaDisplay *display, MetaAtom meta_atom)
 
5202
{
 
5203
  Atom *atoms = & display->atom_WM_PROTOCOLS;
 
5204
 
 
5205
  return atoms[meta_atom - 1];
 
5206
}