You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

5663 lines
172 KiB

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