~ubuntu-branches/ubuntu/saucy/mutter/saucy

« back to all changes in this revision

Viewing changes to src/core/window.c

  • Committer: Bazaar Package Importer
  • Author(s): Rico Tzschichholz
  • Date: 2011-04-10 22:27:59 UTC
  • mfrom: (0.7.1 upstream) (0.3.20 experimental)
  • Revision ID: james.westby@ubuntu.com-20110410222759-o6n1i5p0unsti44n
Tags: 3.0.0-0ubuntu1
* New upstream release

* Merge with debian experimental (LP: #742458), remaining changes:
  + debian/patches/03_link_gles2.patch: Link to clutter-glx-1.0
    explicitily at the end of link flags, to bring in libGLESv2 on armel.
* debian/control.in:
  + rename gir package to gir1.2-mutter-3.0
* debian/libmutter0.symbols:
  + updated
* debian/patches:
  + fix 03_link_gles2.patch 

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include "window-private.h"
29
29
#include "boxes-private.h"
30
30
#include "edge-resistance.h"
31
 
#include "util.h"
32
 
#include "frame-private.h"
33
 
#include "errors.h"
 
31
#include <meta/util.h>
 
32
#include "frame.h"
 
33
#include <meta/errors.h>
34
34
#include "workspace-private.h"
35
35
#include "stack.h"
36
36
#include "keybindings-private.h"
37
37
#include "ui.h"
38
38
#include "place.h"
39
39
#include "session.h"
40
 
#include "prefs.h"
 
40
#include <meta/prefs.h>
41
41
#include "resizepopup.h"
42
42
#include "xprops.h"
43
 
#include "group.h"
 
43
#include <meta/group.h>
44
44
#include "window-props.h"
45
45
#include "constraints.h"
46
46
#include "mutter-enum-types.h"
64
64
static void     recalc_window_features    (MetaWindow     *window);
65
65
static void     invalidate_work_areas     (MetaWindow     *window);
66
66
static void     recalc_window_type        (MetaWindow     *window);
 
67
static void     set_wm_state_on_xwindow   (MetaDisplay    *display,
 
68
                                           Window          xwindow,
 
69
                                           int             state);
67
70
static void     set_wm_state              (MetaWindow     *window,
68
71
                                           int             state);
69
72
static void     set_net_wm_state          (MetaWindow     *window);
111
114
                                       int           y,
112
115
                                       gboolean      force);
113
116
static gboolean update_resize_timeout (gpointer data);
114
 
 
 
117
static gboolean should_be_on_all_workspaces (MetaWindow *window);
115
118
 
116
119
static void meta_window_flush_calc_showing   (MetaWindow *window);
117
120
 
151
154
  PROP_USER_TIME,
152
155
  PROP_DEMANDS_ATTENTION,
153
156
  PROP_URGENT,
154
 
  PROP_MUTTER_HINTS
 
157
  PROP_MUTTER_HINTS,
 
158
  PROP_APPEARS_FOCUSED
155
159
};
156
160
 
157
161
enum
236
240
    case PROP_MUTTER_HINTS:
237
241
      g_value_set_string (value, win->mutter_hints);
238
242
      break;
 
243
    case PROP_APPEARS_FOCUSED:
 
244
      g_value_set_boolean (value, meta_window_appears_focused (win));
 
245
      break;
239
246
    default:
240
247
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
241
248
      break;
363
370
                                                        "Contents of the _MUTTER_HINTS property of this window",
364
371
                                                        NULL,
365
372
                                                        G_PARAM_READABLE));
 
373
  g_object_class_install_property (object_class,
 
374
                                   PROP_APPEARS_FOCUSED,
 
375
                                   g_param_spec_boolean ("appears-focused",
 
376
                                                         "Appears focused",
 
377
                                                         "Whether the window is drawn as being focused",
 
378
                                                         FALSE,
 
379
                                                         G_PARAM_READABLE));
 
380
 
366
381
  window_signals[WORKSPACE_CHANGED] =
367
382
    g_signal_new ("workspace-changed",
368
383
                  G_TYPE_FROM_CLASS (object_class),
517
532
  return window;
518
533
}
519
534
 
 
535
/* The MUTTER_WM_CLASS_FILTER environment variable is designed for
 
536
 * performance and regression testing environments where we want to do
 
537
 * tests with only a limited set of windows and ignore all other windows
 
538
 *
 
539
 * When it is set to a comma separated list of WM_CLASS class names, all
 
540
 * windows not matching the list will be ignored.
 
541
 *
 
542
 * Returns TRUE if window has been filtered out and should be ignored.
 
543
 */
 
544
static gboolean
 
545
maybe_filter_window (MetaDisplay       *display,
 
546
                     Window             xwindow,
 
547
                     gboolean           must_be_viewable,
 
548
                     XWindowAttributes *attrs)
 
549
{
 
550
  static char **filter_wm_classes = NULL;
 
551
  static gboolean initialized = FALSE;
 
552
  XClassHint class_hint;
 
553
  gboolean filtered;
 
554
  Status success;
 
555
  int i;
 
556
 
 
557
  if (!initialized)
 
558
    {
 
559
      const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER");
 
560
      if (filter_string)
 
561
        filter_wm_classes = g_strsplit (filter_string, ",", -1);
 
562
      initialized = TRUE;
 
563
    }
 
564
 
 
565
  if (!filter_wm_classes || !filter_wm_classes[0])
 
566
    return FALSE;
 
567
 
 
568
  filtered = TRUE;
 
569
 
 
570
  meta_error_trap_push (display);
 
571
  success = XGetClassHint (display->xdisplay, xwindow, &class_hint);
 
572
 
 
573
  if (success)
 
574
    {
 
575
      for (i = 0; filter_wm_classes[i]; i++)
 
576
        {
 
577
          if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0)
 
578
            {
 
579
              filtered = FALSE;
 
580
              break;
 
581
            }
 
582
        }
 
583
 
 
584
      XFree (class_hint.res_name);
 
585
      XFree (class_hint.res_class);
 
586
    }
 
587
 
 
588
  if (filtered)
 
589
    {
 
590
      /* We want to try and get the window managed by the next WM that come along,
 
591
       * so we need to make sure that windows that are requested to be mapped while
 
592
       * Mutter is running (!must_be_viewable), or windows already viewable at startup
 
593
       * get a non-withdrawn WM_STATE property. Previously unmapped windows are left
 
594
       * with whatever WM_STATE property they had.
 
595
       */
 
596
      if (!must_be_viewable || attrs->map_state == IsViewable)
 
597
        {
 
598
          gulong old_state;
 
599
 
 
600
          if (!meta_prop_get_cardinal_with_atom_type (display, xwindow,
 
601
                                                      display->atom_WM_STATE,
 
602
                                                      display->atom_WM_STATE,
 
603
                                                      &old_state))
 
604
            old_state = WithdrawnState;
 
605
 
 
606
          if (old_state == WithdrawnState)
 
607
            set_wm_state_on_xwindow (display, xwindow, NormalState);
 
608
        }
 
609
 
 
610
      /* Make sure filtered windows are hidden from view */
 
611
      XUnmapWindow (display->xdisplay, xwindow);
 
612
    }
 
613
 
 
614
  meta_error_trap_pop (display);
 
615
 
 
616
  return filtered;
 
617
}
 
618
 
520
619
MetaWindow*
521
620
meta_window_new_with_attrs (MetaDisplay       *display,
522
621
                            Window             xwindow,
579
678
    return NULL;
580
679
  }
581
680
 
 
681
  if (maybe_filter_window (display, xwindow, must_be_viewable, attrs))
 
682
    {
 
683
      meta_verbose ("Not managing filtered window\n");
 
684
      return NULL;
 
685
    }
 
686
 
582
687
  /* Grab server */
583
688
  meta_display_grab (display);
584
689
  meta_error_trap_push (display); /* Push a trap over all of window
763
868
 
764
869
  window->frame = NULL;
765
870
  window->has_focus = FALSE;
 
871
  window->attached_focus_window = NULL;
766
872
 
767
873
  window->maximized_horizontally = FALSE;
768
874
  window->maximized_vertically = FALSE;
776
882
  window->require_on_single_monitor = TRUE;
777
883
  window->require_titlebar_visible = TRUE;
778
884
  window->on_all_workspaces = FALSE;
 
885
  window->on_all_workspaces_requested = FALSE;
779
886
  window->tile_mode = META_TILE_NONE;
780
887
  window->shaded = FALSE;
781
888
  window->initially_iconic = FALSE;
880
987
 
881
988
  window->compositor_private = NULL;
882
989
 
 
990
  window->monitor = meta_screen_get_monitor_for_window (window->screen, window);
 
991
 
883
992
  if (window->override_redirect)
884
993
    {
885
994
      window->decorated = FALSE;
983
1092
    }
984
1093
 
985
1094
  if (window->type == META_WINDOW_DESKTOP ||
986
 
      window->type == META_WINDOW_DOCK ||
987
 
      window->override_redirect)
 
1095
      window->type == META_WINDOW_DOCK)
988
1096
    {
989
1097
      /* Change the default, but don't enforce this if the user
990
1098
       * focuses the dock/desktop and unsticks it using key shortcuts.
991
1099
       * Need to set this before adding to the workspaces so the MRU
992
1100
       * lists will be updated.
993
1101
       */
994
 
      window->on_all_workspaces = TRUE;
 
1102
      window->on_all_workspaces_requested = TRUE;
995
1103
    }
996
1104
 
 
1105
  window->on_all_workspaces = should_be_on_all_workspaces (window);
 
1106
 
997
1107
  /* For the workspace, first honor hints,
998
1108
   * if that fails put transients with parents,
999
1109
   * otherwise put window on active space
1010
1120
          /* need to set on_all_workspaces first so that it will be
1011
1121
           * added to all the MRU lists
1012
1122
           */
 
1123
          window->on_all_workspaces_requested = TRUE;
1013
1124
          window->on_all_workspaces = TRUE;
1014
1125
          meta_workspace_add_window (window->screen->active_workspace, window);
1015
1126
        }
1051
1162
                          "Putting window %s on same workspace as parent %s\n",
1052
1163
                          window->desc, parent->desc);
1053
1164
 
1054
 
              if (parent->on_all_workspaces)
1055
 
                window->on_all_workspaces = TRUE;
 
1165
              if (parent->on_all_workspaces_requested)
 
1166
                {
 
1167
                  window->on_all_workspaces_requested = TRUE;
 
1168
                  window->on_all_workspaces = TRUE;
 
1169
                }
1056
1170
 
1057
1171
              /* this will implicitly add to the appropriate MRU lists
1058
1172
               */
1077
1191
      meta_window_update_struts (window);
1078
1192
    }
1079
1193
 
 
1194
  g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window);
 
1195
 
1080
1196
  /* Must add window to stack before doing move/resize, since the
1081
1197
   * window might have fullscreen size (i.e. should have been
1082
1198
   * fullscreen'd; acrobat is one such braindead case; it withdraws
1237
1353
 
1238
1354
  if (info->on_all_workspaces_set)
1239
1355
    {
1240
 
      window->on_all_workspaces = info->on_all_workspaces;
 
1356
      window->on_all_workspaces_requested = info->on_all_workspaces;
 
1357
      meta_window_update_on_all_workspaces (window);
1241
1358
      meta_topic (META_DEBUG_SM,
1242
1359
                  "Restoring sticky state %d for window %s\n",
1243
 
                  window->on_all_workspaces, window->desc);
 
1360
                  window->on_all_workspaces_requested, window->desc);
1244
1361
    }
1245
1362
 
1246
1363
  if (info->workspace_indices)
1384
1501
      meta_workspace_focus_default_window (window->screen->active_workspace,
1385
1502
                                           window,
1386
1503
                                           timestamp);
 
1504
      meta_window_propagate_focus_appearance (window, FALSE);
1387
1505
    }
1388
1506
  else if (window->display->expected_focus_window == window)
1389
1507
    {
1456
1574
    }
1457
1575
#endif
1458
1576
 
 
1577
  if (window->monitor)
 
1578
    {
 
1579
      g_signal_emit_by_name (window->screen, "window-left-monitor",
 
1580
                             window->monitor->number, window);
 
1581
      window->monitor = NULL;
 
1582
    }
 
1583
 
1459
1584
  if (!window->override_redirect)
1460
1585
    meta_stack_remove (window->screen->stack, window);
1461
1586
 
1560
1685
  g_object_unref (window);
1561
1686
}
1562
1687
 
 
1688
static gboolean
 
1689
should_be_on_all_workspaces (MetaWindow *window)
 
1690
{
 
1691
  return
 
1692
    window->on_all_workspaces_requested ||
 
1693
    window->override_redirect ||
 
1694
    (meta_prefs_get_workspaces_only_on_primary () &&
 
1695
     !meta_window_is_on_primary_monitor (window));
 
1696
}
 
1697
 
 
1698
void
 
1699
meta_window_update_on_all_workspaces (MetaWindow *window)
 
1700
{
 
1701
  gboolean old_value;
 
1702
 
 
1703
  old_value = window->on_all_workspaces;
 
1704
 
 
1705
  window->on_all_workspaces = should_be_on_all_workspaces (window);
 
1706
 
 
1707
  if (window->on_all_workspaces != old_value &&
 
1708
      !window->override_redirect)
 
1709
    {
 
1710
      if (window->on_all_workspaces)
 
1711
        {
 
1712
          GList* tmp = window->screen->workspaces;
 
1713
 
 
1714
          /* Add to all MRU lists */
 
1715
          while (tmp)
 
1716
            {
 
1717
              MetaWorkspace* work = (MetaWorkspace*) tmp->data;
 
1718
              if (!g_list_find (work->mru_list, window))
 
1719
                work->mru_list = g_list_prepend (work->mru_list, window);
 
1720
 
 
1721
              tmp = tmp->next;
 
1722
            }
 
1723
        }
 
1724
      else
 
1725
        {
 
1726
          GList* tmp = window->screen->workspaces;
 
1727
 
 
1728
          /* Remove from MRU lists except the window's workspace */
 
1729
          while (tmp)
 
1730
            {
 
1731
              MetaWorkspace* work = (MetaWorkspace*) tmp->data;
 
1732
              if (work != window->workspace)
 
1733
                work->mru_list = g_list_remove (work->mru_list, window);
 
1734
              tmp = tmp->next;
 
1735
            }
 
1736
        }
 
1737
      meta_window_set_current_workspace_hint (window);
 
1738
    }
 
1739
}
 
1740
 
1563
1741
static void
1564
 
set_wm_state (MetaWindow *window,
1565
 
              int         state)
 
1742
set_wm_state_on_xwindow (MetaDisplay *display,
 
1743
                         Window       xwindow,
 
1744
                         int          state)
1566
1745
{
1567
1746
  unsigned long data[2];
1568
1747
 
1569
 
  meta_verbose ("Setting wm state %s on %s\n",
1570
 
                wm_state_to_string (state), window->desc);
1571
 
 
1572
1748
  /* Mutter doesn't use icon windows, so data[1] should be None
1573
1749
   * according to the ICCCM 2.0 Section 4.1.3.1.
1574
1750
   */
1575
1751
  data[0] = state;
1576
1752
  data[1] = None;
1577
1753
 
1578
 
  meta_error_trap_push (window->display);
1579
 
  XChangeProperty (window->display->xdisplay, window->xwindow,
1580
 
                   window->display->atom_WM_STATE,
1581
 
                   window->display->atom_WM_STATE,
 
1754
  meta_error_trap_push (display);
 
1755
  XChangeProperty (display->xdisplay, xwindow,
 
1756
                   display->atom_WM_STATE,
 
1757
                   display->atom_WM_STATE,
1582
1758
                   32, PropModeReplace, (guchar*) data, 2);
1583
 
  meta_error_trap_pop (window->display);
 
1759
  meta_error_trap_pop (display);
 
1760
}
 
1761
 
 
1762
static void
 
1763
set_wm_state (MetaWindow *window,
 
1764
              int         state)
 
1765
{
 
1766
  meta_verbose ("Setting wm state %s on %s\n",
 
1767
                wm_state_to_string (state), window->desc);
 
1768
 
 
1769
  set_wm_state_on_xwindow (window->display, window->xwindow, state);
1584
1770
}
1585
1771
 
1586
1772
static void
1645
1831
      data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION;
1646
1832
      ++i;
1647
1833
    }
1648
 
  if (window->on_all_workspaces)
 
1834
  if (window->on_all_workspaces_requested)
1649
1835
    {
1650
1836
      data[i] = window->display->atom__NET_WM_STATE_STICKY;
1651
1837
      ++i;
1711
1897
  return is_minimized;
1712
1898
}
1713
1899
 
 
1900
/**
 
1901
 * meta_window_showing_on_its_workspace:
 
1902
 * @window: A #MetaWindow
 
1903
 *
 
1904
 * Returns: %TRUE if window would be visible, if its workspace was current
 
1905
 */
1714
1906
gboolean
1715
1907
meta_window_showing_on_its_workspace (MetaWindow *window)
1716
1908
{
1849
2041
  MetaWindow *first_window;
1850
2042
  guint queue_index = GPOINTER_TO_INT (data);
1851
2043
 
 
2044
  g_return_val_if_fail (queue_pending[queue_index] != NULL, FALSE);
 
2045
 
1852
2046
  meta_topic (META_DEBUG_WINDOW_STATE,
1853
2047
              "Clearing the calc_showing queue\n");
1854
2048
 
3205
3399
  return window->fullscreen;
3206
3400
}
3207
3401
 
 
3402
/**
 
3403
 * meta_window_is_on_primary_monitor:
 
3404
 *
 
3405
 * Return value: %TRUE if the window is on the primary monitor
 
3406
 */
 
3407
gboolean
 
3408
meta_window_is_on_primary_monitor (MetaWindow *window)
 
3409
{
 
3410
  return window->monitor->number == window->screen->primary_monitor_index;
 
3411
}
 
3412
 
3208
3413
void
3209
3414
meta_window_tile (MetaWindow *window)
3210
3415
{
3987
4192
  return FALSE;
3988
4193
}
3989
4194
 
 
4195
/**
 
4196
 * meta_window_get_monitor:
 
4197
 * @window: a #MetaWindow
 
4198
 *
 
4199
 * Gets index of the monitor that this window is on.
 
4200
 *
 
4201
 * Return Value: The index of the monitor in the screens monitor list
 
4202
 */
 
4203
int
 
4204
meta_window_get_monitor (MetaWindow *window)
 
4205
{
 
4206
  return window->monitor->number;
 
4207
}
 
4208
 
 
4209
void
 
4210
meta_window_update_monitor (MetaWindow *window)
 
4211
{
 
4212
  const MetaMonitorInfo *old;
 
4213
 
 
4214
  old = window->monitor;
 
4215
  window->monitor = meta_screen_get_monitor_for_window (window->screen, window);
 
4216
  if (old != window->monitor)
 
4217
    {
 
4218
      meta_window_update_on_all_workspaces (window);
 
4219
 
 
4220
      /* If workspaces only on primary and we moved back to primary, ensure that the
 
4221
       * window is now in that workspace. We do this because while the window is on a
 
4222
       * non-primary monitor it is always visible, so it would be very jarring if it
 
4223
       * disappeared when it crossed the monitor border.
 
4224
       * The one time we want it to both change to the primary monitor and a non-active
 
4225
       * workspace is when dropping the window on some other workspace thumbnail directly.
 
4226
       * That should be handled by explicitly moving the window before changing the
 
4227
       * workspace
 
4228
       * Don't do this if old == NULL, because thats what happens when we're updating
 
4229
       * the monitors due to a monitors change event, and we don't want to move
 
4230
       * everything to the currently active workspace.
 
4231
       */
 
4232
      if (meta_prefs_get_workspaces_only_on_primary () &&
 
4233
          meta_window_is_on_primary_monitor (window)  &&
 
4234
          old != NULL &&
 
4235
          window->screen->active_workspace != window->workspace)
 
4236
        meta_window_change_workspace (window, window->screen->active_workspace);
 
4237
 
 
4238
      if (old)
 
4239
        g_signal_emit_by_name (window->screen, "window-left-monitor", old->number, window);
 
4240
      g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window);
 
4241
    }
 
4242
}
 
4243
 
3990
4244
static void
3991
4245
meta_window_move_resize_internal (MetaWindow          *window,
3992
4246
                                  MetaMoveResizeFlags  flags,
4438
4692
 
4439
4693
  meta_window_refresh_resize_popup (window);
4440
4694
 
 
4695
  meta_window_update_monitor (window);
 
4696
 
4441
4697
  /* Invariants leaving this function are:
4442
4698
   *   a) window->rect and frame->rect reflect the actual
4443
4699
   *      server-side size/pos of window->xwindow and frame->xwindow
4448
4704
    meta_window_foreach_transient (window, move_attached_dialog, NULL);
4449
4705
}
4450
4706
 
 
4707
/**
 
4708
 * meta_window_resize:
 
4709
 * @window: a #MetaWindow
 
4710
 * @user_op: bool to indicate whether or not this is a user operation
 
4711
 * @w: desired width
 
4712
 * @h: desired height
 
4713
 *
 
4714
 * Resize the window to the desired size.
 
4715
 */
4451
4716
void
4452
4717
meta_window_resize (MetaWindow  *window,
4453
4718
                    gboolean     user_op,
4468
4733
                                    x, y, w, h);
4469
4734
}
4470
4735
 
 
4736
/**
 
4737
 * meta_window_move:
 
4738
 * @window: a #MetaWindow
 
4739
 * @user_op: bool to indicate whether or not this is a user operation
 
4740
 * @root_x_nw: desired x pos
 
4741
 * @root_y_nw: desired y pos
 
4742
 *
 
4743
 * Moves the window to the desired location on window's assigned workspace.
 
4744
 * NOTE: does NOT place according to the origin of the enclosing
 
4745
 * frame/window-decoration, but according to the origin of the window,
 
4746
 * itself.
 
4747
 */
4471
4748
void
4472
4749
meta_window_move (MetaWindow  *window,
4473
4750
                  gboolean     user_op,
4487
4764
                                    window->rect.width,
4488
4765
                                    window->rect.height);
4489
4766
}
 
4767
/**
 
4768
 * meta_window_move_frame:
 
4769
 * @window: a #MetaWindow
 
4770
 * @user_op: bool to indicate whether or not this is a user operation
 
4771
 * @root_x_nw: desired x pos
 
4772
 * @root_y_nw: desired y pos
 
4773
 *
 
4774
 * Moves the window to the desired location on window's assigned
 
4775
 * workspace, using the northwest edge of the frame as the reference,
 
4776
 * instead of the actual window's origin, but only if a frame is present.
 
4777
 * Otherwise, acts identically to meta_window_move().
 
4778
 */
 
4779
void
 
4780
meta_window_move_frame (MetaWindow  *window,
 
4781
                  gboolean     user_op,
 
4782
                  int          root_x_nw,
 
4783
                  int          root_y_nw)
 
4784
{
 
4785
  int x = root_x_nw;
 
4786
  int y = root_y_nw;
 
4787
 
 
4788
  if (window->frame)
 
4789
    {
 
4790
      /* offset by the distance between the origin of the window
 
4791
       * and the origin of the enclosing window decorations
 
4792
       */
 
4793
      x += window->frame->child_x;
 
4794
      y += window->frame->child_y;
 
4795
    }
 
4796
  meta_window_move (window, user_op, x, y);
 
4797
}
 
4798
 
 
4799
/**
 
4800
 * meta_window_move_to_monitor:
 
4801
 * @window: a #MetaWindow
 
4802
 * @monitor: desired monitor index
 
4803
 *
 
4804
 * Moves the window to the monitor with index @monitor, keeping
 
4805
 * the relative position of the window's top left corner.
 
4806
 */
 
4807
void
 
4808
meta_window_move_to_monitor (MetaWindow  *window,
 
4809
                             int          monitor)
 
4810
{
 
4811
  MetaRectangle old_area, new_area;
 
4812
  int rel_x, rel_y;
 
4813
  double scale_x, scale_y;
 
4814
 
 
4815
  if (monitor == window->monitor->number)
 
4816
    return;
 
4817
 
 
4818
  meta_window_get_work_area_for_monitor (window,
 
4819
                                         window->monitor->number,
 
4820
                                         &old_area);
 
4821
  meta_window_get_work_area_for_monitor (window,
 
4822
                                         monitor,
 
4823
                                         &new_area);
 
4824
 
 
4825
  rel_x = window->user_rect.x - old_area.x;
 
4826
  rel_y = window->user_rect.y - old_area.y;
 
4827
  scale_x = (double)new_area.width / old_area.width;
 
4828
  scale_y = (double)new_area.height / old_area.height;
 
4829
 
 
4830
  window->user_rect.x = new_area.x + rel_x * scale_x;
 
4831
  window->user_rect.y = new_area.y + rel_y * scale_y;
 
4832
  window->saved_rect.x = window->user_rect.x;
 
4833
  window->saved_rect.y = window->user_rect.y;
 
4834
 
 
4835
  meta_window_move_resize (window, FALSE,
 
4836
                           window->user_rect.x,
 
4837
                           window->user_rect.y,
 
4838
                           window->user_rect.width,
 
4839
                           window->user_rect.height);
 
4840
}
4490
4841
 
4491
4842
void
4492
4843
meta_window_move_resize (MetaWindow  *window,
4601
4952
  window->rect.y = event->y;
4602
4953
  window->rect.width = event->width;
4603
4954
  window->rect.height = event->height;
 
4955
  meta_window_update_monitor (window);
 
4956
 
4604
4957
  if (!event->override_redirect && !event->send_event)
4605
4958
    meta_warning ("Unhandled change of windows override redirect status\n");
4606
4959
 
4916
5269
  meta_verbose ("Changing window %s to workspace %d\n",
4917
5270
                window->desc, meta_workspace_index (workspace));
4918
5271
 
4919
 
  if (!window->on_all_workspaces)
 
5272
  if (!window->on_all_workspaces_requested)
4920
5273
    {
4921
5274
      old_workspace = meta_workspace_index (window->workspace);
4922
5275
    }
4925
5278
   * meta_window_change_workspace recursively if the window
4926
5279
   * is not in the active workspace.
4927
5280
   */
4928
 
  if (window->on_all_workspaces)
 
5281
  if (window->on_all_workspaces_requested)
4929
5282
    meta_window_unstick (window);
4930
5283
 
4931
5284
  /* See if we're already on this space. If not, make sure we are */
4963
5316
static void
4964
5317
window_stick_impl (MetaWindow  *window)
4965
5318
{
4966
 
  GList *tmp;
4967
 
  MetaWorkspace *workspace;
4968
 
 
4969
5319
  meta_verbose ("Sticking window %s current on_all_workspaces = %d\n",
4970
5320
                window->desc, window->on_all_workspaces);
4971
5321
 
4972
 
  if (window->on_all_workspaces)
 
5322
  if (window->on_all_workspaces_requested)
4973
5323
    return;
4974
5324
 
4975
5325
  /* We don't change window->workspaces, because we revert
4976
5326
   * to that original workspace list if on_all_workspaces is
4977
5327
   * toggled back off.
4978
5328
   */
4979
 
  window->on_all_workspaces = TRUE;
4980
 
 
4981
 
  /* We do, however, change the MRU lists of all the workspaces
4982
 
   */
4983
 
  tmp = window->screen->workspaces;
4984
 
  while (tmp)
4985
 
    {
4986
 
      workspace = (MetaWorkspace *) tmp->data;
4987
 
      if (!g_list_find (workspace->mru_list, window))
4988
 
        workspace->mru_list = g_list_prepend (workspace->mru_list, window);
4989
 
 
4990
 
      tmp = tmp->next;
4991
 
    }
4992
 
 
4993
 
  meta_window_set_current_workspace_hint (window);
 
5329
  window->on_all_workspaces_requested = TRUE;
 
5330
  meta_window_update_on_all_workspaces (window);
4994
5331
 
4995
5332
  meta_window_queue(window, META_QUEUE_CALC_SHOWING);
4996
5333
}
4998
5335
static void
4999
5336
window_unstick_impl (MetaWindow  *window)
5000
5337
{
5001
 
  GList *tmp;
5002
 
  MetaWorkspace *workspace;
5003
 
 
5004
 
  if (!window->on_all_workspaces)
 
5338
  if (!window->on_all_workspaces_requested)
5005
5339
    return;
5006
5340
 
5007
5341
  /* Revert to window->workspaces */
5008
5342
 
5009
 
  window->on_all_workspaces = FALSE;
5010
 
 
5011
 
  /* Remove window from MRU lists that it doesn't belong in */
5012
 
  tmp = window->screen->workspaces;
5013
 
  while (tmp)
5014
 
    {
5015
 
      workspace = (MetaWorkspace *) tmp->data;
5016
 
      if (window->workspace != workspace)
5017
 
        workspace->mru_list = g_list_remove (workspace->mru_list, window);
5018
 
      tmp = tmp->next;
5019
 
    }
 
5343
  window->on_all_workspaces_requested = FALSE;
 
5344
  meta_window_update_on_all_workspaces (window);
5020
5345
 
5021
5346
  /* We change ourselves to the active workspace, since otherwise you'd get
5022
5347
   * a weird window-vaporization effect. Once we have UI for being
5026
5351
  if (window->screen->active_workspace != window->workspace)
5027
5352
    meta_window_change_workspace (window, window->screen->active_workspace);
5028
5353
 
5029
 
  meta_window_set_current_workspace_hint (window);
5030
 
 
5031
5354
  meta_window_queue(window, META_QUEUE_CALC_SHOWING);
5032
5355
}
5033
5356
 
5553
5876
 
5554
5877
  if (workspace)
5555
5878
    {
5556
 
      if (window->on_all_workspaces)
 
5879
      if (window->on_all_workspaces_requested)
5557
5880
        meta_window_unstick (window);
5558
5881
 
5559
5882
      meta_window_change_workspace (window, workspace);
5628
5951
 
5629
5952
      if (workspace)
5630
5953
        {
5631
 
          if (window->on_all_workspaces)
 
5954
          if (window->on_all_workspaces_requested)
5632
5955
            meta_window_unstick (window);
5633
5956
          meta_window_change_workspace (window, workspace);
5634
5957
        }
5827
6150
          second == display->atom__NET_WM_STATE_STICKY)
5828
6151
        {
5829
6152
          if ((action == _NET_WM_STATE_ADD) ||
5830
 
              (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces))
 
6153
              (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested))
5831
6154
            meta_window_stick (window);
5832
6155
          else
5833
6156
            meta_window_unstick (window);
6056
6379
  return FALSE;
6057
6380
}
6058
6381
 
6059
 
static void
6060
 
check_ancestor_focus_appearance (MetaWindow *window)
 
6382
void
 
6383
meta_window_propagate_focus_appearance (MetaWindow *window,
 
6384
                                        gboolean    focused)
6061
6385
{
6062
 
  MetaWindow *parent = meta_window_get_transient_for (window);
 
6386
  MetaWindow *child, *parent;
6063
6387
 
6064
6388
  if (!meta_prefs_get_attach_modal_dialogs ())
6065
6389
    return;
6066
6390
 
6067
 
  if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
6068
 
    return;
6069
 
  if (parent->frame)
6070
 
    meta_frame_queue_draw (parent->frame);
6071
 
 
6072
 
  check_ancestor_focus_appearance (parent);
 
6391
  child = window;
 
6392
  parent = meta_window_get_transient_for (child);
 
6393
  while (child->type == META_WINDOW_MODAL_DIALOG && parent)
 
6394
    {
 
6395
      gboolean child_focus_state_changed;
 
6396
 
 
6397
      if (focused)
 
6398
        {
 
6399
          if (parent->attached_focus_window == window)
 
6400
            break;
 
6401
          child_focus_state_changed = (parent->attached_focus_window == NULL);
 
6402
          parent->attached_focus_window = window;
 
6403
        }
 
6404
      else
 
6405
        {
 
6406
          if (parent->attached_focus_window != window)
 
6407
            break;
 
6408
          child_focus_state_changed = (parent->attached_focus_window != NULL);
 
6409
          parent->attached_focus_window = NULL;
 
6410
        }
 
6411
 
 
6412
      if (child_focus_state_changed && !parent->has_focus)
 
6413
        {
 
6414
          g_object_notify (G_OBJECT (parent), "appears-focused");
 
6415
          if (parent->frame)
 
6416
            meta_frame_queue_draw (parent->frame);
 
6417
        }
 
6418
 
 
6419
      child = parent;
 
6420
      parent = meta_window_get_transient_for (child);
 
6421
    }
6073
6422
}
6074
6423
 
6075
6424
gboolean
6214
6563
              !meta_prefs_get_raise_on_click())
6215
6564
            meta_display_ungrab_focus_window_button (window->display, window);
6216
6565
 
6217
 
          /* parent window become active. */
6218
 
          check_ancestor_focus_appearance (window);
6219
 
 
6220
6566
          g_signal_emit (window, window_signals[FOCUS], 0);
6221
6567
          g_object_notify (G_OBJECT (window->display), "focus-window");
 
6568
 
 
6569
          if (!window->attached_focus_window)
 
6570
            {
 
6571
              g_object_notify (G_OBJECT (window), "appears-focused");
 
6572
              if (window->frame)
 
6573
                meta_frame_queue_draw (window->frame);
 
6574
            }
 
6575
          meta_window_propagate_focus_appearance (window, TRUE);
6222
6576
        }
6223
6577
    }
6224
6578
  else if (event->type == FocusOut ||
6246
6600
          window->display->focus_window = NULL;
6247
6601
          g_object_notify (G_OBJECT (window->display), "focus-window");
6248
6602
          window->has_focus = FALSE;
6249
 
          /* parent window become inactive. */
6250
 
          check_ancestor_focus_appearance (window);
6251
6603
 
6252
 
          if (window->frame)
6253
 
            meta_frame_queue_draw (window->frame);
 
6604
          if (!window->attached_focus_window)
 
6605
            {
 
6606
              g_object_notify (G_OBJECT (window), "appears-focused");
 
6607
              if (window->frame)
 
6608
                meta_frame_queue_draw (window->frame);
 
6609
            }
 
6610
          meta_window_propagate_focus_appearance (window, FALSE);
6254
6611
 
6255
6612
          meta_error_trap_push (window->display);
6256
6613
          XUninstallColormap (window->display->xdisplay,
7173
7530
    {
7174
7531
      MetaWindow *parent = meta_window_get_transient_for (window);
7175
7532
      if (parent)
7176
 
        {
7177
 
          window->has_resize_func = FALSE;
7178
 
          window->border_only = TRUE;
7179
 
        }
 
7533
        window->border_only = TRUE;
7180
7534
    }
7181
7535
 
7182
7536
  if (window->type == META_WINDOW_DESKTOP ||
7507
7861
      window->type != META_WINDOW_DESKTOP)
7508
7862
    ops |= META_MENU_OP_RECOVER;
7509
7863
 
7510
 
  n_workspaces = meta_screen_get_n_workspaces (window->screen);
7511
 
 
7512
 
  if (n_workspaces > 1)
7513
 
    ops |= META_MENU_OP_WORKSPACES;
7514
 
 
7515
 
  meta_screen_calc_workspace_layout (window->screen,
7516
 
                                     n_workspaces,
7517
 
                                     meta_workspace_index ( window->screen->active_workspace),
7518
 
                                     &layout);
7519
 
 
7520
 
  if (!window->on_all_workspaces)
 
7864
  if (!meta_prefs_get_workspaces_only_on_primary () ||
 
7865
      meta_window_is_on_primary_monitor (window))
7521
7866
    {
7522
 
      ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
7523
 
 
7524
 
      if (layout.current_col > 0)
7525
 
        ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
7526
 
      if ((layout.current_col < layout.cols - 1) &&
7527
 
          (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
7528
 
        ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
7529
 
      if (layout.current_row > 0)
7530
 
        ops |= META_MENU_OP_MOVE_UP;
7531
 
      if ((layout.current_row < layout.rows - 1) &&
7532
 
          ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
7533
 
        ops |= META_MENU_OP_MOVE_DOWN;
 
7867
      n_workspaces = meta_screen_get_n_workspaces (window->screen);
 
7868
 
 
7869
      if (n_workspaces > 1)
 
7870
        ops |= META_MENU_OP_WORKSPACES;
 
7871
 
 
7872
      meta_screen_calc_workspace_layout (window->screen,
 
7873
                                         n_workspaces,
 
7874
                                         meta_workspace_index ( window->screen->active_workspace),
 
7875
                                         &layout);
 
7876
 
 
7877
      if (!window->on_all_workspaces)
 
7878
        {
 
7879
          ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
 
7880
 
 
7881
          if (layout.current_col > 0)
 
7882
            ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
 
7883
          if ((layout.current_col < layout.cols - 1) &&
 
7884
              (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
 
7885
            ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
 
7886
          if (layout.current_row > 0)
 
7887
            ops |= META_MENU_OP_MOVE_UP;
 
7888
          if ((layout.current_row < layout.rows - 1) &&
 
7889
              ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
 
7890
            ops |= META_MENU_OP_MOVE_DOWN;
 
7891
        }
 
7892
 
 
7893
      meta_screen_free_workspace_layout (&layout);
 
7894
 
 
7895
      ops |= META_MENU_OP_UNSTICK;
 
7896
      ops |= META_MENU_OP_STICK;
7534
7897
    }
7535
7898
 
7536
 
  meta_screen_free_workspace_layout (&layout);
7537
 
 
7538
7899
  if (META_WINDOW_MAXIMIZED (window))
7539
7900
    ops |= META_MENU_OP_UNMAXIMIZE;
7540
7901
  else
7547
7908
    ops |= META_MENU_OP_SHADE;
7548
7909
#endif
7549
7910
 
7550
 
  ops |= META_MENU_OP_UNSTICK;
7551
 
  ops |= META_MENU_OP_STICK;
7552
 
 
7553
7911
  if (window->wm_state_above)
7554
7912
    ops |= META_MENU_OP_UNABOVE;
7555
7913
  else
7860
8218
 
7861
8219
      if (meta_window_can_tile_side_by_side (window))
7862
8220
        {
7863
 
          if (y >= monitor->rect.y &&
7864
 
              y < (monitor->rect.y + monitor->rect.height))
7865
 
            {
7866
 
              /* check if cursor is near an edge of the work area */
7867
 
              if (x >= monitor->rect.x && x < (work_area.x + shake_threshold))
7868
 
                window->tile_mode = META_TILE_LEFT;
7869
 
              else if (x >= work_area.x + work_area.width - shake_threshold &&
7870
 
                       x < (monitor->rect.x + monitor->rect.width))
7871
 
                window->tile_mode = META_TILE_RIGHT;
7872
 
              else
7873
 
                window->tile_mode = META_TILE_NONE;
7874
 
            }
 
8221
          /* check if cursor is near an edge of the work area */
 
8222
          if (x >= monitor->rect.x && x < (work_area.x + shake_threshold))
 
8223
            window->tile_mode = META_TILE_LEFT;
 
8224
          else if (x >= work_area.x + work_area.width - shake_threshold &&
 
8225
                   x < (monitor->rect.x + monitor->rect.width))
 
8226
            window->tile_mode = META_TILE_RIGHT;
 
8227
          else
 
8228
            window->tile_mode = META_TILE_NONE;
7875
8229
        }
7876
8230
 
7877
8231
      /* For maximized tiling we are interested in the outside top edge
7880
8234
       * We use the outside edge instead of the inside edge, because we
7881
8235
       * don't want to force users to maximize windows they are placing
7882
8236
       * near the top of their screens.
 
8237
       *
 
8238
       * If window->tile_mode is not NONE, that means that either we are
 
8239
       * on an edge and set it above, or we are currently tiled (in
 
8240
       * which case meta_window_can_tile_side_by_side() and
 
8241
       * meta_window_can_tile_maximized() return FALSE).
7883
8242
       */
7884
 
      if (meta_window_can_tile_maximized (window))
 
8243
      if (window->tile_mode == META_TILE_NONE && meta_window_can_tile_maximized (window))
7885
8244
        {
7886
 
          if (x >= monitor->rect.x &&
7887
 
              x < (monitor->rect.x + monitor->rect.width))
7888
 
            {
7889
 
              /* check if cursor is on the top edge of the monitor*/
7890
 
              if (y >= monitor->rect.y && y <= work_area.y)
7891
 
                  window->tile_mode = META_TILE_MAXIMIZED;
7892
 
            }
 
8245
          /* check if cursor is on the top edge of the monitor*/
 
8246
          if (y >= monitor->rect.y && y <= work_area.y)
 
8247
              window->tile_mode = META_TILE_MAXIMIZED;
7893
8248
        }
7894
8249
    }
7895
8250
 
8162
8517
  dx = x - window->display->grab_anchor_root_x;
8163
8518
  dy = y - window->display->grab_anchor_root_y;
8164
8519
 
 
8520
  /* Attached modal dialogs are special in that horizontal
 
8521
   * size changes apply to both sides, so that the dialog
 
8522
   * remains centered to the parent.
 
8523
   */
 
8524
  if (window->type == META_WINDOW_MODAL_DIALOG &&
 
8525
      meta_prefs_get_attach_modal_dialogs () &&
 
8526
      meta_window_get_transient_for (window) != NULL)
 
8527
    dx *= 2;
 
8528
 
8165
8529
  new_w = window->display->grab_anchor_window_pos.width;
8166
8530
  new_h = window->display->grab_anchor_window_pos.height;
8167
8531
 
9382
9746
  return window->frame;
9383
9747
}
9384
9748
 
9385
 
static gboolean
9386
 
transient_has_focus (MetaWindow *window,
9387
 
                     void       *data)
9388
 
{
9389
 
  if (window->type == META_WINDOW_MODAL_DIALOG && meta_window_appears_focused (window))
9390
 
    *((gboolean *)data) = TRUE;
9391
 
 
9392
 
  return FALSE;
9393
 
}
9394
 
 
9395
9749
/**
9396
9750
 * meta_window_appears_focused:
9397
9751
 * @window: a #MetaWindow
9405
9759
gboolean
9406
9760
meta_window_appears_focused (MetaWindow *window)
9407
9761
{
9408
 
  /* FIXME: meta_window_foreach_transient() iterates over all windows; we
9409
 
   *  should eat the complexity to cache a bit for this.
9410
 
   */
9411
 
  if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ())
9412
 
    {
9413
 
      gboolean focus = FALSE;
9414
 
      meta_window_foreach_transient (window, transient_has_focus, &focus);
9415
 
      return focus;
9416
 
    }
9417
 
  return window->has_focus;
 
9762
  return window->has_focus || (window->attached_focus_window != NULL);
9418
9763
}
9419
9764
 
9420
9765
gboolean
9459
9804
  return window->skip_taskbar;
9460
9805
}
9461
9806
 
 
9807
/**
 
9808
 * meta_window_get_rect:
 
9809
 * @window: a #MetaWindow
 
9810
 *
 
9811
 * Gets the rectangle that bounds @window, ignoring any window decorations.
 
9812
 *
 
9813
 * Return value: (transfer none): the #MetaRectangle for the window
 
9814
 */
9462
9815
MetaRectangle *
9463
9816
meta_window_get_rect (MetaWindow *window)
9464
9817
{