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.
 
 
 
 

12048 lines
379 KiB

  1. /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2. /*
  3. * Copyright (C) 2001 Havoc Pennington, Anders Carlsson
  4. * Copyright (C) 2002, 2003 Red Hat, Inc.
  5. * Copyright (C) 2003 Rob Adams
  6. * Copyright (C) 2004-2006 Elijah Newren
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
  21. * 02110-1335, USA.
  22. */
  23. /**
  24. * SECTION:window
  25. * @title: MetaWindow
  26. * @short_description: Muffin X managed windows
  27. */
  28. #include <config.h>
  29. #include "window-private.h"
  30. #include "boxes-private.h"
  31. #include "edge-resistance.h"
  32. #include <meta/util.h>
  33. #include "frame.h"
  34. #include <meta/errors.h>
  35. #include "workspace-private.h"
  36. #include "stack.h"
  37. #include "keybindings-private.h"
  38. #include "ui.h"
  39. #include "place.h"
  40. #include "session.h"
  41. #include <meta/prefs.h>
  42. #include "resizepopup.h"
  43. #include "xprops.h"
  44. #include <meta/group.h>
  45. #include "window-props.h"
  46. #include "constraints.h"
  47. #include "muffin-enum-types.h"
  48. #include <clutter/clutter.h>
  49. #include <X11/Xatom.h>
  50. #include <X11/Xlibint.h> /* For display->resource_mask */
  51. #include <string.h>
  52. #include <math.h>
  53. #ifdef HAVE_SHAPE
  54. #include <X11/extensions/shape.h>
  55. #endif
  56. #include <X11/XKBlib.h>
  57. #include <X11/extensions/Xcomposite.h>
  58. #include <gdk/gdkx.h>
  59. static int destroying_windows_disallowed = 0;
  60. static void update_sm_hints (MetaWindow *window);
  61. static void update_net_frame_extents (MetaWindow *window);
  62. static void recalc_window_type (MetaWindow *window);
  63. static void recalc_window_features (MetaWindow *window);
  64. static void invalidate_work_areas (MetaWindow *window);
  65. static void recalc_window_type (MetaWindow *window);
  66. static void set_wm_state_on_xwindow (MetaDisplay *display,
  67. Window xwindow,
  68. int state);
  69. static void set_wm_state (MetaWindow *window,
  70. int state);
  71. static void set_net_wm_state (MetaWindow *window);
  72. static void meta_window_set_above (MetaWindow *window,
  73. gboolean new_value);
  74. static void send_configure_notify (MetaWindow *window);
  75. static gboolean process_property_notify (MetaWindow *window,
  76. XPropertyEvent *event);
  77. static void meta_window_force_placement (MetaWindow *window);
  78. static void meta_window_show (MetaWindow *window);
  79. static void meta_window_hide (MetaWindow *window);
  80. static gboolean meta_window_same_client (MetaWindow *window,
  81. MetaWindow *other_window);
  82. static void meta_window_save_rect (MetaWindow *window);
  83. static void save_user_window_placement (MetaWindow *window);
  84. static void force_save_user_window_placement (MetaWindow *window);
  85. static void meta_window_move_resize_internal (MetaWindow *window,
  86. MetaMoveResizeFlags flags,
  87. int resize_gravity,
  88. int root_x_nw,
  89. int root_y_nw,
  90. int w,
  91. int h);
  92. static void ensure_mru_position_after (MetaWindow *window,
  93. MetaWindow *after_this_one);
  94. static void meta_window_move_resize_now (MetaWindow *window);
  95. static void meta_window_unqueue (MetaWindow *window, guint queuebits);
  96. static void update_move (MetaWindow *window,
  97. gboolean legacy_snap,
  98. gboolean snap_mode,
  99. int x,
  100. int y);
  101. static gboolean update_move_timeout (gpointer data);
  102. static void update_resize (MetaWindow *window,
  103. gboolean snap,
  104. int x,
  105. int y,
  106. gboolean force);
  107. static gboolean update_resize_timeout (gpointer data);
  108. static gboolean should_be_on_all_workspaces (MetaWindow *window);
  109. static void meta_window_flush_calc_showing (MetaWindow *window);
  110. static gboolean queue_calc_showing_func (MetaWindow *window,
  111. void *data);
  112. static void meta_window_apply_session_info (MetaWindow *window,
  113. const MetaWindowSessionInfo *info);
  114. static void meta_window_move_between_rects (MetaWindow *window,
  115. const MetaRectangle *old_area,
  116. const MetaRectangle *new_area);
  117. static void unmaximize_window_before_freeing (MetaWindow *window);
  118. static void unminimize_window_and_all_transient_parents (MetaWindow *window);
  119. static void notify_tile_type (MetaWindow *window);
  120. static void normalize_tile_state (MetaWindow *window);
  121. static unsigned int get_mask_from_snap_keysym (MetaWindow *window);
  122. /* Idle handlers for the three queues (run with meta_later_add()). The
  123. * "data" parameter in each case will be a GINT_TO_POINTER of the
  124. * index into the queue arrays to use.
  125. *
  126. * TODO: Possibly there is still some code duplication among these, which we
  127. * need to sort out at some point.
  128. */
  129. static gboolean idle_calc_showing (gpointer data);
  130. static gboolean idle_move_resize (gpointer data);
  131. static gboolean idle_update_icon (gpointer data);
  132. G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT);
  133. #define SNAP_DELAY 2000
  134. enum {
  135. PROP_0,
  136. PROP_TITLE,
  137. PROP_ICON,
  138. PROP_MINI_ICON,
  139. PROP_DECORATED,
  140. PROP_FULLSCREEN,
  141. PROP_MAXIMIZED_HORIZONTALLY,
  142. PROP_MAXIMIZED_VERTICALLY,
  143. PROP_TILE_TYPE,
  144. PROP_MINIMIZED,
  145. PROP_WINDOW_TYPE,
  146. PROP_USER_TIME,
  147. PROP_DEMANDS_ATTENTION,
  148. PROP_URGENT,
  149. PROP_MUFFIN_HINTS,
  150. PROP_APPEARS_FOCUSED,
  151. PROP_RESIZEABLE,
  152. PROP_ABOVE,
  153. PROP_WM_CLASS,
  154. PROP_GTK_APPLICATION_ID,
  155. PROP_GTK_UNIQUE_BUS_NAME,
  156. PROP_GTK_APPLICATION_OBJECT_PATH,
  157. PROP_GTK_WINDOW_OBJECT_PATH,
  158. PROP_GTK_APP_MENU_OBJECT_PATH,
  159. PROP_GTK_MENUBAR_OBJECT_PATH
  160. };
  161. enum
  162. {
  163. WORKSPACE_CHANGED,
  164. FOCUS,
  165. RAISED,
  166. UNMANAGED,
  167. LAST_SIGNAL
  168. };
  169. typedef enum
  170. {
  171. ZONE_TOP = 1 << 0,
  172. ZONE_RIGHT = 1 << 1,
  173. ZONE_BOTTOM = 1 << 2,
  174. ZONE_LEFT = 1 << 3,
  175. ZONE_ULC = ZONE_TOP | ZONE_LEFT,
  176. ZONE_LLC = ZONE_BOTTOM | ZONE_LEFT,
  177. ZONE_URC = ZONE_TOP | ZONE_RIGHT,
  178. ZONE_LRC = ZONE_BOTTOM | ZONE_RIGHT
  179. } TileZone;
  180. static guint window_signals[LAST_SIGNAL] = { 0 };
  181. static void
  182. prefs_changed_callback (MetaPreference pref,
  183. gpointer data)
  184. {
  185. MetaWindow *window = data;
  186. if (pref != META_PREF_WORKSPACES_ONLY_ON_PRIMARY)
  187. return;
  188. meta_window_update_on_all_workspaces (window);
  189. meta_window_queue (window, META_QUEUE_CALC_SHOWING);
  190. }
  191. static void
  192. meta_window_finalize (GObject *object)
  193. {
  194. MetaWindow *window = META_WINDOW (object);
  195. if (window->icon)
  196. g_object_unref (G_OBJECT (window->icon));
  197. if (window->mini_icon)
  198. g_object_unref (G_OBJECT (window->mini_icon));
  199. if (window->frame_bounds)
  200. cairo_region_destroy (window->frame_bounds);
  201. meta_icon_cache_free (&window->icon_cache);
  202. g_free (window->sm_client_id);
  203. g_free (window->wm_client_machine);
  204. g_free (window->startup_id);
  205. g_free (window->role);
  206. g_free (window->res_class);
  207. g_free (window->res_name);
  208. g_free (window->title);
  209. g_free (window->icon_name);
  210. g_free (window->desc);
  211. g_free (window->gtk_theme_variant);
  212. g_free (window->gtk_application_id);
  213. g_free (window->gtk_unique_bus_name);
  214. g_free (window->gtk_application_object_path);
  215. g_free (window->gtk_window_object_path);
  216. g_free (window->gtk_app_menu_object_path);
  217. g_free (window->gtk_menubar_object_path);
  218. G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
  219. }
  220. static void
  221. meta_window_get_property(GObject *object,
  222. guint prop_id,
  223. GValue *value,
  224. GParamSpec *pspec)
  225. {
  226. MetaWindow *win = META_WINDOW (object);
  227. switch (prop_id)
  228. {
  229. case PROP_TITLE:
  230. g_value_set_string (value, win->title);
  231. break;
  232. case PROP_ICON:
  233. g_value_set_object (value, win->icon);
  234. break;
  235. case PROP_MINI_ICON:
  236. g_value_set_object (value, win->mini_icon);
  237. break;
  238. case PROP_DECORATED:
  239. g_value_set_boolean (value, win->decorated);
  240. break;
  241. case PROP_FULLSCREEN:
  242. g_value_set_boolean (value, win->fullscreen);
  243. break;
  244. case PROP_MAXIMIZED_HORIZONTALLY:
  245. g_value_set_boolean (value, win->maximized_horizontally);
  246. break;
  247. case PROP_MAXIMIZED_VERTICALLY:
  248. g_value_set_boolean (value, win->maximized_vertically);
  249. break;
  250. case PROP_TILE_TYPE:
  251. g_value_set_int (value, win->tile_type);
  252. break;
  253. case PROP_MINIMIZED:
  254. g_value_set_boolean (value, win->minimized);
  255. break;
  256. case PROP_WINDOW_TYPE:
  257. g_value_set_enum (value, win->type);
  258. break;
  259. case PROP_USER_TIME:
  260. g_value_set_uint (value, win->net_wm_user_time);
  261. break;
  262. case PROP_DEMANDS_ATTENTION:
  263. g_value_set_boolean (value, win->wm_state_demands_attention);
  264. break;
  265. case PROP_URGENT:
  266. g_value_set_boolean (value, win->wm_hints_urgent);
  267. break;
  268. case PROP_MUFFIN_HINTS:
  269. g_value_set_string (value, win->muffin_hints);
  270. break;
  271. case PROP_APPEARS_FOCUSED:
  272. g_value_set_boolean (value, meta_window_appears_focused (win));
  273. break;
  274. case PROP_WM_CLASS:
  275. g_value_set_string (value, win->res_class);
  276. break;
  277. case PROP_RESIZEABLE:
  278. g_value_set_boolean (value, win->has_resize_func);
  279. break;
  280. case PROP_ABOVE:
  281. g_value_set_boolean (value, win->wm_state_above);
  282. break;
  283. case PROP_GTK_APPLICATION_ID:
  284. g_value_set_string (value, win->gtk_application_id);
  285. break;
  286. case PROP_GTK_UNIQUE_BUS_NAME:
  287. g_value_set_string (value, win->gtk_unique_bus_name);
  288. break;
  289. case PROP_GTK_APPLICATION_OBJECT_PATH:
  290. g_value_set_string (value, win->gtk_application_object_path);
  291. break;
  292. case PROP_GTK_WINDOW_OBJECT_PATH:
  293. g_value_set_string (value, win->gtk_window_object_path);
  294. break;
  295. case PROP_GTK_APP_MENU_OBJECT_PATH:
  296. g_value_set_string (value, win->gtk_app_menu_object_path);
  297. break;
  298. case PROP_GTK_MENUBAR_OBJECT_PATH:
  299. g_value_set_string (value, win->gtk_menubar_object_path);
  300. break;
  301. default:
  302. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  303. break;
  304. }
  305. }
  306. static void
  307. meta_window_set_property(GObject *object,
  308. guint prop_id,
  309. const GValue *value,
  310. GParamSpec *pspec)
  311. {
  312. switch (prop_id)
  313. {
  314. default:
  315. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  316. break;
  317. }
  318. }
  319. static void
  320. meta_window_class_init (MetaWindowClass *klass)
  321. {
  322. GObjectClass *object_class = G_OBJECT_CLASS (klass);
  323. object_class->finalize = meta_window_finalize;
  324. object_class->get_property = meta_window_get_property;
  325. object_class->set_property = meta_window_set_property;
  326. g_object_class_install_property (object_class,
  327. PROP_TITLE,
  328. g_param_spec_string ("title",
  329. "Title",
  330. "The title of the window",
  331. NULL,
  332. G_PARAM_READABLE));
  333. g_object_class_install_property (object_class,
  334. PROP_ICON,
  335. g_param_spec_object ("icon",
  336. "Icon",
  337. "32 pixel sized icon",
  338. GDK_TYPE_PIXBUF,
  339. G_PARAM_READABLE));
  340. g_object_class_install_property (object_class,
  341. PROP_MINI_ICON,
  342. g_param_spec_object ("mini-icon",
  343. "Mini Icon",
  344. "16 pixel sized icon",
  345. GDK_TYPE_PIXBUF,
  346. G_PARAM_READABLE));
  347. g_object_class_install_property (object_class,
  348. PROP_DECORATED,
  349. g_param_spec_boolean ("decorated",
  350. "Decorated",
  351. "Whether window is decorated",
  352. TRUE,
  353. G_PARAM_READABLE));
  354. g_object_class_install_property (object_class,
  355. PROP_FULLSCREEN,
  356. g_param_spec_boolean ("fullscreen",
  357. "Fullscreen",
  358. "Whether window is fullscreened",
  359. FALSE,
  360. G_PARAM_READABLE));
  361. g_object_class_install_property (object_class,
  362. PROP_MAXIMIZED_HORIZONTALLY,
  363. g_param_spec_boolean ("maximized-horizontally",
  364. "Maximized horizontally",
  365. "Whether window is maximized horizontally",
  366. FALSE,
  367. G_PARAM_READABLE));
  368. g_object_class_install_property (object_class,
  369. PROP_MAXIMIZED_VERTICALLY,
  370. g_param_spec_boolean ("maximized-vertically",
  371. "Maximizing vertically",
  372. "Whether window is maximized vertically",
  373. FALSE,
  374. G_PARAM_READABLE));
  375. g_object_class_install_property (object_class,
  376. PROP_TILE_TYPE,
  377. g_param_spec_int ("tile-type",
  378. "Window is tiled or snapped",
  379. "Whether window is tiled or snapped",
  380. META_WINDOW_TILE_TYPE_NONE,
  381. META_WINDOW_TILE_TYPE_SNAPPED,
  382. META_WINDOW_TILE_TYPE_NONE,
  383. G_PARAM_READABLE));
  384. g_object_class_install_property (object_class,
  385. PROP_MINIMIZED,
  386. g_param_spec_boolean ("minimized",
  387. "Minimizing",
  388. "Whether window is minimized",
  389. FALSE,
  390. G_PARAM_READABLE));
  391. g_object_class_install_property (object_class,
  392. PROP_WINDOW_TYPE,
  393. g_param_spec_enum ("window-type",
  394. "Window Type",
  395. "The type of the window",
  396. META_TYPE_WINDOW_TYPE,
  397. META_WINDOW_NORMAL,
  398. G_PARAM_READABLE));
  399. g_object_class_install_property (object_class,
  400. PROP_USER_TIME,
  401. g_param_spec_uint ("user-time",
  402. "User time",
  403. "Timestamp of last user interaction",
  404. 0,
  405. G_MAXUINT,
  406. 0,
  407. G_PARAM_READABLE));
  408. g_object_class_install_property (object_class,
  409. PROP_DEMANDS_ATTENTION,
  410. g_param_spec_boolean ("demands-attention",
  411. "Demands Attention",
  412. "Whether the window has _NET_WM_STATE_DEMANDS_ATTENTION set",
  413. FALSE,
  414. G_PARAM_READABLE));
  415. g_object_class_install_property (object_class,
  416. PROP_URGENT,
  417. g_param_spec_boolean ("urgent",
  418. "Urgent",
  419. "Whether the urgent flag of WM_HINTS is set",
  420. FALSE,
  421. G_PARAM_READABLE));
  422. g_object_class_install_property (object_class,
  423. PROP_MUFFIN_HINTS,
  424. g_param_spec_string ("muffin-hints",
  425. "_MUFFIN_HINTS",
  426. "Contents of the _MUFFIN_HINTS property of this window",
  427. NULL,
  428. G_PARAM_READABLE));
  429. g_object_class_install_property (object_class,
  430. PROP_APPEARS_FOCUSED,
  431. g_param_spec_boolean ("appears-focused",
  432. "Appears focused",
  433. "Whether the window is drawn as being focused",
  434. FALSE,
  435. G_PARAM_READABLE));
  436. g_object_class_install_property (object_class,
  437. PROP_RESIZEABLE,
  438. g_param_spec_boolean ("resizeable",
  439. "Resizeable",
  440. "Whether the window can be resized",
  441. FALSE,
  442. G_PARAM_READABLE));
  443. g_object_class_install_property (object_class,
  444. PROP_ABOVE,
  445. g_param_spec_boolean ("above",
  446. "Above",
  447. "Whether the window is shown as always-on-top",
  448. FALSE,
  449. G_PARAM_READABLE));
  450. g_object_class_install_property (object_class,
  451. PROP_WM_CLASS,
  452. g_param_spec_string ("wm-class",
  453. "WM_CLASS",
  454. "Contents of the WM_CLASS property of this window",
  455. NULL,
  456. G_PARAM_READABLE));
  457. g_object_class_install_property (object_class,
  458. PROP_GTK_APPLICATION_ID,
  459. g_param_spec_string ("gtk-application-id",
  460. "_GTK_APPLICATION_ID",
  461. "Contents of the _GTK_APPLICATION_ID property of this window",
  462. NULL,
  463. G_PARAM_READABLE));
  464. g_object_class_install_property (object_class,
  465. PROP_GTK_UNIQUE_BUS_NAME,
  466. g_param_spec_string ("gtk-unique-bus-name",
  467. "_GTK_UNIQUE_BUS_NAME",
  468. "Contents of the _GTK_UNIQUE_BUS_NAME property of this window",
  469. NULL,
  470. G_PARAM_READABLE));
  471. g_object_class_install_property (object_class,
  472. PROP_GTK_APPLICATION_OBJECT_PATH,
  473. g_param_spec_string ("gtk-application-object-path",
  474. "_GTK_APPLICATION_OBJECT_PATH",
  475. "Contents of the _GTK_APPLICATION_OBJECT_PATH property of this window",
  476. NULL,
  477. G_PARAM_READABLE));
  478. g_object_class_install_property (object_class,
  479. PROP_GTK_WINDOW_OBJECT_PATH,
  480. g_param_spec_string ("gtk-window-object-path",
  481. "_GTK_WINDOW_OBJECT_PATH",
  482. "Contents of the _GTK_WINDOW_OBJECT_PATH property of this window",
  483. NULL,
  484. G_PARAM_READABLE));
  485. g_object_class_install_property (object_class,
  486. PROP_GTK_APP_MENU_OBJECT_PATH,
  487. g_param_spec_string ("gtk-app-menu-object-path",
  488. "_GTK_APP_MENU_OBJECT_PATH",
  489. "Contents of the _GTK_APP_MENU_OBJECT_PATH property of this window",
  490. NULL,
  491. G_PARAM_READABLE));
  492. g_object_class_install_property (object_class,
  493. PROP_GTK_MENUBAR_OBJECT_PATH,
  494. g_param_spec_string ("gtk-menubar-object-path",
  495. "_GTK_MENUBAR_OBJECT_PATH",
  496. "Contents of the _GTK_MENUBAR_OBJECT_PATH property of this window",
  497. NULL,
  498. G_PARAM_READABLE));
  499. window_signals[WORKSPACE_CHANGED] =
  500. g_signal_new ("workspace-changed",
  501. G_TYPE_FROM_CLASS (object_class),
  502. G_SIGNAL_RUN_LAST,
  503. G_STRUCT_OFFSET (MetaWindowClass, workspace_changed),
  504. NULL, NULL, NULL,
  505. G_TYPE_NONE, 1,
  506. G_TYPE_INT);
  507. window_signals[FOCUS] =
  508. g_signal_new ("focus",
  509. G_TYPE_FROM_CLASS (object_class),
  510. G_SIGNAL_RUN_LAST,
  511. G_STRUCT_OFFSET (MetaWindowClass, focus),
  512. NULL, NULL, NULL,
  513. G_TYPE_NONE, 0);
  514. window_signals[RAISED] =
  515. g_signal_new ("raised",
  516. G_TYPE_FROM_CLASS (object_class),
  517. G_SIGNAL_RUN_LAST,
  518. G_STRUCT_OFFSET (MetaWindowClass, raised),
  519. NULL, NULL, NULL,
  520. G_TYPE_NONE, 0);
  521. window_signals[UNMANAGED] =
  522. g_signal_new ("unmanaged",
  523. G_TYPE_FROM_CLASS (object_class),
  524. G_SIGNAL_RUN_LAST,
  525. G_STRUCT_OFFSET (MetaWindowClass, unmanaged),
  526. NULL, NULL, NULL,
  527. G_TYPE_NONE, 0);
  528. }
  529. static void
  530. meta_window_init (MetaWindow *self)
  531. {
  532. meta_prefs_add_listener (prefs_changed_callback, self);
  533. }
  534. #ifdef WITH_VERBOSE_MODE
  535. static const char*
  536. wm_state_to_string (int state)
  537. {
  538. switch (state)
  539. {
  540. case NormalState:
  541. return "NormalState";
  542. case IconicState:
  543. return "IconicState";
  544. case WithdrawnState:
  545. return "WithdrawnState";
  546. }
  547. return "Unknown";
  548. }
  549. #endif
  550. static gboolean
  551. is_desktop_or_dock_foreach (MetaWindow *window,
  552. void *data)
  553. {
  554. gboolean *result = data;
  555. *result =
  556. window->type == META_WINDOW_DESKTOP ||
  557. window->type == META_WINDOW_DOCK;
  558. if (*result)
  559. return FALSE; /* stop as soon as we find one */
  560. else
  561. return TRUE;
  562. }
  563. /* window is the window that's newly mapped provoking
  564. * the possible change
  565. */
  566. static void
  567. maybe_leave_show_desktop_mode (MetaWindow *window)
  568. {
  569. gboolean is_desktop_or_dock;
  570. if (!window->screen->active_workspace->showing_desktop)
  571. return;
  572. /* If the window is a transient for the dock or desktop, don't
  573. * leave show desktop mode when the window opens. That's
  574. * so you can e.g. hide all windows, manipulate a file on
  575. * the desktop via a dialog, then unshow windows again.
  576. */
  577. is_desktop_or_dock = FALSE;
  578. is_desktop_or_dock_foreach (window,
  579. &is_desktop_or_dock);
  580. meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
  581. &is_desktop_or_dock);
  582. if (!is_desktop_or_dock)
  583. {
  584. meta_screen_minimize_all_on_active_workspace_except (window->screen,
  585. window);
  586. meta_screen_unshow_desktop (window->screen);
  587. }
  588. }
  589. static gboolean
  590. client_window_should_be_mapped (MetaWindow *window)
  591. {
  592. return !window->shaded;
  593. }
  594. static void
  595. sync_client_window_mapped (MetaWindow *window)
  596. {
  597. gboolean should_be_mapped = client_window_should_be_mapped (window);
  598. g_return_if_fail (!window->override_redirect);
  599. if (window->mapped == should_be_mapped)
  600. return;
  601. window->mapped = should_be_mapped;
  602. meta_error_trap_push (window->display);
  603. if (should_be_mapped)
  604. {
  605. XMapWindow (window->display->xdisplay, window->xwindow);
  606. }
  607. else
  608. {
  609. XUnmapWindow (window->display->xdisplay, window->xwindow);
  610. window->unmaps_pending ++;
  611. }
  612. meta_error_trap_pop (window->display);
  613. }
  614. LOCAL_SYMBOL MetaWindow*
  615. meta_window_new (MetaDisplay *display,
  616. Window xwindow,
  617. gboolean must_be_viewable)
  618. {
  619. XWindowAttributes attrs;
  620. MetaWindow *window;
  621. meta_display_grab (display);
  622. meta_error_trap_push (display); /* Push a trap over all of window
  623. * creation, to reduce XSync() calls
  624. */
  625. meta_error_trap_push_with_return (display);
  626. if (XGetWindowAttributes (display->xdisplay,xwindow, &attrs))
  627. {
  628. if(meta_error_trap_pop_with_return (display) != Success)
  629. {
  630. meta_verbose ("Failed to get attributes for window 0x%lx\n",
  631. xwindow);
  632. meta_error_trap_pop (display);
  633. meta_display_ungrab (display);
  634. return NULL;
  635. }
  636. window = meta_window_new_with_attrs (display, xwindow,
  637. must_be_viewable,
  638. META_COMP_EFFECT_CREATE,
  639. &attrs);
  640. }
  641. else
  642. {
  643. meta_error_trap_pop_with_return (display);
  644. meta_verbose ("Failed to get attributes for window 0x%lx\n",
  645. xwindow);
  646. meta_error_trap_pop (display);
  647. meta_display_ungrab (display);
  648. return NULL;
  649. }
  650. meta_error_trap_pop (display);
  651. meta_display_ungrab (display);
  652. return window;
  653. }
  654. /* The MUFFIN_WM_CLASS_FILTER environment variable is designed for
  655. * performance and regression testing environments where we want to do
  656. * tests with only a limited set of windows and ignore all other windows
  657. *
  658. * When it is set to a comma separated list of WM_CLASS class names, all
  659. * windows not matching the list will be ignored.
  660. *
  661. * Returns TRUE if window has been filtered out and should be ignored.
  662. */
  663. static gboolean
  664. maybe_filter_window (MetaDisplay *display,
  665. Window xwindow,
  666. gboolean must_be_viewable,
  667. XWindowAttributes *attrs)
  668. {
  669. static char **filter_wm_classes = NULL;
  670. static gboolean initialized = FALSE;
  671. XClassHint class_hint;
  672. gboolean filtered;
  673. Status success;
  674. int i;
  675. if (!initialized)
  676. {
  677. const char *filter_string = g_getenv ("MUFFIN_WM_CLASS_FILTER");
  678. if (filter_string)
  679. filter_wm_classes = g_strsplit (filter_string, ",", -1);
  680. initialized = TRUE;
  681. }
  682. if (!filter_wm_classes || !filter_wm_classes[0])
  683. return FALSE;
  684. filtered = TRUE;
  685. meta_error_trap_push (display);
  686. success = XGetClassHint (display->xdisplay, xwindow, &class_hint);
  687. if (success)
  688. {
  689. for (i = 0; filter_wm_classes[i]; i++)
  690. {
  691. if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0)
  692. {
  693. filtered = FALSE;
  694. break;
  695. }
  696. }
  697. XFree (class_hint.res_name);
  698. XFree (class_hint.res_class);
  699. }
  700. if (filtered)
  701. {
  702. /* We want to try and get the window managed by the next WM that come along,
  703. * so we need to make sure that windows that are requested to be mapped while
  704. * Muffin is running (!must_be_viewable), or windows already viewable at startup
  705. * get a non-withdrawn WM_STATE property. Previously unmapped windows are left
  706. * with whatever WM_STATE property they had.
  707. */
  708. if (!must_be_viewable || attrs->map_state == IsViewable)
  709. {
  710. gulong old_state;
  711. if (!meta_prop_get_cardinal_with_atom_type (display, xwindow,
  712. display->atom_WM_STATE,
  713. display->atom_WM_STATE,
  714. &old_state))
  715. old_state = WithdrawnState;
  716. if (old_state == WithdrawnState)
  717. set_wm_state_on_xwindow (display, xwindow, NormalState);
  718. }
  719. /* Make sure filtered windows are hidden from view */
  720. XUnmapWindow (display->xdisplay, xwindow);
  721. }
  722. meta_error_trap_pop (display);
  723. return filtered;
  724. }
  725. LOCAL_SYMBOL gboolean
  726. meta_window_should_attach_to_parent (MetaWindow *window)
  727. {
  728. MetaWindow *parent;
  729. if (!meta_prefs_get_attach_modal_dialogs () ||
  730. window->type != META_WINDOW_MODAL_DIALOG)
  731. return FALSE;
  732. parent = meta_window_get_transient_for (window);
  733. if (!parent)
  734. return FALSE;
  735. switch (parent->type)
  736. {
  737. case META_WINDOW_NORMAL:
  738. case META_WINDOW_DIALOG:
  739. case META_WINDOW_MODAL_DIALOG:
  740. return TRUE;
  741. default:
  742. return FALSE;
  743. }
  744. }
  745. LOCAL_SYMBOL LOCAL_SYMBOL MetaWindow*
  746. meta_window_new_with_attrs (MetaDisplay *display,
  747. Window xwindow,
  748. gboolean must_be_viewable,
  749. MetaCompEffect effect,
  750. XWindowAttributes *attrs)
  751. {
  752. MetaWindow *window;
  753. GSList *tmp;
  754. MetaWorkspace *space;
  755. gulong existing_wm_state;
  756. gulong event_mask;
  757. MetaMoveResizeFlags flags;
  758. gboolean has_shape;
  759. MetaScreen *screen;
  760. g_assert (attrs != NULL);
  761. meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
  762. if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
  763. {
  764. meta_verbose ("Not managing no_focus_window 0x%lx\n",
  765. xwindow);
  766. return NULL;
  767. }
  768. screen = NULL;
  769. for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
  770. {
  771. MetaScreen *scr = tmp->data;
  772. if (scr->xroot == attrs->root)
  773. {
  774. screen = tmp->data;
  775. break;
  776. }
  777. }
  778. g_assert (screen);
  779. /* A black list of override redirect windows that we don't need to manage: */
  780. if (attrs->override_redirect &&
  781. (xwindow == screen->no_focus_window ||
  782. xwindow == screen->flash_window ||
  783. xwindow == screen->wm_sn_selection_window ||
  784. attrs->class == InputOnly ||
  785. /* any windows created via meta_create_offscreen_window: */
  786. (attrs->x == -100 && attrs->y == -100
  787. && attrs->width == 1 && attrs->height == 1) ||
  788. xwindow == screen->wm_cm_selection_window ||
  789. xwindow == screen->guard_window ||
  790. xwindow == XCompositeGetOverlayWindow (display->xdisplay,
  791. screen->xroot)
  792. )
  793. ) {
  794. meta_verbose ("Not managing our own windows\n");
  795. return NULL;
  796. }
  797. if (maybe_filter_window (display, xwindow, must_be_viewable, attrs))
  798. {
  799. meta_verbose ("Not managing filtered window\n");
  800. return NULL;
  801. }
  802. /* Grab server */
  803. meta_display_grab (display);
  804. meta_error_trap_push (display); /* Push a trap over all of window
  805. * creation, to reduce XSync() calls
  806. */
  807. meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
  808. must_be_viewable,
  809. attrs->map_state,
  810. (attrs->map_state == IsUnmapped) ?
  811. "IsUnmapped" :
  812. (attrs->map_state == IsViewable) ?
  813. "IsViewable" :
  814. (attrs->map_state == IsUnviewable) ?
  815. "IsUnviewable" :
  816. "(unknown)");
  817. existing_wm_state = WithdrawnState;
  818. if (must_be_viewable && attrs->map_state != IsViewable)
  819. {
  820. /* Only manage if WM_STATE is IconicState or NormalState */
  821. gulong state;
  822. /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
  823. if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
  824. display->atom_WM_STATE,
  825. display->atom_WM_STATE,
  826. &state) &&
  827. (state == IconicState || state == NormalState)))
  828. {
  829. meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
  830. meta_error_trap_pop (display);
  831. meta_display_ungrab (display);
  832. return NULL;
  833. }
  834. existing_wm_state = state;
  835. meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
  836. wm_state_to_string (existing_wm_state));
  837. }
  838. meta_error_trap_push_with_return (display);
  839. /*
  840. * XAddToSaveSet can only be called on windows created by a different client.
  841. * with Muffin we want to be able to create manageable windows from within
  842. * the process (such as a dummy desktop window), so we do not want this
  843. * call failing to prevent the window from being managed -- wrap it in its
  844. * own error trap (we use the _with_return() version here to ensure that
  845. * XSync() is done on the pop, otherwise the error will not get caught).
  846. */
  847. meta_error_trap_push_with_return (display);
  848. XAddToSaveSet (display->xdisplay, xwindow);
  849. meta_error_trap_pop_with_return (display);
  850. event_mask =
  851. PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
  852. FocusChangeMask | ColormapChangeMask;
  853. if (attrs->override_redirect)
  854. event_mask |= StructureNotifyMask;
  855. /* If the window is from this client (a menu, say) we need to augment
  856. * the event mask, not replace it. For windows from other clients,
  857. * attrs->your_event_mask will be empty at this point.
  858. */
  859. XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
  860. has_shape = FALSE;
  861. #ifdef HAVE_SHAPE
  862. if (META_DISPLAY_HAS_SHAPE (display))
  863. {
  864. int x_bounding, y_bounding, x_clip, y_clip;
  865. unsigned w_bounding, h_bounding, w_clip, h_clip;
  866. int bounding_shaped, clip_shaped;
  867. XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
  868. XShapeQueryExtents (display->xdisplay, xwindow,
  869. &bounding_shaped, &x_bounding, &y_bounding,
  870. &w_bounding, &h_bounding,
  871. &clip_shaped, &x_clip, &y_clip,
  872. &w_clip, &h_clip);
  873. has_shape = bounding_shaped != FALSE;
  874. meta_topic (META_DEBUG_SHAPES,
  875. "Window has_shape = %d extents %d,%d %u x %u\n",
  876. has_shape, x_bounding, y_bounding,
  877. w_bounding, h_bounding);
  878. }
  879. #endif
  880. /* Get rid of any borders */
  881. if (attrs->border_width != 0)
  882. XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
  883. /* Get rid of weird gravities */
  884. if (attrs->win_gravity != NorthWestGravity)
  885. {
  886. XSetWindowAttributes set_attrs;
  887. set_attrs.win_gravity = NorthWestGravity;
  888. XChangeWindowAttributes (display->xdisplay,
  889. xwindow,
  890. CWWinGravity,
  891. &set_attrs);
  892. }
  893. if (meta_error_trap_pop_with_return (display) != Success)
  894. {
  895. meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
  896. xwindow);
  897. meta_error_trap_pop (display);
  898. meta_display_ungrab (display);
  899. return NULL;
  900. }
  901. window = g_object_new (META_TYPE_WINDOW, NULL);
  902. window->constructing = TRUE;
  903. window->dialog_pid = -1;
  904. window->xwindow = xwindow;
  905. /* this is in window->screen->display, but that's too annoying to
  906. * type
  907. */
  908. window->display = display;
  909. window->workspace = NULL;
  910. #ifdef HAVE_XSYNC
  911. window->sync_request_counter = None;
  912. window->sync_request_serial = 0;
  913. window->sync_request_timeout_id = 0;
  914. window->sync_request_alarm = None;
  915. #endif
  916. window->screen = screen;
  917. window->desc = g_strdup_printf ("0x%lx", window->xwindow);
  918. window->override_redirect = attrs->override_redirect;
  919. /* avoid tons of stack updates */
  920. meta_stack_freeze (window->screen->stack);
  921. window->has_shape = has_shape;
  922. window->rect.x = attrs->x;
  923. window->rect.y = attrs->y;
  924. window->rect.width = attrs->width;
  925. window->rect.height = attrs->height;
  926. /* And border width, size_hints are the "request" */
  927. window->border_width = attrs->border_width;
  928. window->size_hints.x = attrs->x;
  929. window->size_hints.y = attrs->y;
  930. window->size_hints.width = attrs->width;
  931. window->size_hints.height = attrs->height;
  932. /* initialize the remaining size_hints as if size_hints.flags were zero */
  933. meta_set_normal_hints (window, NULL);
  934. /* And this is our unmaximized size */
  935. window->saved_rect = window->rect;
  936. window->user_rect = window->rect;
  937. window->snapped_rect = window->rect;
  938. window->depth = attrs->depth;
  939. window->xvisual = attrs->visual;
  940. window->colormap = attrs->colormap;
  941. window->title = NULL;
  942. window->icon_name = NULL;
  943. window->icon = NULL;
  944. window->mini_icon = NULL;
  945. meta_icon_cache_init (&window->icon_cache);
  946. window->wm_hints_pixmap = None;
  947. window->wm_hints_mask = None;
  948. window->wm_hints_urgent = FALSE;
  949. window->frame = NULL;
  950. window->has_focus = FALSE;
  951. window->attached_focus_window = NULL;
  952. window->maximized_horizontally = FALSE;
  953. window->maximized_vertically = FALSE;
  954. window->tile_type = META_WINDOW_TILE_TYPE_NONE;
  955. window->snap_queued = FALSE;
  956. window->current_proximity_zone = 0;
  957. window->mouse_on_edge = FALSE;
  958. window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE;
  959. window->custom_snap_size = FALSE;
  960. window->zone_queued = ZONE_NONE;
  961. window->maximize_horizontally_after_placement = FALSE;
  962. window->maximize_vertically_after_placement = FALSE;
  963. window->minimize_after_placement = FALSE;
  964. window->tile_after_placement = FALSE;
  965. window->move_after_placement = FALSE;
  966. window->fullscreen = FALSE;
  967. window->fullscreen_after_placement = FALSE;
  968. window->fullscreen_monitors[0] = -1;
  969. window->require_fully_onscreen = TRUE;
  970. window->require_on_single_monitor = TRUE;
  971. window->require_titlebar_visible = TRUE;
  972. window->on_all_workspaces = FALSE;
  973. window->on_all_workspaces_requested = FALSE;
  974. window->tile_mode = META_TILE_NONE;
  975. window->last_tile_mode = META_TILE_NONE;
  976. window->resize_tile_mode = META_TILE_NONE;
  977. window->maybe_retile_maximize = FALSE;
  978. window->tile_monitor_number = -1;
  979. window->shaded = FALSE;
  980. window->initially_iconic = FALSE;
  981. window->minimized = FALSE;
  982. window->tab_unminimized = FALSE;
  983. window->iconic = FALSE;
  984. window->mapped = attrs->map_state != IsUnmapped;
  985. window->hidden = FALSE;
  986. window->visible_to_compositor = FALSE;
  987. window->pending_compositor_effect = effect;
  988. /* if already mapped, no need to worry about focus-on-first-time-showing */
  989. window->showing_for_first_time = !window->mapped;
  990. /* if already mapped we don't want to do the placement thing;
  991. * override-redirect windows are placed by the app */
  992. window->placed = ((window->mapped && !window->hidden) || window->override_redirect);
  993. if (window->placed)
  994. meta_topic (META_DEBUG_PLACEMENT,
  995. "Not placing window 0x%lx since it's already mapped\n",
  996. xwindow);
  997. window->force_save_user_rect = TRUE;
  998. window->denied_focus_and_not_transient = FALSE;
  999. window->unmanaging = FALSE;
  1000. window->is_in_queues = 0;
  1001. window->keys_grabbed = FALSE;
  1002. window->grab_on_frame = FALSE;
  1003. window->all_keys_grabbed = FALSE;
  1004. window->withdrawn = FALSE;
  1005. window->initial_workspace_set = FALSE;
  1006. window->initial_timestamp_set = FALSE;
  1007. window->net_wm_user_time_set = FALSE;
  1008. window->user_time_window = None;
  1009. window->take_focus = FALSE;
  1010. window->delete_window = FALSE;
  1011. window->net_wm_ping = FALSE;
  1012. window->input = TRUE;
  1013. window->calc_placement = FALSE;
  1014. window->shaken_loose = FALSE;
  1015. window->have_focus_click_grab = FALSE;
  1016. window->disable_sync = FALSE;
  1017. window->unmaps_pending = 0;
  1018. window->mwm_decorated = TRUE;
  1019. window->mwm_border_only = FALSE;
  1020. window->mwm_has_close_func = TRUE;
  1021. window->mwm_has_minimize_func = TRUE;
  1022. window->mwm_has_maximize_func = TRUE;
  1023. window->mwm_has_move_func = TRUE;
  1024. window->mwm_has_resize_func = TRUE;
  1025. window->decorated = TRUE;
  1026. window->has_close_func = TRUE;
  1027. window->has_minimize_func = TRUE;
  1028. window->has_maximize_func = TRUE;
  1029. window->has_move_func = TRUE;
  1030. window->has_resize_func = TRUE;
  1031. window->has_shade_func = TRUE;
  1032. window->has_fullscreen_func = TRUE;
  1033. window->always_sticky = FALSE;
  1034. window->wm_state_modal = FALSE;
  1035. window->skip_taskbar = FALSE;
  1036. window->skip_pager = FALSE;
  1037. window->wm_state_skip_taskbar = FALSE;
  1038. window->wm_state_skip_pager = FALSE;
  1039. window->wm_state_above = FALSE;
  1040. window->wm_state_below = FALSE;
  1041. window->wm_state_demands_attention = FALSE;
  1042. window->res_class = NULL;
  1043. window->res_name = NULL;
  1044. window->role = NULL;
  1045. window->sm_client_id = NULL;
  1046. window->wm_client_machine = NULL;
  1047. window->startup_id = NULL;
  1048. window->net_wm_pid = -1;
  1049. window->xtransient_for = None;
  1050. window->xclient_leader = None;
  1051. window->transient_parent_is_root_window = FALSE;
  1052. window->type = META_WINDOW_NORMAL;
  1053. window->type_atom = None;
  1054. window->struts = NULL;
  1055. window->using_net_wm_name = FALSE;
  1056. window->using_net_wm_visible_name = FALSE;
  1057. window->using_net_wm_icon_name = FALSE;
  1058. window->using_net_wm_visible_icon_name = FALSE;
  1059. window->need_reread_icon = TRUE;
  1060. window->layer = META_LAYER_LAST; /* invalid value */
  1061. window->stack_position = -1;
  1062. window->initial_workspace = 0; /* not used */
  1063. window->initial_timestamp = 0; /* not used */
  1064. window->compositor_private = NULL;
  1065. window->monitor = meta_screen_get_monitor_for_window (window->screen, window);
  1066. window->tile_match = NULL;
  1067. if (window->override_redirect)
  1068. {
  1069. window->decorated = FALSE;
  1070. window->always_sticky = TRUE;
  1071. window->has_close_func = FALSE;
  1072. window->has_shade_func = FALSE;
  1073. window->has_move_func = FALSE;
  1074. window->has_resize_func = FALSE;
  1075. }
  1076. meta_display_register_x_window (display, &window->xwindow, window);
  1077. /* Assign this #MetaWindow a sequence number which can be used
  1078. * for sorting.
  1079. */
  1080. window->stable_sequence = ++display->window_sequence_counter;
  1081. /* assign the window to its group, or create a new group if needed
  1082. */
  1083. window->group = NULL;
  1084. window->xgroup_leader = None;
  1085. meta_window_compute_group (window);
  1086. meta_window_load_initial_properties (window);
  1087. if (!window->override_redirect)
  1088. {
  1089. update_sm_hints (window); /* must come after transient_for */
  1090. meta_window_update_role (window);
  1091. }
  1092. meta_window_update_net_wm_type (window);
  1093. if (!window->override_redirect)
  1094. meta_window_update_icon_now (window);
  1095. if (window->initially_iconic)
  1096. {
  1097. /* WM_HINTS said minimized */
  1098. window->minimized = TRUE;
  1099. meta_verbose ("Window %s asked to start out minimized\n", window->desc);
  1100. }
  1101. if (existing_wm_state == IconicState)
  1102. {
  1103. /* WM_STATE said minimized */
  1104. window->minimized = TRUE;
  1105. meta_verbose ("Window %s had preexisting WM_STATE = IconicState, minimizing\n",
  1106. window->desc);
  1107. /* Assume window was previously placed, though perhaps it's
  1108. * been iconic its whole life, we have no way of knowing.
  1109. */
  1110. window->placed = TRUE;
  1111. }
  1112. /* Apply any window attributes such as initial workspace
  1113. * based on startup notification
  1114. */
  1115. meta_screen_apply_startup_properties (window->screen, window);
  1116. /* Try to get a "launch timestamp" for the window. If the window is
  1117. * a transient, we'd like to be able to get a last-usage timestamp
  1118. * from the parent window. If the window has no parent, there isn't
  1119. * much we can do...except record the current time so that any children
  1120. * can use this time as a fallback.
  1121. */
  1122. if (!window->override_redirect && !window->net_wm_user_time_set) {
  1123. MetaWindow *parent = NULL;
  1124. if (window->xtransient_for)
  1125. parent = meta_display_lookup_x_window (window->display,
  1126. window->xtransient_for);
  1127. /* First, maybe the app was launched with startup notification using an
  1128. * obsolete version of the spec; use that timestamp if it exists.
  1129. */
  1130. if (window->initial_timestamp_set)
  1131. /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
  1132. * being recorded as a fallback for potential transients
  1133. */
  1134. window->net_wm_user_time = window->initial_timestamp;
  1135. else if (parent != NULL)
  1136. meta_window_set_user_time(window, parent->net_wm_user_time);
  1137. else
  1138. /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
  1139. * being recorded as a fallback for potential transients
  1140. */
  1141. window->net_wm_user_time =
  1142. meta_display_get_current_time_roundtrip (window->display);
  1143. }
  1144. window->attached = meta_window_should_attach_to_parent (window);
  1145. if (window->attached)
  1146. recalc_window_features (window);
  1147. if (window->decorated)
  1148. meta_window_ensure_frame (window);
  1149. meta_window_grab_keys (window);
  1150. if (window->type != META_WINDOW_DOCK && !window->override_redirect)
  1151. {
  1152. meta_display_grab_window_buttons (window->display, window->xwindow);
  1153. meta_display_grab_focus_window_button (window->display, window);
  1154. }
  1155. if (window->type == META_WINDOW_DESKTOP ||
  1156. window->type == META_WINDOW_DOCK)
  1157. {
  1158. /* Change the default, but don't enforce this if the user
  1159. * focuses the dock/desktop and unsticks it using key shortcuts.
  1160. * Need to set this before adding to the workspaces so the MRU
  1161. * lists will be updated.
  1162. */
  1163. window->on_all_workspaces_requested = TRUE;
  1164. }
  1165. window->on_all_workspaces = should_be_on_all_workspaces (window);
  1166. /* For the workspace, first honor hints,
  1167. * if that fails put transients with parents,
  1168. * otherwise put window on active space
  1169. */
  1170. if (window->initial_workspace_set)
  1171. {
  1172. if (window->initial_workspace == (int) 0xFFFFFFFF)
  1173. {
  1174. meta_topic (META_DEBUG_PLACEMENT,
  1175. "Window %s is initially on all spaces\n",
  1176. window->desc);
  1177. /* need to set on_all_workspaces first so that it will be
  1178. * added to all the MRU lists
  1179. */
  1180. window->on_all_workspaces_requested = TRUE;
  1181. window->on_all_workspaces = TRUE;
  1182. meta_workspace_add_window (window->screen->active_workspace, window);
  1183. }
  1184. else
  1185. {
  1186. meta_topic (META_DEBUG_PLACEMENT,
  1187. "Window %s is initially on space %d\n",
  1188. window->desc, window->initial_workspace);
  1189. space =
  1190. meta_screen_get_workspace_by_index (window->screen,
  1191. window->initial_workspace);
  1192. if (space)
  1193. meta_workspace_add_window (space, window);
  1194. }
  1195. }
  1196. /* override-redirect windows are subtly different from other windows
  1197. * with window->on_all_workspaces == TRUE. Other windows are part of
  1198. * some workspace (so they can return to that if the flag is turned off),
  1199. * but appear on other workspaces. override-redirect windows are part
  1200. * of no workspace.
  1201. */
  1202. if (!window->override_redirect)
  1203. {
  1204. if (window->workspace == NULL &&
  1205. window->xtransient_for != None)
  1206. {
  1207. /* Try putting dialog on parent's workspace */
  1208. MetaWindow *parent;
  1209. parent = meta_display_lookup_x_window (window->display,
  1210. window->xtransient_for);
  1211. if (parent && parent->workspace)
  1212. {
  1213. meta_topic (META_DEBUG_PLACEMENT,
  1214. "Putting window %s on same workspace as parent %s\n",
  1215. window->desc, parent->desc);
  1216. if (parent->on_all_workspaces_requested)
  1217. {
  1218. window->on_all_workspaces_requested = TRUE;
  1219. window->on_all_workspaces = TRUE;
  1220. }
  1221. /* this will implicitly add to the appropriate MRU lists
  1222. */
  1223. meta_workspace_add_window (parent->workspace, window);
  1224. }
  1225. }
  1226. if (window->workspace == NULL)
  1227. {
  1228. meta_topic (META_DEBUG_PLACEMENT,
  1229. "Putting window %s on active workspace\n",
  1230. window->desc);
  1231. space = window->screen->active_workspace;
  1232. meta_workspace_add_window (space, window);
  1233. }
  1234. /* for the various on_all_workspaces = TRUE possible above */
  1235. meta_window_set_current_workspace_hint (window);
  1236. meta_window_update_struts (window);
  1237. }
  1238. g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window);
  1239. g_signal_emit_by_name (window->screen, "window-added", window, window->monitor->number);
  1240. /* Must add window to stack before doing move/resize, since the
  1241. * window might have fullscreen size (i.e. should have been
  1242. * fullscreen'd; acrobat is one such braindead case; it withdraws
  1243. * and remaps its window whenever trying to become fullscreen...)
  1244. * and thus constraints may try to auto-fullscreen it which also
  1245. * means restacking it.
  1246. */
  1247. if (!window->override_redirect)
  1248. meta_stack_add (window->screen->stack,
  1249. window);
  1250. else
  1251. window->layer = META_LAYER_OVERRIDE_REDIRECT; /* otherwise set by MetaStack */
  1252. /* Put our state back where it should be,
  1253. * passing TRUE for is_configure_request, ICCCM says
  1254. * initial map is handled same as configure request
  1255. */
  1256. flags =
  1257. META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
  1258. if (!window->override_redirect)
  1259. meta_window_move_resize_internal (window,
  1260. flags,
  1261. window->size_hints.win_gravity,
  1262. window->size_hints.x,
  1263. window->size_hints.y,
  1264. window->size_hints.width,
  1265. window->size_hints.height);
  1266. /* Now try applying saved stuff from the session */
  1267. {
  1268. const MetaWindowSessionInfo *info;
  1269. info = meta_window_lookup_saved_state (window);
  1270. if (info)
  1271. {
  1272. meta_window_apply_session_info (window, info);
  1273. meta_window_release_saved_state (info);
  1274. }
  1275. }
  1276. if (!window->override_redirect)
  1277. {
  1278. /* FIXME we have a tendency to set this then immediately
  1279. * change it again.
  1280. */
  1281. set_wm_state (window, window->iconic ? IconicState : NormalState);
  1282. set_net_wm_state (window);
  1283. }
  1284. meta_compositor_add_window (screen->display->compositor, window);
  1285. /* Sync stack changes */
  1286. meta_stack_thaw (window->screen->stack);
  1287. /* Usually the we'll have queued a stack sync anyways, because we've
  1288. * added a new frame window or restacked. But if an undecorated
  1289. * window is mapped, already stacked in the right place, then we
  1290. * might need to do this explicitly.
  1291. */
  1292. meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
  1293. /* disable show desktop mode unless we're a desktop component */
  1294. maybe_leave_show_desktop_mode (window);
  1295. meta_window_queue (window, META_QUEUE_CALC_SHOWING);
  1296. /* See bug 303284; a transient of the given window can already exist, in which
  1297. * case we think it should probably be shown.
  1298. */
  1299. meta_window_foreach_transient (window,
  1300. queue_calc_showing_func,
  1301. NULL);
  1302. /* See bug 334899; the window may have minimized ancestors
  1303. * which need to be shown.
  1304. *
  1305. * However, we shouldn't unminimize windows here when opening
  1306. * a new display because that breaks passing _NET_WM_STATE_HIDDEN
  1307. * between window managers when replacing them; see bug 358042.
  1308. *
  1309. * And we shouldn't unminimize windows if they were initially
  1310. * iconic.
  1311. */
  1312. if (!window->override_redirect &&
  1313. !display->display_opening &&
  1314. !window->initially_iconic)
  1315. unminimize_window_and_all_transient_parents (window);
  1316. meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
  1317. meta_display_ungrab (display);
  1318. window->constructing = FALSE;
  1319. meta_display_notify_window_created (display, window);
  1320. if (window->wm_state_demands_attention)
  1321. g_signal_emit_by_name (window->display, "window-demands-attention", window);
  1322. if (window->wm_hints_urgent)
  1323. g_signal_emit_by_name (window->display, "window-marked-urgent", window);
  1324. return window;
  1325. }
  1326. /* This function should only be called from the end of meta_window_new_with_attrs () */
  1327. static void
  1328. meta_window_apply_session_info (MetaWindow *window,
  1329. const MetaWindowSessionInfo *info)
  1330. {
  1331. if (info->stack_position_set)
  1332. {
  1333. meta_topic (META_DEBUG_SM,
  1334. "Restoring stack position %d for window %s\n",
  1335. info->stack_position, window->desc);
  1336. /* FIXME well, I'm not sure how to do this. */
  1337. }
  1338. if (info->minimized_set)
  1339. {
  1340. meta_topic (META_DEBUG_SM,
  1341. "Restoring minimized state %d for window %s\n",
  1342. info->minimized, window->desc);
  1343. if (window->has_minimize_func && info->minimized)
  1344. meta_window_minimize (window);
  1345. }
  1346. if (info->maximized_set)
  1347. {
  1348. meta_topic (META_DEBUG_SM,
  1349. "Restoring maximized state %d for window %s\n",
  1350. info->maximized, window->desc);
  1351. if (window->has_maximize_func && info->maximized)
  1352. {
  1353. meta_window_maximize (window,
  1354. META_MAXIMIZE_HORIZONTAL |
  1355. META_MAXIMIZE_VERTICAL);
  1356. if (info->saved_rect_set)
  1357. {
  1358. meta_topic (META_DEBUG_SM,
  1359. "Restoring saved rect %d,%d %dx%d for window %s\n",
  1360. info->saved_rect.x,
  1361. info->saved_rect.y,
  1362. info->saved_rect.width,
  1363. info->saved_rect.height,
  1364. window->desc);
  1365. window->saved_rect.x = info->saved_rect.x;
  1366. window->saved_rect.y = info->saved_rect.y;
  1367. window->saved_rect.width = info->saved_rect.width;
  1368. window->saved_rect.height = info->saved_rect.height;
  1369. }
  1370. }
  1371. }
  1372. if (info->on_all_workspaces_set)
  1373. {
  1374. window->on_all_workspaces_requested = info->on_all_workspaces;
  1375. meta_window_update_on_all_workspaces (window);
  1376. meta_topic (META_DEBUG_SM,
  1377. "Restoring sticky state %d for window %s\n",
  1378. window->on_all_workspaces_requested, window->desc);
  1379. }
  1380. if (info->workspace_indices)
  1381. {
  1382. GSList *tmp;
  1383. GSList *spaces;
  1384. spaces = NULL;
  1385. tmp = info->workspace_indices;
  1386. while (tmp != NULL)
  1387. {
  1388. MetaWorkspace *space;
  1389. space =
  1390. meta_screen_get_workspace_by_index (window->screen,
  1391. GPOINTER_TO_INT (tmp->data));
  1392. if (space)
  1393. spaces = g_slist_prepend (spaces, space);
  1394. tmp = tmp->next;
  1395. }
  1396. if (spaces)
  1397. {
  1398. /* This briefly breaks the invariant that we are supposed
  1399. * to always be on some workspace. But we paranoically
  1400. * ensured that one of the workspaces from the session was
  1401. * indeed valid, so we know we'll go right back to one.
  1402. */
  1403. if (window->workspace)
  1404. meta_workspace_remove_window (window->workspace, window);
  1405. /* Only restore to the first workspace if the window
  1406. * happened to be on more than one, since we have replaces
  1407. * window->workspaces with window->workspace
  1408. */
  1409. meta_workspace_add_window (spaces->data, window);
  1410. meta_topic (META_DEBUG_SM,
  1411. "Restoring saved window %s to workspace %d\n",
  1412. window->desc,
  1413. meta_workspace_index (spaces->data));
  1414. g_slist_free (spaces);
  1415. }
  1416. }
  1417. if (info->geometry_set)
  1418. {
  1419. int x, y, w, h;
  1420. MetaMoveResizeFlags flags;
  1421. window->placed = TRUE; /* don't do placement algorithms later */
  1422. x = info->rect.x;
  1423. y = info->rect.y;
  1424. w = window->size_hints.base_width +
  1425. info->rect.width * window->size_hints.width_inc;
  1426. h = window->size_hints.base_height +
  1427. info->rect.height * window->size_hints.height_inc;
  1428. /* Force old gravity, ignoring anything now set */
  1429. window->size_hints.win_gravity = info->gravity;
  1430. meta_topic (META_DEBUG_SM,
  1431. "Restoring pos %d,%d size %d x %d for %s\n",
  1432. x, y, w, h, window->desc);
  1433. flags = META_DO_GRAVITY_ADJUST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
  1434. meta_window_move_resize_internal (window,
  1435. flags,
  1436. window->size_hints.win_gravity,
  1437. x, y, w, h);
  1438. }
  1439. }
  1440. static gboolean
  1441. detach_foreach_func (MetaWindow *window,
  1442. void *data)
  1443. {
  1444. GList **children = data;
  1445. MetaWindow *parent;
  1446. if (window->attached)
  1447. {
  1448. /* Only return the immediate children of the window being unmanaged */
  1449. parent = meta_window_get_transient_for (window);
  1450. if (parent->unmanaging)
  1451. *children = g_list_prepend (*children, window);
  1452. }
  1453. return TRUE;
  1454. }
  1455. LOCAL_SYMBOL void
  1456. meta_window_unmanage (MetaWindow *window,
  1457. guint32 timestamp)
  1458. {
  1459. GList *tmp;
  1460. meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
  1461. if (window->visible_to_compositor || meta_window_is_attached_dialog (window))
  1462. meta_compositor_hide_window (window->display->compositor, window,
  1463. META_COMP_EFFECT_DESTROY);
  1464. meta_compositor_remove_window (window->display->compositor, window);
  1465. if (window->display->window_with_menu == window)
  1466. {
  1467. meta_ui_window_menu_free (window->display->window_menu);
  1468. window->display->window_menu = NULL;
  1469. window->display->window_with_menu = NULL;
  1470. }
  1471. if (destroying_windows_disallowed > 0)
  1472. meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
  1473. window->desc);
  1474. window->unmanaging = TRUE;
  1475. if (meta_prefs_get_attach_modal_dialogs ())
  1476. {
  1477. GList *attached_children = NULL, *iter;
  1478. /* Detach any attached dialogs by unmapping and letting them
  1479. * be remapped after @window is destroyed.
  1480. */
  1481. meta_window_foreach_transient (window,
  1482. detach_foreach_func,
  1483. &attached_children);
  1484. for (iter = attached_children; iter; iter = iter->next)
  1485. meta_window_unmanage (iter->data, timestamp);
  1486. g_list_free (attached_children);
  1487. }
  1488. if (window->fullscreen)
  1489. {
  1490. MetaGroup *group;
  1491. /* If the window is fullscreen, it may be forcing
  1492. * other windows in its group to a higher layer
  1493. */
  1494. meta_stack_freeze (window->screen->stack);
  1495. group = meta_window_get_group (window);
  1496. if (group)
  1497. meta_group_update_layers (group);
  1498. meta_stack_thaw (window->screen->stack);
  1499. }
  1500. meta_window_shutdown_group (window); /* safe to do this early as
  1501. * group.c won't re-add to the
  1502. * group if window->unmanaging
  1503. */
  1504. /* If we have the focus, focus some other window.
  1505. * This is done first, so that if the unmap causes
  1506. * an EnterNotify the EnterNotify will have final say
  1507. * on what gets focused, maintaining sloppy focus
  1508. * invariants.
  1509. */
  1510. if (meta_window_appears_focused (window))
  1511. meta_window_propagate_focus_appearance (window, FALSE);
  1512. if (window->has_focus)
  1513. {
  1514. meta_topic (META_DEBUG_FOCUS,
  1515. "Focusing default window since we're unmanaging %s\n",
  1516. window->desc);
  1517. meta_workspace_focus_default_window (window->screen->active_workspace,
  1518. window,
  1519. timestamp);
  1520. }
  1521. else if (window->display->expected_focus_window == window)
  1522. {
  1523. meta_topic (META_DEBUG_FOCUS,
  1524. "Focusing default window since expected focus window freed %s\n",
  1525. window->desc);
  1526. window->display->expected_focus_window = NULL;
  1527. meta_workspace_focus_default_window (window->screen->active_workspace,
  1528. window,
  1529. timestamp);
  1530. }
  1531. else
  1532. {
  1533. meta_topic (META_DEBUG_FOCUS,
  1534. "Unmanaging window %s which doesn't currently have focus\n",
  1535. window->desc);
  1536. }
  1537. if (window->struts)
  1538. {
  1539. meta_free_gslist_and_elements (window->struts);
  1540. window->struts = NULL;
  1541. meta_topic (META_DEBUG_WORKAREA,
  1542. "Unmanaging window %s which has struts, so invalidating work areas\n",
  1543. window->desc);
  1544. invalidate_work_areas (window);
  1545. }
  1546. if (window->sync_request_timeout_id)
  1547. {
  1548. g_source_remove (window->sync_request_timeout_id);
  1549. window->sync_request_timeout_id = 0;
  1550. }
  1551. if (window->display->grab_window == window)
  1552. meta_display_end_grab_op (window->display, timestamp);
  1553. g_assert (window->display->grab_window != window);
  1554. if (window->display->focus_window == window)
  1555. {
  1556. window->display->focus_window = NULL;
  1557. g_object_notify (G_OBJECT (window->display), "focus-window");
  1558. }
  1559. if (window->maximized_horizontally || window->maximized_vertically ||
  1560. window->tile_type != META_WINDOW_TILE_TYPE_NONE)
  1561. unmaximize_window_before_freeing (window);
  1562. meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
  1563. META_QUEUE_MOVE_RESIZE |
  1564. META_QUEUE_UPDATE_ICON);
  1565. meta_window_free_delete_dialog (window);
  1566. if (window->workspace)
  1567. meta_workspace_remove_window (window->workspace, window);
  1568. g_assert (window->workspace == NULL);
  1569. #ifndef G_DISABLE_CHECKS
  1570. tmp = window->screen->workspaces;
  1571. while (tmp != NULL)
  1572. {
  1573. MetaWorkspace *workspace = tmp->data;
  1574. g_assert (g_list_find (workspace->windows, window) == NULL);
  1575. g_assert (g_list_find (workspace->mru_list, window) == NULL);
  1576. tmp = tmp->next;
  1577. }
  1578. #endif
  1579. if (window->monitor)
  1580. {
  1581. g_signal_emit_by_name (window->screen, "window-left-monitor",
  1582. window->monitor->number, window);
  1583. window->monitor = NULL;
  1584. }
  1585. if (!window->override_redirect)
  1586. meta_stack_remove (window->screen->stack, window);
  1587. meta_window_destroy_sync_request_alarm (window);
  1588. if (window->frame)
  1589. {
  1590. /* The XReparentWindow call in meta_window_destroy_frame() moves the
  1591. * window so we need to send a configure notify; see bug 399552. (We
  1592. * also do this just in case a window got unmaximized.)
  1593. */
  1594. send_configure_notify (window);
  1595. meta_window_destroy_frame (window);
  1596. }
  1597. /* If an undecorated window is being withdrawn, that will change the
  1598. * stack as presented to the compositing manager, without actually
  1599. * changing the stacking order of X windows.
  1600. */
  1601. meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
  1602. if (window->withdrawn)
  1603. {
  1604. /* We need to clean off the window's state so it
  1605. * won't be restored if the app maps it again.
  1606. */
  1607. meta_error_trap_push (window->display);
  1608. meta_verbose ("Cleaning state from window %s\n", window->desc);
  1609. XDeleteProperty (window->display->xdisplay,
  1610. window->xwindow,
  1611. window->display->atom__NET_WM_DESKTOP);
  1612. XDeleteProperty (window->display->xdisplay,
  1613. window->xwindow,
  1614. window->display->atom__NET_WM_STATE);
  1615. XDeleteProperty (window->display->xdisplay,
  1616. window->xwindow,
  1617. window->display->atom__NET_WM_FULLSCREEN_MONITORS);
  1618. set_wm_state (window, WithdrawnState);
  1619. meta_error_trap_pop (window->display);
  1620. }
  1621. else
  1622. {
  1623. /* We need to put WM_STATE so that others will understand it on
  1624. * restart.
  1625. */
  1626. if (!window->minimized)
  1627. {
  1628. meta_error_trap_push (window->display);
  1629. set_wm_state (window, NormalState);
  1630. meta_error_trap_pop (window->display);
  1631. }
  1632. /* If we're unmanaging a window that is not withdrawn, then
  1633. * either (a) muffin is exiting, in which case we need to map
  1634. * the window so the next WM will know that it's not Withdrawn,
  1635. * or (b) we want to create a new MetaWindow to replace the
  1636. * current one, which will happen automatically if we re-map
  1637. * the X Window.
  1638. */
  1639. meta_error_trap_push (window->display);
  1640. XMapWindow (window->display->xdisplay,
  1641. window->xwindow);
  1642. meta_error_trap_pop (window->display);
  1643. }
  1644. meta_window_ungrab_keys (window);
  1645. meta_display_ungrab_window_buttons (window->display, window->xwindow);
  1646. meta_display_ungrab_focus_window_button (window->display, window);
  1647. meta_display_unregister_x_window (window->display, window->xwindow);
  1648. meta_error_trap_push (window->display);
  1649. /* Put back anything we messed up */
  1650. if (window->border_width != 0)
  1651. XSetWindowBorderWidth (window->display->xdisplay,
  1652. window->xwindow,
  1653. window->border_width);
  1654. /* No save set */
  1655. XRemoveFromSaveSet (window->display->xdisplay,
  1656. window->xwindow);
  1657. /* Even though the window is now unmanaged, we can't unselect events. This
  1658. * window might be a window from this process, like a GdkMenu, in
  1659. * which case it will have pointer events and so forth selected
  1660. * for it by GDK. There's no way to disentangle those events from the events
  1661. * we've selected. Even for a window from a different X client,
  1662. * GDK could also have selected events for it for IPC purposes, so we
  1663. * can't unselect in that case either.
  1664. *
  1665. * Similarly, we can't unselected for events on window->user_time_window.
  1666. * It might be our own GDK focus window, or it might be a window that a
  1667. * different client is using for multiple different things:
  1668. * _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
  1669. */
  1670. if (window->user_time_window != None)
  1671. {
  1672. meta_display_unregister_x_window (window->display,
  1673. window->user_time_window);
  1674. window->user_time_window = None;
  1675. }
  1676. #ifdef HAVE_SHAPE
  1677. if (META_DISPLAY_HAS_SHAPE (window->display))
  1678. XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
  1679. #endif
  1680. meta_error_trap_pop (window->display);
  1681. meta_prefs_remove_listener (prefs_changed_callback, window);
  1682. meta_screen_queue_check_fullscreen (window->screen);
  1683. g_signal_emit (window, window_signals[UNMANAGED], 0);
  1684. g_signal_emit_by_name (window->screen, "window-removed", window);
  1685. g_object_unref (window);
  1686. }
  1687. static gboolean
  1688. should_be_on_all_workspaces (MetaWindow *window)
  1689. {
  1690. return
  1691. window->on_all_workspaces_requested ||
  1692. window->override_redirect ||
  1693. (meta_prefs_get_workspaces_only_on_primary () &&
  1694. !meta_window_is_on_primary_monitor (window));
  1695. }
  1696. LOCAL_SYMBOL void
  1697. meta_window_update_on_all_workspaces (MetaWindow *window)
  1698. {
  1699. gboolean old_value;
  1700. old_value = window->on_all_workspaces;
  1701. window->on_all_workspaces = should_be_on_all_workspaces (window);
  1702. if (window->on_all_workspaces != old_value &&
  1703. !window->override_redirect)
  1704. {
  1705. if (window->on_all_workspaces)
  1706. {
  1707. GList* tmp = window->screen->workspaces;
  1708. /* Add to all MRU lists */
  1709. while (tmp)
  1710. {
  1711. MetaWorkspace* work = (MetaWorkspace*) tmp->data;
  1712. if (!g_list_find (work->mru_list, window))
  1713. work->mru_list = g_list_prepend (work->mru_list, window);
  1714. tmp = tmp->next;
  1715. }
  1716. }
  1717. else
  1718. {
  1719. GList* tmp = window->screen->workspaces;
  1720. /* Remove from MRU lists except the window's workspace */
  1721. while (tmp)
  1722. {
  1723. MetaWorkspace* work = (MetaWorkspace*) tmp->data;
  1724. if (work != window->workspace)
  1725. work->mru_list = g_list_remove (work->mru_list, window);
  1726. tmp = tmp->next;
  1727. }
  1728. }
  1729. meta_window_set_current_workspace_hint (window);
  1730. }
  1731. meta_screen_update_snapped_windows (window->screen);
  1732. }
  1733. static void
  1734. set_wm_state_on_xwindow (MetaDisplay *display,
  1735. Window xwindow,
  1736. int state)
  1737. {
  1738. unsigned long data[2];
  1739. /* Muffin doesn't use icon windows, so data[1] should be None
  1740. * according to the ICCCM 2.0 Section 4.1.3.1.
  1741. */
  1742. data[0] = state;
  1743. data[1] = None;
  1744. meta_error_trap_push (display);
  1745. XChangeProperty (display->xdisplay, xwindow,
  1746. display->atom_WM_STATE,
  1747. display->atom_WM_STATE,
  1748. 32, PropModeReplace, (guchar*) data, 2);
  1749. meta_error_trap_pop (display);
  1750. }
  1751. static void
  1752. set_wm_state (MetaWindow *window,
  1753. int state)
  1754. {
  1755. meta_verbose ("Setting wm state %s on %s\n",
  1756. wm_state_to_string (state), window->desc);
  1757. set_wm_state_on_xwindow (window->display, window->xwindow, state);
  1758. }
  1759. static void
  1760. set_net_wm_state (MetaWindow *window)
  1761. {
  1762. int i;
  1763. unsigned long data[14];
  1764. i = 0;
  1765. if (window->shaded)
  1766. {
  1767. data[i] = window->display->atom__NET_WM_STATE_SHADED;
  1768. ++i;
  1769. }
  1770. if (window->wm_state_modal)
  1771. {
  1772. data[i] = window->display->atom__NET_WM_STATE_MODAL;
  1773. ++i;
  1774. }
  1775. if (window->skip_pager)
  1776. {
  1777. data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER;
  1778. ++i;
  1779. }
  1780. if (window->skip_taskbar)
  1781. {
  1782. data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR;
  1783. ++i;
  1784. }
  1785. if (window->maximized_horizontally)
  1786. {
  1787. data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ;
  1788. ++i;
  1789. }
  1790. /* As of 3.10, Gtk considers _NET_WM_STATE_MAXIMIZED_VERT to be a tiled window also */
  1791. if (window->maximized_vertically || window->tile_type != META_WINDOW_TILE_TYPE_NONE)
  1792. {
  1793. data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT;
  1794. ++i;
  1795. }
  1796. if (window->tile_type != META_WINDOW_TILE_TYPE_NONE)
  1797. {
  1798. data[i] = window->display->atom__NET_WM_STATE_TILED;
  1799. ++i;
  1800. }
  1801. if (window->fullscreen)
  1802. {
  1803. data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN;
  1804. ++i;
  1805. }
  1806. if (!meta_window_showing_on_its_workspace (window) || window->shaded)
  1807. {
  1808. data[i] = window->display->atom__NET_WM_STATE_HIDDEN;
  1809. ++i;
  1810. }
  1811. if (window->wm_state_above)
  1812. {
  1813. data[i] = window->display->atom__NET_WM_STATE_ABOVE;
  1814. ++i;
  1815. }
  1816. if (window->wm_state_below)
  1817. {
  1818. data[i] = window->display->atom__NET_WM_STATE_BELOW;
  1819. ++i;
  1820. }
  1821. if (window->wm_state_demands_attention)
  1822. {
  1823. data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION;
  1824. ++i;
  1825. }
  1826. if (window->on_all_workspaces_requested)
  1827. {
  1828. data[i] = window->display->atom__NET_WM_STATE_STICKY;
  1829. ++i;
  1830. }
  1831. if (meta_window_appears_focused (window))
  1832. {
  1833. data[i] = window->display->atom__NET_WM_STATE_FOCUSED;
  1834. ++i;
  1835. }
  1836. meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i);
  1837. meta_error_trap_push (window->display);
  1838. XChangeProperty (window->display->xdisplay, window->xwindow,
  1839. window->display->atom__NET_WM_STATE,
  1840. XA_ATOM,
  1841. 32, PropModeReplace, (guchar*) data, i);
  1842. meta_error_trap_pop (window->display);
  1843. if (window->fullscreen)
  1844. {
  1845. data[0] = window->fullscreen_monitors[0];
  1846. data[1] = window->fullscreen_monitors[1];
  1847. data[2] = window->fullscreen_monitors[2];
  1848. data[3] = window->fullscreen_monitors[3];
  1849. meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
  1850. meta_error_trap_push (window->display);
  1851. XChangeProperty (window->display->xdisplay,
  1852. window->xwindow,
  1853. window->display->atom__NET_WM_FULLSCREEN_MONITORS,
  1854. XA_CARDINAL, 32, PropModeReplace,
  1855. (guchar*) data, 4);
  1856. meta_error_trap_pop (window->display);
  1857. }
  1858. if (window->tile_type != META_WINDOW_TILE_TYPE_NONE)
  1859. {
  1860. MetaRectangle rect;
  1861. meta_window_get_outer_rect (window, &rect);
  1862. data[0] = (unsigned long) window->tile_mode;
  1863. data[1] = (unsigned long) window->tile_type;
  1864. data[2] = (unsigned long) rect.x;
  1865. data[3] = (unsigned long) rect.y;
  1866. data[4] = (unsigned long) rect.width;
  1867. data[5] = (unsigned long) rect.height;
  1868. data[6] = (unsigned long) window->tile_monitor_number;
  1869. data[7] = (unsigned long) window->custom_snap_size ? 1 : 0;
  1870. meta_error_trap_push (window->display);
  1871. XChangeProperty (window->display->xdisplay, window->xwindow,
  1872. window->display->atom__NET_WM_WINDOW_TILE_INFO,
  1873. XA_CARDINAL,
  1874. 32, PropModeReplace, (guchar*) data, 8);
  1875. meta_error_trap_pop (window->display);
  1876. } else {
  1877. meta_error_trap_push (window->display);
  1878. XDeleteProperty (window->display->xdisplay,
  1879. window->xwindow,
  1880. window->display->atom__NET_WM_WINDOW_TILE_INFO);
  1881. meta_error_trap_pop (window->display);
  1882. }
  1883. }
  1884. LOCAL_SYMBOL gboolean
  1885. meta_window_located_on_workspace (MetaWindow *window,
  1886. MetaWorkspace *workspace)
  1887. {
  1888. return (window->on_all_workspaces && window->screen == workspace->screen) ||
  1889. (window->workspace == workspace);
  1890. }
  1891. static gboolean
  1892. is_minimized_foreach (MetaWindow *window,
  1893. void *data)
  1894. {
  1895. gboolean *result = data;
  1896. *result = window->minimized;
  1897. if (*result)
  1898. return FALSE; /* stop as soon as we find one */
  1899. else
  1900. return TRUE;
  1901. }
  1902. static gboolean
  1903. ancestor_is_minimized (MetaWindow *window)
  1904. {
  1905. gboolean is_minimized;
  1906. is_minimized = FALSE;
  1907. meta_window_foreach_ancestor (window, is_minimized_foreach, &is_minimized);
  1908. return is_minimized;
  1909. }
  1910. /**
  1911. * meta_window_showing_on_its_workspace:
  1912. * @window: A #MetaWindow
  1913. *
  1914. * Returns: %TRUE if window would be visible, if its workspace was current
  1915. */
  1916. gboolean
  1917. meta_window_showing_on_its_workspace (MetaWindow *window)
  1918. {
  1919. gboolean showing;
  1920. gboolean is_desktop_or_dock;
  1921. MetaWorkspace* workspace_of_window;
  1922. showing = TRUE;
  1923. /* 1. See if we're minimized */
  1924. if (window->minimized)
  1925. showing = FALSE;
  1926. /* 2. See if we're in "show desktop" mode */
  1927. is_desktop_or_dock = FALSE;
  1928. is_desktop_or_dock_foreach (window,
  1929. &is_desktop_or_dock);
  1930. meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
  1931. &is_desktop_or_dock);
  1932. if (window->on_all_workspaces)
  1933. workspace_of_window = window->screen->active_workspace;
  1934. else if (window->workspace)
  1935. workspace_of_window = window->workspace;
  1936. else /* This only seems to be needed for startup */
  1937. workspace_of_window = NULL;
  1938. if (showing &&
  1939. workspace_of_window && workspace_of_window->showing_desktop &&
  1940. !is_desktop_or_dock)
  1941. {
  1942. meta_verbose ("We're showing the desktop on the workspace(s) that window %s is on\n",
  1943. window->desc);
  1944. showing = FALSE;
  1945. }
  1946. /* 3. See if an ancestor is minimized (note that
  1947. * ancestor's "mapped" field may not be up to date
  1948. * since it's being computed in this same idle queue)
  1949. */
  1950. if (showing)
  1951. {
  1952. if (ancestor_is_minimized (window))
  1953. showing = FALSE;
  1954. }
  1955. return showing;
  1956. }
  1957. LOCAL_SYMBOL gboolean
  1958. meta_window_should_be_showing (MetaWindow *window)
  1959. {
  1960. gboolean on_workspace;
  1961. meta_verbose ("Should be showing for window %s\n", window->desc);
  1962. /* See if we're on the workspace */
  1963. on_workspace = meta_window_located_on_workspace (window,
  1964. window->screen->active_workspace);
  1965. if (!on_workspace)
  1966. meta_verbose ("Window %s is not on workspace %d\n",
  1967. window->desc,
  1968. meta_workspace_index (window->screen->active_workspace));
  1969. else
  1970. meta_verbose ("Window %s is on the active workspace %d\n",
  1971. window->desc,
  1972. meta_workspace_index (window->screen->active_workspace));
  1973. if (window->on_all_workspaces)
  1974. meta_verbose ("Window %s is on all workspaces\n", window->desc);
  1975. return on_workspace && meta_window_showing_on_its_workspace (window);
  1976. }
  1977. static void
  1978. implement_showing (MetaWindow *window,
  1979. gboolean showing)
  1980. {
  1981. /* Actually show/hide the window */
  1982. meta_verbose ("Implement showing = %d for window %s\n",
  1983. showing, window->desc);
  1984. if (!showing)
  1985. {
  1986. /* When we manage a new window, we normally delay placing it
  1987. * until it is is first shown, but if we're previewing hidden
  1988. * windows we might want to know where they are on the screen,
  1989. * so we should place the window even if we're hiding it rather
  1990. * than showing it.
  1991. */
  1992. if (!window->placed)
  1993. meta_window_force_placement (window);
  1994. meta_window_hide (window);
  1995. }
  1996. else
  1997. meta_window_show (window);
  1998. if (!window->override_redirect)
  1999. sync_client_window_mapped (window);
  2000. window->pending_compositor_effect = META_COMP_EFFECT_NONE;
  2001. }
  2002. static void
  2003. meta_window_calc_showing (MetaWindow *window)
  2004. {
  2005. implement_showing (window, meta_window_should_be_showing (window));
  2006. }
  2007. static guint queue_later[NUMBER_OF_QUEUES] = {0, 0, 0};
  2008. static GSList *queue_pending[NUMBER_OF_QUEUES] = {NULL, NULL, NULL};
  2009. static int
  2010. stackcmp (gconstpointer a, gconstpointer b)
  2011. {
  2012. MetaWindow *aw = (gpointer) a;
  2013. MetaWindow *bw = (gpointer) b;
  2014. if (aw->screen != bw->screen)
  2015. return 0; /* don't care how they sort with respect to each other */
  2016. else
  2017. return meta_stack_windows_cmp (aw->screen->stack,
  2018. aw, bw);
  2019. }
  2020. static gboolean
  2021. idle_calc_showing (gpointer data)
  2022. {
  2023. GSList *tmp;
  2024. GSList *copy;
  2025. GSList *should_show;
  2026. GSList *should_hide;
  2027. GSList *unplaced;
  2028. GSList *displays;
  2029. MetaWindow *first_window;
  2030. guint queue_index = GPOINTER_TO_INT (data);
  2031. g_return_val_if_fail (queue_pending[queue_index] != NULL, FALSE);
  2032. meta_topic (META_DEBUG_WINDOW_STATE,
  2033. "Clearing the calc_showing queue\n");
  2034. /* Work with a copy, for reentrancy. The allowed reentrancy isn't
  2035. * complete; destroying a window while we're in here would result in
  2036. * badness. But it's OK to queue/unqueue calc_showings.
  2037. */
  2038. copy = g_slist_copy (queue_pending[queue_index]);
  2039. g_slist_free (queue_pending[queue_index]);
  2040. queue_pending[queue_index] = NULL;
  2041. queue_later[queue_index] = 0;
  2042. destroying_windows_disallowed += 1;
  2043. /* We map windows from top to bottom and unmap from bottom to
  2044. * top, to avoid extra expose events. The exception is
  2045. * for unplaced windows, which have to be mapped from bottom to
  2046. * top so placement works.
  2047. */
  2048. should_show = NULL;
  2049. should_hide = NULL;
  2050. unplaced = NULL;
  2051. displays = NULL;
  2052. tmp = copy;
  2053. while (tmp != NULL)
  2054. {
  2055. MetaWindow *window;
  2056. window = tmp->data;
  2057. if (!window->placed)
  2058. unplaced = g_slist_prepend (unplaced, window);
  2059. else if (meta_window_should_be_showing (window))
  2060. should_show = g_slist_prepend (should_show, window);
  2061. else
  2062. should_hide = g_slist_prepend (should_hide, window);
  2063. tmp = tmp->next;
  2064. }
  2065. /* bottom to top */
  2066. unplaced = g_slist_sort (unplaced, stackcmp);
  2067. should_hide = g_slist_sort (should_hide, stackcmp);
  2068. /* top to bottom */
  2069. should_show = g_slist_sort (should_show, stackcmp);
  2070. should_show = g_slist_reverse (should_show);
  2071. first_window = copy->data;
  2072. meta_display_grab (first_window->display);
  2073. tmp = unplaced;
  2074. while (tmp != NULL)
  2075. {
  2076. MetaWindow *window;
  2077. window = tmp->data;
  2078. meta_window_calc_showing (window);
  2079. tmp = tmp->next;
  2080. }
  2081. tmp = should_show;
  2082. while (tmp != NULL)
  2083. {
  2084. MetaWindow *window;
  2085. window = tmp->data;
  2086. implement_showing (window, TRUE);
  2087. tmp = tmp->next;
  2088. }
  2089. tmp = should_hide;
  2090. while (tmp != NULL)
  2091. {
  2092. MetaWindow *window;
  2093. window = tmp->data;
  2094. implement_showing (window, FALSE);
  2095. tmp = tmp->next;
  2096. }
  2097. tmp = copy;
  2098. while (tmp != NULL)
  2099. {
  2100. MetaWindow *window;
  2101. window = tmp->data;
  2102. /* important to set this here for reentrancy -
  2103. * if we queue a window again while it's in "copy",
  2104. * then queue_calc_showing will just return since
  2105. * we are still in the calc_showing queue
  2106. */
  2107. window->is_in_queues &= ~META_QUEUE_CALC_SHOWING;
  2108. tmp = tmp->next;
  2109. }
  2110. if (meta_prefs_get_focus_mode () != C_DESKTOP_FOCUS_MODE_CLICK)
  2111. {
  2112. /* When display->mouse_mode is false, we want to ignore
  2113. * EnterNotify events unless they come from mouse motion. To do
  2114. * that, we set a sentinel property on the root window if we're
  2115. * not in mouse_mode.
  2116. */
  2117. tmp = should_show;
  2118. while (tmp != NULL)
  2119. {
  2120. MetaWindow *window = tmp->data;
  2121. if (!window->display->mouse_mode)
  2122. meta_display_increment_focus_sentinel (window->display);
  2123. tmp = tmp->next;
  2124. }
  2125. }
  2126. meta_display_ungrab (first_window->display);
  2127. g_slist_free (copy);
  2128. g_slist_free (unplaced);
  2129. g_slist_free (should_show);
  2130. g_slist_free (should_hide);
  2131. g_slist_free (displays);
  2132. destroying_windows_disallowed -= 1;
  2133. return FALSE;
  2134. }
  2135. #ifdef WITH_VERBOSE_MODE
  2136. static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] =
  2137. {"calc_showing", "move_resize", "update_icon"};
  2138. #endif
  2139. static void
  2140. meta_window_unqueue (MetaWindow *window, guint queuebits)
  2141. {
  2142. gint queuenum;
  2143. for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++)
  2144. {
  2145. if ((queuebits & 1<<queuenum) /* they have asked to unqueue */
  2146. &&
  2147. (window->is_in_queues & 1<<queuenum)) /* it's in the queue */
  2148. {
  2149. meta_topic (META_DEBUG_WINDOW_STATE,
  2150. "Removing %s from the %s queue\n",
  2151. window->desc,
  2152. meta_window_queue_names[queuenum]);
  2153. /* Note that window may not actually be in the queue
  2154. * because it may have been in "copy" inside the idle handler
  2155. */
  2156. queue_pending[queuenum] = g_slist_remove (queue_pending[queuenum], window);
  2157. window->is_in_queues &= ~(1<<queuenum);
  2158. /* Okay, so maybe we've used up all the entries in the queue.
  2159. * In that case, we should kill the function that deals with
  2160. * the queue, because there's nothing left for it to do.
  2161. */
  2162. if (queue_pending[queuenum] == NULL && queue_later[queuenum] != 0)
  2163. {
  2164. meta_later_remove (queue_later[queuenum]);
  2165. queue_later[queuenum] = 0;
  2166. }
  2167. }
  2168. }
  2169. }
  2170. static void
  2171. meta_window_flush_calc_showing (MetaWindow *window)
  2172. {
  2173. if (window->is_in_queues & META_QUEUE_CALC_SHOWING)
  2174. {
  2175. meta_window_unqueue (window, META_QUEUE_CALC_SHOWING);
  2176. meta_window_calc_showing (window);
  2177. }
  2178. }
  2179. LOCAL_SYMBOL void
  2180. meta_window_queue (MetaWindow *window, guint queuebits)
  2181. {
  2182. guint queuenum;
  2183. /* Easier to debug by checking here rather than in the idle */
  2184. g_return_if_fail (!window->override_redirect || (queuebits & META_QUEUE_MOVE_RESIZE) == 0);
  2185. for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++)
  2186. {
  2187. if (queuebits & 1<<queuenum)
  2188. {
  2189. /* Data which varies between queues.
  2190. * Yes, these do look a lot like associative arrays:
  2191. * I seem to be turning into a Perl programmer.
  2192. */
  2193. const MetaLaterType window_queue_later_when[NUMBER_OF_QUEUES] =
  2194. {
  2195. META_LATER_CALC_SHOWING, /* CALC_SHOWING */
  2196. META_LATER_RESIZE, /* MOVE_RESIZE */
  2197. META_LATER_BEFORE_REDRAW /* UPDATE_ICON */
  2198. };
  2199. const GSourceFunc window_queue_later_handler[NUMBER_OF_QUEUES] =
  2200. {
  2201. idle_calc_showing,
  2202. idle_move_resize,
  2203. idle_update_icon,
  2204. };
  2205. /* If we're about to drop the window, there's no point in putting
  2206. * it on a queue.
  2207. */
  2208. if (window->unmanaging)
  2209. break;
  2210. /* If the window already claims to be in that queue, there's no
  2211. * point putting it in the queue.
  2212. */
  2213. if (window->is_in_queues & 1<<queuenum)
  2214. break;
  2215. meta_topic (META_DEBUG_WINDOW_STATE,
  2216. "Putting %s in the %s queue\n",
  2217. window->desc,
  2218. meta_window_queue_names[queuenum]);
  2219. /* So, mark it as being in this queue. */
  2220. window->is_in_queues |= 1<<queuenum;
  2221. /* There's not a lot of point putting things into a queue if
  2222. * nobody's on the other end pulling them out. Therefore,
  2223. * let's check to see whether an idle handler exists to do
  2224. * that. If not, we'll create one.
  2225. */
  2226. if (queue_later[queuenum] == 0)
  2227. queue_later[queuenum] = meta_later_add
  2228. (
  2229. window_queue_later_when[queuenum],
  2230. window_queue_later_handler[queuenum],
  2231. GUINT_TO_POINTER(queuenum),
  2232. NULL
  2233. );
  2234. /* And now we actually put it on the queue. */
  2235. queue_pending[queuenum] = g_slist_prepend (queue_pending[queuenum],
  2236. window);
  2237. }
  2238. }
  2239. }
  2240. static gboolean
  2241. intervening_user_event_occurred (MetaWindow *window)
  2242. {
  2243. guint32 compare;
  2244. MetaWindow *focus_window;
  2245. focus_window = window->display->focus_window;
  2246. meta_topic (META_DEBUG_STARTUP,
  2247. "COMPARISON:\n"
  2248. " net_wm_user_time_set : %d\n"
  2249. " net_wm_user_time : %u\n"
  2250. " initial_timestamp_set: %d\n"
  2251. " initial_timestamp : %u\n",
  2252. window->net_wm_user_time_set,
  2253. window->net_wm_user_time,
  2254. window->initial_timestamp_set,
  2255. window->initial_timestamp);
  2256. if (focus_window != NULL)
  2257. {
  2258. meta_topic (META_DEBUG_STARTUP,
  2259. "COMPARISON (continued):\n"
  2260. " focus_window : %s\n"
  2261. " fw->net_wm_user_time_set : %d\n"
  2262. " fw->net_wm_user_time : %u\n",
  2263. focus_window->desc,
  2264. focus_window->net_wm_user_time_set,
  2265. focus_window->net_wm_user_time);
  2266. }
  2267. /* We expect the most common case for not focusing a new window
  2268. * to be when a hint to not focus it has been set. Since we can
  2269. * deal with that case rapidly, we use special case it--this is
  2270. * merely a preliminary optimization. :)
  2271. */
  2272. if ( ((window->net_wm_user_time_set == TRUE) &&
  2273. (window->net_wm_user_time == 0))
  2274. ||
  2275. ((window->initial_timestamp_set == TRUE) &&
  2276. (window->initial_timestamp == 0)))
  2277. {
  2278. meta_topic (META_DEBUG_STARTUP,
  2279. "window %s explicitly requested no focus\n",
  2280. window->desc);
  2281. return TRUE;
  2282. }
  2283. if (!(window->net_wm_user_time_set) && !(window->initial_timestamp_set))
  2284. {
  2285. meta_topic (META_DEBUG_STARTUP,
  2286. "no information about window %s found\n",
  2287. window->desc);
  2288. return FALSE;
  2289. }
  2290. if (focus_window != NULL &&
  2291. !focus_window->net_wm_user_time_set)
  2292. {
  2293. meta_topic (META_DEBUG_STARTUP,
  2294. "focus window, %s, doesn't have a user time set yet!\n",
  2295. window->desc);
  2296. return FALSE;
  2297. }
  2298. /* To determine the "launch" time of an application,
  2299. * startup-notification can set the TIMESTAMP and the
  2300. * application (usually via its toolkit such as gtk or qt) can
  2301. * set the _NET_WM_USER_TIME. If both are set, we need to be
  2302. * using the newer of the two values.
  2303. *
  2304. * See http://bugzilla.gnome.org/show_bug.cgi?id=573922
  2305. */
  2306. compare = 0;
  2307. if (window->net_wm_user_time_set &&
  2308. window->initial_timestamp_set)
  2309. compare =
  2310. XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,
  2311. window->initial_timestamp) ?
  2312. window->initial_timestamp : window->net_wm_user_time;
  2313. else if (window->net_wm_user_time_set)
  2314. compare = window->net_wm_user_time;
  2315. else if (window->initial_timestamp_set)
  2316. compare = window->initial_timestamp;
  2317. if ((focus_window != NULL) &&
  2318. XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
  2319. {
  2320. meta_topic (META_DEBUG_STARTUP,
  2321. "window %s focus prevented by other activity; %u < %u\n",
  2322. window->desc,
  2323. compare,
  2324. focus_window->net_wm_user_time);
  2325. return TRUE;
  2326. }
  2327. else
  2328. {
  2329. meta_topic (META_DEBUG_STARTUP,
  2330. "new window %s with no intervening events\n",
  2331. window->desc);
  2332. return FALSE;
  2333. }
  2334. }
  2335. /* This function is an ugly hack. It's experimental in nature and ought to be
  2336. * replaced by a real hint from the app to the WM if we decide the experimental
  2337. * behavior is worthwhile. The basic idea is to get more feedback about how
  2338. * usage scenarios of "strict" focus users and what they expect. See #326159.
  2339. */
  2340. LOCAL_SYMBOL gboolean
  2341. __window_is_terminal (MetaWindow *window)
  2342. {
  2343. if (window == NULL || window->res_class == NULL)
  2344. return FALSE;
  2345. /*
  2346. * Compare res_class, which is not user-settable, and thus theoretically
  2347. * a more-reliable indication of term-ness.
  2348. */
  2349. /* gnome-terminal -- if you couldn't guess */
  2350. if (strcmp (window->res_class, "Gnome-terminal") == 0)
  2351. return TRUE;
  2352. /* xterm, rxvt, aterm */
  2353. else if (strcmp (window->res_class, "XTerm") == 0)
  2354. return TRUE;
  2355. /* konsole, KDE's terminal program */
  2356. else if (strcmp (window->res_class, "Konsole") == 0)
  2357. return TRUE;
  2358. /* rxvt-unicode */
  2359. else if (strcmp (window->res_class, "URxvt") == 0)
  2360. return TRUE;
  2361. /* eterm */
  2362. else if (strcmp (window->res_class, "Eterm") == 0)
  2363. return TRUE;
  2364. /* KTerm -- some terminal not KDE based; so not like Konsole */
  2365. else if (strcmp (window->res_class, "KTerm") == 0)
  2366. return TRUE;
  2367. /* Multi-gnome-terminal */
  2368. else if (strcmp (window->res_class, "Multi-gnome-terminal") == 0)
  2369. return TRUE;
  2370. /* mlterm ("multi lingual terminal emulator on X") */
  2371. else if (strcmp (window->res_class, "mlterm") == 0)
  2372. return TRUE;
  2373. /* Terminal -- XFCE Terminal */
  2374. else if (strcmp (window->res_class, "Terminal") == 0)
  2375. return TRUE;
  2376. return FALSE;
  2377. }
  2378. /* This function determines what state the window should have assuming that it
  2379. * and the focus_window have no relation
  2380. */
  2381. static void
  2382. window_state_on_map (MetaWindow *window,
  2383. gboolean *takes_focus,
  2384. gboolean *places_on_top)
  2385. {
  2386. gboolean intervening_events;
  2387. intervening_events = intervening_user_event_occurred (window);
  2388. *takes_focus = !intervening_events;
  2389. *places_on_top = *takes_focus;
  2390. /* don't initially focus windows that are intended to not accept
  2391. * focus
  2392. */
  2393. if (!(window->input || window->take_focus))
  2394. {
  2395. *takes_focus = FALSE;
  2396. return;
  2397. }
  2398. /* Terminal usage may be different; some users intend to launch
  2399. * many apps in quick succession or to just view things in the new
  2400. * window while still interacting with the terminal. In that case,
  2401. * apps launched from the terminal should not take focus. This
  2402. * isn't quite the same as not allowing focus to transfer from
  2403. * terminals due to new window map, but the latter is a much easier
  2404. * approximation to enforce so we do that.
  2405. */
  2406. if (*takes_focus &&
  2407. meta_prefs_get_focus_new_windows () == C_DESKTOP_FOCUS_NEW_WINDOWS_STRICT &&
  2408. !window->display->allow_terminal_deactivation &&
  2409. __window_is_terminal (window->display->focus_window) &&
  2410. !meta_window_is_ancestor_of_transient (window->display->focus_window,
  2411. window))
  2412. {
  2413. meta_topic (META_DEBUG_FOCUS,
  2414. "focus_window is terminal; not focusing new window.\n");
  2415. *takes_focus = FALSE;
  2416. *places_on_top = FALSE;
  2417. }
  2418. switch (window->type)
  2419. {
  2420. case META_WINDOW_UTILITY:
  2421. case META_WINDOW_TOOLBAR:
  2422. *takes_focus = FALSE;
  2423. *places_on_top = FALSE;
  2424. break;
  2425. case META_WINDOW_DOCK:
  2426. case META_WINDOW_DESKTOP:
  2427. case META_WINDOW_SPLASHSCREEN:
  2428. case META_WINDOW_MENU:
  2429. /* override redirect types: */
  2430. case META_WINDOW_DROPDOWN_MENU:
  2431. case META_WINDOW_POPUP_MENU:
  2432. case META_WINDOW_TOOLTIP:
  2433. case META_WINDOW_NOTIFICATION:
  2434. case META_WINDOW_COMBO:
  2435. case META_WINDOW_DND:
  2436. case META_WINDOW_OVERRIDE_OTHER:
  2437. /* don't focus any of these; places_on_top may be irrelevant for some of
  2438. * these (e.g. dock)--but you never know--the focus window might also be
  2439. * of the same type in some weird situation...
  2440. */
  2441. *takes_focus = FALSE;
  2442. break;
  2443. case META_WINDOW_NORMAL:
  2444. case META_WINDOW_DIALOG:
  2445. case META_WINDOW_MODAL_DIALOG:
  2446. /* The default is correct for these */
  2447. break;
  2448. }
  2449. }
  2450. static gboolean
  2451. windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
  2452. {
  2453. MetaRectangle w1rect, w2rect;
  2454. meta_window_get_outer_rect (w1, &w1rect);
  2455. meta_window_get_outer_rect (w2, &w2rect);
  2456. return meta_rectangle_overlap (&w1rect, &w2rect);
  2457. }
  2458. /* Returns whether a new window would be covered by any
  2459. * existing window on the same workspace that is set
  2460. * to be "above" ("always on top"). A window that is not
  2461. * set "above" would be underneath the new window anyway.
  2462. *
  2463. * We take "covered" to mean even partially covered, but
  2464. * some people might prefer entirely covered. I think it
  2465. * is more useful to behave this way if any part of the
  2466. * window is covered, because a partial coverage could be
  2467. * (say) ninety per cent and almost indistinguishable from total.
  2468. */
  2469. static gboolean
  2470. window_would_be_covered (const MetaWindow *newbie)
  2471. {
  2472. MetaWorkspace *workspace = newbie->workspace;
  2473. GList *tmp, *windows;
  2474. windows = meta_workspace_list_windows (workspace);
  2475. tmp = windows;
  2476. while (tmp != NULL)
  2477. {
  2478. MetaWindow *w = tmp->data;
  2479. if (w->wm_state_above && w != newbie)
  2480. {
  2481. /* We have found a window that is "above". Perhaps it overlaps. */
  2482. if (windows_overlap (w, newbie))
  2483. {
  2484. g_list_free (windows); /* clean up... */
  2485. return TRUE; /* yes, it does */
  2486. }
  2487. }
  2488. tmp = tmp->next;
  2489. }
  2490. g_list_free (windows);
  2491. return FALSE; /* none found */
  2492. }
  2493. static void
  2494. meta_window_force_placement (MetaWindow *window)
  2495. {
  2496. if (window->placed)
  2497. return;
  2498. /* We have to recalc the placement here since other windows may
  2499. * have been mapped/placed since we last did constrain_position
  2500. */
  2501. /* calc_placement is an efficiency hack to avoid
  2502. * multiple placement calculations before we finally
  2503. * show the window.
  2504. */
  2505. window->calc_placement = TRUE;
  2506. meta_window_move_resize_now (window);
  2507. window->calc_placement = FALSE;
  2508. /* don't ever do the initial position constraint thing again.
  2509. * This is toggled here so that initially-iconified windows
  2510. * still get placed when they are ultimately shown.
  2511. */
  2512. window->placed = TRUE;
  2513. /* Don't want to accidentally reuse the fact that we had been denied
  2514. * focus in any future constraints unless we're denied focus again.
  2515. */
  2516. window->denied_focus_and_not_transient = FALSE;
  2517. }
  2518. static void
  2519. meta_window_show (MetaWindow *window)
  2520. {
  2521. gboolean did_show;
  2522. gboolean takes_focus_on_map;
  2523. gboolean place_on_top_on_map;
  2524. gboolean needs_stacking_adjustment;
  2525. MetaWindow *focus_window;
  2526. gboolean notify_demands_attention = FALSE;
  2527. meta_topic (META_DEBUG_WINDOW_STATE,
  2528. "Showing window %s, shaded: %d iconic: %d placed: %d\n",
  2529. window->desc, window->shaded, window->iconic, window->placed);
  2530. focus_window = window->display->focus_window; /* May be NULL! */
  2531. did_show = FALSE;
  2532. window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
  2533. needs_stacking_adjustment = FALSE;
  2534. meta_topic (META_DEBUG_WINDOW_STATE,
  2535. "Window %s %s focus on map, and %s place on top on map.\n",
  2536. window->desc,
  2537. takes_focus_on_map ? "does" : "does not",
  2538. place_on_top_on_map ? "does" : "does not");
  2539. /* Now, in some rare cases we should *not* put a new window on top.
  2540. * These cases include certain types of windows showing for the first
  2541. * time, and any window which would be covered because of another window
  2542. * being set "above" ("always on top").
  2543. *
  2544. * FIXME: Although "place_on_top_on_map" and "takes_focus_on_map" are
  2545. * generally based on the window type, there is a special case when the
  2546. * focus window is a terminal for them both to be false; this should
  2547. * probably rather be a term in the "if" condition below.
  2548. */
  2549. if ( focus_window != NULL && window->showing_for_first_time &&
  2550. ( (!place_on_top_on_map && !takes_focus_on_map) ||
  2551. window_would_be_covered (window) )
  2552. ) {
  2553. if (meta_window_is_ancestor_of_transient (focus_window, window))
  2554. {
  2555. guint32 timestamp;
  2556. timestamp = meta_display_get_current_time_roundtrip (window->display);
  2557. /* This happens for error dialogs or alerts; these need to remain on
  2558. * top, but it would be confusing to have its ancestor remain
  2559. * focused.
  2560. */
  2561. meta_topic (META_DEBUG_STARTUP,
  2562. "The focus window %s is an ancestor of the newly mapped "
  2563. "window %s which isn't being focused. Unfocusing the "
  2564. "ancestor.\n",
  2565. focus_window->desc, window->desc);
  2566. meta_display_focus_the_no_focus_window (window->display,
  2567. window->screen,
  2568. timestamp);
  2569. }
  2570. else
  2571. {
  2572. needs_stacking_adjustment = TRUE;
  2573. if (!window->placed)
  2574. window->denied_focus_and_not_transient = TRUE;
  2575. }
  2576. }
  2577. if (!window->placed)
  2578. {
  2579. meta_window_force_placement (window);
  2580. }
  2581. if (needs_stacking_adjustment)
  2582. {
  2583. gboolean overlap;
  2584. /* This window isn't getting focus on map. We may need to do some
  2585. * special handing with it in regards to
  2586. * - the stacking of the window
  2587. * - the MRU position of the window
  2588. * - the demands attention setting of the window
  2589. *
  2590. * Firstly, set the flag so we don't give the window focus anyway
  2591. * and confuse people.
  2592. */
  2593. takes_focus_on_map = FALSE;
  2594. overlap = windows_overlap (window, focus_window);
  2595. /* We want alt tab to go to the denied-focus window */
  2596. ensure_mru_position_after (window, focus_window);
  2597. /* We don't want the denied-focus window to obscure the focus
  2598. * window, and if we're in both click-to-focus mode and
  2599. * raise-on-click mode then we want to maintain the invariant
  2600. * that MRU order == stacking order. The need for this if
  2601. * comes from the fact that in sloppy/mouse focus the focus
  2602. * window may not overlap other windows and also can be
  2603. * considered "below" them; this combination means that
  2604. * placing the denied-focus window "below" the focus window
  2605. * in the stack when it doesn't overlap it confusingly places
  2606. * that new window below a lot of other windows.
  2607. */
  2608. if (overlap ||
  2609. (meta_prefs_get_focus_mode () == C_DESKTOP_FOCUS_MODE_CLICK &&
  2610. meta_prefs_get_raise_on_click ()))
  2611. meta_window_stack_just_below (window, focus_window);
  2612. /* If the window will be obscured by the focus window, then the
  2613. * user might not notice the window appearing so set the
  2614. * demands attention hint.
  2615. *
  2616. * We set the hint ourselves rather than calling
  2617. * meta_window_set_demands_attention() because that would cause
  2618. * a recalculation of overlap, and a call to set_net_wm_state()
  2619. * which we are going to call ourselves here a few lines down.
  2620. */
  2621. if (overlap)
  2622. {
  2623. if (!window->wm_state_demands_attention)
  2624. {
  2625. window->wm_state_demands_attention = TRUE;
  2626. notify_demands_attention = TRUE;
  2627. }
  2628. }
  2629. }
  2630. if (window->hidden)
  2631. {
  2632. meta_stack_freeze (window->screen->stack);
  2633. window->hidden = FALSE;
  2634. meta_stack_thaw (window->screen->stack);
  2635. did_show = TRUE;
  2636. }
  2637. if (window->iconic)
  2638. {
  2639. window->iconic = FALSE;
  2640. set_wm_state (window, NormalState);
  2641. }
  2642. if (!window->visible_to_compositor)
  2643. {
  2644. window->visible_to_compositor = TRUE;
  2645. MetaCompEffect effect = META_COMP_EFFECT_NONE;
  2646. switch (window->pending_compositor_effect)
  2647. {
  2648. case META_COMP_EFFECT_CREATE:
  2649. case META_COMP_EFFECT_UNMINIMIZE:
  2650. effect = window->pending_compositor_effect;
  2651. break;
  2652. case META_COMP_EFFECT_NONE:
  2653. case META_COMP_EFFECT_DESTROY:
  2654. case META_COMP_EFFECT_MINIMIZE:
  2655. break;
  2656. }
  2657. meta_compositor_show_window (window->display->compositor,
  2658. window, effect);
  2659. }
  2660. /* We don't want to worry about all cases from inside
  2661. * implement_showing(); we only want to worry about focus if this
  2662. * window has not been shown before.
  2663. */
  2664. if (window->showing_for_first_time)
  2665. {
  2666. window->showing_for_first_time = FALSE;
  2667. if (takes_focus_on_map)
  2668. {
  2669. guint32 timestamp;
  2670. timestamp = meta_display_get_current_time_roundtrip (window->display);
  2671. meta_window_focus (window, timestamp);
  2672. if (window->move_after_placement)
  2673. {
  2674. timestamp = meta_display_get_current_time_roundtrip (window->display);
  2675. meta_window_begin_grab_op(window, META_GRAB_OP_KEYBOARD_MOVING,
  2676. FALSE, timestamp);
  2677. window->move_after_placement = FALSE;
  2678. }
  2679. }
  2680. else
  2681. {
  2682. /* Prevent EnterNotify events in sloppy/mouse focus from
  2683. * erroneously focusing the window that had been denied
  2684. * focus. FIXME: This introduces a race; I have a couple
  2685. * ideas for a better way to accomplish the same thing, but
  2686. * they're more involved so do it this way for now.
  2687. */
  2688. meta_display_increment_focus_sentinel (window->display);
  2689. }
  2690. }
  2691. set_net_wm_state (window);
  2692. if (did_show && window->struts)
  2693. {
  2694. meta_topic (META_DEBUG_WORKAREA,
  2695. "Mapped window %s with struts, so invalidating work areas\n",
  2696. window->desc);
  2697. invalidate_work_areas (window);
  2698. }
  2699. if (did_show)
  2700. meta_screen_queue_check_fullscreen (window->screen);
  2701. /*
  2702. * Now that we have shown the window, we no longer want to consider the
  2703. * initial timestamp in any subsequent deliberations whether to focus this
  2704. * window or not, so clear the flag.
  2705. *
  2706. * See http://bugzilla.gnome.org/show_bug.cgi?id=573922
  2707. */
  2708. window->initial_timestamp_set = FALSE;
  2709. if (notify_demands_attention)
  2710. {
  2711. g_object_notify (G_OBJECT (window), "demands-attention");
  2712. g_signal_emit_by_name (window->display, "window-demands-attention",
  2713. window);
  2714. }
  2715. }
  2716. static void
  2717. meta_window_hide (MetaWindow *window)
  2718. {
  2719. gboolean did_hide;
  2720. meta_topic (META_DEBUG_WINDOW_STATE,
  2721. "Hiding window %s\n", window->desc);
  2722. if (window->visible_to_compositor)
  2723. {
  2724. window->visible_to_compositor = FALSE;
  2725. MetaCompEffect effect = META_COMP_EFFECT_NONE;
  2726. switch (window->pending_compositor_effect)
  2727. {
  2728. case META_COMP_EFFECT_CREATE:
  2729. case META_COMP_EFFECT_UNMINIMIZE:
  2730. case META_COMP_EFFECT_NONE:
  2731. break;
  2732. case META_COMP_EFFECT_DESTROY:
  2733. case META_COMP_EFFECT_MINIMIZE:
  2734. effect = window->pending_compositor_effect;
  2735. break;
  2736. }
  2737. meta_compositor_hide_window (window->display->compositor,
  2738. window, effect);
  2739. }
  2740. did_hide = FALSE;
  2741. if (!window->hidden)
  2742. {
  2743. meta_stack_freeze (window->screen->stack);
  2744. window->hidden = TRUE;
  2745. meta_stack_thaw (window->screen->stack);
  2746. did_hide = TRUE;
  2747. }
  2748. if (!window->iconic)
  2749. {
  2750. window->iconic = TRUE;
  2751. set_wm_state (window, IconicState);
  2752. }
  2753. set_net_wm_state (window);
  2754. if (did_hide && window->struts)
  2755. {
  2756. meta_topic (META_DEBUG_WORKAREA,
  2757. "Unmapped window %s with struts, so invalidating work areas\n",
  2758. window->desc);
  2759. invalidate_work_areas (window);
  2760. }
  2761. /* The check on expected_focus_window is a temporary workaround for
  2762. * https://bugzilla.gnome.org/show_bug.cgi?id=597352
  2763. * We may have already switched away from this window but not yet
  2764. * gotten FocusIn/FocusOut events. A more complete comprehensive
  2765. * fix for these type of issues is described in the bug.
  2766. */
  2767. if (window->has_focus &&
  2768. window == window->display->expected_focus_window)
  2769. {
  2770. MetaWindow *not_this_one = NULL;
  2771. MetaWorkspace *my_workspace = meta_window_get_workspace (window);
  2772. guint32 timestamp = meta_display_get_current_time_roundtrip (window->display);
  2773. /*
  2774. * If this window is modal, passing the not_this_one window to
  2775. * _focus_default_window() makes the focus to be given to this window's
  2776. * ancestor. This can only be the case if the window is on the currently
  2777. * active workspace; when it is not, we need to pass in NULL, so as to
  2778. * focus the default window for the active workspace (this scenario
  2779. * arises when we are switching workspaces).
  2780. */
  2781. if (window->type == META_WINDOW_MODAL_DIALOG &&
  2782. my_workspace == window->screen->active_workspace)
  2783. not_this_one = window;
  2784. meta_workspace_focus_default_window (window->screen->active_workspace,
  2785. not_this_one,
  2786. timestamp);
  2787. }
  2788. if (did_hide)
  2789. meta_screen_queue_check_fullscreen (window->screen);
  2790. }
  2791. static gboolean
  2792. queue_calc_showing_func (MetaWindow *window,
  2793. void *data)
  2794. {
  2795. meta_window_queue(window, META_QUEUE_CALC_SHOWING);
  2796. return TRUE;
  2797. }
  2798. void
  2799. meta_window_minimize (MetaWindow *window)
  2800. {
  2801. g_return_if_fail (!window->override_redirect);
  2802. if (!window->minimized)
  2803. {
  2804. window->minimized = TRUE;
  2805. window->pending_compositor_effect = META_COMP_EFFECT_MINIMIZE;
  2806. meta_window_queue(window, META_QUEUE_CALC_SHOWING);
  2807. meta_window_foreach_transient (window,
  2808. queue_calc_showing_func,
  2809. NULL);
  2810. if (window->has_focus)
  2811. {
  2812. meta_topic (META_DEBUG_FOCUS,
  2813. "Focusing default window due to minimization of focus window %s\n",
  2814. window->desc);
  2815. }
  2816. else
  2817. {
  2818. meta_topic (META_DEBUG_FOCUS,
  2819. "Minimizing window %s which doesn't have the focus\n",
  2820. window->desc);
  2821. }
  2822. g_object_notify (G_OBJECT (window), "minimized");
  2823. }
  2824. meta_screen_update_snapped_windows (window->screen);
  2825. }
  2826. void
  2827. meta_window_unminimize (MetaWindow *window)
  2828. {
  2829. g_return_if_fail (!window->override_redirect);
  2830. if (window->minimized)
  2831. {
  2832. window->minimized = FALSE;
  2833. window->pending_compositor_effect = META_COMP_EFFECT_UNMINIMIZE;
  2834. meta_window_queue(window, META_QUEUE_CALC_SHOWING);
  2835. meta_window_foreach_transient (window,
  2836. queue_calc_showing_func,
  2837. NULL);
  2838. g_object_notify (G_OBJECT (window), "minimized");
  2839. }
  2840. meta_screen_update_snapped_windows (window->screen);
  2841. }
  2842. static void
  2843. ensure_size_hints_satisfied (MetaRectangle *rect,
  2844. const XSizeHints *size_hints)
  2845. {
  2846. int minw, minh, maxw, maxh; /* min/max width/height */
  2847. int basew, baseh, winc, hinc; /* base width/height, width/height increment */
  2848. int extra_width, extra_height;
  2849. minw = size_hints->min_width; minh = size_hints->min_height;
  2850. maxw = size_hints->max_width; maxh = size_hints->max_height;
  2851. basew = size_hints->base_width; baseh = size_hints->base_height;
  2852. winc = size_hints->width_inc; hinc = size_hints->height_inc;
  2853. /* First, enforce min/max size constraints */
  2854. rect->width = CLAMP (rect->width, minw, maxw);
  2855. rect->height = CLAMP (rect->height, minh, maxh);
  2856. /* Now, verify size increment constraints are satisfied, or make them be */
  2857. extra_width = (rect->width - basew) % winc;
  2858. extra_height = (rect->height - baseh) % hinc;
  2859. rect->width -= extra_width;
  2860. rect->height -= extra_height;
  2861. /* Adjusting width/height down, as done above, may violate minimum size
  2862. * constraints, so one last fix.
  2863. */
  2864. if (rect->width < minw)
  2865. rect->width += ((minw - rect->width)/winc + 1)*winc;
  2866. if (rect->height < minh)
  2867. rect->height += ((minh - rect->height)/hinc + 1)*hinc;
  2868. }
  2869. static void
  2870. meta_window_save_rect (MetaWindow *window)
  2871. {
  2872. if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_OR_SNAPPED (window) || window->fullscreen))
  2873. {
  2874. /* save size/pos as appropriate args for move_resize */
  2875. if (!window->maximized_horizontally)
  2876. {
  2877. window->saved_rect.x = window->rect.x;
  2878. window->saved_rect.width = window->rect.width;
  2879. if (window->frame)
  2880. window->saved_rect.x += window->frame->rect.x;
  2881. }
  2882. if (!window->maximized_vertically)
  2883. {
  2884. window->saved_rect.y = window->rect.y;
  2885. window->saved_rect.height = window->rect.height;
  2886. if (window->frame)
  2887. window->saved_rect.y += window->frame->rect.y;
  2888. }
  2889. }
  2890. }
  2891. /*
  2892. * Save the user_rect regardless of whether the window is maximized or
  2893. * fullscreen. See save_user_window_placement() for most uses.
  2894. *
  2895. * \param window Store current position of this window for future reference
  2896. */
  2897. static void
  2898. force_save_user_window_placement (MetaWindow *window)
  2899. {
  2900. meta_window_get_client_root_coords (window, &window->user_rect);
  2901. }
  2902. /*
  2903. * Save the user_rect, but only if the window is neither maximized nor
  2904. * fullscreen, otherwise the window may snap back to those dimensions
  2905. * (bug #461927).
  2906. *
  2907. * \param window Store current position of this window for future reference
  2908. */
  2909. static void
  2910. save_user_window_placement (MetaWindow *window)
  2911. {
  2912. if (!(META_WINDOW_MAXIMIZED (window) || META_WINDOW_TILED_OR_SNAPPED (window) || window->fullscreen))
  2913. {
  2914. MetaRectangle user_rect;
  2915. meta_window_get_client_root_coords (window, &user_rect);
  2916. if (!window->maximized_horizontally)
  2917. {
  2918. window->user_rect.x = user_rect.x;
  2919. window->user_rect.width = user_rect.width;
  2920. }
  2921. if (!window->maximized_vertically)
  2922. {
  2923. window->user_rect.y = user_rect.y;
  2924. window->user_rect.height = user_rect.height;
  2925. }
  2926. }
  2927. }
  2928. LOCAL_SYMBOL void
  2929. meta_window_maximize_internal (MetaWindow *window,
  2930. MetaMaximizeFlags directions,
  2931. MetaRectangle *saved_rect)
  2932. {
  2933. /* At least one of the two directions ought to be set */
  2934. gboolean maximize_horizontally, maximize_vertically;
  2935. maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
  2936. maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
  2937. g_assert (maximize_horizontally || maximize_vertically);
  2938. meta_topic (META_DEBUG_WINDOW_OPS,
  2939. "Maximizing %s%s\n",
  2940. window->desc,
  2941. maximize_horizontally && maximize_vertically ? "" :
  2942. maximize_horizontally ? " horizontally" :
  2943. maximize_vertically ? " vertically" : "BUGGGGG");
  2944. if (saved_rect != NULL)
  2945. window->saved_rect = *saved_rect;
  2946. else
  2947. meta_window_save_rect (window);
  2948. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE);
  2949. window->tile_mode = META_TILE_NONE;
  2950. notify_tile_type (window);
  2951. normalize_tile_state (window);
  2952. if (maximize_horizontally && maximize_vertically)
  2953. window->saved_maximize = TRUE;
  2954. window->maximized_horizontally =
  2955. window->maximized_horizontally || maximize_horizontally;
  2956. window->maximized_vertically =
  2957. window->maximized_vertically || maximize_vertically;
  2958. if (maximize_horizontally || maximize_vertically)
  2959. window->force_save_user_rect = FALSE;
  2960. recalc_window_features (window);
  2961. set_net_wm_state (window);
  2962. if (window->monitor->in_fullscreen)
  2963. meta_screen_queue_check_fullscreen (window->screen);
  2964. g_object_freeze_notify (G_OBJECT (window));
  2965. g_object_notify (G_OBJECT (window), "maximized-horizontally");
  2966. g_object_notify (G_OBJECT (window), "maximized-vertically");
  2967. g_object_thaw_notify (G_OBJECT (window));
  2968. }
  2969. void
  2970. meta_window_maximize (MetaWindow *window,
  2971. MetaMaximizeFlags directions)
  2972. {
  2973. MetaRectangle *saved_rect = NULL;
  2974. gboolean maximize_horizontally, maximize_vertically;
  2975. g_return_if_fail (!window->override_redirect);
  2976. /* At least one of the two directions ought to be set */
  2977. maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
  2978. maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
  2979. g_assert (maximize_horizontally || maximize_vertically);
  2980. /* Only do something if the window isn't already maximized in the
  2981. * given direction(s).
  2982. */
  2983. if ((maximize_horizontally && !window->maximized_horizontally) ||
  2984. (maximize_vertically && !window->maximized_vertically))
  2985. {
  2986. if (window->shaded && maximize_vertically)
  2987. {
  2988. /* Shading sucks anyway; I'm not adding a timestamp argument
  2989. * to this function just for this niche usage & corner case.
  2990. */
  2991. guint32 timestamp =
  2992. meta_display_get_current_time_roundtrip (window->display);
  2993. meta_window_unshade (window, timestamp);
  2994. }
  2995. /* if the window hasn't been placed yet, we'll maximize it then
  2996. */
  2997. if (!window->placed)
  2998. {
  2999. window->maximize_horizontally_after_placement =
  3000. window->maximize_horizontally_after_placement ||
  3001. maximize_horizontally;
  3002. window->maximize_vertically_after_placement =
  3003. window->maximize_vertically_after_placement ||
  3004. maximize_vertically;
  3005. return;
  3006. }
  3007. if ((window->tile_mode != META_TILE_NONE ||
  3008. window->last_tile_mode != META_TILE_NONE) &&
  3009. window->tile_mode != META_TILE_MAXIMIZE)
  3010. {
  3011. saved_rect = &window->saved_rect;
  3012. window->maximized_vertically = FALSE;
  3013. }
  3014. meta_window_maximize_internal (window,
  3015. directions,
  3016. saved_rect);
  3017. MetaRectangle old_rect;
  3018. MetaRectangle new_rect;
  3019. meta_window_get_outer_rect (window, &old_rect);
  3020. meta_window_move_resize_now (window);
  3021. meta_window_get_outer_rect (window, &new_rect);
  3022. meta_compositor_maximize_window (window->display->compositor,
  3023. window,
  3024. &old_rect,
  3025. &new_rect);
  3026. }
  3027. meta_screen_tile_preview_hide (window->screen);
  3028. normalize_tile_state (window);
  3029. }
  3030. /**
  3031. * meta_window_get_maximized:
  3032. *
  3033. * Gets the current maximization state of the window, as combination
  3034. * of the %META_MAXIMIZE_HORIZONTAL and %META_MAXIMIZE_VERTICAL flags;
  3035. *
  3036. * Return value: current maximization state
  3037. */
  3038. MetaMaximizeFlags
  3039. meta_window_get_maximized (MetaWindow *window)
  3040. {
  3041. return ((window->maximized_horizontally ? META_MAXIMIZE_HORIZONTAL : 0) |
  3042. (window->maximized_vertically ? META_MAXIMIZE_VERTICAL : 0));
  3043. }
  3044. /**
  3045. * meta_window_is_fullscreen:
  3046. *
  3047. * Return value: %TRUE if the window is currently fullscreen
  3048. */
  3049. gboolean
  3050. meta_window_is_fullscreen (MetaWindow *window)
  3051. {
  3052. return window->fullscreen;
  3053. }
  3054. /**
  3055. * meta_window_get_all_monitors:
  3056. * @window: The #MetaWindow
  3057. * @length: (out caller-allocates): gint holding the length, may be %NULL to
  3058. * ignore
  3059. *
  3060. * Returns: (array length=length) (element-type gint) (transfer container):
  3061. * List of the monitor indices the window is on.
  3062. */
  3063. gint *
  3064. meta_window_get_all_monitors (MetaWindow *window, gsize *length)
  3065. {
  3066. GArray *monitors;
  3067. MetaRectangle window_rect;
  3068. int i;
  3069. monitors = g_array_new (FALSE, FALSE, sizeof (int));
  3070. meta_window_get_outer_rect (window, &window_rect);
  3071. for (i = 0; i < window->screen->n_monitor_infos; i++)
  3072. {
  3073. MetaRectangle *monitor_rect = &window->screen->monitor_infos[i].rect;
  3074. if (meta_rectangle_overlap (&window_rect, monitor_rect))
  3075. g_array_append_val (monitors, i);
  3076. }
  3077. if (length)
  3078. *length = monitors->len;
  3079. i = -1;
  3080. g_array_append_val (monitors, i);
  3081. return (gint*) g_array_free (monitors, FALSE);
  3082. }
  3083. /**
  3084. * meta_window_is_monitor_sized:
  3085. *
  3086. * Return value: %TRUE if the window is occupies an entire monitor or
  3087. * the whole screen.
  3088. */
  3089. gboolean
  3090. meta_window_is_monitor_sized (MetaWindow *window)
  3091. {
  3092. if (window->fullscreen)
  3093. return TRUE;
  3094. if (window->override_redirect)
  3095. {
  3096. MetaRectangle window_rect, monitor_rect;
  3097. int screen_width, screen_height;
  3098. meta_screen_get_size (window->screen, &screen_width, &screen_height);
  3099. meta_window_get_outer_rect (window, &window_rect);
  3100. if (window_rect.x == 0 && window_rect.y == 0 &&
  3101. window_rect.width == screen_width && window_rect.height == screen_height)
  3102. return TRUE;
  3103. meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
  3104. if (meta_rectangle_equal (&window_rect, &monitor_rect))
  3105. return TRUE;
  3106. }
  3107. return FALSE;
  3108. }
  3109. /**
  3110. * meta_window_is_on_primary_monitor:
  3111. *
  3112. * Return value: %TRUE if the window is on the primary monitor
  3113. */
  3114. gboolean
  3115. meta_window_is_on_primary_monitor (MetaWindow *window)
  3116. {
  3117. return window->monitor->is_primary;
  3118. }
  3119. /**
  3120. * meta_window_requested_bypass_compositor:
  3121. *
  3122. * Return value: %TRUE if the window requested to bypass the compositor
  3123. */
  3124. gboolean
  3125. meta_window_requested_bypass_compositor (MetaWindow *window)
  3126. {
  3127. return window->bypass_compositor;
  3128. }
  3129. /**
  3130. * meta_window_requested_dont_bypass_compositor:
  3131. *
  3132. * Return value: %TRUE if the window requested to opt out of unredirecting
  3133. */
  3134. gboolean
  3135. meta_window_requested_dont_bypass_compositor (MetaWindow *window)
  3136. {
  3137. return window->dont_bypass_compositor;
  3138. }
  3139. static void
  3140. notify_tile_type (MetaWindow *window)
  3141. {
  3142. g_object_freeze_notify (G_OBJECT (window));
  3143. g_object_notify (G_OBJECT (window), "tile-type");
  3144. g_object_thaw_notify (G_OBJECT (window));
  3145. }
  3146. static void
  3147. normalize_tile_state (MetaWindow *window)
  3148. {
  3149. window->snap_queued = FALSE;
  3150. window->resize_tile_mode = META_TILE_NONE;
  3151. window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE;
  3152. meta_screen_update_snapped_windows (window->screen);
  3153. }
  3154. LOCAL_SYMBOL void
  3155. meta_window_real_tile (MetaWindow *window, gboolean force)
  3156. {
  3157. /* Don't do anything if no tiling is requested or we're already tiled */
  3158. if (window->tile_mode == META_TILE_NONE || (META_WINDOW_TILED_OR_SNAPPED (window) && !force))
  3159. return;
  3160. if (window->last_tile_mode == META_TILE_NONE &&
  3161. window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE &&
  3162. !META_WINDOW_MAXIMIZED (window))
  3163. {
  3164. meta_window_save_rect (window);
  3165. }
  3166. window->maximized_horizontally = FALSE;
  3167. window->maximized_vertically = FALSE;
  3168. if (window->tile_mode != META_TILE_NONE) {
  3169. if (window->snap_queued || window->resizing_tile_type == META_WINDOW_TILE_TYPE_SNAPPED) {
  3170. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_SNAPPED);
  3171. } else {
  3172. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_TILED);
  3173. }
  3174. } else {
  3175. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE);
  3176. }
  3177. recalc_window_features (window);
  3178. meta_screen_tile_preview_update (window->screen, FALSE);
  3179. if (window->resize_tile_mode == META_TILE_NONE)
  3180. {
  3181. MetaRectangle old_rect;
  3182. MetaRectangle new_rect;
  3183. meta_window_get_outer_rect (window, &old_rect);
  3184. meta_window_move_resize_now (window);
  3185. meta_window_get_outer_rect (window, &new_rect);
  3186. meta_compositor_tile_window (window->display->compositor,
  3187. window,
  3188. &old_rect,
  3189. &new_rect);
  3190. if (window->frame)
  3191. meta_ui_queue_frame_draw (window->screen->ui,
  3192. window->frame->xwindow);
  3193. }
  3194. else
  3195. {
  3196. /* move_resize with new tiling constraints
  3197. */
  3198. meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
  3199. }
  3200. normalize_tile_state (window);
  3201. set_net_wm_state (window);
  3202. meta_screen_tile_preview_hide (window->screen);
  3203. meta_window_get_outer_rect (window, &window->snapped_rect);
  3204. notify_tile_type (window);
  3205. }
  3206. static gboolean
  3207. meta_window_can_tile_maximized (MetaWindow *window)
  3208. {
  3209. return window->has_maximize_func;
  3210. }
  3211. LOCAL_SYMBOL gboolean
  3212. meta_window_can_tile_side_by_side (MetaWindow *window)
  3213. {
  3214. int monitor;
  3215. MetaRectangle tile_area;
  3216. MetaFrameBorders borders;
  3217. if (!meta_window_can_tile_maximized (window))
  3218. return FALSE;
  3219. monitor = meta_screen_get_current_monitor (window->screen);
  3220. meta_window_get_work_area_for_monitor (window, monitor, &tile_area);
  3221. tile_area.width /= 2;
  3222. meta_frame_calc_borders (window->frame, &borders);
  3223. meta_window_unextend_by_frame (window, &tile_area, &borders);
  3224. return tile_area.width >= window->size_hints.min_width &&
  3225. tile_area.height >= window->size_hints.min_height;
  3226. }
  3227. LOCAL_SYMBOL gboolean
  3228. meta_window_can_tile_top_bottom (MetaWindow *window)
  3229. {
  3230. int monitor;
  3231. MetaRectangle tile_area;
  3232. MetaFrameBorders borders;
  3233. if (!meta_window_can_tile_maximized (window))
  3234. return FALSE;
  3235. monitor = meta_screen_get_current_monitor (window->screen);
  3236. meta_window_get_work_area_for_monitor (window, monitor, &tile_area);
  3237. tile_area.height /= 2;
  3238. meta_frame_calc_borders (window->frame, &borders);
  3239. meta_window_unextend_by_frame (window, &tile_area, &borders);
  3240. return tile_area.width >= window->size_hints.min_width &&
  3241. tile_area.height >= window->size_hints.min_height;
  3242. }
  3243. LOCAL_SYMBOL gboolean
  3244. meta_window_can_tile_corner (MetaWindow *window)
  3245. {
  3246. int monitor;
  3247. MetaRectangle tile_area;
  3248. MetaFrameBorders borders;
  3249. if (!meta_window_can_tile_maximized (window))
  3250. return FALSE;
  3251. monitor = meta_screen_get_current_monitor (window->screen);
  3252. meta_window_get_work_area_for_monitor (window, monitor, &tile_area);
  3253. tile_area.width /= 2;
  3254. tile_area.height /= 2;
  3255. meta_frame_calc_borders (window->frame, &borders);
  3256. meta_window_unextend_by_frame (window, &tile_area, &borders);
  3257. return tile_area.width >= window->size_hints.min_width &&
  3258. tile_area.height >= window->size_hints.min_height;
  3259. }
  3260. static void
  3261. unmaximize_window_before_freeing (MetaWindow *window)
  3262. {
  3263. meta_topic (META_DEBUG_WINDOW_OPS,
  3264. "Unmaximizing %s just before freeing\n",
  3265. window->desc);
  3266. window->maximized_horizontally = FALSE;
  3267. window->maximized_vertically = FALSE;
  3268. window->custom_snap_size = FALSE;
  3269. if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) {
  3270. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE);
  3271. meta_screen_update_snapped_windows (window->screen);
  3272. notify_tile_type (window);
  3273. }
  3274. if (window->withdrawn) /* See bug #137185 */
  3275. {
  3276. window->rect = window->saved_rect;
  3277. set_net_wm_state (window);
  3278. }
  3279. else if (window->screen->closing) /* See bug #358042 */
  3280. {
  3281. /* Do NOT update net_wm_state: this screen is closing,
  3282. * it likely will be managed by another window manager
  3283. * that will need the current _NET_WM_STATE atoms.
  3284. * Moreover, it will need to know the unmaximized geometry,
  3285. * therefore move_resize the window to saved_rect here
  3286. * before closing it. */
  3287. meta_window_move_resize (window,
  3288. FALSE,
  3289. window->saved_rect.x,
  3290. window->saved_rect.y,
  3291. window->saved_rect.width,
  3292. window->saved_rect.height);
  3293. }
  3294. }
  3295. static void
  3296. meta_window_unmaximize_internal (MetaWindow *window,
  3297. MetaMaximizeFlags directions,
  3298. MetaRectangle *desired_rect,
  3299. int gravity)
  3300. {
  3301. gboolean unmaximize_horizontally, unmaximize_vertically;
  3302. g_return_if_fail (!window->override_redirect);
  3303. /* At least one of the two directions ought to be set */
  3304. unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
  3305. unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL;
  3306. if (unmaximize_horizontally && unmaximize_vertically)
  3307. window->saved_maximize = FALSE;
  3308. /* Only do something if the window isn't already maximized in the
  3309. * given direction(s).
  3310. */
  3311. if ((unmaximize_horizontally && window->maximized_horizontally) ||
  3312. (unmaximize_vertically && window->maximized_vertically) ||
  3313. window->tile_type == META_WINDOW_TILE_TYPE_NONE ||
  3314. window->tile_mode == META_TILE_NONE)
  3315. {
  3316. MetaRectangle target_rect;
  3317. MetaRectangle work_area;
  3318. window->last_tile_mode = META_TILE_NONE;
  3319. window->tile_mode = META_TILE_NONE;
  3320. window->resizing_tile_type = META_WINDOW_TILE_TYPE_NONE;
  3321. window->tile_type = META_WINDOW_TILE_TYPE_NONE;
  3322. meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
  3323. meta_topic (META_DEBUG_WINDOW_OPS,
  3324. "Unmaximizing %s%s\n",
  3325. window->desc,
  3326. unmaximize_horizontally && unmaximize_vertically ? "" :
  3327. unmaximize_horizontally ? " horizontally" :
  3328. unmaximize_vertically ? " vertically" : "BUGGGGG");
  3329. window->maximized_horizontally =
  3330. window->maximized_horizontally && !unmaximize_horizontally;
  3331. window->maximized_vertically =
  3332. window->maximized_vertically && !unmaximize_vertically;
  3333. /* Unmaximize to the saved_rect position in the direction(s)
  3334. * being unmaximized.
  3335. */
  3336. meta_window_get_client_root_coords (window, &target_rect);
  3337. if (unmaximize_horizontally)
  3338. {
  3339. target_rect.x = desired_rect->x;
  3340. target_rect.width = desired_rect->width;
  3341. }
  3342. if (unmaximize_vertically)
  3343. {
  3344. target_rect.y = desired_rect->y;
  3345. target_rect.height = desired_rect->height;
  3346. }
  3347. /* Window's size hints may have changed while maximized, making
  3348. * saved_rect invalid. #329152
  3349. */
  3350. ensure_size_hints_satisfied (&target_rect, &window->size_hints);
  3351. if (window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE)
  3352. {
  3353. MetaRectangle old_rect, new_rect;
  3354. meta_window_get_outer_rect (window, &old_rect);
  3355. meta_window_move_resize_internal (window,
  3356. META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
  3357. gravity,
  3358. target_rect.x,
  3359. target_rect.y,
  3360. target_rect.width,
  3361. target_rect.height);
  3362. meta_window_get_outer_rect (window, &new_rect);
  3363. meta_compositor_unmaximize_window (window->display->compositor,
  3364. window,
  3365. &old_rect,
  3366. &new_rect);
  3367. }
  3368. else
  3369. {
  3370. meta_window_move_resize_internal (window,
  3371. META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
  3372. gravity,
  3373. target_rect.x,
  3374. target_rect.y,
  3375. target_rect.width,
  3376. target_rect.height);
  3377. }
  3378. /* Make sure user_rect is current.
  3379. */
  3380. force_save_user_window_placement (window);
  3381. /* When we unmaximize, if we're doing a mouse move also we could
  3382. * get the window suddenly jumping to the upper left corner of
  3383. * the workspace, since that's where it was when the grab op
  3384. * started. So we need to update the grab state. We have to do
  3385. * it after the actual operation, as the window may have been moved
  3386. * by constraints.
  3387. */
  3388. if (meta_grab_op_is_moving (window->display->grab_op) &&
  3389. window->display->grab_window == window)
  3390. {
  3391. window->display->grab_anchor_window_pos = window->user_rect;
  3392. }
  3393. if (window->tile_type != META_WINDOW_TILE_TYPE_NONE) {
  3394. meta_window_set_tile_type (window, META_WINDOW_TILE_TYPE_NONE);
  3395. notify_tile_type (window);
  3396. }
  3397. if (window->resizing_tile_type == META_WINDOW_TILE_TYPE_NONE)
  3398. window->custom_snap_size = FALSE;
  3399. meta_screen_update_snapped_windows (window->screen);
  3400. recalc_window_features (window);
  3401. set_net_wm_state (window);
  3402. if (!window->monitor->in_fullscreen)
  3403. meta_screen_queue_check_fullscreen (window->screen);
  3404. }
  3405. g_object_freeze_notify (G_OBJECT (window));
  3406. g_object_notify (G_OBJECT (window), "maximized-horizontally");
  3407. g_object_notify (G_OBJECT (window), "maximized-vertically");
  3408. g_object_thaw_notify (G_OBJECT (window));
  3409. }
  3410. void
  3411. meta_window_unmaximize (MetaWindow *window,
  3412. MetaMaximizeFlags directions)
  3413. {
  3414. /* Restore tiling if necessary */
  3415. if (window->tile_mode == META_TILE_LEFT ||
  3416. window->tile_mode == META_TILE_RIGHT)
  3417. {
  3418. window->maximized_horizontally = FALSE;
  3419. meta_window_real_tile (window, FALSE);
  3420. return;
  3421. }
  3422. meta_window_unmaximize_internal (window, directions, &window->saved_rect,
  3423. NorthWestGravity);
  3424. }
  3425. /* Like meta_window_unmaximize(), but instead of unmaximizing to the
  3426. * saved position, we give the new desired size, and the gravity that
  3427. * determines the positioning relationship between the area occupied
  3428. * maximized and the new are. The arguments are similar to
  3429. * meta_window_resize_with_gravity().
  3430. * Unlike meta_window_unmaximize(), tiling is not restored for windows
  3431. * with a tile mode other than META_TILE_NONE.
  3432. */
  3433. LOCAL_SYMBOL void
  3434. meta_window_unmaximize_with_gravity (MetaWindow *window,
  3435. MetaMaximizeFlags directions,
  3436. int new_width,
  3437. int new_height,
  3438. int gravity)
  3439. {
  3440. MetaRectangle desired_rect;
  3441. meta_window_get_position (window, &desired_rect.x, &desired_rect.y);
  3442. desired_rect.width = new_width;
  3443. desired_rect.height = new_height;
  3444. meta_window_unmaximize_internal (window, directions, &desired_rect, gravity);
  3445. }
  3446. LOCAL_SYMBOL void
  3447. meta_window_make_above (MetaWindow *window)
  3448. {
  3449. g_return_if_fail (!window->override_redirect);
  3450. meta_window_set_above (window, TRUE);
  3451. meta_window_raise (window);
  3452. }
  3453. LOCAL_SYMBOL void
  3454. meta_window_unmake_above (MetaWindow *window)
  3455. {
  3456. g_return_if_fail (!window->override_redirect);
  3457. meta_window_set_above (window, FALSE);
  3458. meta_window_raise (window);
  3459. }
  3460. static void
  3461. meta_window_set_above (MetaWindow *window,
  3462. gboolean new_value)
  3463. {
  3464. new_value = new_value != FALSE;
  3465. if (new_value == window->wm_state_above)
  3466. return;
  3467. window->wm_state_above = new_value;
  3468. meta_window_update_layer (window);
  3469. set_net_wm_state (window);
  3470. g_object_notify (G_OBJECT (window), "above");
  3471. }
  3472. LOCAL_SYMBOL LOCAL_SYMBOL void
  3473. meta_window_make_fullscreen_internal (MetaWindow *window)
  3474. {
  3475. if (!window->fullscreen)
  3476. {
  3477. meta_topic (META_DEBUG_WINDOW_OPS,
  3478. "Fullscreening %s\n", window->desc);
  3479. if (window->shaded)
  3480. {
  3481. /* Shading sucks anyway; I'm not adding a timestamp argument
  3482. * to this function just for this niche usage & corner case.
  3483. */
  3484. guint32 timestamp =
  3485. meta_display_get_current_time_roundtrip (window->display);
  3486. meta_window_unshade (window, timestamp);
  3487. }
  3488. meta_window_save_rect (window);
  3489. window->fullscreen = TRUE;
  3490. window->force_save_user_rect = FALSE;
  3491. meta_stack_freeze (window->screen->stack);
  3492. meta_window_update_layer (window);
  3493. meta_window_raise (window);
  3494. meta_stack_thaw (window->screen->stack);
  3495. recalc_window_features (window);
  3496. set_net_wm_state (window);
  3497. /* For the auto-minimize feature, if we fail to get focus */
  3498. meta_screen_queue_check_fullscreen (window->screen);
  3499. meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
  3500. g_object_notify (G_OBJECT (window), "fullscreen");
  3501. }
  3502. }
  3503. LOCAL_SYMBOL void
  3504. meta_window_make_fullscreen (MetaWindow *window)
  3505. {
  3506. g_return_if_fail (!window->override_redirect);
  3507. if (!window->fullscreen)
  3508. {
  3509. meta_window_make_fullscreen_internal (window);
  3510. /* move_resize with new constraints
  3511. */
  3512. meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
  3513. }
  3514. }
  3515. LOCAL_SYMBOL void
  3516. meta_window_unmake_fullscreen (MetaWindow *window)
  3517. {
  3518. g_return_if_fail (!window->override_redirect);
  3519. if (window->fullscreen)
  3520. {
  3521. MetaRectangle target_rect;
  3522. meta_topic (META_DEBUG_WINDOW_OPS,
  3523. "Unfullscreening %s\n", window->desc);
  3524. window->fullscreen = FALSE;
  3525. target_rect = window->saved_rect;
  3526. /* Window's size hints may have changed while maximized, making
  3527. * saved_rect invalid. #329152
  3528. */
  3529. ensure_size_hints_satisfied (&target_rect, &window->size_hints);
  3530. /* Need to update window->has_resize_func before we move_resize()
  3531. */
  3532. recalc_window_features (window);
  3533. set_net_wm_state (window);
  3534. meta_window_move_resize (window,
  3535. FALSE,
  3536. target_rect.x,
  3537. target_rect.y,
  3538. target_rect.width,
  3539. target_rect.height);
  3540. /* Make sure user_rect is current.
  3541. */
  3542. force_save_user_window_placement (window);
  3543. meta_window_update_layer (window);
  3544. meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
  3545. g_object_notify (G_OBJECT (window), "fullscreen");
  3546. }
  3547. }
  3548. LOCAL_SYMBOL void
  3549. meta_window_update_fullscreen_monitors (MetaWindow *window,
  3550. unsigned long top,
  3551. unsigned long bottom,
  3552. unsigned long left,
  3553. unsigned long right)
  3554. {
  3555. if ((int)top < window->screen->n_monitor_infos &&
  3556. (int)bottom < window->screen->n_monitor_infos &&
  3557. (int)left < window->screen->n_monitor_infos &&
  3558. (int)right < window->screen->n_monitor_infos)
  3559. {
  3560. window->fullscreen_monitors[0] = top;
  3561. window->fullscreen_monitors[1] = bottom;
  3562. window->fullscreen_monitors[2] = left;
  3563. window->fullscreen_monitors[3] = right;
  3564. }
  3565. else
  3566. {
  3567. window->fullscreen_monitors[0] = -1;
  3568. }
  3569. if (window->fullscreen)
  3570. {
  3571. meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
  3572. }
  3573. }
  3574. LOCAL_SYMBOL void
  3575. meta_window_shade (MetaWindow *window,
  3576. guint32 timestamp)
  3577. {
  3578. g_return_if_fail (!window->override_redirect);
  3579. meta_topic (META_DEBUG_WINDOW_OPS,
  3580. "Shading %s\n", window->desc);
  3581. if (!window->shaded)
  3582. {
  3583. window->shaded = TRUE;
  3584. meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
  3585. /* After queuing the calc showing, since _focus flushes it,
  3586. * and we need to focus the frame
  3587. */
  3588. meta_topic (META_DEBUG_FOCUS,
  3589. "Re-focusing window %s after shading it\n",
  3590. window->desc);
  3591. meta_window_focus (window, timestamp);
  3592. set_net_wm_state (window);
  3593. }
  3594. }
  3595. LOCAL_SYMBOL void
  3596. meta_window_unshade (MetaWindow *window,
  3597. guint32 timestamp)
  3598. {
  3599. g_return_if_fail (!window->override_redirect);
  3600. meta_topic (META_DEBUG_WINDOW_OPS,
  3601. "Unshading %s\n", window->desc);
  3602. if (window->shaded)
  3603. {
  3604. window->shaded = FALSE;
  3605. meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
  3606. /* focus the window */
  3607. meta_topic (META_DEBUG_FOCUS,
  3608. "Focusing window %s after unshading it\n",
  3609. window->desc);
  3610. meta_window_focus (window, timestamp);
  3611. set_net_wm_state (window);
  3612. }
  3613. }
  3614. #define OPACITY_STEP 32
  3615. LOCAL_SYMBOL void
  3616. meta_window_adjust_opacity (MetaWindow *window,
  3617. gboolean increase)
  3618. {
  3619. ClutterActor *actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
  3620. gint current_opacity, new_opacity;
  3621. current_opacity = clutter_actor_get_opacity (actor);
  3622. if (increase) {
  3623. new_opacity = MIN (current_opacity + OPACITY_STEP, 255);
  3624. } else {
  3625. new_opacity = MAX (current_opacity - OPACITY_STEP, MAX (0, meta_prefs_get_min_win_opacity ()));
  3626. }
  3627. if (new_opacity != current_opacity) {
  3628. clutter_actor_set_opacity (actor, (guint8) new_opacity);
  3629. }
  3630. }
  3631. void
  3632. meta_window_reset_opacity (MetaWindow *window)
  3633. {
  3634. ClutterActor *actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
  3635. clutter_actor_set_opacity (actor, 255);
  3636. }
  3637. static gboolean
  3638. unminimize_func (MetaWindow *window,
  3639. void *data)
  3640. {
  3641. meta_window_unminimize (window);
  3642. return TRUE;
  3643. }
  3644. static void
  3645. unminimize_window_and_all_transient_parents (MetaWindow *window)
  3646. {
  3647. meta_window_unminimize (window);
  3648. meta_window_foreach_ancestor (window, unminimize_func, NULL);
  3649. }
  3650. static void
  3651. window_activate (MetaWindow *window,
  3652. guint32 timestamp,
  3653. MetaClientType source_indication,
  3654. MetaWorkspace *workspace)
  3655. {
  3656. meta_topic (META_DEBUG_FOCUS,
  3657. "_NET_ACTIVE_WINDOW message sent for %s at time %u "
  3658. "by client type %u.\n",
  3659. window->desc, timestamp, source_indication);
  3660. if (timestamp != 0 &&
  3661. XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time))
  3662. {
  3663. meta_topic (META_DEBUG_FOCUS,
  3664. "last_user_time (%u) is more recent; ignoring "
  3665. " _NET_ACTIVE_WINDOW message.\n",
  3666. window->display->last_user_time);
  3667. meta_window_set_demands_attention(window);
  3668. return;
  3669. }
  3670. if (timestamp == 0)
  3671. timestamp = meta_display_get_current_time_roundtrip (window->display);
  3672. meta_window_set_user_time (window, timestamp);
  3673. /* disable show desktop mode unless we're a desktop component */
  3674. maybe_leave_show_desktop_mode (window);
  3675. /* Get window on current or given workspace */
  3676. if (workspace == NULL)
  3677. workspace = window->screen->active_workspace;
  3678. /* For non-transient windows, we just set up a pulsing indicator,
  3679. rather than move windows or workspaces.
  3680. See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
  3681. if (window->xtransient_for == None &&
  3682. !meta_window_located_on_workspace (window, window->screen->active_workspace))
  3683. {
  3684. meta_window_set_demands_attention (window);
  3685. /* We've marked it as demanding, don't need to do anything else. */
  3686. return;
  3687. }
  3688. else if (window->xtransient_for != None)
  3689. {
  3690. /* Move transients to current workspace - preference dialogs should appear over
  3691. the source window. */
  3692. meta_window_change_workspace (window, workspace);
  3693. }
  3694. if (window->shaded)
  3695. meta_window_unshade (window, timestamp);
  3696. unminimize_window_and_all_transient_parents (window);
  3697. if (meta_prefs_get_raise_on_click () ||
  3698. source_indication == META_CLIENT_TYPE_PAGER)
  3699. meta_window_raise (window);
  3700. meta_topic (META_DEBUG_FOCUS,
  3701. "Focusing window %s due to activation\n",
  3702. window->desc);
  3703. meta_window_focus (window, timestamp);
  3704. }
  3705. /* This function exists since most of the functionality in window_activate
  3706. * is useful for Muffin, but Muffin shouldn't need to specify a client
  3707. * type for itself. ;-)
  3708. */
  3709. void
  3710. meta_window_activate (MetaWindow *window,
  3711. guint32 timestamp)
  3712. {
  3713. g_return_if_fail (!window->override_redirect);
  3714. /* We're not really a pager, but the behavior we want is the same as if
  3715. * we were such. If we change the pager behavior later, we could revisit
  3716. * this and just add extra flags to window_activate.
  3717. */
  3718. window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL);
  3719. }
  3720. void
  3721. meta_window_activate_with_workspace (MetaWindow *window,
  3722. guint32 timestamp,
  3723. MetaWorkspace *workspace)
  3724. {
  3725. g_return_if_fail (!window->override_redirect);
  3726. /* We're not really a pager, but the behavior we want is the same as if
  3727. * we were such. If we change the pager behavior later, we could revisit
  3728. * this and just add extra flags to window_activate.
  3729. */
  3730. window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace);
  3731. }
  3732. /* Manually fix all the weirdness explained in the big comment at the
  3733. * beginning of meta_window_move_resize_internal() giving positions
  3734. * expected by meta_window_constrain (i.e. positions & sizes of the
  3735. * internal or client window).
  3736. */
  3737. static void
  3738. adjust_for_gravity (MetaWindow *window,
  3739. MetaFrameBorders *borders,
  3740. gboolean coords_assume_border,
  3741. int gravity,
  3742. MetaRectangle *rect)
  3743. {
  3744. int ref_x, ref_y;
  3745. int bw;
  3746. int child_x, child_y;
  3747. int frame_width, frame_height;
  3748. if (coords_assume_border)
  3749. bw = window->border_width;
  3750. else
  3751. bw = 0;
  3752. if (borders)
  3753. {
  3754. child_x = borders->visible.left;
  3755. child_y = borders->visible.top;
  3756. frame_width = child_x + rect->width + borders->visible.right;
  3757. frame_height = child_y + rect->height + borders->visible.bottom;
  3758. }
  3759. else
  3760. {
  3761. child_x = 0;
  3762. child_y = 0;
  3763. frame_width = rect->width;
  3764. frame_height = rect->height;
  3765. }
  3766. /* We're computing position to pass to window_move, which is
  3767. * the position of the client window (StaticGravity basically)
  3768. *
  3769. * (see WM spec description of gravity computation, but note that
  3770. * their formulas assume we're honoring the border width, rather
  3771. * than compensating for having turned it off)
  3772. */
  3773. switch (gravity)
  3774. {
  3775. case NorthWestGravity:
  3776. ref_x = rect->x;
  3777. ref_y = rect->y;
  3778. break;
  3779. case NorthGravity:
  3780. ref_x = rect->x + rect->width / 2 + bw;
  3781. ref_y = rect->y;
  3782. break;
  3783. case NorthEastGravity:
  3784. ref_x = rect->x + rect->width + bw * 2;
  3785. ref_y = rect->y;
  3786. break;
  3787. case WestGravity:
  3788. ref_x = rect->x;
  3789. ref_y = rect->y + rect->height / 2 + bw;
  3790. break;
  3791. case CenterGravity:
  3792. ref_x = rect->x + rect->width / 2 + bw;
  3793. ref_y = rect->y + rect->height / 2 + bw;
  3794. break;
  3795. case EastGravity:
  3796. ref_x = rect->x + rect->width + bw * 2;
  3797. ref_y = rect->y + rect->height / 2 + bw;
  3798. break;
  3799. case SouthWestGravity:
  3800. ref_x = rect->x;
  3801. ref_y = rect->y + rect->height + bw * 2;
  3802. break;
  3803. case SouthGravity:
  3804. ref_x = rect->x + rect->width / 2 + bw;
  3805. ref_y = rect->y + rect->height + bw * 2;
  3806. break;
  3807. case SouthEastGravity:
  3808. ref_x = rect->x + rect->width + bw * 2;
  3809. ref_y = rect->y + rect->height + bw * 2;
  3810. break;
  3811. case StaticGravity:
  3812. default:
  3813. ref_x = rect->x;
  3814. ref_y = rect->y;
  3815. break;
  3816. }
  3817. switch (gravity)
  3818. {
  3819. case NorthWestGravity:
  3820. rect->x = ref_x + child_x;
  3821. rect->y = ref_y + child_y;
  3822. break;
  3823. case NorthGravity:
  3824. rect->x = ref_x - frame_width / 2 + child_x;
  3825. rect->y = ref_y + child_y;
  3826. break;
  3827. case NorthEastGravity:
  3828. rect->x = ref_x - frame_width + child_x;
  3829. rect->y = ref_y + child_y;
  3830. break;
  3831. case WestGravity:
  3832. rect->x = ref_x + child_x;
  3833. rect->y = ref_y - frame_height / 2 + child_y;
  3834. break;
  3835. case CenterGravity:
  3836. rect->x = ref_x - frame_width / 2 + child_x;
  3837. rect->y = ref_y - frame_height / 2 + child_y;
  3838. break;
  3839. case EastGravity:
  3840. rect->x = ref_x - frame_width + child_x;
  3841. rect->y = ref_y - frame_height / 2 + child_y;
  3842. break;
  3843. case SouthWestGravity:
  3844. rect->x = ref_x + child_x;
  3845. rect->y = ref_y - frame_height + child_y;
  3846. break;
  3847. case SouthGravity:
  3848. rect->x = ref_x - frame_width / 2 + child_x;
  3849. rect->y = ref_y - frame_height + child_y;
  3850. break;
  3851. case SouthEastGravity:
  3852. rect->x = ref_x - frame_width + child_x;
  3853. rect->y = ref_y - frame_height + child_y;
  3854. break;
  3855. case StaticGravity:
  3856. default:
  3857. rect->x = ref_x;
  3858. rect->y = ref_y;
  3859. break;
  3860. }
  3861. }
  3862. static gboolean
  3863. static_gravity_works (MetaDisplay *display)
  3864. {
  3865. return display->static_gravity_works;
  3866. }
  3867. void
  3868. meta_window_create_sync_request_alarm (MetaWindow *window)
  3869. {
  3870. #ifdef HAVE_XSYNC
  3871. XSyncAlarmAttributes values;
  3872. XSyncValue init;
  3873. if (window->sync_request_counter == None ||
  3874. window->sync_request_alarm != None)
  3875. return;
  3876. meta_error_trap_push_with_return (window->display);
  3877. /* In the new (extended style), the counter value is initialized by
  3878. * the client before mapping the window. In the old style, we're
  3879. * responsible for setting the initial value of the counter.
  3880. */
  3881. if (window->extended_sync_request_counter)
  3882. {
  3883. if (!XSyncQueryCounter(window->display->xdisplay,
  3884. window->sync_request_counter,
  3885. &init))
  3886. {
  3887. meta_error_trap_pop_with_return (window->display);
  3888. window->sync_request_counter = None;
  3889. return;
  3890. }
  3891. window->sync_request_serial =
  3892. XSyncValueLow32 (init) + ((gint64)XSyncValueHigh32 (init) << 32);
  3893. /* if the value is odd, the window starts off with updates frozen */
  3894. meta_compositor_set_updates_frozen (window->display->compositor, window,
  3895. meta_window_updates_are_frozen (window));
  3896. }
  3897. else
  3898. {
  3899. XSyncIntToValue (&init, 0);
  3900. XSyncSetCounter (window->display->xdisplay,
  3901. window->sync_request_counter, init);
  3902. window->sync_request_serial = 0;
  3903. }
  3904. values.trigger.counter = window->sync_request_counter;
  3905. values.trigger.test_type = XSyncPositiveComparison;
  3906. /* Initialize to one greater than the current value */
  3907. values.trigger.value_type = XSyncRelative;
  3908. XSyncIntToValue (&values.trigger.wait_value, 1);
  3909. /* After triggering, increment test_value by this until
  3910. * until the test condition is false */
  3911. XSyncIntToValue (&values.delta, 1);
  3912. /* we want events (on by default anyway) */
  3913. values.events = True;
  3914. window->sync_request_alarm = XSyncCreateAlarm (window->display->xdisplay,
  3915. XSyncCACounter |
  3916. XSyncCAValueType |
  3917. XSyncCAValue |
  3918. XSyncCATestType |
  3919. XSyncCADelta |
  3920. XSyncCAEvents,
  3921. &values);
  3922. if (meta_error_trap_pop_with_return (window->display) == Success)
  3923. meta_display_register_sync_alarm (window->display, &window->sync_request_alarm, window);
  3924. else
  3925. {
  3926. window->sync_request_alarm = None;
  3927. window->sync_request_counter = None;
  3928. }
  3929. #endif
  3930. }
  3931. void
  3932. meta_window_destroy_sync_request_alarm (MetaWindow *window)
  3933. {
  3934. #ifdef HAVE_XSYNC
  3935. if (window->sync_request_alarm != None)
  3936. {
  3937. /* Has to be unregistered _before_ clearing the structure field */
  3938. meta_display_unregister_sync_alarm (window->display, window->sync_request_alarm);
  3939. XSyncDestroyAlarm (window->display->xdisplay,
  3940. window->sync_request_alarm);
  3941. window->sync_request_alarm = None;
  3942. }
  3943. #endif /* HAVE_XSYNC */
  3944. }
  3945. #ifdef HAVE_XSYNC
  3946. static gboolean
  3947. sync_request_timeout (gpointer data)
  3948. {
  3949. MetaWindow *window = data;
  3950. window->sync_request_timeout_id = 0;
  3951. /* We have now waited for more than a second for the
  3952. * application to respond to the sync request
  3953. */
  3954. window->disable_sync = TRUE;
  3955. /* Reset the wait serial, so we don't continue freezing
  3956. * window updates
  3957. */
  3958. window->sync_request_wait_serial = 0;
  3959. meta_compositor_set_updates_frozen (window->display->compositor, window,
  3960. meta_window_updates_are_frozen (window));
  3961. if (window == window->display->grab_window &&
  3962. meta_grab_op_is_resizing (window->display->grab_op))
  3963. {
  3964. update_resize (window,
  3965. window->display->grab_last_user_action_was_snap,
  3966. window->display->grab_latest_motion_x,
  3967. window->display->grab_latest_motion_y,
  3968. TRUE);
  3969. }
  3970. return FALSE;
  3971. }
  3972. static void
  3973. send_sync_request (MetaWindow *window)
  3974. {
  3975. XClientMessageEvent ev;
  3976. gint64 wait_serial;
  3977. /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to
  3978. * increase the value, but for the new "extended" style we need to
  3979. * pick an even (unfrozen) value sufficiently ahead of the last serial
  3980. * that we received from the client; the same code still works
  3981. * for the old style. The increment of 240 is specified by the EWMH
  3982. * and is (1 second) * (60fps) * (an increment of 4 per frame).
  3983. */
  3984. wait_serial = window->sync_request_serial + 240;
  3985. window->sync_request_wait_serial = wait_serial;
  3986. ev.type = ClientMessage;
  3987. ev.window = window->xwindow;
  3988. ev.message_type = window->display->atom_WM_PROTOCOLS;
  3989. ev.format = 32;
  3990. ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST;
  3991. /* FIXME: meta_display_get_current_time() is bad, but since calls
  3992. * come from meta_window_move_resize_internal (which in turn come
  3993. * from all over), I'm not sure what we can do to fix it. Do we
  3994. * want to use _roundtrip, though?
  3995. */
  3996. ev.data.l[1] = meta_display_get_current_time (window->display);
  3997. ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff);
  3998. ev.data.l[3] = wait_serial >> 32;
  3999. ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0;
  4000. /* We don't need to trap errors here as we are already
  4001. * inside an error_trap_push()/pop() pair.
  4002. */
  4003. XSendEvent (window->display->xdisplay,
  4004. window->xwindow, False, 0, (XEvent*) &ev);
  4005. /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST;
  4006. * if this time expires, we consider the window unresponsive
  4007. * and resize it unsynchonized.
  4008. */
  4009. window->sync_request_timeout_id = g_timeout_add (1000,
  4010. sync_request_timeout,
  4011. window);
  4012. meta_compositor_set_updates_frozen (window->display->compositor, window,
  4013. meta_window_updates_are_frozen (window));
  4014. }
  4015. #endif
  4016. /**
  4017. * meta_window_updates_are_frozen:
  4018. * @window: a #MetaWindow
  4019. *
  4020. * Gets whether the compositor should be updating the window contents;
  4021. * window content updates may be frozen at client request by setting
  4022. * an odd value in the extended _NET_WM_SYNC_REQUEST_COUNTER counter r
  4023. * by the window manager during a resize operation while waiting for
  4024. * the client to redraw.
  4025. *
  4026. * Return value: %TRUE if updates are currently frozen
  4027. */
  4028. gboolean
  4029. meta_window_updates_are_frozen (MetaWindow *window)
  4030. {
  4031. #ifdef HAVE_XSYNC
  4032. if (window->extended_sync_request_counter &&
  4033. window->sync_request_serial % 2 == 1)
  4034. return TRUE;
  4035. if (window->sync_request_serial < window->sync_request_wait_serial)
  4036. return TRUE;
  4037. #endif
  4038. return FALSE;
  4039. }
  4040. static gboolean
  4041. maybe_move_attached_dialog (MetaWindow *window,
  4042. void *data)
  4043. {
  4044. if (meta_window_is_attached_dialog (window))
  4045. /* It ignores x,y for such a dialog */
  4046. meta_window_move (window, FALSE, 0, 0);
  4047. return FALSE;
  4048. }
  4049. /**
  4050. * meta_window_get_monitor:
  4051. * @window: a #MetaWindow
  4052. *
  4053. * Gets index of the monitor that this window is on.
  4054. *
  4055. * Return Value: The index of the monitor in the screens monitor list
  4056. */
  4057. int
  4058. meta_window_get_monitor (MetaWindow *window)
  4059. {
  4060. g_return_val_if_fail (META_IS_WINDOW (window), -1);
  4061. if (window->monitor == NULL)
  4062. return -1;
  4063. return window->monitor->number;
  4064. }
  4065. /* This is called when the monitor setup has changed. The window->monitor
  4066. * reference is still "valid", but refer to the previous monitor setup */
  4067. LOCAL_SYMBOL void
  4068. meta_window_update_for_monitors_changed (MetaWindow *window)
  4069. {
  4070. const MetaMonitorInfo *old, *new;
  4071. int i;
  4072. old = window->monitor;
  4073. /* Start on primary */
  4074. new = &window->screen->monitor_infos[window->screen->primary_monitor_index];
  4075. /* But, if we can find the old output on a new monitor, use that */
  4076. for (i = 0; i < window->screen->n_monitor_infos; i++)
  4077. {
  4078. MetaMonitorInfo *info = &window->screen->monitor_infos[i];
  4079. if (info->output == old->output)
  4080. {
  4081. new = info;
  4082. break;
  4083. }
  4084. }
  4085. if (window->tile_mode != META_TILE_NONE)
  4086. window->tile_monitor_number = new->number;
  4087. /* This will eventually reach meta_window_update_monitor that
  4088. * will send leave/enter-monitor events. The old != new monitor
  4089. * check will always fail (due to the new monitor_infos set) so
  4090. * we will always send the events, even if the new and old monitor
  4091. * index is the same. That is right, since the enumeration of the
  4092. * monitors changed and the same index could be refereing
  4093. * to a different monitor. */
  4094. meta_window_move_between_rects (window,
  4095. &old->rect,
  4096. &new->rect);
  4097. }
  4098. static void
  4099. meta_window_update_monitor (MetaWindow *window)
  4100. {
  4101. const MetaMonitorInfo *old;
  4102. old = window->monitor;
  4103. window->monitor = meta_screen_get_monitor_for_window (window->screen, window);
  4104. if (old != window->monitor)
  4105. {
  4106. meta_window_update_on_all_workspaces (window);
  4107. /* If workspaces only on primary and we moved back to primary, ensure that the
  4108. * window is now in that workspace. We do this because while the window is on a
  4109. * non-primary monitor it is always visible, so it would be very jarring if it
  4110. * disappeared when it crossed the monitor border.
  4111. * The one time we want it to both change to the primary monitor and a non-active
  4112. * workspace is when dropping the window on some other workspace thumbnail directly.
  4113. * That should be handled by explicitly moving the window before changing the
  4114. * workspace
  4115. * Don't do this if old == NULL, because thats what happens when starting up, and
  4116. * we don't want to move all windows around from a previous WM instance. Nor do
  4117. * we want it when moving from one primary monitor to another (can happen during
  4118. * screen reconfiguration.
  4119. */
  4120. if (meta_prefs_get_workspaces_only_on_primary () &&
  4121. meta_window_is_on_primary_monitor (window) &&
  4122. old != NULL && !old->is_primary &&
  4123. window->screen->active_workspace != window->workspace)
  4124. meta_window_change_workspace (window, window->screen->active_workspace);
  4125. if (old)
  4126. g_signal_emit_by_name (window->screen, "window-left-monitor", old->number, window);
  4127. g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window);
  4128. g_signal_emit_by_name (window->screen, "window-monitor-changed", window, window->monitor->number);
  4129. /* If we're changing monitors, we need to update the has_maximize_func flag,
  4130. * as the working area has changed. */
  4131. recalc_window_features (window);
  4132. }
  4133. }
  4134. static void
  4135. meta_window_move_resize_internal (MetaWindow *window,
  4136. MetaMoveResizeFlags flags,
  4137. int gravity,
  4138. int root_x_nw,
  4139. int root_y_nw,
  4140. int w,
  4141. int h)
  4142. {
  4143. /* meta_window_move_resize_internal gets called with very different
  4144. * meanings for root_x_nw and root_y_nw. w & h are always the area
  4145. * of the inner or client window (i.e. excluding the frame) and
  4146. * gravity is the relevant gravity associated with the request (note
  4147. * that gravity is ignored for move-only operations unless its
  4148. * e.g. a configure request). The location is different for
  4149. * different cases because of how this function gets called; note
  4150. * that in all cases what we want to find out is the upper left
  4151. * corner of the position of the inner window:
  4152. *
  4153. * Case | Called from (flags; gravity)
  4154. * -----+-----------------------------------------------
  4155. * 1 | A resize only ConfigureRequest
  4156. * 1 | meta_window_resize
  4157. * 1 | meta_window_resize_with_gravity
  4158. * 2 | New window
  4159. * 2 | Session restore
  4160. * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
  4161. * 3 | meta_window_move
  4162. * 3 | meta_window_move_resize
  4163. *
  4164. * For each of the cases, root_x_nw and root_y_nw must be treated as follows:
  4165. *
  4166. * (1) They should be entirely ignored; instead the previous position
  4167. * and size of the window should be resized according to the given
  4168. * gravity in order to determine the new position of the window.
  4169. * (2) Needs to be fixed up by adjust_for_gravity() as these
  4170. * coordinates are relative to some corner or side of the outer
  4171. * window (except for the case of StaticGravity) and we want to
  4172. * know the location of the upper left corner of the inner window.
  4173. * (3) These values are already the desired positon of the NW corner
  4174. * of the inner window
  4175. */
  4176. XWindowChanges values;
  4177. unsigned int mask;
  4178. gboolean need_configure_notify;
  4179. MetaFrameBorders borders;
  4180. gboolean need_move_client = FALSE;
  4181. gboolean need_move_frame = FALSE;
  4182. gboolean need_resize_client = FALSE;
  4183. gboolean need_resize_frame = FALSE;
  4184. int frame_size_dx;
  4185. int frame_size_dy;
  4186. int size_dx;
  4187. int size_dy;
  4188. gboolean frame_shape_changed = FALSE;
  4189. gboolean is_configure_request;
  4190. gboolean do_gravity_adjust;
  4191. gboolean is_user_action;
  4192. gboolean did_placement;
  4193. gboolean configure_frame_first;
  4194. gboolean use_static_gravity;
  4195. /* used for the configure request, but may not be final
  4196. * destination due to StaticGravity etc.
  4197. */
  4198. int client_move_x;
  4199. int client_move_y;
  4200. MetaRectangle new_rect;
  4201. MetaRectangle old_rect;
  4202. g_return_if_fail (!window->override_redirect);
  4203. is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
  4204. do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
  4205. is_user_action = (flags & META_IS_USER_ACTION) != 0;
  4206. /* The action has to be a move or a resize or both... */
  4207. g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION));
  4208. /* We don't need it in the idle queue anymore. */
  4209. meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
  4210. meta_window_get_client_root_coords (window, &old_rect);
  4211. meta_topic (META_DEBUG_GEOMETRY,
  4212. "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n",
  4213. window->desc, root_x_nw, root_y_nw, w, h,
  4214. is_configure_request ? " (configure request)" : "",
  4215. is_user_action ? " (user move/resize)" : "",
  4216. old_rect.x, old_rect.y, old_rect.width, old_rect.height);
  4217. meta_frame_calc_borders (window->frame,
  4218. &borders);
  4219. new_rect.x = root_x_nw;
  4220. new_rect.y = root_y_nw;
  4221. new_rect.width = w;
  4222. new_rect.height = h;
  4223. /* If this is a resize only, the position should be ignored and
  4224. * instead obtained by resizing the old rectangle according to the
  4225. * relevant gravity.
  4226. */
  4227. if ((flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) ==
  4228. META_IS_RESIZE_ACTION)
  4229. {
  4230. meta_rectangle_resize_with_gravity (&old_rect,
  4231. &new_rect,
  4232. gravity,
  4233. new_rect.width,
  4234. new_rect.height);
  4235. meta_topic (META_DEBUG_GEOMETRY,
  4236. "Compensated for gravity in resize action; new pos %d,%d\n",
  4237. new_rect.x, new_rect.y);
  4238. }
  4239. else if (is_configure_request || do_gravity_adjust)
  4240. {
  4241. adjust_for_gravity (window,
  4242. window->frame ? &borders : NULL,
  4243. /* configure request coords assume
  4244. * the border width existed
  4245. */
  4246. is_configure_request,
  4247. gravity,
  4248. &new_rect);
  4249. meta_topic (META_DEBUG_GEOMETRY,
  4250. "Compensated for configure_request/do_gravity_adjust needing "
  4251. "weird positioning; new pos %d,%d\n",
  4252. new_rect.x, new_rect.y);
  4253. }
  4254. did_placement = !window->placed && window->calc_placement;
  4255. meta_window_constrain (window,
  4256. window->frame ? &borders : NULL,
  4257. flags,
  4258. gravity,
  4259. &old_rect,
  4260. &new_rect);
  4261. w = new_rect.width;
  4262. h = new_rect.height;
  4263. root_x_nw = new_rect.x;
  4264. root_y_nw = new_rect.y;
  4265. if (w != window->rect.width ||
  4266. h != window->rect.height)
  4267. need_resize_client = TRUE;
  4268. window->rect.width = w;
  4269. window->rect.height = h;
  4270. if (window->frame)
  4271. {
  4272. int new_w, new_h;
  4273. new_w = window->rect.width + borders.total.left + borders.total.right;
  4274. if (window->shaded)
  4275. new_h = borders.total.top;
  4276. else
  4277. new_h = window->rect.height + borders.total.top + borders.total.bottom;
  4278. frame_size_dx = new_w - window->frame->rect.width;
  4279. frame_size_dy = new_h - window->frame->rect.height;
  4280. need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
  4281. window->frame->rect.width = new_w;
  4282. window->frame->rect.height = new_h;
  4283. meta_topic (META_DEBUG_GEOMETRY,
  4284. "Calculated frame size %dx%d\n",
  4285. window->frame->rect.width,
  4286. window->frame->rect.height);
  4287. }
  4288. /* For nice effect, when growing the window we want to move/resize
  4289. * the frame first, when shrinking the window we want to move/resize
  4290. * the client first. If we grow one way and shrink the other,
  4291. * see which way we're moving "more"
  4292. *
  4293. * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
  4294. * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
  4295. *
  4296. * An annoying fact you need to know in this code is that StaticGravity
  4297. * does nothing if you _only_ resize or _only_ move the frame;
  4298. * it must move _and_ resize, otherwise you get NorthWestGravity
  4299. * behavior. The move and resize must actually occur, it is not
  4300. * enough to set CWX | CWWidth but pass in the current size/pos.
  4301. */
  4302. if (window->frame)
  4303. {
  4304. int new_x, new_y;
  4305. int frame_pos_dx, frame_pos_dy;
  4306. /* Compute new frame coords */
  4307. new_x = root_x_nw - borders.total.left;
  4308. new_y = root_y_nw - borders.total.top;
  4309. frame_pos_dx = new_x - window->frame->rect.x;
  4310. frame_pos_dy = new_y - window->frame->rect.y;
  4311. need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
  4312. window->frame->rect.x = new_x;
  4313. window->frame->rect.y = new_y;
  4314. /* If frame will both move and resize, then StaticGravity
  4315. * on the child window will kick in and implicitly move
  4316. * the child with respect to the frame. The implicit
  4317. * move will keep the child in the same place with
  4318. * respect to the root window. If frame only moves
  4319. * or only resizes, then the child will just move along
  4320. * with the frame.
  4321. */
  4322. /* window->rect.x, window->rect.y are relative to frame,
  4323. * remember they are the server coords
  4324. */
  4325. new_x = borders.total.left;
  4326. new_y = borders.total.top;
  4327. if (need_resize_frame && need_move_frame &&
  4328. static_gravity_works (window->display))
  4329. {
  4330. /* static gravity kicks in because frame
  4331. * is both moved and resized
  4332. */
  4333. /* when we move the frame by frame_pos_dx, frame_pos_dy the
  4334. * client will implicitly move relative to frame by the
  4335. * inverse delta.
  4336. *
  4337. * When moving client then frame, we move the client by the
  4338. * frame delta, to be canceled out by the implicit move by
  4339. * the inverse frame delta, resulting in a client at new_x,
  4340. * new_y.
  4341. *
  4342. * When moving frame then client, we move the client
  4343. * by the same delta as the frame, because the client
  4344. * was "left behind" by the frame - resulting in a client
  4345. * at new_x, new_y.
  4346. *
  4347. * In both cases we need to move the client window
  4348. * in all cases where we had to move the frame window.
  4349. */
  4350. client_move_x = new_x + frame_pos_dx;
  4351. client_move_y = new_y + frame_pos_dy;
  4352. if (need_move_frame)
  4353. need_move_client = TRUE;
  4354. use_static_gravity = TRUE;
  4355. }
  4356. else
  4357. {
  4358. client_move_x = new_x;
  4359. client_move_y = new_y;
  4360. if (client_move_x != window->rect.x ||
  4361. client_move_y != window->rect.y)
  4362. need_move_client = TRUE;
  4363. use_static_gravity = FALSE;
  4364. }
  4365. /* This is the final target position, but not necessarily what
  4366. * we pass to XConfigureWindow, due to StaticGravity implicit
  4367. * movement.
  4368. */
  4369. window->rect.x = new_x;
  4370. window->rect.y = new_y;
  4371. }
  4372. else
  4373. {
  4374. if (root_x_nw != window->rect.x ||
  4375. root_y_nw != window->rect.y)
  4376. need_move_client = TRUE;
  4377. window->rect.x = root_x_nw;
  4378. window->rect.y = root_y_nw;
  4379. client_move_x = window->rect.x;
  4380. client_move_y = window->rect.y;
  4381. use_static_gravity = FALSE;
  4382. }
  4383. /* If frame extents have changed, fill in other frame fields and
  4384. change frame's extents property. */
  4385. if (window->frame &&
  4386. (window->frame->child_x != borders.total.left ||
  4387. window->frame->child_y != borders.total.top ||
  4388. window->frame->right_width != borders.total.right ||
  4389. window->frame->bottom_height != borders.total.bottom))
  4390. {
  4391. window->frame->child_x = borders.total.left;
  4392. window->frame->child_y = borders.total.top;
  4393. window->frame->right_width = borders.total.right;
  4394. window->frame->bottom_height = borders.total.bottom;
  4395. update_net_frame_extents (window);
  4396. }
  4397. /* See ICCCM 4.1.5 for when to send ConfigureNotify */
  4398. need_configure_notify = FALSE;
  4399. /* If this is a configure request and we change nothing, then we
  4400. * must send configure notify.
  4401. */
  4402. if (is_configure_request &&
  4403. !(need_move_client || need_move_frame ||
  4404. need_resize_client || need_resize_frame ||
  4405. window->border_width != 0))
  4406. need_configure_notify = TRUE;
  4407. /* We must send configure notify if we move but don't resize, since
  4408. * the client window may not get a real event
  4409. */
  4410. if ((need_move_client || need_move_frame) &&
  4411. !(need_resize_client || need_resize_frame))
  4412. need_configure_notify = TRUE;
  4413. /* MapRequest events with a PPosition or UPosition hint with a frame
  4414. * are moved by muffin without resizing; send a configure notify
  4415. * in such cases. See #322840. (Note that window->constructing is
  4416. * only true iff this call is due to a MapRequest, and when
  4417. * PPosition/UPosition hints aren't set, muffin seems to send a
  4418. * ConfigureNotify anyway due to the above code.)
  4419. */
  4420. if (window->constructing && window->frame &&
  4421. ((window->size_hints.flags & PPosition) ||
  4422. (window->size_hints.flags & USPosition)))
  4423. need_configure_notify = TRUE;
  4424. /* The rest of this function syncs our new size/pos with X as
  4425. * efficiently as possible
  4426. */
  4427. /* Normally, we configure the frame first depending on whether
  4428. * we grow the frame more than we shrink. The idea is to avoid
  4429. * messing up the window contents by having a temporary situation
  4430. * where the frame is smaller than the window. However, if we're
  4431. * cooperating with the client to create an atomic frame upate,
  4432. * and the window is redirected, then we should always update
  4433. * the frame first, since updating the frame will force a new
  4434. * backing pixmap to be allocated, and the old backing pixmap
  4435. * will be left undisturbed for us to paint to the screen until
  4436. * the client finishes redrawing.
  4437. */
  4438. if (window->extended_sync_request_counter)
  4439. {
  4440. configure_frame_first = TRUE;
  4441. }
  4442. else
  4443. {
  4444. size_dx = w - window->rect.width;
  4445. size_dy = h - window->rect.height;
  4446. configure_frame_first = size_dx + size_dy >= 0;
  4447. }
  4448. if (use_static_gravity)
  4449. meta_window_set_gravity (window, StaticGravity);
  4450. if (configure_frame_first && window->frame)
  4451. frame_shape_changed = meta_frame_sync_to_window (window->frame,
  4452. gravity,
  4453. need_move_frame, need_resize_frame);
  4454. values.border_width = 0;
  4455. values.x = client_move_x;
  4456. values.y = client_move_y;
  4457. values.width = window->rect.width;
  4458. values.height = window->rect.height;
  4459. mask = 0;
  4460. if (is_configure_request && window->border_width != 0)
  4461. mask |= CWBorderWidth; /* must force to 0 */
  4462. if (need_move_client)
  4463. mask |= (CWX | CWY);
  4464. if (need_resize_client)
  4465. mask |= (CWWidth | CWHeight);
  4466. if (mask != 0)
  4467. {
  4468. {
  4469. int newx, newy;
  4470. meta_window_get_position (window, &newx, &newy);
  4471. meta_topic (META_DEBUG_GEOMETRY,
  4472. "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
  4473. newx, newy,
  4474. window->rect.width, window->rect.height,
  4475. mask & CWBorderWidth ? "true" : "false",
  4476. need_move_client ? "true" : "false",
  4477. need_resize_client ? "true" : "false");
  4478. }
  4479. meta_error_trap_push (window->display);
  4480. #ifdef HAVE_XSYNC
  4481. if (window == window->display->grab_window &&
  4482. meta_grab_op_is_resizing (window->display->grab_op) &&
  4483. !window->disable_sync &&
  4484. window->sync_request_counter != None &&
  4485. window->sync_request_alarm != None &&
  4486. window->sync_request_timeout_id == 0)
  4487. {
  4488. send_sync_request (window);
  4489. }
  4490. #endif
  4491. XConfigureWindow (window->display->xdisplay,
  4492. window->xwindow,
  4493. mask,
  4494. &values);
  4495. meta_error_trap_pop (window->display);
  4496. }
  4497. if (!configure_frame_first && window->frame)
  4498. frame_shape_changed = meta_frame_sync_to_window (window->frame,
  4499. gravity,
  4500. need_move_frame, need_resize_frame);
  4501. /* Put gravity back to be nice to lesser window managers */
  4502. if (use_static_gravity)
  4503. meta_window_set_gravity (window, NorthWestGravity);
  4504. if (need_configure_notify)
  4505. send_configure_notify (window);
  4506. if (!window->placed && window->force_save_user_rect && !window->fullscreen)
  4507. force_save_user_window_placement (window);
  4508. else if (is_user_action)
  4509. save_user_window_placement (window);
  4510. if (need_move_frame || need_resize_frame ||
  4511. need_move_client || need_resize_client ||
  4512. did_placement)
  4513. {
  4514. int newx, newy;
  4515. meta_window_get_position (window, &newx, &newy);
  4516. meta_topic (META_DEBUG_GEOMETRY,
  4517. "New size/position %d,%d %dx%d (user %d,%d %dx%d)\n",
  4518. newx, newy, window->rect.width, window->rect.height,
  4519. window->user_rect.x, window->user_rect.y,
  4520. window->user_rect.width, window->user_rect.height);
  4521. meta_compositor_sync_window_geometry (window->display->compositor,
  4522. window,
  4523. did_placement);
  4524. }
  4525. else
  4526. {
  4527. meta_topic (META_DEBUG_GEOMETRY, "Size/position not modified\n");
  4528. }
  4529. meta_window_refresh_resize_popup (window);
  4530. meta_window_update_monitor (window);
  4531. /* Invariants leaving this function are:
  4532. * a) window->rect and frame->rect reflect the actual
  4533. * server-side size/pos of window->xwindow and frame->xwindow
  4534. * b) all constraints are obeyed by window->rect and frame->rect
  4535. */
  4536. if (frame_shape_changed && window->frame_bounds)
  4537. {
  4538. cairo_region_destroy (window->frame_bounds);
  4539. window->frame_bounds = NULL;
  4540. }
  4541. meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL);
  4542. meta_stack_update_window_tile_matches (window->screen->stack,
  4543. window->screen->active_workspace);
  4544. }
  4545. /**
  4546. * meta_window_resize:
  4547. * @window: a #MetaWindow
  4548. * @user_op: bool to indicate whether or not this is a user operation
  4549. * @w: desired width
  4550. * @h: desired height
  4551. *
  4552. * Resize the window to the desired size.
  4553. */
  4554. void
  4555. meta_window_resize (MetaWindow *window,
  4556. gboolean user_op,
  4557. int w,
  4558. int h)
  4559. {
  4560. int x, y;
  4561. MetaMoveResizeFlags flags;
  4562. g_return_if_fail (!window->override_redirect);
  4563. meta_window_get_position (window, &x, &y);
  4564. flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
  4565. meta_window_move_resize_internal (window,
  4566. flags,
  4567. NorthWestGravity,
  4568. x, y, w, h);
  4569. }
  4570. /**
  4571. * meta_window_move:
  4572. * @window: a #MetaWindow
  4573. * @user_op: bool to indicate whether or not this is a user operation
  4574. * @root_x_nw: desired x pos
  4575. * @root_y_nw: desired y pos
  4576. *
  4577. * Moves the window to the desired location on window's assigned workspace.
  4578. * NOTE: does NOT place according to the origin of the enclosing
  4579. * frame/window-decoration, but according to the origin of the window,
  4580. * itself.
  4581. */
  4582. void
  4583. meta_window_move (MetaWindow *window,
  4584. gboolean user_op,
  4585. int root_x_nw,
  4586. int root_y_nw)
  4587. {
  4588. MetaMoveResizeFlags flags;
  4589. g_return_if_fail (!window->override_redirect);
  4590. flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION;
  4591. meta_window_move_resize_internal (window,
  4592. flags,
  4593. NorthWestGravity,
  4594. root_x_nw, root_y_nw,
  4595. window->rect.width,
  4596. window->rect.height);
  4597. }
  4598. /**
  4599. * meta_window_move_frame:
  4600. * @window: a #MetaWindow
  4601. * @user_op: bool to indicate whether or not this is a user operation
  4602. * @root_x_nw: desired x pos
  4603. * @root_y_nw: desired y pos
  4604. *
  4605. * Moves the window to the desired location on window's assigned
  4606. * workspace, using the northwest edge of the frame as the reference,
  4607. * instead of the actual window's origin, but only if a frame is present.
  4608. * Otherwise, acts identically to meta_window_move().
  4609. */
  4610. void
  4611. meta_window_move_frame (MetaWindow *window,
  4612. gboolean user_op,
  4613. int root_x_nw,
  4614. int root_y_nw)
  4615. {
  4616. int x = root_x_nw;
  4617. int y = root_y_nw;
  4618. if (window->frame)
  4619. {
  4620. MetaFrameBorders borders;
  4621. meta_frame_calc_borders (window->frame, &borders);
  4622. /* root_x_nw and root_y_nw correspond to where the top of
  4623. * the visible frame should be. Offset by the distance between
  4624. * the origin of the window and the origin of the enclosing
  4625. * window decorations.
  4626. */
  4627. x += window->frame->child_x - borders.invisible.left;
  4628. y += window->frame->child_y - borders.invisible.top;
  4629. }
  4630. meta_window_move (window, user_op, x, y);
  4631. }
  4632. static void
  4633. meta_window_move_between_rects (MetaWindow *window,
  4634. const MetaRectangle *old_area,
  4635. const MetaRectangle *new_area)
  4636. {
  4637. int rel_x, rel_y;
  4638. double scale_x, scale_y;
  4639. rel_x = window->user_rect.x - old_area->x;
  4640. rel_y = window->user_rect.y - old_area->y;
  4641. scale_x = (double)new_area->width / old_area->width;
  4642. scale_y = (double)new_area->height / old_area->height;
  4643. window->user_rect.x = new_area->x + rel_x * scale_x;
  4644. window->user_rect.y = new_area->y + rel_y * scale_y;
  4645. window->saved_rect.x = window->user_rect.x;
  4646. window->saved_rect.y = window->user_rect.y;
  4647. meta_window_move_resize (window, FALSE,
  4648. window->user_rect.x,
  4649. window->user_rect.y,
  4650. window->user_rect.width,
  4651. window->user_rect.height);
  4652. }
  4653. /**
  4654. * meta_window_move_resize_frame:
  4655. * @window: a #MetaWindow
  4656. * @user_op: bool to indicate whether or not this is a user operation
  4657. * @root_x_nw: new x
  4658. * @root_y_nw: new y
  4659. * @w: desired width
  4660. * @h: desired height
  4661. *
  4662. * Resizes the window so that its outer bounds (including frame)
  4663. * fit within the given rect
  4664. */
  4665. void
  4666. meta_window_move_resize_frame (MetaWindow *window,
  4667. gboolean user_op,
  4668. int root_x_nw,
  4669. int root_y_nw,
  4670. int w,
  4671. int h)
  4672. {
  4673. MetaFrameBorders borders;
  4674. meta_frame_calc_borders (window->frame, &borders);
  4675. /* offset by the distance between the origin of the window
  4676. * and the origin of the enclosing window decorations ( + border)
  4677. */
  4678. root_x_nw += borders.visible.left;
  4679. root_y_nw += borders.visible.top;
  4680. w -= borders.visible.left + borders.visible.right;
  4681. h -= borders.visible.top + borders.visible.bottom;
  4682. meta_window_move_resize (window, user_op, root_x_nw, root_y_nw, w, h);
  4683. }
  4684. /**
  4685. * meta_window_move_to_monitor:
  4686. * @window: a #MetaWindow
  4687. * @monitor: desired monitor index
  4688. *
  4689. * Moves the window to the monitor with index @monitor, keeping
  4690. * the relative position of the window's top left corner.
  4691. */
  4692. void
  4693. meta_window_move_to_monitor (MetaWindow *window,
  4694. int monitor)
  4695. {
  4696. MetaRectangle old_area, new_area;
  4697. if (monitor == window->monitor->number)
  4698. return;
  4699. meta_window_get_work_area_for_monitor (window,
  4700. window->monitor->number,
  4701. &old_area);
  4702. meta_window_get_work_area_for_monitor (window,
  4703. monitor,
  4704. &new_area);
  4705. if (window->tile_mode != META_TILE_NONE)
  4706. window->tile_monitor_number = monitor;
  4707. meta_window_move_between_rects (window, &old_area, &new_area);
  4708. }
  4709. void
  4710. meta_window_move_resize (MetaWindow *window,
  4711. gboolean user_op,
  4712. int root_x_nw,
  4713. int root_y_nw,
  4714. int w,
  4715. int h)
  4716. {
  4717. MetaMoveResizeFlags flags;
  4718. g_return_if_fail (!window->override_redirect);
  4719. flags = (user_op ? META_IS_USER_ACTION : 0) |
  4720. META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
  4721. meta_window_move_resize_internal (window,
  4722. flags,
  4723. NorthWestGravity,
  4724. root_x_nw, root_y_nw,
  4725. w, h);
  4726. }
  4727. LOCAL_SYMBOL void
  4728. meta_window_resize_with_gravity (MetaWindow *window,
  4729. gboolean user_op,
  4730. int w,
  4731. int h,
  4732. int gravity)
  4733. {
  4734. int x, y;
  4735. MetaMoveResizeFlags flags;
  4736. meta_window_get_position (window, &x, &y);
  4737. flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
  4738. meta_window_move_resize_internal (window,
  4739. flags,
  4740. gravity,
  4741. x, y, w, h);
  4742. }
  4743. static void
  4744. meta_window_move_resize_now (MetaWindow *window)
  4745. {
  4746. /* If constraints have changed then we want to snap back to wherever
  4747. * the user had the window. We use user_rect for this reason. See
  4748. * also bug 426519 comment 3.
  4749. */
  4750. meta_window_move_resize (window, FALSE,
  4751. window->user_rect.x,
  4752. window->user_rect.y,
  4753. window->user_rect.width,
  4754. window->user_rect.height);
  4755. }
  4756. static gboolean
  4757. idle_move_resize (gpointer data)
  4758. {
  4759. GSList *tmp;
  4760. GSList *copy;
  4761. guint queue_index = GPOINTER_TO_INT (data);
  4762. meta_topic (META_DEBUG_GEOMETRY, "Clearing the move_resize queue\n");
  4763. /* Work with a copy, for reentrancy. The allowed reentrancy isn't
  4764. * complete; destroying a window while we're in here would result in
  4765. * badness. But it's OK to queue/unqueue move_resizes.
  4766. */
  4767. copy = g_slist_copy (queue_pending[queue_index]);
  4768. g_slist_free (queue_pending[queue_index]);
  4769. queue_pending[queue_index] = NULL;
  4770. queue_later[queue_index] = 0;
  4771. destroying_windows_disallowed += 1;
  4772. tmp = copy;
  4773. while (tmp != NULL)
  4774. {
  4775. MetaWindow *window;
  4776. window = tmp->data;
  4777. /* As a side effect, sets window->move_resize_queued = FALSE */
  4778. meta_window_move_resize_now (window);
  4779. tmp = tmp->next;
  4780. }
  4781. g_slist_free (copy);
  4782. destroying_windows_disallowed -= 1;
  4783. return FALSE;
  4784. }
  4785. /**
  4786. * meta_window_configure_notify: (skip)
  4787. * @window: a #MetaWindow
  4788. * @event: a #XConfigureEvent
  4789. *
  4790. * This is used to notify us of an unrequested configuration
  4791. * (only applicable to override redirect windows)
  4792. */
  4793. void
  4794. meta_window_configure_notify (MetaWindow *window,
  4795. XConfigureEvent *event)
  4796. {
  4797. g_assert (window->override_redirect);
  4798. g_assert (window->frame == NULL);
  4799. window->rect.x = event->x;
  4800. window->rect.y = event->y;
  4801. window->rect.width = event->width;
  4802. window->rect.height = event->height;
  4803. meta_window_update_monitor (window);
  4804. /* Whether an override-redirect window is considered fullscreen depends
  4805. * on its geometry.
  4806. */
  4807. if (window->override_redirect)
  4808. meta_screen_queue_check_fullscreen (window->screen);
  4809. if (!event->override_redirect && !event->send_event)
  4810. meta_warning ("Unhandled change of windows override redirect status\n");
  4811. meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE);
  4812. }
  4813. LOCAL_SYMBOL void
  4814. meta_window_get_position (MetaWindow *window,
  4815. int *x,
  4816. int *y)
  4817. {
  4818. if (window->frame)
  4819. {
  4820. if (x)
  4821. *x = window->frame->rect.x + window->frame->child_x;
  4822. if (y)
  4823. *y = window->frame->rect.y + window->frame->child_y;
  4824. }
  4825. else
  4826. {
  4827. if (x)
  4828. *x = window->rect.x;
  4829. if (y)
  4830. *y = window->rect.y;
  4831. }
  4832. }
  4833. LOCAL_SYMBOL void
  4834. meta_window_get_client_root_coords (MetaWindow *window,
  4835. MetaRectangle *rect)
  4836. {
  4837. meta_window_get_position (window, &rect->x, &rect->y);
  4838. rect->width = window->rect.width;
  4839. rect->height = window->rect.height;
  4840. }
  4841. LOCAL_SYMBOL void
  4842. meta_window_get_gravity_position (MetaWindow *window,
  4843. int gravity,
  4844. int *root_x,
  4845. int *root_y)
  4846. {
  4847. MetaRectangle frame_extents;
  4848. int w, h;
  4849. int x, y;
  4850. w = window->rect.width;
  4851. h = window->rect.height;
  4852. if (gravity == StaticGravity)
  4853. {
  4854. frame_extents = window->rect;
  4855. if (window->frame)
  4856. {
  4857. frame_extents.x = window->frame->rect.x + window->frame->child_x;
  4858. frame_extents.y = window->frame->rect.y + window->frame->child_y;
  4859. }
  4860. }
  4861. else
  4862. {
  4863. if (window->frame == NULL)
  4864. frame_extents = window->rect;
  4865. else
  4866. frame_extents = window->frame->rect;
  4867. }
  4868. x = frame_extents.x;
  4869. y = frame_extents.y;
  4870. switch (gravity)
  4871. {
  4872. case NorthGravity:
  4873. case CenterGravity:
  4874. case SouthGravity:
  4875. /* Find center of frame. */
  4876. x += frame_extents.width / 2;
  4877. /* Center client window on that point. */
  4878. x -= w / 2;
  4879. break;
  4880. case SouthEastGravity:
  4881. case EastGravity:
  4882. case NorthEastGravity:
  4883. /* Find right edge of frame */
  4884. x += frame_extents.width;
  4885. /* Align left edge of client at that point. */
  4886. x -= w;
  4887. break;
  4888. default:
  4889. break;
  4890. }
  4891. switch (gravity)
  4892. {
  4893. case WestGravity:
  4894. case CenterGravity:
  4895. case EastGravity:
  4896. /* Find center of frame. */
  4897. y += frame_extents.height / 2;
  4898. /* Center client window there. */
  4899. y -= h / 2;
  4900. break;
  4901. case SouthWestGravity:
  4902. case SouthGravity:
  4903. case SouthEastGravity:
  4904. /* Find south edge of frame */
  4905. y += frame_extents.height;
  4906. /* Place bottom edge of client there */
  4907. y -= h;
  4908. break;
  4909. default:
  4910. break;
  4911. }
  4912. if (root_x)
  4913. *root_x = x;
  4914. if (root_y)
  4915. *root_y = y;
  4916. }
  4917. LOCAL_SYMBOL void
  4918. meta_window_get_geometry (MetaWindow *window,
  4919. int *x,
  4920. int *y,
  4921. int *width,
  4922. int *height)
  4923. {
  4924. meta_window_get_gravity_position (window,
  4925. window->size_hints.win_gravity,
  4926. x, y);
  4927. *width = (window->rect.width - window->size_hints.base_width) /
  4928. window->size_hints.width_inc;
  4929. *height = (window->rect.height - window->size_hints.base_height) /
  4930. window->size_hints.height_inc;
  4931. }
  4932. /**
  4933. * meta_window_get_input_rect:
  4934. * @window: a #MetaWindow
  4935. * @rect: (out): pointer to an allocated #MetaRectangle
  4936. *
  4937. * Gets the rectangle that bounds @window that is responsive to mouse events.
  4938. * This includes decorations - the visible portion of its border - and (if
  4939. * present) any invisible area that we make make responsive to mouse clicks in
  4940. * order to allow convenient border dragging.
  4941. */
  4942. void
  4943. meta_window_get_input_rect (const MetaWindow *window,
  4944. MetaRectangle *rect)
  4945. {
  4946. if (window->frame)
  4947. *rect = window->frame->rect;
  4948. else
  4949. *rect = window->rect;
  4950. }
  4951. /**
  4952. * meta_window_get_outer_rect:
  4953. * @window: a #MetaWindow
  4954. * @rect: (out): pointer to an allocated #MetaRectangle
  4955. *
  4956. * Gets the rectangle that bounds @window that is responsive to mouse events.
  4957. * This includes only what is visible; it doesn't include any extra reactive
  4958. * area we add to the edges of windows.
  4959. */
  4960. void
  4961. meta_window_get_outer_rect (const MetaWindow *window,
  4962. MetaRectangle *rect)
  4963. {
  4964. if (window->frame)
  4965. {
  4966. MetaFrameBorders borders;
  4967. *rect = window->frame->rect;
  4968. meta_frame_calc_borders (window->frame, &borders);
  4969. rect->x += borders.invisible.left;
  4970. rect->y += borders.invisible.top;
  4971. rect->width -= borders.invisible.left + borders.invisible.right;
  4972. rect->height -= borders.invisible.top + borders.invisible.bottom;
  4973. }
  4974. else
  4975. {
  4976. *rect = window->rect;
  4977. if (window->has_custom_frame_extents)
  4978. {
  4979. const GtkBorder *extents = &window->custom_frame_extents;
  4980. rect->x += extents->left;
  4981. rect->y += extents->top;
  4982. rect->width -= extents->left + extents->right;
  4983. rect->height -= extents->top + extents->bottom;
  4984. }
  4985. }
  4986. }
  4987. MetaSide
  4988. meta_window_get_tile_side (MetaWindow *window)
  4989. {
  4990. MetaSide side;
  4991. switch (window->tile_mode) {
  4992. case META_TILE_LEFT:
  4993. side = META_SIDE_LEFT;
  4994. break;
  4995. case META_TILE_ULC:
  4996. side = (META_SIDE_LEFT | META_SIDE_TOP);
  4997. break;
  4998. case META_TILE_LLC:
  4999. side = (META_SIDE_LEFT | META_SIDE_BOTTOM);
  5000. break;
  5001. case META_TILE_RIGHT:
  5002. side = META_SIDE_RIGHT;
  5003. break;
  5004. case META_TILE_URC:
  5005. side = (META_SIDE_RIGHT | META_SIDE_TOP);
  5006. break;
  5007. case META_TILE_LRC:
  5008. side = (META_SIDE_RIGHT | META_SIDE_BOTTOM);
  5009. break;
  5010. case META_TILE_TOP:
  5011. side = META_SIDE_TOP;
  5012. break;
  5013. case META_TILE_BOTTOM:
  5014. side = META_SIDE_BOTTOM;
  5015. break;
  5016. default:
  5017. side = META_SIDE_TOP;
  5018. break;
  5019. }
  5020. return side;
  5021. }
  5022. void
  5023. meta_window_get_titlebar_rect (MetaWindow *window,
  5024. MetaRectangle *rect)
  5025. {
  5026. meta_window_get_outer_rect (window, rect);
  5027. /* The returned rectangle is relative to the frame rect. */
  5028. rect->x = 0;
  5029. rect->y = 0;
  5030. if (window->frame)
  5031. {
  5032. rect->height = window->frame->child_y;
  5033. }
  5034. else
  5035. {
  5036. /* Pick an arbitrary height for a titlebar. We might want to
  5037. * eventually have CSD windows expose their borders to us. */
  5038. rect->height = CSD_TITLEBAR_HEIGHT * meta_prefs_get_ui_scale ();
  5039. }
  5040. }
  5041. const char*
  5042. meta_window_get_startup_id (MetaWindow *window)
  5043. {
  5044. if (window->startup_id == NULL)
  5045. {
  5046. MetaGroup *group;
  5047. group = meta_window_get_group (window);
  5048. if (group != NULL)
  5049. return meta_group_get_startup_id (group);
  5050. }
  5051. return window->startup_id;
  5052. }
  5053. static MetaWindow*
  5054. get_modal_transient (MetaWindow *window)
  5055. {
  5056. GSList *windows;
  5057. GSList *tmp;
  5058. MetaWindow *modal_transient;
  5059. /* A window can't be the transient of itself, but this is just for
  5060. * convenience in the loop below; we manually fix things up at the
  5061. * end if no real modal transient was found.
  5062. */
  5063. modal_transient = window;
  5064. windows = meta_display_list_windows (window->display, META_LIST_DEFAULT);
  5065. tmp = windows;
  5066. while (tmp != NULL)
  5067. {
  5068. MetaWindow *transient = tmp->data;
  5069. if (transient->xtransient_for == modal_transient->xwindow &&
  5070. transient->wm_state_modal)
  5071. {
  5072. modal_transient = transient;
  5073. tmp = windows;
  5074. continue;
  5075. }
  5076. tmp = tmp->next;
  5077. }
  5078. g_slist_free (windows);
  5079. if (window == modal_transient)
  5080. modal_transient = NULL;
  5081. return modal_transient;
  5082. }
  5083. /* XXX META_EFFECT_FOCUS */
  5084. LOCAL_SYMBOL void
  5085. meta_window_focus (MetaWindow *window,
  5086. guint32 timestamp)
  5087. {
  5088. MetaWindow *modal_transient;
  5089. g_return_if_fail (!window->override_redirect);
  5090. meta_topic (META_DEBUG_FOCUS,
  5091. "Setting input focus to window %s, input: %d take_focus: %d\n",
  5092. window->desc, window->input, window->take_focus);
  5093. if (window->display->grab_window &&
  5094. window->display->grab_window->all_keys_grabbed)
  5095. {
  5096. meta_topic (META_DEBUG_FOCUS,
  5097. "Current focus window %s has global keygrab, not focusing window %s after all\n",
  5098. window->display->grab_window->desc, window->desc);
  5099. return;
  5100. }
  5101. modal_transient = get_modal_transient (window);
  5102. if (modal_transient != NULL &&
  5103. !modal_transient->unmanaging)
  5104. {
  5105. meta_topic (META_DEBUG_FOCUS,
  5106. "%s has %s as a modal transient, so focusing it instead.\n",
  5107. window->desc, modal_transient->desc);
  5108. if (!modal_transient->on_all_workspaces &&
  5109. modal_transient->workspace != window->screen->active_workspace)
  5110. meta_window_change_workspace (modal_transient,
  5111. window->screen->active_workspace);
  5112. window = modal_transient;
  5113. }
  5114. meta_window_flush_calc_showing (window);
  5115. if ((!window->mapped || window->hidden) && !window->shaded)
  5116. {
  5117. meta_topic (META_DEBUG_FOCUS,
  5118. "Window %s is not showing, not focusing after all\n",
  5119. window->desc);
  5120. return;
  5121. }
  5122. /* For output-only or shaded windows, focus the frame.
  5123. * This seems to result in the client window getting key events
  5124. * though, so I don't know if it's icccm-compliant.
  5125. *
  5126. * Still, we have to do this or keynav breaks for these windows.
  5127. */
  5128. if (window->frame &&
  5129. (window->shaded ||
  5130. !(window->input || window->take_focus)))
  5131. {
  5132. if (window->frame)
  5133. {
  5134. meta_topic (META_DEBUG_FOCUS,
  5135. "Focusing frame of %s\n", window->desc);
  5136. meta_display_set_input_focus_window (window->display,
  5137. window,
  5138. TRUE,
  5139. timestamp);
  5140. }
  5141. }
  5142. else
  5143. {
  5144. if (window->input)
  5145. {
  5146. meta_topic (META_DEBUG_FOCUS,
  5147. "Setting input focus on %s since input = true\n",
  5148. window->desc);
  5149. meta_display_set_input_focus_window (window->display,
  5150. window,
  5151. FALSE,
  5152. timestamp);
  5153. }
  5154. if (window->take_focus)
  5155. {
  5156. meta_topic (META_DEBUG_FOCUS,
  5157. "Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
  5158. window->desc);
  5159. meta_window_send_icccm_message (window,
  5160. window->display->atom_WM_TAKE_FOCUS,
  5161. timestamp);
  5162. window->display->expected_focus_window = window;
  5163. }
  5164. }
  5165. if (window->wm_state_demands_attention)
  5166. meta_window_unset_demands_attention(window);
  5167. /* meta_effect_run_focus(window, NULL, NULL); */
  5168. }
  5169. static void
  5170. meta_window_change_workspace_without_transients (MetaWindow *window,
  5171. MetaWorkspace *workspace)
  5172. {
  5173. int old_workspace = -1;
  5174. meta_verbose ("Changing window %s to workspace %d\n",
  5175. window->desc, meta_workspace_index (workspace));
  5176. if (!window->on_all_workspaces_requested)
  5177. {
  5178. old_workspace = meta_workspace_index (window->workspace);
  5179. }
  5180. /* unstick if stuck. meta_window_unstick would call
  5181. * meta_window_change_workspace recursively if the window
  5182. * is not in the active workspace.
  5183. */
  5184. if (window->on_all_workspaces_requested)
  5185. meta_window_unstick (window);
  5186. /* See if we're already on this space. If not, make sure we are */
  5187. if (window->workspace != workspace)
  5188. {
  5189. meta_workspace_remove_window (window->workspace, window);
  5190. meta_workspace_add_window (workspace, window);
  5191. g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0,
  5192. old_workspace);
  5193. g_signal_emit_by_name (window->screen, "window-workspace-changed", window, window->workspace);
  5194. }
  5195. }
  5196. static gboolean
  5197. change_workspace_foreach (MetaWindow *window,
  5198. void *data)
  5199. {
  5200. meta_window_change_workspace_without_transients (window, data);
  5201. return TRUE;
  5202. }
  5203. /**
  5204. * meta_window_change_workspace:
  5205. * @window: a #MetaWindow
  5206. * @workspace: the #MetaWorkspace where to put the window
  5207. *
  5208. * Moves the window to the specified workspace.
  5209. */
  5210. void
  5211. meta_window_change_workspace (MetaWindow *window,
  5212. MetaWorkspace *workspace)
  5213. {
  5214. g_return_if_fail (!window->override_redirect);
  5215. meta_window_change_workspace_without_transients (window, workspace);
  5216. meta_window_foreach_transient (window, change_workspace_foreach,
  5217. workspace);
  5218. meta_window_foreach_ancestor (window, change_workspace_foreach,
  5219. workspace);
  5220. }
  5221. static void
  5222. window_stick_impl (MetaWindow *window)
  5223. {
  5224. meta_verbose ("Sticking window %s current on_all_workspaces = %d\n",
  5225. window->desc, window->on_all_workspaces);
  5226. if (window->on_all_workspaces_requested)
  5227. return;
  5228. /* We don't change window->workspaces, because we revert
  5229. * to that original workspace list if on_all_workspaces is
  5230. * toggled back off.
  5231. */
  5232. int old_workspace = meta_workspace_index (window->workspace);
  5233. window->on_all_workspaces_requested = TRUE;
  5234. meta_window_update_on_all_workspaces (window);
  5235. meta_window_queue(window, META_QUEUE_CALC_SHOWING);
  5236. g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0,
  5237. old_workspace);
  5238. }
  5239. static void
  5240. window_unstick_impl (MetaWindow *window)
  5241. {
  5242. if (!window->on_all_workspaces_requested)
  5243. return;
  5244. /* Revert to window->workspaces */
  5245. window->on_all_workspaces_requested = FALSE;
  5246. meta_window_update_on_all_workspaces (window);
  5247. /* We change ourselves to the active workspace, since otherwise you'd get
  5248. * a weird window-vaporization effect. Once we have UI for being
  5249. * on more than one workspace this should probably be add_workspace
  5250. * not change_workspace.
  5251. */
  5252. if (window->screen->active_workspace != window->workspace)
  5253. meta_window_change_workspace (window, window->screen->active_workspace);
  5254. meta_window_queue(window, META_QUEUE_CALC_SHOWING);
  5255. g_signal_emit (window, window_signals[WORKSPACE_CHANGED], 0, -1);
  5256. }
  5257. static gboolean
  5258. stick_foreach_func (MetaWindow *window,
  5259. void *data)
  5260. {
  5261. gboolean stick;
  5262. stick = *(gboolean*)data;
  5263. if (stick)
  5264. window_stick_impl (window);
  5265. else
  5266. window_unstick_impl (window);
  5267. return TRUE;
  5268. }
  5269. void
  5270. meta_window_stick (MetaWindow *window)
  5271. {
  5272. gboolean stick = TRUE;
  5273. g_return_if_fail (!window->override_redirect);
  5274. window_stick_impl (window);
  5275. meta_window_foreach_transient (window,
  5276. stick_foreach_func,
  5277. &stick);
  5278. }
  5279. void
  5280. meta_window_unstick (MetaWindow *window)
  5281. {
  5282. gboolean stick = FALSE;
  5283. g_return_if_fail (!window->override_redirect);
  5284. window_unstick_impl (window);
  5285. meta_window_foreach_transient (window,
  5286. stick_foreach_func,
  5287. &stick);
  5288. }
  5289. LOCAL_SYMBOL unsigned long
  5290. meta_window_get_net_wm_desktop (MetaWindow *window)
  5291. {
  5292. if (window->on_all_workspaces)
  5293. return 0xFFFFFFFF;
  5294. else
  5295. return meta_workspace_index (window->workspace);
  5296. }
  5297. static void
  5298. update_net_frame_extents (MetaWindow *window)
  5299. {
  5300. unsigned long data[4];
  5301. MetaFrameBorders borders;
  5302. meta_frame_calc_borders (window->frame, &borders);
  5303. /* Left */
  5304. data[0] = borders.visible.left;
  5305. /* Right */
  5306. data[1] = borders.visible.right;
  5307. /* Top */
  5308. data[2] = borders.visible.top;
  5309. /* Bottom */
  5310. data[3] = borders.visible.bottom;
  5311. meta_topic (META_DEBUG_GEOMETRY,
  5312. "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
  5313. "to left = %lu, right = %lu, top = %lu, bottom = %lu\n",
  5314. window->xwindow, data[0], data[1], data[2], data[3]);
  5315. meta_error_trap_push (window->display);
  5316. XChangeProperty (window->display->xdisplay, window->xwindow,
  5317. window->display->atom__NET_FRAME_EXTENTS,
  5318. XA_CARDINAL,
  5319. 32, PropModeReplace, (guchar*) data, 4);
  5320. meta_error_trap_pop (window->display);
  5321. }
  5322. LOCAL_SYMBOL void
  5323. meta_window_set_current_workspace_hint (MetaWindow *window)
  5324. {
  5325. /* FIXME if on more than one workspace, we claim to be "sticky",
  5326. * the WM spec doesn't say what to do here.
  5327. */
  5328. unsigned long data[1];
  5329. if (window->workspace == NULL)
  5330. {
  5331. /* this happens when unmanaging windows */
  5332. return;
  5333. }
  5334. data[0] = meta_window_get_net_wm_desktop (window);
  5335. meta_verbose ("Setting _NET_WM_DESKTOP of %s to %lu\n",
  5336. window->desc, data[0]);
  5337. meta_error_trap_push (window->display);
  5338. XChangeProperty (window->display->xdisplay, window->xwindow,
  5339. window->display->atom__NET_WM_DESKTOP,
  5340. XA_CARDINAL,
  5341. 32, PropModeReplace, (guchar*) data, 1);
  5342. meta_error_trap_pop (window->display);
  5343. }
  5344. static gboolean
  5345. find_root_ancestor (MetaWindow *window,
  5346. void *data)
  5347. {
  5348. MetaWindow **ancestor = data;
  5349. /* Overwrite the previously "most-root" ancestor with the new one found */
  5350. *ancestor = window;
  5351. /* We want this to continue until meta_window_foreach_ancestor quits because
  5352. * there are no more valid ancestors.
  5353. */
  5354. return TRUE;
  5355. }
  5356. /**
  5357. * meta_window_find_root_ancestor:
  5358. * @window: a #MetaWindow
  5359. *
  5360. * Follow the chain of parents of @window, skipping transient windows,
  5361. * and return the "root" window which has no non-transient parent.
  5362. *
  5363. * Returns: (transfer none): The root ancestor window
  5364. */
  5365. MetaWindow *
  5366. meta_window_find_root_ancestor (MetaWindow *window)
  5367. {
  5368. MetaWindow *ancestor;
  5369. ancestor = window;
  5370. meta_window_foreach_ancestor (window, find_root_ancestor, &ancestor);
  5371. return ancestor;
  5372. }
  5373. void
  5374. meta_window_raise (MetaWindow *window)
  5375. {
  5376. MetaWindow *ancestor;
  5377. g_return_if_fail (!window->override_redirect);
  5378. ancestor = meta_window_find_root_ancestor (window);
  5379. meta_topic (META_DEBUG_WINDOW_OPS,
  5380. "Raising window %s, ancestor of %s\n",
  5381. ancestor->desc, window->desc);
  5382. /* Raise the ancestor of the window (if the window has no ancestor,
  5383. * then ancestor will be set to the window itself); do this because
  5384. * it's weird to see windows from other apps stacked between a child
  5385. * and parent window of the currently active app. The stacking
  5386. * constraints in stack.c then magically take care of raising all
  5387. * the child windows appropriately.
  5388. */
  5389. if (window->screen->stack == ancestor->screen->stack)
  5390. meta_stack_raise (window->screen->stack, ancestor);
  5391. else
  5392. {
  5393. meta_warning (
  5394. "Either stacks aren't per screen or some window has a weird "
  5395. "transient_for hint; window->screen->stack != "
  5396. "ancestor->screen->stack. window = %s, ancestor = %s.\n",
  5397. window->desc, ancestor->desc);
  5398. /* We could raise the window here, but don't want to do that twice and
  5399. * so we let the case below handle that.
  5400. */
  5401. }
  5402. /* Okay, so stacking constraints misses one case: If a window has
  5403. * two children and we want to raise one of those children, then
  5404. * raising the ancestor isn't enough; we need to also raise the
  5405. * correct child. See bug 307875.
  5406. */
  5407. if (window != ancestor)
  5408. meta_stack_raise (window->screen->stack, window);
  5409. g_signal_emit (window, window_signals[RAISED], 0);
  5410. }
  5411. void
  5412. meta_window_lower (MetaWindow *window)
  5413. {
  5414. g_return_if_fail (!window->override_redirect);
  5415. meta_topic (META_DEBUG_WINDOW_OPS,
  5416. "Lowering window %s\n", window->desc);
  5417. meta_stack_lower (window->screen->stack, window);
  5418. }
  5419. LOCAL_SYMBOL void
  5420. meta_window_send_icccm_message (MetaWindow *window,
  5421. Atom atom,
  5422. guint32 timestamp)
  5423. {
  5424. /* This comment and code are from twm, copyright
  5425. * Open Group, Evans & Sutherland, etc.
  5426. */
  5427. /*
  5428. * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
  5429. * client messages will have the following form:
  5430. *
  5431. * event type ClientMessage
  5432. * message type _XA_WM_PROTOCOLS
  5433. * window tmp->w
  5434. * format 32
  5435. * data[0] message atom
  5436. * data[1] time stamp
  5437. */
  5438. XClientMessageEvent ev;
  5439. ev.type = ClientMessage;
  5440. ev.window = window->xwindow;
  5441. ev.message_type = window->display->atom_WM_PROTOCOLS;
  5442. ev.format = 32;
  5443. ev.data.l[0] = atom;
  5444. ev.data.l[1] = timestamp;
  5445. meta_error_trap_push (window->display);
  5446. XSendEvent (window->display->xdisplay,
  5447. window->xwindow, False, 0, (XEvent*) &ev);
  5448. meta_error_trap_pop (window->display);
  5449. }
  5450. LOCAL_SYMBOL void
  5451. meta_window_move_resize_request (MetaWindow *window,
  5452. guint value_mask,
  5453. int gravity,
  5454. int new_x,
  5455. int new_y,
  5456. int new_width,
  5457. int new_height)
  5458. {
  5459. int x, y, width, height;
  5460. gboolean allow_position_change;
  5461. gboolean in_grab_op;
  5462. MetaMoveResizeFlags flags;
  5463. /* We ignore configure requests while the user is moving/resizing
  5464. * the window, since these represent the app sucking and fighting
  5465. * the user, most likely due to a bug in the app (e.g. pfaedit
  5466. * seemed to do this)
  5467. *
  5468. * Still have to do the ConfigureNotify and all, but pretend the
  5469. * app asked for the current size/position instead of the new one.
  5470. */
  5471. in_grab_op = FALSE;
  5472. if (window->display->grab_op != META_GRAB_OP_NONE &&
  5473. window == window->display->grab_window)
  5474. {
  5475. switch (window->display->grab_op)
  5476. {
  5477. case META_GRAB_OP_MOVING:
  5478. case META_GRAB_OP_RESIZING_SE:
  5479. case META_GRAB_OP_RESIZING_S:
  5480. case META_GRAB_OP_RESIZING_SW:
  5481. case META_GRAB_OP_RESIZING_N:
  5482. case META_GRAB_OP_RESIZING_NE:
  5483. case META_G