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.
 
 
 
 

1794 lines
50 KiB

  1. /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2. /**
  3. * SECTION:stack
  4. * @short_description: Which windows cover which other windows
  5. */
  6. /*
  7. * Copyright (C) 2001 Havoc Pennington
  8. * Copyright (C) 2002, 2003 Red Hat, Inc.
  9. * Copyright (C) 2004 Rob Adams
  10. * Copyright (C) 2004, 2005 Elijah Newren
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License as
  14. * published by the Free Software Foundation; either version 2 of the
  15. * License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
  25. * 02110-1335, USA.
  26. */
  27. #include <config.h>
  28. #include "stack.h"
  29. #include "window-private.h"
  30. #include <meta/errors.h>
  31. #include "frame.h"
  32. #include <meta/group.h>
  33. #include <meta/prefs.h>
  34. #include <meta/workspace.h>
  35. #include <X11/Xatom.h>
  36. #define WINDOW_HAS_TRANSIENT_TYPE(w) \
  37. (w->type == META_WINDOW_DIALOG || \
  38. w->type == META_WINDOW_MODAL_DIALOG || \
  39. w->type == META_WINDOW_TOOLBAR || \
  40. w->type == META_WINDOW_MENU || \
  41. w->type == META_WINDOW_UTILITY)
  42. #define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \
  43. ((w->xtransient_for == None || \
  44. w->transient_parent_is_root_window) && \
  45. WINDOW_HAS_TRANSIENT_TYPE (w))
  46. #define WINDOW_IN_STACK(w) (w->stack_position >= 0)
  47. static void stack_sync_to_server (MetaStack *stack);
  48. static void meta_window_set_stack_position_no_sync (MetaWindow *window,
  49. int position);
  50. static void stack_do_window_deletions (MetaStack *stack);
  51. static void stack_do_window_additions (MetaStack *stack);
  52. static void stack_do_relayer (MetaStack *stack);
  53. static void stack_do_constrain (MetaStack *stack);
  54. static void stack_do_resort (MetaStack *stack);
  55. static void stack_ensure_sorted (MetaStack *stack);
  56. LOCAL_SYMBOL MetaStack*
  57. meta_stack_new (MetaScreen *screen)
  58. {
  59. MetaStack *stack;
  60. stack = g_new (MetaStack, 1);
  61. stack->screen = screen;
  62. stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
  63. stack->sorted = NULL;
  64. stack->added = NULL;
  65. stack->removed = NULL;
  66. stack->freeze_count = 0;
  67. stack->last_root_children_stacked = NULL;
  68. stack->n_positions = 0;
  69. stack->need_resort = FALSE;
  70. stack->need_relayer = FALSE;
  71. stack->need_constrain = FALSE;
  72. return stack;
  73. }
  74. LOCAL_SYMBOL void
  75. meta_stack_free (MetaStack *stack)
  76. {
  77. g_array_free (stack->windows, TRUE);
  78. g_list_free (stack->sorted);
  79. g_list_free (stack->added);
  80. g_list_free (stack->removed);
  81. if (stack->last_root_children_stacked)
  82. g_array_free (stack->last_root_children_stacked, TRUE);
  83. g_free (stack);
  84. }
  85. LOCAL_SYMBOL void
  86. meta_stack_add (MetaStack *stack,
  87. MetaWindow *window)
  88. {
  89. meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc);
  90. if (window->stack_position >= 0)
  91. meta_bug ("Window %s had stack position already\n", window->desc);
  92. stack->added = g_list_prepend (stack->added, window);
  93. window->stack_position = stack->n_positions;
  94. stack->n_positions += 1;
  95. meta_topic (META_DEBUG_STACK,
  96. "Window %s has stack_position initialized to %d\n",
  97. window->desc, window->stack_position);
  98. stack_sync_to_server (stack);
  99. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  100. }
  101. LOCAL_SYMBOL void
  102. meta_stack_remove (MetaStack *stack,
  103. MetaWindow *window)
  104. {
  105. meta_topic (META_DEBUG_STACK, "Removing window %s from the stack\n", window->desc);
  106. if (window->stack_position < 0)
  107. meta_bug ("Window %s removed from stack but had no stack position\n",
  108. window->desc);
  109. /* Set window to top position, so removing it will not leave gaps
  110. * in the set of positions
  111. */
  112. meta_window_set_stack_position_no_sync (window,
  113. stack->n_positions - 1);
  114. window->stack_position = -1;
  115. stack->n_positions -= 1;
  116. /* We don't know if it's been moved from "added" to "stack" yet */
  117. stack->added = g_list_remove (stack->added, window);
  118. stack->sorted = g_list_remove (stack->sorted, window);
  119. /* Remember the window ID to remove it from the stack array.
  120. * The macro is safe to use: Window is guaranteed to be 32 bits, and
  121. * GUINT_TO_POINTER says it only works on 32 bits.
  122. */
  123. stack->removed = g_list_prepend (stack->removed,
  124. GUINT_TO_POINTER (window->xwindow));
  125. if (window->frame)
  126. stack->removed = g_list_prepend (stack->removed,
  127. GUINT_TO_POINTER (window->frame->xwindow));
  128. stack_sync_to_server (stack);
  129. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  130. }
  131. LOCAL_SYMBOL void
  132. meta_stack_update_layer (MetaStack *stack,
  133. MetaWindow *window)
  134. {
  135. stack->need_relayer = TRUE;
  136. stack_sync_to_server (stack);
  137. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  138. }
  139. LOCAL_SYMBOL void
  140. meta_stack_update_transient (MetaStack *stack,
  141. MetaWindow *window)
  142. {
  143. stack->need_constrain = TRUE;
  144. stack_sync_to_server (stack);
  145. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  146. }
  147. /* raise/lower within a layer */
  148. LOCAL_SYMBOL void
  149. meta_stack_raise (MetaStack *stack,
  150. MetaWindow *window)
  151. {
  152. GList *l;
  153. int max_stack_position = window->stack_position;
  154. MetaWorkspace *workspace;
  155. stack_ensure_sorted (stack);
  156. workspace = meta_window_get_workspace (window);
  157. for (l = stack->sorted; l; l = l->next)
  158. {
  159. MetaWindow *w = (MetaWindow *) l->data;
  160. if (meta_window_located_on_workspace (w, workspace) &&
  161. w->stack_position > max_stack_position)
  162. max_stack_position = w->stack_position;
  163. }
  164. if (max_stack_position == window->stack_position)
  165. return;
  166. meta_window_set_stack_position_no_sync (window, max_stack_position);
  167. stack_sync_to_server (stack);
  168. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  169. }
  170. LOCAL_SYMBOL void
  171. meta_stack_lower (MetaStack *stack,
  172. MetaWindow *window)
  173. {
  174. GList *l;
  175. int min_stack_position = window->stack_position;
  176. MetaWorkspace *workspace;
  177. stack_ensure_sorted (stack);
  178. workspace = meta_window_get_workspace (window);
  179. for (l = stack->sorted; l; l = l->next)
  180. {
  181. MetaWindow *w = (MetaWindow *) l->data;
  182. if (meta_window_located_on_workspace (w, workspace) &&
  183. w->stack_position < min_stack_position)
  184. min_stack_position = w->stack_position;
  185. }
  186. if (min_stack_position == window->stack_position)
  187. return;
  188. meta_window_set_stack_position_no_sync (window, min_stack_position);
  189. stack_sync_to_server (stack);
  190. meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
  191. }
  192. LOCAL_SYMBOL void
  193. meta_stack_freeze (MetaStack *stack)
  194. {
  195. stack->freeze_count += 1;
  196. }
  197. LOCAL_SYMBOL void
  198. meta_stack_thaw (MetaStack *stack)
  199. {
  200. g_return_if_fail (stack->freeze_count > 0);
  201. stack->freeze_count -= 1;
  202. stack_sync_to_server (stack);
  203. meta_stack_update_window_tile_matches (stack, NULL);
  204. }
  205. LOCAL_SYMBOL void
  206. meta_stack_update_window_tile_matches (MetaStack *stack,
  207. MetaWorkspace *workspace)
  208. {
  209. GList *windows, *tmp;
  210. if (stack->freeze_count > 0)
  211. return;
  212. windows = meta_stack_list_windows (stack, workspace);
  213. tmp = windows;
  214. while (tmp)
  215. {
  216. meta_window_compute_tile_match ((MetaWindow *) tmp->data);
  217. tmp = tmp->next;
  218. }
  219. g_list_free (windows);
  220. }
  221. static gboolean
  222. is_focused_foreach (MetaWindow *window,
  223. void *data)
  224. {
  225. if (window == window->display->expected_focus_window)
  226. {
  227. *((gboolean*) data) = TRUE;
  228. return FALSE;
  229. }
  230. return TRUE;
  231. }
  232. static gboolean
  233. windows_on_different_monitor (MetaWindow *a,
  234. MetaWindow *b)
  235. {
  236. if (a->screen != b->screen)
  237. return TRUE;
  238. return meta_screen_get_monitor_for_window (a->screen, a) !=
  239. meta_screen_get_monitor_for_window (b->screen, b);
  240. }
  241. /* Get layer ignoring any transient or group relationships */
  242. static MetaStackLayer
  243. get_standalone_layer (MetaWindow *window)
  244. {
  245. MetaStackLayer layer;
  246. gboolean focused_transient = FALSE;
  247. switch (window->type)
  248. {
  249. case META_WINDOW_DESKTOP:
  250. layer = META_LAYER_DESKTOP;
  251. break;
  252. case META_WINDOW_DOCK:
  253. /* still experimenting here */
  254. if (window->wm_state_below)
  255. layer = META_LAYER_BOTTOM;
  256. else
  257. layer = META_LAYER_DOCK;
  258. break;
  259. case META_WINDOW_DROPDOWN_MENU:
  260. case META_WINDOW_POPUP_MENU:
  261. case META_WINDOW_TOOLTIP:
  262. case META_WINDOW_NOTIFICATION:
  263. case META_WINDOW_COMBO:
  264. case META_WINDOW_OVERRIDE_OTHER:
  265. layer = META_LAYER_OVERRIDE_REDIRECT;
  266. break;
  267. default:
  268. meta_window_foreach_transient (window,
  269. is_focused_foreach,
  270. &focused_transient);
  271. if (window->wm_state_below)
  272. layer = META_LAYER_BOTTOM;
  273. else if (window->fullscreen &&
  274. (focused_transient ||
  275. window == window->display->expected_focus_window ||
  276. window->display->expected_focus_window == NULL ||
  277. (window->display->expected_focus_window != NULL &&
  278. windows_on_different_monitor (window,
  279. window->display->expected_focus_window))))
  280. layer = META_LAYER_FULLSCREEN;
  281. else if (window->wm_state_above)
  282. layer = META_LAYER_TOP;
  283. else
  284. layer = META_LAYER_NORMAL;
  285. break;
  286. }
  287. return layer;
  288. }
  289. /* Note that this function can never use window->layer only
  290. * get_standalone_layer, or we'd have issues.
  291. */
  292. static MetaStackLayer
  293. get_maximum_layer_in_group (MetaWindow *window)
  294. {
  295. GSList *members;
  296. MetaGroup *group;
  297. GSList *tmp;
  298. MetaStackLayer max;
  299. MetaStackLayer layer;
  300. max = META_LAYER_DESKTOP;
  301. group = meta_window_get_group (window);
  302. if (group != NULL)
  303. members = meta_group_list_windows (group);
  304. else
  305. members = NULL;
  306. tmp = members;
  307. while (tmp != NULL)
  308. {
  309. MetaWindow *w = tmp->data;
  310. if (!w->override_redirect)
  311. {
  312. layer = get_standalone_layer (w);
  313. if (layer > max)
  314. max = layer;
  315. }
  316. tmp = tmp->next;
  317. }
  318. g_slist_free (members);
  319. return max;
  320. }
  321. static void
  322. compute_layer (MetaWindow *window)
  323. {
  324. MetaStackLayer old_layer = window->layer;
  325. window->layer = get_standalone_layer (window);
  326. /* We can only do promotion-due-to-group for dialogs and other
  327. * transients, or weird stuff happens like the desktop window and
  328. * nautilus windows getting in the same layer, or all gnome-terminal
  329. * windows getting in fullscreen layer if any terminal is
  330. * fullscreen.
  331. */
  332. if (window->layer != META_LAYER_DESKTOP &&
  333. WINDOW_HAS_TRANSIENT_TYPE(window) &&
  334. (window->xtransient_for == None ||
  335. window->transient_parent_is_root_window))
  336. {
  337. /* We only do the group thing if the dialog is NOT transient for
  338. * a particular window. Imagine a group with a normal window, a dock,
  339. * and a dialog transient for the normal window; you don't want the dialog
  340. * above the dock if it wouldn't normally be.
  341. */
  342. MetaStackLayer group_max;
  343. group_max = get_maximum_layer_in_group (window);
  344. if (group_max > window->layer)
  345. {
  346. meta_topic (META_DEBUG_STACK,
  347. "Promoting window %s from layer %u to %u due to group membership\n",
  348. window->desc, window->layer, group_max);
  349. window->layer = group_max;
  350. }
  351. }
  352. meta_topic (META_DEBUG_STACK, "Window %s on layer %u type = %u has_focus = %d\n",
  353. window->desc, window->layer,
  354. window->type, window->has_focus);
  355. if (window->layer != old_layer &&
  356. (old_layer == META_LAYER_FULLSCREEN || window->layer == META_LAYER_FULLSCREEN))
  357. meta_screen_queue_check_fullscreen (window->screen);
  358. }
  359. /* Front of the layer list is the topmost window,
  360. * so the lower stack position is later in the list
  361. */
  362. static int
  363. compare_window_position (void *a,
  364. void *b)
  365. {
  366. MetaWindow *window_a = a;
  367. MetaWindow *window_b = b;
  368. /* Go by layer, then stack_position */
  369. if (window_a->layer < window_b->layer)
  370. return 1; /* move window_a later in list */
  371. else if (window_a->layer > window_b->layer)
  372. return -1;
  373. else if (window_a->stack_position < window_b->stack_position)
  374. return 1; /* move window_a later in list */
  375. else if (window_a->stack_position > window_b->stack_position)
  376. return -1;
  377. else
  378. return 0; /* not reached */
  379. }
  380. /*
  381. * Stacking constraints
  382. *
  383. * Assume constraints of the form "AB" meaning "window A must be
  384. * below window B"
  385. *
  386. * If we have windows stacked from bottom to top
  387. * "ABC" then raise A we get "BCA". Say C is
  388. * transient for B is transient for A. So
  389. * we have constraints AB and BC.
  390. *
  391. * After raising A, we need to reapply the constraints.
  392. * If we do this by raising one window at a time -
  393. *
  394. * start: BCA
  395. * apply AB: CAB
  396. * apply BC: ABC
  397. *
  398. * but apply constraints in the wrong order and it breaks:
  399. *
  400. * start: BCA
  401. * apply BC: BCA
  402. * apply AB: CAB
  403. *
  404. * We make a directed graph of the constraints by linking
  405. * from "above windows" to "below windows as follows:
  406. *
  407. * AB -> BC -> CD
  408. * \
  409. * CE
  410. *
  411. * If we then walk that graph and apply the constraints in the order
  412. * that they appear, we will apply them correctly. Note that the
  413. * graph MAY have cycles, so we have to guard against that.
  414. *
  415. */
  416. typedef struct Constraint Constraint;
  417. struct Constraint
  418. {
  419. MetaWindow *above;
  420. MetaWindow *below;
  421. /* used to keep the constraint in the
  422. * list of constraints for window "below"
  423. */
  424. Constraint *next;
  425. /* used to create the graph. */
  426. GSList *next_nodes;
  427. /* constraint has been applied, used
  428. * to detect cycles.
  429. */
  430. unsigned int applied : 1;
  431. /* constraint has a previous node in the graph,
  432. * used to find places to start in the graph.
  433. * (I think this also has the side effect
  434. * of preventing cycles, since cycles will
  435. * have no starting point - so maybe
  436. * the "applied" flag isn't needed.)
  437. */
  438. unsigned int has_prev : 1;
  439. };
  440. /* We index the array of constraints by window
  441. * stack positions, just because the stack
  442. * positions are a convenient index.
  443. */
  444. static void
  445. add_constraint (Constraint **constraints,
  446. MetaWindow *above,
  447. MetaWindow *below)
  448. {
  449. Constraint *c;
  450. g_assert (above->screen == below->screen);
  451. /* check if constraint is a duplicate */
  452. c = constraints[below->stack_position];
  453. while (c != NULL)
  454. {
  455. if (c->above == above)
  456. return;
  457. c = c->next;
  458. }
  459. /* if not, add the constraint */
  460. c = g_new (Constraint, 1);
  461. c->above = above;
  462. c->below = below;
  463. c->next = constraints[below->stack_position];
  464. c->next_nodes = NULL;
  465. c->applied = FALSE;
  466. c->has_prev = FALSE;
  467. constraints[below->stack_position] = c;
  468. }
  469. static void
  470. create_constraints (Constraint **constraints,
  471. GList *windows)
  472. {
  473. GList *tmp;
  474. tmp = windows;
  475. while (tmp != NULL)
  476. {
  477. MetaWindow *w = tmp->data;
  478. if (!WINDOW_IN_STACK (w))
  479. {
  480. meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n",
  481. w->desc);
  482. tmp = tmp->next;
  483. continue;
  484. }
  485. if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w))
  486. {
  487. GSList *group_windows;
  488. GSList *tmp2;
  489. MetaGroup *group;
  490. group = meta_window_get_group (w);
  491. if (group != NULL)
  492. group_windows = meta_group_list_windows (group);
  493. else
  494. group_windows = NULL;
  495. tmp2 = group_windows;
  496. while (tmp2 != NULL)
  497. {
  498. MetaWindow *group_window = tmp2->data;
  499. if (!WINDOW_IN_STACK (group_window) ||
  500. w->screen != group_window->screen ||
  501. group_window->override_redirect)
  502. {
  503. tmp2 = tmp2->next;
  504. continue;
  505. }
  506. #if 0
  507. /* old way of doing it */
  508. if (!(meta_window_is_ancestor_of_transient (w, group_window)) &&
  509. !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window)) /* note */;/*note*/
  510. #else
  511. /* better way I think, so transient-for-group are constrained
  512. * only above non-transient-type windows in their group
  513. */
  514. if (!WINDOW_HAS_TRANSIENT_TYPE (group_window))
  515. #endif
  516. {
  517. meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n",
  518. w->desc, group_window->desc);
  519. add_constraint (constraints, w, group_window);
  520. }
  521. tmp2 = tmp2->next;
  522. }
  523. g_slist_free (group_windows);
  524. }
  525. else if (w->xtransient_for != None &&
  526. !w->transient_parent_is_root_window)
  527. {
  528. MetaWindow *parent;
  529. parent =
  530. meta_display_lookup_x_window (w->display, w->xtransient_for);
  531. if (parent && WINDOW_IN_STACK (parent) &&
  532. parent->screen == w->screen)
  533. {
  534. meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n",
  535. w->desc, parent->desc);
  536. add_constraint (constraints, w, parent);
  537. }
  538. }
  539. tmp = tmp->next;
  540. }
  541. }
  542. static void
  543. graph_constraints (Constraint **constraints,
  544. int n_constraints)
  545. {
  546. int i;
  547. i = 0;
  548. while (i < n_constraints)
  549. {
  550. Constraint *c;
  551. /* If we have "A below B" and "B below C" then AB -> BC so we
  552. * add BC to next_nodes in AB.
  553. */
  554. c = constraints[i];
  555. while (c != NULL)
  556. {
  557. Constraint *n;
  558. g_assert (c->below->stack_position == i);
  559. /* Constraints where ->above is below are our
  560. * next_nodes and we are their previous
  561. */
  562. n = constraints[c->above->stack_position];
  563. while (n != NULL)
  564. {
  565. c->next_nodes = g_slist_prepend (c->next_nodes,
  566. n);
  567. /* c is a previous node of n */
  568. n->has_prev = TRUE;
  569. n = n->next;
  570. }
  571. c = c->next;
  572. }
  573. ++i;
  574. }
  575. }
  576. static void
  577. free_constraints (Constraint **constraints,
  578. int n_constraints)
  579. {
  580. int i;
  581. i = 0;
  582. while (i < n_constraints)
  583. {
  584. Constraint *c;
  585. c = constraints[i];
  586. while (c != NULL)
  587. {
  588. Constraint *next = c->next;
  589. g_slist_free (c->next_nodes);
  590. g_free (c);
  591. c = next;
  592. }
  593. ++i;
  594. }
  595. }
  596. static void
  597. ensure_above (MetaWindow *above,
  598. MetaWindow *below)
  599. {
  600. if (WINDOW_HAS_TRANSIENT_TYPE(above) &&
  601. above->layer < below->layer)
  602. {
  603. meta_topic (META_DEBUG_STACK,
  604. "Promoting window %s from layer %u to %u due to contraint\n",
  605. above->desc, above->layer, below->layer);
  606. above->layer = below->layer;
  607. }
  608. if (above->stack_position < below->stack_position)
  609. {
  610. /* move above to below->stack_position bumping below down the stack */
  611. meta_window_set_stack_position_no_sync (above, below->stack_position);
  612. g_assert (below->stack_position + 1 == above->stack_position);
  613. }
  614. meta_topic (META_DEBUG_STACK, "%s above at %d > %s below at %d\n",
  615. above->desc, above->stack_position,
  616. below->desc, below->stack_position);
  617. }
  618. static void
  619. traverse_constraint (Constraint *c)
  620. {
  621. GSList *tmp;
  622. if (c->applied)
  623. return;
  624. ensure_above (c->above, c->below);
  625. c->applied = TRUE;
  626. tmp = c->next_nodes;
  627. while (tmp != NULL)
  628. {
  629. traverse_constraint (tmp->data);
  630. tmp = tmp->next;
  631. }
  632. }
  633. static void
  634. apply_constraints (Constraint **constraints,
  635. int n_constraints)
  636. {
  637. GSList *heads;
  638. GSList *tmp;
  639. int i;
  640. /* List all heads in an ordered constraint chain */
  641. heads = NULL;
  642. i = 0;
  643. while (i < n_constraints)
  644. {
  645. Constraint *c;
  646. c = constraints[i];
  647. while (c != NULL)
  648. {
  649. if (!c->has_prev)
  650. heads = g_slist_prepend (heads, c);
  651. c = c->next;
  652. }
  653. ++i;
  654. }
  655. /* Now traverse the chain and apply constraints */
  656. tmp = heads;
  657. while (tmp != NULL)
  658. {
  659. Constraint *c = tmp->data;
  660. traverse_constraint (c);
  661. tmp = tmp->next;
  662. }
  663. g_slist_free (heads);
  664. }
  665. /*
  666. * Go through "deleted" and take the matching windows
  667. * out of "windows".
  668. */
  669. static void
  670. stack_do_window_deletions (MetaStack *stack)
  671. {
  672. /* Do removals before adds, with paranoid idea that we might re-add
  673. * the same window IDs.
  674. */
  675. GList *tmp;
  676. int i;
  677. tmp = stack->removed;
  678. while (tmp != NULL)
  679. {
  680. Window xwindow;
  681. xwindow = GPOINTER_TO_UINT (tmp->data);
  682. /* We go from the end figuring removals are more
  683. * likely to be recent.
  684. */
  685. i = stack->windows->len;
  686. while (i > 0)
  687. {
  688. --i;
  689. /* there's no guarantee we'll actually find windows to
  690. * remove, e.g. the same xwindow could have been
  691. * added/removed before we ever synced, and we put
  692. * both the window->xwindow and window->frame->xwindow
  693. * in the removal list.
  694. */
  695. if (xwindow == g_array_index (stack->windows, Window, i))
  696. {
  697. g_array_remove_index (stack->windows, i);
  698. goto next;
  699. }
  700. }
  701. next:
  702. tmp = tmp->next;
  703. }
  704. g_list_free (stack->removed);
  705. stack->removed = NULL;
  706. }
  707. static void
  708. stack_do_window_additions (MetaStack *stack)
  709. {
  710. GList *tmp;
  711. gint i, n_added;
  712. n_added = g_list_length (stack->added);
  713. if (n_added > 0)
  714. {
  715. Window *end;
  716. int old_size;
  717. meta_topic (META_DEBUG_STACK,
  718. "Adding %d windows to sorted list\n",
  719. n_added);
  720. old_size = stack->windows->len;
  721. g_array_set_size (stack->windows, old_size + n_added);
  722. end = &g_array_index (stack->windows, Window, old_size);
  723. /* stack->added has the most recent additions at the
  724. * front of the list, so we need to reverse it
  725. */
  726. stack->added = g_list_reverse (stack->added);
  727. i = 0;
  728. tmp = stack->added;
  729. while (tmp != NULL)
  730. {
  731. MetaWindow *w;
  732. w = tmp->data;
  733. end[i] = w->xwindow;
  734. /* add to the main list */
  735. stack->sorted = g_list_prepend (stack->sorted, w);
  736. ++i;
  737. tmp = tmp->next;
  738. }
  739. stack->need_resort = TRUE; /* may not be needed as we add to top */
  740. stack->need_constrain = TRUE;
  741. stack->need_relayer = TRUE;
  742. }
  743. g_list_free (stack->added);
  744. stack->added = NULL;
  745. }
  746. /*
  747. * Update the layers that windows are in
  748. */
  749. static void
  750. stack_do_relayer (MetaStack *stack)
  751. {
  752. GList *tmp;
  753. if (!stack->need_relayer)
  754. return;
  755. meta_topic (META_DEBUG_STACK,
  756. "Recomputing layers\n");
  757. tmp = stack->sorted;
  758. while (tmp != NULL)
  759. {
  760. MetaWindow *w;
  761. MetaStackLayer old_layer;
  762. w = tmp->data;
  763. old_layer = w->layer;
  764. compute_layer (w);
  765. if (w->layer != old_layer)
  766. {
  767. meta_topic (META_DEBUG_STACK,
  768. "Window %s moved from layer %u to %u\n",
  769. w->desc, old_layer, w->layer);
  770. stack->need_resort = TRUE;
  771. stack->need_constrain = TRUE;
  772. /* don't need to constrain as constraining
  773. * purely operates in terms of stack_position
  774. * not layer
  775. */
  776. }
  777. tmp = tmp->next;
  778. }
  779. stack->need_relayer = FALSE;
  780. }
  781. /*
  782. * Update stack_position and layer to reflect transiency
  783. * constraints
  784. */
  785. static void
  786. stack_do_constrain (MetaStack *stack)
  787. {
  788. Constraint **constraints;
  789. /* It'd be nice if this were all faster, probably */
  790. if (!stack->need_constrain)
  791. return;
  792. meta_topic (META_DEBUG_STACK,
  793. "Reapplying constraints\n");
  794. constraints = g_new0 (Constraint*,
  795. stack->n_positions);
  796. create_constraints (constraints, stack->sorted);
  797. graph_constraints (constraints, stack->n_positions);
  798. apply_constraints (constraints, stack->n_positions);
  799. free_constraints (constraints, stack->n_positions);
  800. g_free (constraints);
  801. stack->need_constrain = FALSE;
  802. }
  803. /*
  804. * Sort stack->sorted with layers having priority over stack_position.
  805. */
  806. static void
  807. stack_do_resort (MetaStack *stack)
  808. {
  809. if (!stack->need_resort)
  810. return;
  811. meta_topic (META_DEBUG_STACK,
  812. "Sorting stack list\n");
  813. stack->sorted = g_list_sort (stack->sorted,
  814. (GCompareFunc) compare_window_position);
  815. stack->need_resort = FALSE;
  816. }
  817. /*
  818. * Puts the stack into canonical form.
  819. *
  820. * Honour the removed and added lists of the stack, and then recalculate
  821. * all the layers (if the flag is set), re-run all the constraint calculations
  822. * (if the flag is set), and finally re-sort the stack (if the flag is set,
  823. * and if it wasn't already it might have become so during all the previous
  824. * activity).
  825. */
  826. static void
  827. stack_ensure_sorted (MetaStack *stack)
  828. {
  829. stack_do_window_deletions (stack);
  830. stack_do_window_additions (stack);
  831. stack_do_relayer (stack);
  832. stack_do_constrain (stack);
  833. stack_do_resort (stack);
  834. }
  835. /*
  836. * This function is used to avoid raising a window above popup
  837. * menus and other such things.
  838. *
  839. * The key to the operation of this function is that we are expecting
  840. * at most one window to be added at a time. If xwindow is newly added,
  841. * then its own stack position will be too high (the frame window
  842. * is created at the top of the stack), but if we ignore xwindow,
  843. * then the *next* managed window in the stack will be a window that
  844. * we've already stacked.
  845. *
  846. * We could generalize this and remove the assumption that windows
  847. * are added one at a time by keeping an explicit ->stacked flag in
  848. * MetaWindow.
  849. *
  850. * An alternate approach would be to reverse the stacking algorithm to
  851. * work by placing each window above the others, and start by lowering
  852. * a window to the bottom (instead of the current way, which works by
  853. * placing each window below another and starting with a raise)
  854. */
  855. static void
  856. raise_window_relative_to_managed_windows (MetaScreen *screen,
  857. Window xwindow)
  858. {
  859. Window *children;
  860. int n_children;
  861. int i;
  862. meta_stack_tracker_get_stack (screen->stack_tracker,
  863. &children, &n_children);
  864. /* Children are in order from bottom to top. We want to
  865. * find the topmost managed child, then configure
  866. * our window to be above it.
  867. */
  868. i = n_children - 1;
  869. while (i >= 0)
  870. {
  871. if (children[i] == xwindow)
  872. {
  873. /* Do nothing. This means we're already the topmost managed
  874. * window, but it DOES NOT mean we are already just above
  875. * the topmost managed window. This is important because if
  876. * an override redirect window is up, and we map a new
  877. * managed window, the new window is probably above the old
  878. * popup by default, and we want to push it below that
  879. * popup. So keep looking for a sibling managed window
  880. * to be moved below.
  881. */
  882. }
  883. else
  884. {
  885. MetaWindow *other = meta_display_lookup_x_window (screen->display,
  886. children[i]);
  887. if (other != NULL && !other->override_redirect)
  888. {
  889. XWindowChanges changes;
  890. /* children[i] is the topmost managed child */
  891. meta_topic (META_DEBUG_STACK,
  892. "Moving 0x%lx above topmost managed child window 0x%lx\n",
  893. xwindow, children[i]);
  894. changes.sibling = children[i];
  895. changes.stack_mode = Above;
  896. meta_error_trap_push (screen->display);
  897. meta_stack_tracker_record_raise_above (screen->stack_tracker,
  898. xwindow,
  899. children[i],
  900. XNextRequest (screen->display->xdisplay));
  901. XConfigureWindow (screen->display->xdisplay,
  902. xwindow,
  903. CWSibling | CWStackMode,
  904. &changes);
  905. meta_error_trap_pop (screen->display);
  906. break;
  907. }
  908. }
  909. --i;
  910. }
  911. if (i < 0)
  912. {
  913. /* No sibling to use, just lower ourselves to the bottom
  914. * to be sure we're below any override redirect windows.
  915. */
  916. meta_error_trap_push (screen->display);
  917. meta_stack_tracker_record_lower (screen->stack_tracker,
  918. xwindow,
  919. XNextRequest (screen->display->xdisplay));
  920. XLowerWindow (screen->display->xdisplay,
  921. xwindow);
  922. meta_error_trap_pop (screen->display);
  923. }
  924. }
  925. /*
  926. * Order the windows on the X server to be the same as in our structure.
  927. * We do this using XRestackWindows if we don't know the previous order,
  928. * or XConfigureWindow on a few particular windows if we do and can figure
  929. * out the minimum set of changes. After that, we set __NET_CLIENT_LIST
  930. * and __NET_CLIENT_LIST_STACKING.
  931. *
  932. * FIXME: Now that we have a good view of the stacking order on the server
  933. * with MetaStackTracker it should be possible to do a simpler and better
  934. * job of computing the minimal set of stacking requests needed.
  935. */
  936. static void
  937. stack_sync_to_server (MetaStack *stack)
  938. {
  939. GArray *stacked;
  940. GArray *root_children_stacked;
  941. GList *tmp;
  942. GArray *all_hidden;
  943. int n_override_redirect = 0;
  944. /* Bail out if frozen */
  945. if (stack->freeze_count > 0)
  946. return;
  947. meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
  948. stack_ensure_sorted (stack);
  949. /* Create stacked xwindow arrays.
  950. * Painfully, "stacked" is in bottom-to-top order for the
  951. * _NET hints, and "root_children_stacked" is in top-to-bottom
  952. * order for XRestackWindows()
  953. */
  954. stacked = g_array_new (FALSE, FALSE, sizeof (Window));
  955. root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
  956. all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
  957. /* The screen guard window sits above all hidden windows and acts as
  958. * a barrier to input reaching these windows. */
  959. g_array_append_val (all_hidden, stack->screen->guard_window);
  960. meta_topic (META_DEBUG_STACK, "Top to bottom: ");
  961. meta_push_no_msg_prefix ();
  962. for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next)
  963. {
  964. MetaWindow *w = tmp->data;
  965. Window top_level_window;
  966. meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
  967. w->layer, w->stack_position, w->desc);
  968. /* remember, stacked is in reverse order (bottom to top) */
  969. if (w->override_redirect)
  970. n_override_redirect++;
  971. else
  972. g_array_prepend_val (stacked, w->xwindow);
  973. if (w->frame)
  974. top_level_window = w->frame->xwindow;
  975. else
  976. top_level_window = w->xwindow;
  977. /* We don't restack hidden windows along with the rest, though they are
  978. * reflected in the _NET hints. Hidden windows all get pushed below
  979. * the screens fullscreen guard_window. */
  980. if (w->hidden)
  981. {
  982. g_array_append_val (all_hidden, top_level_window);
  983. continue;
  984. }
  985. /* build XRestackWindows() array from top to bottom */
  986. g_array_append_val (root_children_stacked, top_level_window);
  987. }
  988. meta_topic (META_DEBUG_STACK, "\n");
  989. meta_pop_no_msg_prefix ();
  990. /* All windows should be in some stacking order */
  991. if (stacked->len != stack->windows->len - n_override_redirect)
  992. meta_bug ("%u windows stacked, %u windows exist in stack\n",
  993. stacked->len, stack->windows->len);
  994. /* Sync to server */
  995. meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
  996. root_children_stacked->len);
  997. meta_error_trap_push (stack->screen->display);
  998. if (stack->last_root_children_stacked == NULL)
  999. {
  1000. /* Just impose our stack, we don't know the previous state.
  1001. * This involves a ton of circulate requests and may flicker.
  1002. */
  1003. meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
  1004. if (root_children_stacked->len > 0)
  1005. {
  1006. meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
  1007. (Window *) root_children_stacked->data,
  1008. root_children_stacked->len,
  1009. XNextRequest (stack->screen->display->xdisplay));
  1010. XRestackWindows (stack->screen->display->xdisplay,
  1011. (Window *) root_children_stacked->data,
  1012. root_children_stacked->len);
  1013. }
  1014. }
  1015. else if (root_children_stacked->len > 0)
  1016. {
  1017. /* Try to do minimal window moves to get the stack in order */
  1018. /* A point of note: these arrays include frames not client windows,
  1019. * so if a client window has changed frame since last_root_children_stacked
  1020. * was saved, then we may have inefficiency, but I don't think things
  1021. * break...
  1022. */
  1023. const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
  1024. const Window *new_stack = (Window *) root_children_stacked->data;
  1025. const int old_len = stack->last_root_children_stacked->len;
  1026. const int new_len = root_children_stacked->len;
  1027. const Window *oldp = old_stack;
  1028. const Window *newp = new_stack;
  1029. const Window *old_end = old_stack + old_len;
  1030. const Window *new_end = new_stack + new_len;
  1031. Window last_window = None;
  1032. while (oldp != old_end &&
  1033. newp != new_end)
  1034. {
  1035. if (*oldp == *newp)
  1036. {
  1037. /* Stacks are the same here, move on */
  1038. ++oldp;
  1039. last_window = *newp;
  1040. ++newp;
  1041. }
  1042. else if (meta_display_lookup_x_window (stack->screen->display,
  1043. *oldp) == NULL)
  1044. {
  1045. /* *oldp is no longer known to us (probably destroyed),
  1046. * so we can just skip it
  1047. */
  1048. ++oldp;
  1049. }
  1050. else
  1051. {
  1052. /* Move *newp below last_window */
  1053. if (last_window == None)
  1054. {
  1055. meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
  1056. raise_window_relative_to_managed_windows (stack->screen,
  1057. *newp);
  1058. }
  1059. else
  1060. {
  1061. /* This means that if last_window is dead, but not
  1062. * *newp, then we fail to restack *newp; but on
  1063. * unmanaging last_window, we'll fix it up.
  1064. */
  1065. XWindowChanges changes;
  1066. changes.sibling = last_window;
  1067. changes.stack_mode = Below;
  1068. meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
  1069. *newp, last_window);
  1070. meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
  1071. *newp, last_window,
  1072. XNextRequest (stack->screen->display->xdisplay));
  1073. XConfigureWindow (stack->screen->display->xdisplay,
  1074. *newp,
  1075. CWSibling | CWStackMode,
  1076. &changes);
  1077. }
  1078. last_window = *newp;
  1079. ++newp;
  1080. }
  1081. }
  1082. if (newp != new_end)
  1083. {
  1084. /* Restack remaining windows */
  1085. meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
  1086. (int) (new_end - newp));
  1087. /* We need to include an already-stacked window
  1088. * in the restack call, so we get in the proper position
  1089. * with respect to it.
  1090. */
  1091. if (newp != new_stack)
  1092. --newp;
  1093. meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
  1094. (Window *) newp, new_end - newp,
  1095. XNextRequest (stack->screen->display->xdisplay));
  1096. XRestackWindows (stack->screen->display->xdisplay,
  1097. (Window *) newp, new_end - newp);
  1098. }
  1099. }
  1100. /* Push hidden windows to the bottom of the stack under the guard window */
  1101. meta_stack_tracker_record_lower (stack->screen->stack_tracker,
  1102. stack->screen->guard_window,
  1103. XNextRequest (stack->screen->display->xdisplay));
  1104. XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
  1105. meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
  1106. (Window *)all_hidden->data,
  1107. all_hidden->len,
  1108. XNextRequest (stack->screen->display->xdisplay));
  1109. XRestackWindows (stack->screen->display->xdisplay,
  1110. (Window *)all_hidden->data,
  1111. all_hidden->len);
  1112. g_array_free (all_hidden, TRUE);
  1113. meta_error_trap_pop (stack->screen->display);
  1114. /* on error, a window was destroyed; it should eventually
  1115. * get removed from the stacking list when we unmanage it
  1116. * and we'll fix stacking at that time.
  1117. */
  1118. /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
  1119. XChangeProperty (stack->screen->display->xdisplay,
  1120. stack->screen->xroot,
  1121. stack->screen->display->atom__NET_CLIENT_LIST,
  1122. XA_WINDOW,
  1123. 32, PropModeReplace,
  1124. (unsigned char *)stack->windows->data,
  1125. stack->windows->len);
  1126. XChangeProperty (stack->screen->display->xdisplay,
  1127. stack->screen->xroot,
  1128. stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
  1129. XA_WINDOW,
  1130. 32, PropModeReplace,
  1131. (unsigned char *)stacked->data,
  1132. stacked->len);
  1133. g_array_free (stacked, TRUE);
  1134. if (stack->last_root_children_stacked)
  1135. g_array_free (stack->last_root_children_stacked, TRUE);
  1136. stack->last_root_children_stacked = root_children_stacked;
  1137. /* That was scary... */
  1138. }
  1139. LOCAL_SYMBOL MetaWindow*
  1140. meta_stack_get_top (MetaStack *stack)
  1141. {
  1142. stack_ensure_sorted (stack);
  1143. if (stack->sorted)
  1144. return stack->sorted->data;
  1145. else
  1146. return NULL;
  1147. }
  1148. LOCAL_SYMBOL MetaWindow*
  1149. meta_stack_get_bottom (MetaStack *stack)
  1150. {
  1151. GList *link;
  1152. stack_ensure_sorted (stack);
  1153. link = g_list_last (stack->sorted);
  1154. if (link != NULL)
  1155. return link->data;
  1156. else
  1157. return NULL;
  1158. }
  1159. LOCAL_SYMBOL MetaWindow*
  1160. meta_stack_get_above (MetaStack *stack,
  1161. MetaWindow *window,
  1162. gboolean only_within_layer)
  1163. {
  1164. GList *link;
  1165. MetaWindow *above;
  1166. stack_ensure_sorted (stack);
  1167. link = g_list_find (stack->sorted, window);
  1168. if (link == NULL)
  1169. return NULL;
  1170. if (link->prev == NULL)
  1171. return NULL;
  1172. above = link->prev->data;
  1173. if (only_within_layer &&
  1174. above->layer != window->layer)
  1175. return NULL;
  1176. else
  1177. return above;
  1178. }
  1179. LOCAL_SYMBOL MetaWindow*
  1180. meta_stack_get_below (MetaStack *stack,
  1181. MetaWindow *window,
  1182. gboolean only_within_layer)
  1183. {
  1184. GList *link;
  1185. MetaWindow *below;
  1186. stack_ensure_sorted (stack);
  1187. link = g_list_find (stack->sorted, window);
  1188. if (link == NULL)
  1189. return NULL;
  1190. if (link->next == NULL)
  1191. return NULL;
  1192. below = link->next->data;
  1193. if (only_within_layer &&
  1194. below->layer != window->layer)
  1195. return NULL;
  1196. else
  1197. return below;
  1198. }
  1199. static gboolean
  1200. window_contains_point (MetaWindow *window,
  1201. int root_x,
  1202. int root_y)
  1203. {
  1204. MetaRectangle rect;
  1205. meta_window_get_outer_rect (window, &rect);
  1206. return POINT_IN_RECT (root_x, root_y, rect);
  1207. }
  1208. static MetaWindow*
  1209. get_default_focus_window (MetaStack *stack,
  1210. MetaWorkspace *workspace,
  1211. MetaWindow *not_this_one,
  1212. gboolean must_be_at_point,
  1213. int root_x,
  1214. int root_y)
  1215. {
  1216. /* Find the topmost, focusable, mapped, window.
  1217. * not_this_one is being unfocused or going away, so exclude it.
  1218. * Also, prefer to focus transient parent of not_this_one,
  1219. * or top window in same group as not_this_one.
  1220. */
  1221. MetaWindow *topmost_dock;
  1222. MetaWindow *transient_parent;
  1223. MetaWindow *topmost_in_group;
  1224. MetaWindow *topmost_overall;
  1225. MetaGroup *not_this_one_group;
  1226. GList *link;
  1227. topmost_dock = NULL;
  1228. transient_parent = NULL;
  1229. topmost_in_group = NULL;
  1230. topmost_overall = NULL;
  1231. if (not_this_one)
  1232. not_this_one_group = meta_window_get_group (not_this_one);
  1233. else
  1234. not_this_one_group = NULL;
  1235. stack_ensure_sorted (stack);
  1236. /* top of this layer is at the front of the list */
  1237. link = stack->sorted;
  1238. while (link)
  1239. {
  1240. MetaWindow *window = link->data;
  1241. if (window &&
  1242. window != not_this_one &&
  1243. (window->unmaps_pending == 0) &&
  1244. !window->minimized &&
  1245. (window->input || window->take_focus) &&
  1246. (workspace == NULL ||
  1247. meta_window_located_on_workspace (window, workspace)))
  1248. {
  1249. if (topmost_dock == NULL &&
  1250. window->type == META_WINDOW_DOCK)
  1251. topmost_dock = window;
  1252. if (not_this_one != NULL)
  1253. {
  1254. if (transient_parent == NULL &&
  1255. not_this_one->xtransient_for != None &&
  1256. not_this_one->xtransient_for == window->xwindow &&
  1257. (!must_be_at_point ||
  1258. window_contains_point (window, root_x, root_y)))
  1259. transient_parent = window;
  1260. if (topmost_in_group == NULL &&
  1261. not_this_one_group != NULL &&
  1262. not_this_one_group == meta_window_get_group (window) &&
  1263. (!must_be_at_point ||
  1264. window_contains_point (window, root_x, root_y)))
  1265. topmost_in_group = window;
  1266. }
  1267. /* Note that DESKTOP windows can be topmost_overall so
  1268. * we prefer focusing desktop or other windows over
  1269. * focusing dock, even though docks are stacked higher.
  1270. */
  1271. if (topmost_overall == NULL &&
  1272. window->type != META_WINDOW_DOCK &&
  1273. (!must_be_at_point ||
  1274. window_contains_point (window, root_x, root_y)))
  1275. topmost_overall = window;
  1276. /* We could try to bail out early here for efficiency in
  1277. * some cases, but it's just not worth the code.
  1278. */
  1279. }
  1280. link = link->next;
  1281. }
  1282. if (transient_parent)
  1283. return transient_parent;
  1284. else if (topmost_in_group)
  1285. return topmost_in_group;
  1286. else if (topmost_overall)
  1287. return topmost_overall;
  1288. else
  1289. return topmost_dock;
  1290. }
  1291. LOCAL_SYMBOL MetaWindow*
  1292. meta_stack_get_default_focus_window_at_point (MetaStack *stack,
  1293. MetaWorkspace *workspace,
  1294. MetaWindow *not_this_one,
  1295. int root_x,
  1296. int root_y)
  1297. {
  1298. return get_default_focus_window (stack, workspace, not_this_one,
  1299. TRUE, root_x, root_y);
  1300. }
  1301. LOCAL_SYMBOL MetaWindow*
  1302. meta_stack_get_default_focus_window (MetaStack *stack,
  1303. MetaWorkspace *workspace,
  1304. MetaWindow *not_this_one)
  1305. {
  1306. return get_default_focus_window (stack, workspace, not_this_one,
  1307. FALSE, 0, 0);
  1308. }
  1309. LOCAL_SYMBOL GList*
  1310. meta_stack_list_windows (MetaStack *stack,
  1311. MetaWorkspace *workspace)
  1312. {
  1313. GList *workspace_windows = NULL;
  1314. GList *link;
  1315. stack_ensure_sorted (stack); /* do adds/removes */
  1316. link = stack->sorted;
  1317. while (link)
  1318. {
  1319. MetaWindow *window = link->data;
  1320. if (window &&
  1321. (workspace == NULL || meta_window_located_on_workspace (window, workspace)))
  1322. {
  1323. workspace_windows = g_list_prepend (workspace_windows,
  1324. window);
  1325. }
  1326. link = link->next;
  1327. }
  1328. return workspace_windows;
  1329. }
  1330. LOCAL_SYMBOL int
  1331. meta_stack_windows_cmp (MetaStack *stack,
  1332. MetaWindow *window_a,
  1333. MetaWindow *window_b)
  1334. {
  1335. g_return_val_if_fail (window_a->screen == window_b->screen, 0);
  1336. /* -1 means a below b */
  1337. stack_ensure_sorted (stack); /* update constraints, layers */
  1338. if (window_a->layer < window_b->layer)
  1339. return -1;
  1340. else if (window_a->layer > window_b->layer)
  1341. return 1;
  1342. else if (window_a->stack_position < window_b->stack_position)
  1343. return -1;
  1344. else if (window_a->stack_position > window_b->stack_position)
  1345. return 1;
  1346. else
  1347. return 0; /* not reached */
  1348. }
  1349. static int
  1350. compare_just_window_stack_position (void *a,
  1351. void *b)
  1352. {
  1353. MetaWindow *window_a = a;
  1354. MetaWindow *window_b = b;
  1355. if (window_a->stack_position < window_b->stack_position)
  1356. return -1; /* move window_a earlier in list */
  1357. else if (window_a->stack_position > window_b->stack_position)
  1358. return 1;
  1359. else
  1360. return 0; /* not reached */
  1361. }
  1362. LOCAL_SYMBOL GList*
  1363. meta_stack_get_positions (MetaStack *stack)
  1364. {
  1365. GList *tmp;
  1366. /* Make sure to handle any adds or removes */
  1367. stack_ensure_sorted (stack);
  1368. tmp = g_list_copy (stack->sorted);
  1369. tmp = g_list_sort (tmp, (GCompareFunc) compare_just_window_stack_position);
  1370. return tmp;
  1371. }
  1372. static gint
  1373. compare_pointers (gconstpointer a,
  1374. gconstpointer b)
  1375. {
  1376. if (a > b)
  1377. return 1;
  1378. else if (a < b)
  1379. return -1;
  1380. else
  1381. return 0;
  1382. }
  1383. static gboolean
  1384. lists_contain_same_windows (GList *a,
  1385. GList *b)
  1386. {
  1387. GList *copy1, *copy2;
  1388. GList *tmp1, *tmp2;
  1389. if (g_list_length (a) != g_list_length (b))
  1390. return FALSE;
  1391. tmp1 = copy1 = g_list_sort (g_list_copy (a), compare_pointers);
  1392. tmp2 = copy2 = g_list_sort (g_list_copy (b), compare_pointers);
  1393. while (tmp1 && tmp1->data == tmp2->data) /* tmp2 is non-NULL if tmp1 is */
  1394. {
  1395. tmp1 = tmp1->next;
  1396. tmp2 = tmp2->next;
  1397. }
  1398. g_list_free (copy1);
  1399. g_list_free (copy2);
  1400. return (tmp1 == NULL); /* tmp2 is non-NULL if tmp1 is */
  1401. }
  1402. LOCAL_SYMBOL void
  1403. meta_stack_set_positions (MetaStack *stack,
  1404. GList *windows)
  1405. {
  1406. int i;
  1407. GList *tmp;
  1408. /* Make sure any adds or removes aren't in limbo -- is this needed? */
  1409. stack_ensure_sorted (stack);
  1410. if (!lists_contain_same_windows (windows, stack->sorted))
  1411. {
  1412. meta_warning ("This list of windows has somehow changed; not resetting "
  1413. "positions of the windows.\n");
  1414. return;
  1415. }
  1416. g_list_free (stack->sorted);
  1417. stack->sorted = g_list_copy (windows);
  1418. stack->need_resort = TRUE;
  1419. stack->need_constrain = TRUE;
  1420. i = 0;
  1421. tmp = windows;
  1422. while (tmp != NULL)
  1423. {
  1424. MetaWindow *w = tmp->data;
  1425. w->stack_position = i++;
  1426. tmp = tmp->next;
  1427. }
  1428. meta_topic (META_DEBUG_STACK,
  1429. "Reset the stack positions of (nearly) all windows\n");
  1430. stack_sync_to_server (stack);
  1431. meta_stack_update_window_tile_matches (stack, NULL);
  1432. }
  1433. void
  1434. meta_window_set_stack_position_no_sync (MetaWindow *window,
  1435. int position)
  1436. {
  1437. int low, high, delta;
  1438. GList *tmp;
  1439. g_return_if_fail (window->screen->stack != NULL);
  1440. g_return_if_fail (window->stack_position >= 0);
  1441. g_return_if_fail (position >= 0);
  1442. g_return_if_fail (position < window->screen->stack->n_positions);
  1443. if (position == window->stack_position)
  1444. {
  1445. meta_topic (META_DEBUG_STACK, "Window %s already has position %d\n",
  1446. window->desc, position);
  1447. return;
  1448. }
  1449. window->screen->stack->need_resort = TRUE;
  1450. window->screen->stack->need_constrain = TRUE;
  1451. if (position < window->stack_position)
  1452. {
  1453. low = position;
  1454. high = window->stack_position - 1;
  1455. delta = 1;
  1456. }
  1457. else
  1458. {
  1459. low = window->stack_position + 1;
  1460. high = position;
  1461. delta = -1;
  1462. }
  1463. tmp = window->screen->stack->sorted;
  1464. while (tmp != NULL)
  1465. {
  1466. MetaWindow *w = tmp->data;
  1467. if (w->stack_position >= low &&
  1468. w->stack_position <= high)
  1469. w->stack_position += delta;
  1470. tmp = tmp->next;
  1471. }
  1472. window->stack_position = position;
  1473. meta_topic (META_DEBUG_STACK,
  1474. "Window %s had stack_position set to %d\n",
  1475. window->desc, window->stack_position);
  1476. }
  1477. LOCAL_SYMBOL void
  1478. meta_window_set_stack_position (MetaWindow *window,
  1479. int position)
  1480. {
  1481. meta_window_set_stack_position_no_sync (window, position);
  1482. stack_sync_to_server (window->screen->stack);
  1483. meta_stack_update_window_tile_matches (window->screen->stack,
  1484. window->screen->active_workspace);
  1485. }