28
28
#include "window-private.h"
29
29
#include "boxes-private.h"
30
30
#include "edge-resistance.h"
32
#include "frame-private.h"
31
#include <meta/util.h>
33
#include <meta/errors.h>
34
34
#include "workspace-private.h"
36
36
#include "keybindings-private.h"
39
39
#include "session.h"
40
#include <meta/prefs.h>
41
41
#include "resizepopup.h"
42
42
#include "xprops.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,
67
70
static void set_wm_state (MetaWindow *window,
69
72
static void set_net_wm_state (MetaWindow *window);
363
370
"Contents of the _MUTTER_HINTS property of this window",
365
372
G_PARAM_READABLE));
373
g_object_class_install_property (object_class,
374
PROP_APPEARS_FOCUSED,
375
g_param_spec_boolean ("appears-focused",
377
"Whether the window is drawn as being focused",
366
381
window_signals[WORKSPACE_CHANGED] =
367
382
g_signal_new ("workspace-changed",
368
383
G_TYPE_FROM_CLASS (object_class),
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
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.
542
* Returns TRUE if window has been filtered out and should be ignored.
545
maybe_filter_window (MetaDisplay *display,
547
gboolean must_be_viewable,
548
XWindowAttributes *attrs)
550
static char **filter_wm_classes = NULL;
551
static gboolean initialized = FALSE;
552
XClassHint class_hint;
559
const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER");
561
filter_wm_classes = g_strsplit (filter_string, ",", -1);
565
if (!filter_wm_classes || !filter_wm_classes[0])
570
meta_error_trap_push (display);
571
success = XGetClassHint (display->xdisplay, xwindow, &class_hint);
575
for (i = 0; filter_wm_classes[i]; i++)
577
if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0)
584
XFree (class_hint.res_name);
585
XFree (class_hint.res_class);
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.
596
if (!must_be_viewable || attrs->map_state == IsViewable)
600
if (!meta_prop_get_cardinal_with_atom_type (display, xwindow,
601
display->atom_WM_STATE,
602
display->atom_WM_STATE,
604
old_state = WithdrawnState;
606
if (old_state == WithdrawnState)
607
set_wm_state_on_xwindow (display, xwindow, NormalState);
610
/* Make sure filtered windows are hidden from view */
611
XUnmapWindow (display->xdisplay, xwindow);
614
meta_error_trap_pop (display);
521
620
meta_window_new_with_attrs (MetaDisplay *display,
985
1094
if (window->type == META_WINDOW_DESKTOP ||
986
window->type == META_WINDOW_DOCK ||
987
window->override_redirect)
1095
window->type == META_WINDOW_DOCK)
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.
994
window->on_all_workspaces = TRUE;
1102
window->on_all_workspaces_requested = TRUE;
1105
window->on_all_workspaces = should_be_on_all_workspaces (window);
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
1051
1162
"Putting window %s on same workspace as parent %s\n",
1052
1163
window->desc, parent->desc);
1054
if (parent->on_all_workspaces)
1055
window->on_all_workspaces = TRUE;
1165
if (parent->on_all_workspaces_requested)
1167
window->on_all_workspaces_requested = TRUE;
1168
window->on_all_workspaces = TRUE;
1057
1171
/* this will implicitly add to the appropriate MRU lists
1077
1191
meta_window_update_struts (window);
1194
g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window);
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
1238
1354
if (info->on_all_workspaces_set)
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);
1246
1363
if (info->workspace_indices)
1560
1685
g_object_unref (window);
1689
should_be_on_all_workspaces (MetaWindow *window)
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));
1699
meta_window_update_on_all_workspaces (MetaWindow *window)
1703
old_value = window->on_all_workspaces;
1705
window->on_all_workspaces = should_be_on_all_workspaces (window);
1707
if (window->on_all_workspaces != old_value &&
1708
!window->override_redirect)
1710
if (window->on_all_workspaces)
1712
GList* tmp = window->screen->workspaces;
1714
/* Add to all MRU lists */
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);
1726
GList* tmp = window->screen->workspaces;
1728
/* Remove from MRU lists except the window's workspace */
1731
MetaWorkspace* work = (MetaWorkspace*) tmp->data;
1732
if (work != window->workspace)
1733
work->mru_list = g_list_remove (work->mru_list, window);
1737
meta_window_set_current_workspace_hint (window);
1564
set_wm_state (MetaWindow *window,
1742
set_wm_state_on_xwindow (MetaDisplay *display,
1567
1746
unsigned long data[2];
1569
meta_verbose ("Setting wm state %s on %s\n",
1570
wm_state_to_string (state), window->desc);
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.
1575
1751
data[0] = state;
1576
1752
data[1] = None;
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);
1763
set_wm_state (MetaWindow *window,
1766
meta_verbose ("Setting wm state %s on %s\n",
1767
wm_state_to_string (state), window->desc);
1769
set_wm_state_on_xwindow (window->display, window->xwindow, state);
4196
* meta_window_get_monitor:
4197
* @window: a #MetaWindow
4199
* Gets index of the monitor that this window is on.
4201
* Return Value: The index of the monitor in the screens monitor list
4204
meta_window_get_monitor (MetaWindow *window)
4206
return window->monitor->number;
4210
meta_window_update_monitor (MetaWindow *window)
4212
const MetaMonitorInfo *old;
4214
old = window->monitor;
4215
window->monitor = meta_screen_get_monitor_for_window (window->screen, window);
4216
if (old != window->monitor)
4218
meta_window_update_on_all_workspaces (window);
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
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.
4232
if (meta_prefs_get_workspaces_only_on_primary () &&
4233
meta_window_is_on_primary_monitor (window) &&
4235
window->screen->active_workspace != window->workspace)
4236
meta_window_change_workspace (window, window->screen->active_workspace);
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);
3991
4245
meta_window_move_resize_internal (MetaWindow *window,
3992
4246
MetaMoveResizeFlags flags,
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
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,
4472
4749
meta_window_move (MetaWindow *window,
4473
4750
gboolean user_op,
4487
4764
window->rect.width,
4488
4765
window->rect.height);
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
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().
4780
meta_window_move_frame (MetaWindow *window,
4790
/* offset by the distance between the origin of the window
4791
* and the origin of the enclosing window decorations
4793
x += window->frame->child_x;
4794
y += window->frame->child_y;
4796
meta_window_move (window, user_op, x, y);
4800
* meta_window_move_to_monitor:
4801
* @window: a #MetaWindow
4802
* @monitor: desired monitor index
4804
* Moves the window to the monitor with index @monitor, keeping
4805
* the relative position of the window's top left corner.
4808
meta_window_move_to_monitor (MetaWindow *window,
4811
MetaRectangle old_area, new_area;
4813
double scale_x, scale_y;
4815
if (monitor == window->monitor->number)
4818
meta_window_get_work_area_for_monitor (window,
4819
window->monitor->number,
4821
meta_window_get_work_area_for_monitor (window,
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;
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;
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);
4492
4843
meta_window_move_resize (MetaWindow *window,
4964
5317
window_stick_impl (MetaWindow *window)
4967
MetaWorkspace *workspace;
4969
5319
meta_verbose ("Sticking window %s current on_all_workspaces = %d\n",
4970
5320
window->desc, window->on_all_workspaces);
4972
if (window->on_all_workspaces)
5322
if (window->on_all_workspaces_requested)
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.
4979
window->on_all_workspaces = TRUE;
4981
/* We do, however, change the MRU lists of all the workspaces
4983
tmp = window->screen->workspaces;
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);
4993
meta_window_set_current_workspace_hint (window);
5329
window->on_all_workspaces_requested = TRUE;
5330
meta_window_update_on_all_workspaces (window);
4995
5332
meta_window_queue(window, META_QUEUE_CALC_SHOWING);
4999
5336
window_unstick_impl (MetaWindow *window)
5002
MetaWorkspace *workspace;
5004
if (!window->on_all_workspaces)
5338
if (!window->on_all_workspaces_requested)
5007
5341
/* Revert to window->workspaces */
5009
window->on_all_workspaces = FALSE;
5011
/* Remove window from MRU lists that it doesn't belong in */
5012
tmp = window->screen->workspaces;
5015
workspace = (MetaWorkspace *) tmp->data;
5016
if (window->workspace != workspace)
5017
workspace->mru_list = g_list_remove (workspace->mru_list, window);
5343
window->on_all_workspaces_requested = FALSE;
5344
meta_window_update_on_all_workspaces (window);
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
6060
check_ancestor_focus_appearance (MetaWindow *window)
6383
meta_window_propagate_focus_appearance (MetaWindow *window,
6062
MetaWindow *parent = meta_window_get_transient_for (window);
6386
MetaWindow *child, *parent;
6064
6388
if (!meta_prefs_get_attach_modal_dialogs ())
6067
if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
6070
meta_frame_queue_draw (parent->frame);
6072
check_ancestor_focus_appearance (parent);
6392
parent = meta_window_get_transient_for (child);
6393
while (child->type == META_WINDOW_MODAL_DIALOG && parent)
6395
gboolean child_focus_state_changed;
6399
if (parent->attached_focus_window == window)
6401
child_focus_state_changed = (parent->attached_focus_window == NULL);
6402
parent->attached_focus_window = window;
6406
if (parent->attached_focus_window != window)
6408
child_focus_state_changed = (parent->attached_focus_window != NULL);
6409
parent->attached_focus_window = NULL;
6412
if (child_focus_state_changed && !parent->has_focus)
6414
g_object_notify (G_OBJECT (parent), "appears-focused");
6416
meta_frame_queue_draw (parent->frame);
6420
parent = meta_window_get_transient_for (child);
6214
6563
!meta_prefs_get_raise_on_click())
6215
6564
meta_display_ungrab_focus_window_button (window->display, window);
6217
/* parent window become active. */
6218
check_ancestor_focus_appearance (window);
6220
6566
g_signal_emit (window, window_signals[FOCUS], 0);
6221
6567
g_object_notify (G_OBJECT (window->display), "focus-window");
6569
if (!window->attached_focus_window)
6571
g_object_notify (G_OBJECT (window), "appears-focused");
6573
meta_frame_queue_draw (window->frame);
6575
meta_window_propagate_focus_appearance (window, TRUE);
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);
6253
meta_frame_queue_draw (window->frame);
6604
if (!window->attached_focus_window)
6606
g_object_notify (G_OBJECT (window), "appears-focused");
6608
meta_frame_queue_draw (window->frame);
6610
meta_window_propagate_focus_appearance (window, FALSE);
6255
6612
meta_error_trap_push (window->display);
6256
6613
XUninstallColormap (window->display->xdisplay,
7507
7861
window->type != META_WINDOW_DESKTOP)
7508
7862
ops |= META_MENU_OP_RECOVER;
7510
n_workspaces = meta_screen_get_n_workspaces (window->screen);
7512
if (n_workspaces > 1)
7513
ops |= META_MENU_OP_WORKSPACES;
7515
meta_screen_calc_workspace_layout (window->screen,
7517
meta_workspace_index ( window->screen->active_workspace),
7520
if (!window->on_all_workspaces)
7864
if (!meta_prefs_get_workspaces_only_on_primary () ||
7865
meta_window_is_on_primary_monitor (window))
7522
ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
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);
7869
if (n_workspaces > 1)
7870
ops |= META_MENU_OP_WORKSPACES;
7872
meta_screen_calc_workspace_layout (window->screen,
7874
meta_workspace_index ( window->screen->active_workspace),
7877
if (!window->on_all_workspaces)
7879
ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
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;
7893
meta_screen_free_workspace_layout (&layout);
7895
ops |= META_MENU_OP_UNSTICK;
7896
ops |= META_MENU_OP_STICK;
7536
meta_screen_free_workspace_layout (&layout);
7538
7899
if (META_WINDOW_MAXIMIZED (window))
7539
7900
ops |= META_MENU_OP_UNMAXIMIZE;
7861
8219
if (meta_window_can_tile_side_by_side (window))
7863
if (y >= monitor->rect.y &&
7864
y < (monitor->rect.y + monitor->rect.height))
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;
7873
window->tile_mode = META_TILE_NONE;
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;
8228
window->tile_mode = META_TILE_NONE;
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.
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).
7884
if (meta_window_can_tile_maximized (window))
8243
if (window->tile_mode == META_TILE_NONE && meta_window_can_tile_maximized (window))
7886
if (x >= monitor->rect.x &&
7887
x < (monitor->rect.x + monitor->rect.width))
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;
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;
8162
8517
dx = x - window->display->grab_anchor_root_x;
8163
8518
dy = y - window->display->grab_anchor_root_y;
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.
8524
if (window->type == META_WINDOW_MODAL_DIALOG &&
8525
meta_prefs_get_attach_modal_dialogs () &&
8526
meta_window_get_transient_for (window) != NULL)
8165
8529
new_w = window->display->grab_anchor_window_pos.width;
8166
8530
new_h = window->display->grab_anchor_window_pos.height;
9406
9760
meta_window_appears_focused (MetaWindow *window)
9408
/* FIXME: meta_window_foreach_transient() iterates over all windows; we
9409
* should eat the complexity to cache a bit for this.
9411
if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ())
9413
gboolean focus = FALSE;
9414
meta_window_foreach_transient (window, transient_has_focus, &focus);
9417
return window->has_focus;
9762
return window->has_focus || (window->attached_focus_window != NULL);