Update to 3.12.0

This commit is contained in:
Richard Hughes 2014-06-18 14:17:15 +01:00
parent f4d0e3cec2
commit d77e3e4f57
14 changed files with 8 additions and 2719 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ metacity-2.30.0.tar.bz2
/metacity-2.34.3.tar.xz
/metacity-2.34.8.tar.xz
/metacity-2.34.13.tar.xz
/metacity-3.12.0.tar.xz

View File

@ -1,94 +0,0 @@
From 90dc810b9f501136c6f1cf94bc4f4c1f626412b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 16 May 2013 15:37:43 +0200
Subject: [PATCH] doc: Update man pages
Metacity is not the fastest moving project, however there were
a view additions in the last nine years, document those.
---
doc/man/metacity-message.1 | 13 +++++++++++--
doc/man/metacity.1 | 16 ++++++++++++++--
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/doc/man/metacity-message.1 b/doc/man/metacity-message.1
index 80041f5..13839f8 100644
--- a/doc/man/metacity-message.1
+++ b/doc/man/metacity-message.1
@@ -12,7 +12,7 @@
.\" > Right I know. any licenses that is DFSG-free, I'm ok with whatever,
.\" > since I have contributed that for Debian. so GPL is no problem for me.
.\" -----
-.TH METACITY\-MESSAGE 1 "28 August 2002"
+.TH METACITY\-MESSAGE 1 "16 May 2013"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -29,7 +29,7 @@
METACITY\-MESSAGE \- a command to send a message to Metacity
.SH SYNOPSIS
.B METACITY\-MESSAGE
-[restart|reload\-theme|enable\-keybindings|disable\-keybindings]
+[restart|reload\-theme|enable\-keybindings|disable\-keybindings|enable\-mouse\-button\-modifiers|disable\-mouse\-button\-modifiers|toggle\-verbose]
.SH DESCRIPTION
This manual page documents briefly the
.B metacity\-message\fP.
@@ -53,6 +53,15 @@ Enable all of keybindings which is specified on gsettings database.
.TP
.B disable-keybindings
Disable all of keybindings which is specified on gsettings database.
+.TP
+.B enable-mouse-button-modifiers
+Enable move/resize operations while pressing a modifier key
+.TP
+.B disable-mouse-button-modifiers
+Disable move/resize operations while pressing a modifier key
+.TP
+.B toggle-verbose
+Turn debug messages on or off
.SH SEE ALSO
.BR metacity (1)
.SH AUTHOR
diff --git a/doc/man/metacity.1 b/doc/man/metacity.1
index 0a4c347..eaf75b5 100644
--- a/doc/man/metacity.1
+++ b/doc/man/metacity.1
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH METACITY 1 "11 February 2006"
+.TH METACITY 1 "16 May 2013"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -19,7 +19,7 @@
METACITY \- minimal GTK2 Window Manager
.SH SYNOPSIS
.B metacity
-[\-\-display=\fIDISPLAY\fP] [\-\-replace] [\-\-sm\-client\-id=\fIID\fP] [\-\-sm\-disable] [\-\-sm\-save\-file=\fIFILENAME\fP] [\-\-version] [\-\-help]
+[\-\-display=\fIDISPLAY\fP] [\-\-replace] [\-\-sm\-client\-id=\fIID\fP] [\-\-sm\-disable] [\-\-sm\-save\-file=\fIFILENAME\fP] [\-\-sync] [\-\-composite] [\-\-no-composite] [\-\-no-force-fullscreen] [\-\-version] [\-\-help]
.SH DESCRIPTION
This manual page documents briefly
.B metacity\fP.
@@ -45,6 +45,18 @@ Disable the session management.
.B \-\-sm\-save\-file=FILENAME
Load a session from \fIFILENAME\fP.
.TP
+.B \-\-sync
+Make X calls synchronous
+.TP
+.B \-\-composite
+Turn compositing on
+.TP
+.B \-\-no-composite
+Turn compositing off
+.TP
+.B \-\-no-force-fullscreen
+Don't make fullscreen windows that are maximized and have no decorations
+.TP
.B \-\-version
Print the version number.
.TP
--
1.8.2.1

View File

@ -1,160 +0,0 @@
From 861a3efb0f531eae767926d18c4d690366306bfe Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 21 Oct 2009 19:22:35 -0400
Subject: [PATCH] Add a new-windows-always-on-top preference
Add a new-windows-always-on-top preference. When set, new windows
are always placed on top, even if they are denied focus.
This is useful on large screens and multihead setups where the
tasklist can be hard to notice and difficult to mouse to, so the
normal behavior of flashing in the tasklist is less effective.
---
src/core/prefs.c | 20 +++++++++++++++++++-
src/core/window.c | 6 +++++-
src/include/prefs.h | 2 ++
src/metacity-schemas.convert | 1 +
src/org.gnome.metacity.gschema.xml.in | 22 ++++++++++++++++++++++
5 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 24a98cd..949f6ed 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -73,6 +73,7 @@ static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
static GSList *no_focus_windows = NULL;
static gboolean raise_on_click = TRUE;
+static gboolean new_windows_always_on_top = TRUE;
static char* current_theme = NULL;
static int num_workspaces = 4;
static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE;
@@ -261,6 +262,14 @@ static MetaBoolPreference preferences_bool[] =
TRUE,
},
{
+ { "new-windows-always-on-top",
+ SCHEMA_METACITY,
+ META_PREF_NEW_WINDOWS_ALWAYS_ON_TOP,
+ },
+ &new_windows_always_on_top,
+ TRUE,
+ },
+ {
{ "titlebar-uses-system-font",
SCHEMA_GENERAL,
META_PREF_TITLEBAR_FONT, /* note! shares a pref */
@@ -920,6 +929,12 @@ meta_prefs_get_raise_on_click (void)
return raise_on_click || focus_mode == G_DESKTOP_FOCUS_MODE_CLICK;
}
+gboolean
+meta_prefs_get_new_windows_always_on_top (void)
+{
+ return new_windows_always_on_top;
+}
+
const char*
meta_prefs_get_theme (void)
{
@@ -1386,7 +1401,10 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_RAISE_ON_CLICK:
return "RAISE_ON_CLICK";
-
+
+ case META_PREF_NEW_WINDOWS_ALWAYS_ON_TOP:
+ return "NEW_WINDOWS_ALWAYS_ON_TOP";
+
case META_PREF_THEME:
return "THEME";
diff --git a/src/core/window.c b/src/core/window.c
index 6f5c280..b6a69b0 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2008,7 +2008,7 @@ window_state_on_map (MetaWindow *window,
if (!(window->input || window->take_focus))
{
*takes_focus = FALSE;
- return;
+ goto out;
}
/* Terminal usage may be different; some users intend to launch
@@ -2055,6 +2055,10 @@ window_state_on_map (MetaWindow *window,
/* The default is correct for these */
break;
}
+
+ out:
+ if (meta_prefs_get_new_windows_always_on_top ())
+ *places_on_top = TRUE;
}
static gboolean
diff --git a/src/include/prefs.h b/src/include/prefs.h
index b86843c..c49e93d 100644
--- a/src/include/prefs.h
+++ b/src/include/prefs.h
@@ -37,6 +37,7 @@ typedef enum
META_PREF_FOCUS_MODE,
META_PREF_FOCUS_NEW_WINDOWS,
META_PREF_RAISE_ON_CLICK,
+ META_PREF_NEW_WINDOWS_ALWAYS_ON_TOP,
META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
@@ -81,6 +82,7 @@ guint meta_prefs_get_mouse_button_menu (void);
GDesktopFocusMode meta_prefs_get_focus_mode (void);
GDesktopFocusNewWindows meta_prefs_get_focus_new_windows (void);
gboolean meta_prefs_get_raise_on_click (void);
+gboolean meta_prefs_get_new_windows_always_on_top (void);
const char* meta_prefs_get_theme (void);
/* returns NULL if GTK default should be used */
const PangoFontDescription* meta_prefs_get_titlebar_font (void);
diff --git a/src/metacity-schemas.convert b/src/metacity-schemas.convert
index 9c271c6..f1fce08 100644
--- a/src/metacity-schemas.convert
+++ b/src/metacity-schemas.convert
@@ -2,3 +2,4 @@
compositing-manager = /apps/metacity/general/compositing_manager
reduced-resources = /apps/metacity/general/reduced_resources
no-focus-windows = /apps/metacity/general/no_focus_windows
+new-windows-always-on-top = /apps/metacity/general/new_windows_always_on_top
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index e4f86bd..d69d525 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -46,6 +46,28 @@
this setting.
</_description>
</key>
+ <key name="new-windows-always-on-top" type="b">
+ <default>false</default>
+ <_summary>Whether new windows should always be placed on top</_summary>
+ <_description>
+ The normal behavior is that if a new window is not given the
+ focus (since, for example, the user has interacted with another
+ window after launching an application), then if the window would
+ be stacked on top of the focus window, the window is instead
+ stacked beneath and flashed in the taskbar. This behavior can
+ be annoying on large screens and multihead setups where the
+ taskbar is hard to notice and difficult to get to, so this option,
+ if set, disables this behavior, and new windows are always placed
+ on top, whether or not they get focus.
+
+ Note that if this option is set, a new window may completely hide
+ the focus window but not get focus itself, which can be quite confusing
+ to users. Also, note that setting this option breaks the normal
+ invariant in the 'click' focus mode that the topmost window always
+ has focus, so its most suitable for use with the 'mouse' and
+ 'sloppy' focus modes.
+ </_description>
+ </key>
</schema>
</schemalist>
--
1.7.9

View File

@ -1,881 +0,0 @@
From 60d38a7c6683001ee2beb72b8f0b0beee4f04bb4 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 21 Oct 2009 18:07:12 -0400
Subject: [PATCH] Add no-focus-windows preference to list windows that
shouldn't be focused
Notification windows from legacy software that don't set _NET_WM_USER_TIME
can be a huge annoyance for users, since they will pop up and steal focus.
Add:
no-focus-windows
which is a list of expressions identifying new windows that shouldn't ever
be focused. For example:
(and (eq class 'Mylegacyapp') (glob name 'New mail*'))
https://bugzilla.gnome.org/show_bug.cgi?id=599248
---
src/Makefile.am | 2 +
src/core/prefs.c | 55 +++
src/core/window-matcher.c | 582 +++++++++++++++++++++++++++++++++
src/core/window-matcher.h | 46 +++
src/core/window.c | 9 +-
src/include/prefs.h | 6 +-
src/metacity-schemas.convert | 1 +
src/org.gnome.metacity.gschema.xml.in | 21 ++
8 files changed, 720 insertions(+), 2 deletions(-)
create mode 100644 src/core/window-matcher.c
create mode 100644 src/core/window-matcher.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d405bf..2befe33 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,8 @@ metacity_SOURCES= \
core/stack.h \
core/util.c \
include/util.h \
+ core/window-matcher.c \
+ core/window-matcher.h \
core/window-props.c \
core/window-props.h \
core/window.c \
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 58f11e9..24a98cd 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -26,6 +26,7 @@
#include <config.h>
#include "prefs.h"
+#include "window-matcher.h"
#include "ui.h"
#include "util.h"
#include <glib.h>
@@ -70,6 +71,7 @@ static PangoFontDescription *titlebar_font = NULL;
static MetaVirtualModifier mouse_button_mods = Mod1Mask;
static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
+static GSList *no_focus_windows = NULL;
static gboolean raise_on_click = TRUE;
static char* current_theme = NULL;
static int num_workspaces = 4;
@@ -120,6 +122,7 @@ static void maybe_give_disable_workarounds_warning (void);
static gboolean titlebar_handler (GVariant*, gpointer*, gpointer);
static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
+static gboolean no_focus_windows_handler (GVariant*, gpointer*, gpointer);
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
@@ -367,6 +370,14 @@ static MetaStringPreference preferences_string[] =
NULL,
},
{
+ { "no-focus-windows",
+ SCHEMA_METACITY,
+ META_PREF_NO_FOCUS_WINDOWS,
+ },
+ no_focus_windows_handler,
+ NULL
+ },
+ {
{ KEY_TITLEBAR_FONT,
SCHEMA_GENERAL,
META_PREF_TITLEBAR_FONT,
@@ -998,6 +1009,39 @@ theme_name_handler (GVariant *value,
}
static gboolean
+no_focus_windows_handler (GVariant *value,
+ gpointer *result,
+ gpointer data)
+{
+ const gchar *string_value;
+
+ *result = NULL; /* ignored */
+ string_value = g_variant_get_string (value, NULL);
+
+ if (no_focus_windows)
+ {
+ meta_window_matcher_list_free (no_focus_windows);
+ no_focus_windows = NULL;
+ }
+
+ if (string_value)
+ {
+ GError *error = NULL;
+ no_focus_windows = meta_window_matcher_list_from_string (string_value, &error);
+ if (error != NULL)
+ {
+ meta_warning ("Error parsing no_focus_windows='%s': %s\n",
+ string_value, error->message);
+ g_error_free (error);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
mouse_button_mods_handler (GVariant *value,
gpointer *result,
gpointer data)
@@ -1414,6 +1458,9 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_FORCE_FULLSCREEN:
return "FORCE_FULLSCREEN";
+
+ case META_PREF_NO_FOCUS_WINDOWS:
+ return "NO_FOCUS_WINDOWS";
}
return "(unknown)";
@@ -1710,6 +1757,14 @@ meta_prefs_get_action_right_click_titlebar (void)
}
gboolean
+meta_prefs_window_is_no_focus (const char *window_name,
+ const char *window_class)
+{
+ return meta_window_matcher_list_matches (no_focus_windows,
+ window_name, window_class);
+}
+
+gboolean
meta_prefs_get_auto_raise (void)
{
return auto_raise;
diff --git a/src/core/window-matcher.c b/src/core/window-matcher.c
new file mode 100644
index 0000000..df889eb
--- /dev/null
+++ b/src/core/window-matcher.c
@@ -0,0 +1,582 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Tiny language for matching against windows */
+
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include "window-matcher.h"
+
+typedef struct _MetaWindowMatcher MetaWindowMatcher;
+
+typedef enum {
+ MATCHER_OPERAND_CLASS,
+ MATCHER_OPERAND_NAME
+} MatcherOperand;
+
+typedef enum {
+ MATCHER_TOKEN_AND = G_TOKEN_LAST + 1,
+ MATCHER_TOKEN_OR,
+ MATCHER_TOKEN_NOT,
+ MATCHER_TOKEN_EQ,
+ MATCHER_TOKEN_GLOB,
+ MATCHER_TOKEN_NAME,
+ MATCHER_TOKEN_CLASS
+} MatcherToken;
+
+struct _MetaWindowMatcher {
+ enum {
+ MATCHER_AND,
+ MATCHER_OR,
+ MATCHER_NOT,
+ MATCHER_EQ,
+ MATCHER_GLOB
+ } type;
+
+ union {
+ struct {
+ MetaWindowMatcher *a;
+ MetaWindowMatcher *b;
+ } and;
+ struct {
+ MetaWindowMatcher *a;
+ MetaWindowMatcher *b;
+ } or;
+ struct {
+ MetaWindowMatcher *a;
+ } not;
+ struct {
+ MatcherOperand operand;
+ char *str;
+ } eq;
+ struct {
+ MatcherOperand operand;
+ char *str;
+ GPatternSpec *pattern;
+ } glob;
+ } u;
+};
+
+static void
+meta_window_matcher_free (MetaWindowMatcher *matcher)
+{
+ switch (matcher->type)
+ {
+ case MATCHER_AND:
+ meta_window_matcher_free (matcher->u.and.a);
+ meta_window_matcher_free (matcher->u.and.b);
+ break;
+ case MATCHER_OR:
+ meta_window_matcher_free (matcher->u.or.a);
+ meta_window_matcher_free (matcher->u.or.b);
+ break;
+ case MATCHER_NOT:
+ meta_window_matcher_free (matcher->u.or.a);
+ break;
+ case MATCHER_EQ:
+ g_free (matcher->u.eq.str);
+ break;
+ case MATCHER_GLOB:
+ g_free (matcher->u.glob.str);
+ g_pattern_spec_free (matcher->u.glob.pattern);
+ break;
+ }
+
+ g_slice_free (MetaWindowMatcher, matcher);
+}
+
+void
+meta_window_matcher_list_free (GSList *list)
+{
+ g_slist_foreach (list, (GFunc)meta_window_matcher_free, NULL);
+ g_slist_free (list);
+}
+
+static gboolean
+meta_window_matcher_matches (MetaWindowMatcher *matcher,
+ const char *window_name,
+ const char *window_class)
+{
+ switch (matcher->type)
+ {
+ case MATCHER_AND:
+ return (meta_window_matcher_matches (matcher->u.and.a, window_name, window_class) &&
+ meta_window_matcher_matches (matcher->u.and.b, window_name, window_class));
+ case MATCHER_OR:
+ return (meta_window_matcher_matches (matcher->u.or.a, window_name, window_class) ||
+ meta_window_matcher_matches(matcher->u.or.b, window_name, window_class));
+ case MATCHER_NOT:
+ return !meta_window_matcher_matches (matcher->u.not.a, window_name, window_class);
+ case MATCHER_EQ:
+ if (matcher->u.eq.operand == MATCHER_OPERAND_NAME)
+ return window_name && strcmp (matcher->u.eq.str, window_name) == 0;
+ else
+ return window_class && strcmp (matcher->u.eq.str, window_class) == 0;
+ case MATCHER_GLOB:
+ if (matcher->u.glob.operand == MATCHER_OPERAND_NAME)
+ return window_name && g_pattern_match_string (matcher->u.glob.pattern, window_name);
+ else
+ return window_class && g_pattern_match_string (matcher->u.glob.pattern, window_class);
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean
+meta_window_matcher_list_matches (GSList *list,
+ const char *window_name,
+ const char *window_class)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next)
+ {
+ if (meta_window_matcher_matches (l->data, window_name, window_class))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static const GScannerConfig scanner_config =
+{
+ " \t\r\n" /* cset_skip_characters */,
+ (
+ G_CSET_a_2_z
+ "_"
+ G_CSET_A_2_Z
+ ) /* cset_identifier_first */,
+ (
+ G_CSET_a_2_z
+ "_"
+ G_CSET_A_2_Z
+ G_CSET_DIGITS
+ G_CSET_LATINS
+ G_CSET_LATINC
+ ) /* cset_identifier_nth */,
+ NULL /* cpair_comment_single */,
+ TRUE /* case_sensitive */,
+ TRUE /* skip_comment_multi */,
+ FALSE /* skip_comment_single */,
+ TRUE /* scan_comment_multi */,
+ TRUE /* scan_identifier */,
+ TRUE /* scan_identifier_1char */,
+ FALSE /* scan_identifier_NULL */,
+ TRUE /* scan_symbols */,
+ FALSE /* scan_binary */,
+ TRUE /* scan_octal */,
+ TRUE /* scan_float */,
+ TRUE /* scan_hex */,
+ FALSE /* scan_hex_dollar */,
+ TRUE /* scan_string_sq */,
+ TRUE /* scan_string_dq */,
+ TRUE /* numbers_2_int */,
+ FALSE /* int_2_float */,
+ FALSE /* identifier_2_string */,
+ TRUE /* char_2_token */,
+ TRUE /* symbol_2_token */,
+ FALSE /* scope_0_fallback */,
+ FALSE /* store_int64 */,
+};
+
+static void
+set_error (GScanner *scanner,
+ GError **error,
+ const char *message)
+{
+ g_set_error (error, 0, 0,
+ "Parse error at %d:%d: %s",
+ g_scanner_cur_line (scanner),
+ g_scanner_cur_position (scanner),
+ message);
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_new_and (MetaWindowMatcher *a,
+ MetaWindowMatcher *b)
+{
+ MetaWindowMatcher *matcher = g_slice_new0 (MetaWindowMatcher);
+
+ matcher->type = MATCHER_AND;
+ matcher->u.and.a = a;
+ matcher->u.and.b = b;
+
+ return matcher;
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_new_or (MetaWindowMatcher *a,
+ MetaWindowMatcher *b)
+{
+ MetaWindowMatcher *matcher = g_slice_new0 (MetaWindowMatcher);
+
+ matcher->type = MATCHER_OR;
+ matcher->u.or.a = a;
+ matcher->u.or.b = b;
+
+ return matcher;
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_new_not (MetaWindowMatcher *a)
+{
+ MetaWindowMatcher *matcher = g_slice_new0 (MetaWindowMatcher);
+
+ matcher->type = MATCHER_NOT;
+ matcher->u.not.a = a;
+
+ return matcher;
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_new_eq (MatcherOperand operand,
+ const char *str)
+{
+ MetaWindowMatcher *matcher = g_slice_new0 (MetaWindowMatcher);
+
+ matcher->type = MATCHER_EQ;
+ matcher->u.eq.operand = operand;
+ matcher->u.eq.str = g_strdup (str);
+
+ return matcher;
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_new_glob (MatcherOperand operand,
+ const char *str)
+{
+ MetaWindowMatcher *matcher = g_slice_new0 (MetaWindowMatcher);
+
+ matcher->type = MATCHER_GLOB;
+ matcher->u.glob.operand = operand;
+ matcher->u.glob.str = g_strdup (str);
+ matcher->u.glob.pattern = g_pattern_spec_new (str);
+
+ return matcher;
+}
+
+static MetaWindowMatcher *
+meta_window_matcher_from_scanner (GScanner *scanner,
+ GError **error)
+{
+ MetaWindowMatcher *matcher = NULL;
+ GTokenType token;
+ GTokenValue value;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_LEFT_PAREN)
+ {
+ set_error (scanner, error, "expected '('");
+ return NULL;
+ }
+
+ token = g_scanner_get_next_token (scanner);
+ switch ((MatcherToken) token)
+ {
+ case MATCHER_TOKEN_AND:
+ case MATCHER_TOKEN_OR:
+ case MATCHER_TOKEN_NOT:
+ {
+ MetaWindowMatcher *a, *b;
+
+ a = meta_window_matcher_from_scanner (scanner, error);
+ if (!a)
+ return NULL;
+
+ if ((MatcherToken) token != MATCHER_TOKEN_NOT)
+ {
+ b = meta_window_matcher_from_scanner (scanner, error);
+ if (!b)
+ {
+ meta_window_matcher_free (a);
+ return NULL;
+ }
+ }
+
+ switch ((MatcherToken) token)
+ {
+ case MATCHER_TOKEN_AND:
+ matcher = meta_window_matcher_new_and (a, b);
+ break;
+ case MATCHER_TOKEN_OR:
+ matcher = meta_window_matcher_new_or (a, b);
+ break;
+ case MATCHER_TOKEN_NOT:
+ matcher = meta_window_matcher_new_not (a);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+ break;
+ case MATCHER_TOKEN_EQ:
+ case MATCHER_TOKEN_GLOB:
+ {
+ MatcherOperand operand;
+
+ switch ((MatcherToken) g_scanner_get_next_token (scanner))
+ {
+ case MATCHER_TOKEN_NAME:
+ operand = MATCHER_OPERAND_NAME;
+ break;
+ case MATCHER_TOKEN_CLASS:
+ operand = MATCHER_OPERAND_CLASS;
+ break;
+ default:
+ set_error (scanner, error, "expected name/class");
+ return NULL;
+ }
+
+ if (g_scanner_get_next_token (scanner) != G_TOKEN_STRING)
+ {
+ set_error (scanner, error, "expected string");
+ return NULL;
+ }
+
+ value = g_scanner_cur_value (scanner);
+
+ switch ((MatcherToken) token)
+ {
+ case MATCHER_TOKEN_EQ:
+ matcher = meta_window_matcher_new_eq (operand, value.v_string);
+ break;
+ case MATCHER_TOKEN_GLOB:
+ matcher = meta_window_matcher_new_glob (operand, value.v_string);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
+ default:
+ set_error (scanner, error, "expected and/or/not/eq/glob");
+ return NULL;
+ }
+
+ if (g_scanner_get_next_token (scanner) != G_TOKEN_RIGHT_PAREN)
+ {
+ set_error (scanner, error, "expected ')'");
+ return NULL;
+ }
+
+ return matcher;
+}
+
+GSList *
+meta_window_matcher_list_from_string (const char *str,
+ GError **error)
+{
+ GScanner *scanner = g_scanner_new (&scanner_config);
+ GSList *result = NULL;
+
+ g_scanner_scope_add_symbol (scanner, 0, "and", GINT_TO_POINTER (MATCHER_TOKEN_AND));
+ g_scanner_scope_add_symbol (scanner, 0, "or", GINT_TO_POINTER (MATCHER_TOKEN_OR));
+ g_scanner_scope_add_symbol (scanner, 0, "not", GINT_TO_POINTER (MATCHER_TOKEN_NOT));
+ g_scanner_scope_add_symbol (scanner, 0, "eq", GINT_TO_POINTER (MATCHER_TOKEN_EQ));
+ g_scanner_scope_add_symbol (scanner, 0, "glob", GINT_TO_POINTER (MATCHER_TOKEN_GLOB));
+ g_scanner_scope_add_symbol (scanner, 0, "name", GINT_TO_POINTER (MATCHER_TOKEN_NAME));
+ g_scanner_scope_add_symbol (scanner, 0, "class", GINT_TO_POINTER (MATCHER_TOKEN_CLASS));
+
+ g_scanner_input_text (scanner, str, strlen (str));
+
+ while (g_scanner_peek_next_token (scanner) != G_TOKEN_EOF)
+ {
+ MetaWindowMatcher *matcher = meta_window_matcher_from_scanner (scanner, error);
+ if (!matcher)
+ {
+ meta_window_matcher_list_free (result);
+ return NULL;
+ }
+
+ result = g_slist_prepend (result, matcher);
+ }
+
+ g_scanner_destroy (scanner);
+
+ return g_slist_reverse (result);
+}
+
+#ifdef BUILD_MATCHER_TESTS
+
+static void
+append_operand_to_string (GString *string,
+ MatcherOperand operand)
+{
+ if (operand == MATCHER_OPERAND_NAME)
+ g_string_append (string, "name");
+ else
+ g_string_append (string, "class");
+}
+
+static void
+append_string_to_string (GString *str,
+ const char *to_append)
+{
+ const char *p;
+
+ g_string_append_c (str, '"');
+ for (p = to_append; *p; p++)
+ {
+ if (*p == '"')
+ g_string_append (str, "\\\"");
+ else
+ g_string_append_c (str, *p);
+ }
+ g_string_append_c (str, '"');
+}
+
+static void
+append_matcher_to_string (GString *str,
+ MetaWindowMatcher *matcher)
+{
+ switch (matcher->type)
+ {
+ case MATCHER_AND:
+ g_string_append (str, "(and ");
+ append_matcher_to_string (str, matcher->u.and.a);
+ g_string_append_c (str, ' ');
+ append_matcher_to_string (str, matcher->u.and.b);
+ break;
+ case MATCHER_OR:
+ g_string_append (str, "(or ");
+ append_matcher_to_string (str, matcher->u.or.a);
+ g_string_append_c (str, ' ');
+ append_matcher_to_string (str, matcher->u.or.b);
+ break;
+ case MATCHER_NOT:
+ g_string_append (str, "(not ");
+ append_matcher_to_string (str, matcher->u.not.a);
+ break;
+ case MATCHER_EQ:
+ g_string_append (str, "(eq ");
+ append_operand_to_string (str, matcher->u.eq.operand);
+ g_string_append_c (str, ' ');
+ append_string_to_string (str, matcher->u.eq.str);
+ break;
+ case MATCHER_GLOB:
+ g_string_append (str, "(glob ");
+ append_operand_to_string (str, matcher->u.glob.operand);
+ g_string_append_c (str, ' ');
+ append_string_to_string (str, matcher->u.glob.str);
+ break;
+ }
+
+ g_string_append_c (str, ')');
+}
+
+static char *
+meta_window_matcher_list_to_string (GSList *list)
+{
+ GSList *l;
+ GString *str = g_string_new (NULL);
+
+ for (l = list; l; l = l->next)
+ {
+ if (str->len > 0)
+ g_string_append_c (str, ' ');
+
+ append_matcher_to_string (str, l->data);
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static void
+test_roundtrip (const char *str)
+{
+ GError *error = NULL;
+ GSList *list = meta_window_matcher_list_from_string (str, &error);
+ char *result;
+
+ if (error != NULL)
+ g_error ("Failed to parse '%s': %s\n", str, error->message);
+
+ result = meta_window_matcher_list_to_string (list);
+ if (strcmp (result, str) != 0)
+ g_error ("Round-trip conversion of '%s' gave '%s'\n", str, result);
+
+ g_free (result);
+ meta_window_matcher_list_free (list);
+}
+
+static void
+test_matches (const char *str,
+ const char *window_name,
+ const char *window_class,
+ gboolean expected)
+{
+ GError *error = NULL;
+ GSList *list = meta_window_matcher_list_from_string (str, &error);
+ gboolean matches;
+
+ if (error != NULL)
+ g_error ("Failed to parse '%s': %s\n", str, error->message);
+
+ matches = meta_window_matcher_list_matches (list, window_name, window_class))
+ if (matches != expected)
+ {
+ g_error ("Tested '%s' against name=%s, class=%s, expected %s, got %s\n",
+ str, window_name, window_class,
+ expected ? "true" : "false",
+ matches ? "true" : "false");
+ }
+
+
+ meta_window_matcher_list_free (list);
+}
+
+int main (int argc, char **argv)
+{
+ test_roundtrip ("(eq name \"foo\")");
+ test_roundtrip ("(eq name \"fo\\\"o\")");
+ test_roundtrip ("(glob class \"*bar?baz\")");
+ test_roundtrip ("(and (eq name \"foo\") (glob class \"*bar?baz\"))");
+ test_roundtrip ("(or (eq name \"foo\") (glob class \"*bar?baz\"))");
+ test_roundtrip ("(not (eq name \"foo\"))");
+
+ test_roundtrip ("(eq name \"foo\") (glob class \"*bar?baz\")");
+
+ test_matches ("(eq name 'foo')", "foo", NULL, TRUE);
+ test_matches ("(eq name 'foo')", "foob", NULL, FALSE);
+ test_matches ("(eq name 'foo')", NULL, NULL, FALSE);
+ test_matches ("(eq class 'bar')", "foo", "bar", TRUE);
+ test_matches ("(eq class 'bar')", NULL, NULL, FALSE);
+
+ test_matches ("(glob name 'foo*')", "foooo", NULL, TRUE);
+ test_matches ("(glob name 'foo*')", NULL, NULL, FALSE);
+ test_matches ("(glob class 'b*r')", "foooo", "baaaar", TRUE);
+ test_matches ("(glob class 'b*r')", NULL, NULL, FALSE);
+
+ test_matches ("(and (eq name 'foo') (eq class 'bar'))", "foo", "bar", TRUE);
+ test_matches ("(and (eq name 'foo') (eq class 'bar'))", "foo", "baz", FALSE);
+ test_matches ("(and (eq name 'foo') (not (eq class 'bar')))", "foo", "bar", FALSE);
+ test_matches ("(and (eq name 'foo') (not (eq class 'bar')))", "foo", "baz", TRUE);
+
+ test_matches ("(or (eq name 'foo') (eq class 'bar'))", "foo", "baz", TRUE);
+ test_matches ("(or (eq name 'foo') (eq class 'bar'))", "fof", "baz", FALSE);
+
+ return 0;
+}
+
+#endif /* BUILD_MATCHER_TESTS */
diff --git a/src/core/window-matcher.h b/src/core/window-matcher.h
new file mode 100644
index 0000000..7fc7826
--- /dev/null
+++ b/src/core/window-matcher.h
@@ -0,0 +1,46 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Tiny language for matching against windows
+ *
+ * Expression Syntax:
+ *
+ * (and <expr> <expr>)
+ * (or <expr> <expr>)
+ * (not <expr>)
+ * (eq [name|class] "<value>")
+ * (glob [name|class] "<glob>")
+ *
+ * A "matcher list" is a whitespace-separated list of expressions that are
+ * implicitly or'ed together. Globs are shell style patterns with
+ * matching 0 or more characters and ? matching one character.
+ */
+
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_WINDOW_MATCHER_H
+#define META_WINDOW_MATCHER_H
+
+GSList * meta_window_matcher_list_from_string (const char *str,
+ GError **error);
+void meta_window_matcher_list_free (GSList *list);
+gboolean meta_window_matcher_list_matches (GSList *list,
+ const char *window_name,
+ const char *window_class);
+#endif /* META_WINDOW_MATCHER_H */
diff --git a/src/core/window.c b/src/core/window.c
index 2f2f800..5440160 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1981,7 +1981,14 @@ window_state_on_map (MetaWindow *window,
{
gboolean intervening_events;
- intervening_events = intervening_user_event_occurred (window);
+ /* A 'no focus' window is a window that has been configured in GConf
+ * to never take focus on map; typically it will be a notification
+ * window from a legacy app that doesn't support _NET_WM_USER_TIME.
+ */
+ if (meta_prefs_window_is_no_focus (window->title, window->res_class))
+ intervening_events = TRUE;
+ else
+ intervening_events = intervening_user_event_occurred (window);
*takes_focus = !intervening_events;
*places_on_top = *takes_focus;
diff --git a/src/include/prefs.h b/src/include/prefs.h
index 673cb36..b86843c 100644
--- a/src/include/prefs.h
+++ b/src/include/prefs.h
@@ -60,7 +60,8 @@ typedef enum
META_PREF_CURSOR_SIZE,
META_PREF_COMPOSITING_MANAGER,
META_PREF_RESIZE_WITH_RIGHT_BUTTON,
- META_PREF_FORCE_FULLSCREEN
+ META_PREF_FORCE_FULLSCREEN,
+ META_PREF_NO_FOCUS_WINDOWS
} MetaPreference;
typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
@@ -105,6 +106,9 @@ GDesktopTitlebarAction meta_prefs_get_action_double_click_titlebar (void);
GDesktopTitlebarAction meta_prefs_get_action_middle_click_titlebar (void);
GDesktopTitlebarAction meta_prefs_get_action_right_click_titlebar (void);
+gboolean meta_prefs_window_is_no_focus (const char *window_name,
+ const char *window_class);
+
void meta_prefs_set_num_workspaces (int n_workspaces);
const char* meta_prefs_get_workspace_name (int i);
diff --git a/src/metacity-schemas.convert b/src/metacity-schemas.convert
index 46f3104..9c271c6 100644
--- a/src/metacity-schemas.convert
+++ b/src/metacity-schemas.convert
@@ -1,3 +1,4 @@
[org.gnome.metacity]
compositing-manager = /apps/metacity/general/compositing_manager
reduced-resources = /apps/metacity/general/reduced_resources
+no-focus-windows = /apps/metacity/general/no_focus_windows
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index 8fcdd7c..6900fa6 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -22,6 +22,27 @@
However, the wireframe feature is disabled when accessibility is on.
</_description>
</key>
+ <key name="no-focus-windows" type="s">
+ <default>''</default>
+ <_summary>New windows that shouldn't get focus</_summary>
+ <_description>
+ This option provides a way to specify new windows that shouldn't get
+ focus. Normally an application specifies whether or not it gets focus
+ by setting the _NET_WM_USER_TIME property, but legacy applications
+ may not set this, which can cause unwanted focus stealing.
+
+ The contents of this property is a space-separated list of expressions
+ to match against windows. If any of the expressions match a window
+ then the window will not get focus. The syntax of expressions is:
+
+ (eq [name|class] "&lt;value&gt;"): window name (title) or the class from
+ WM_CLASS matches &lt;value&gt; exactly.
+ (glob [name|class] "&lt;glob&gt;"): window name (title) or the class from
+ WM_CLASS matches the shell-style glob pattern &lt;glob&gt;.
+ (and &lt;expr&gt; &lt;expr&gt;) (or &lt;expr&gt; &lt;expr&gt;) (not &lt;expr): Boolean combinations
+ of expressions.
+ </_description>
+ </key>
</schema>
</schemalist>
--
1.7.9

View File

@ -1,414 +0,0 @@
From 00d291927a59b6bca164fc5cd2d4729604b40d1c Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 23 Jun 2010 15:08:38 -0400
Subject: [PATCH] Allow breaking out from maximization during a mouse
resize
A maximized window can't be resized from the screen edges (preserves
Fitts law goodness for the application), but it's still possible
to start a resize drag with alt-middle-button. Currently we just
don't let the user resize the window, while showing drag feedback;
it's more useful to let the user "break" out from the resize.
This provides a fast way to get a window partially aligned with
the screen edges - maximize, then alt-drag it out from one edge.
Behavior choices in this patch:
- You can drag out a window out of maximization in both directions -
smaller and larger. This can be potentilaly useful in multihead.
- Dragging a window in only one direction unmaximizes the window
fully, rather than leaving it in a horizontally/vertically
maximized state. This is done because the horizontally/vertically
maximzed states don't have clear visual representation and can
be confusing to the user.
- If you drag back to the maximized state after breaking out,
maximization is restored, but you can't maximize a window by
dragging to the full size if it didn't start out that way.
A new internal function meta_window_unmaximize_with_gravity() is
added for implementing this; it's a hybrid of
meta_window_unmaximize() and meta_window_resize_with_gravity().
https://bugzilla.gnome.org/show_bug.cgi?id=622517
---
src/core/display-private.h | 3 +
src/core/display.c | 20 +++-
src/core/window-private.h | 5 +
src/core/window.c | 224 ++++++++++++++++++++++++++++++++++++++++----
4 files changed, 228 insertions(+), 24 deletions(-)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 7f779fd..bb6ba8a 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -178,6 +178,9 @@ struct _MetaDisplay
guint grab_wireframe_active : 1;
guint grab_was_cancelled : 1; /* Only used in wireframe mode */
guint grab_frame_action : 1;
+ /* During a resize operation, the directions in which we've broken
+ * out of the initial maximization state */
+ guint grab_resize_unmaximize : 2; /* MetaMaximizeFlags */
MetaRectangle grab_wireframe_rect;
MetaRectangle grab_wireframe_last_xor_rect;
MetaRectangle grab_initial_window_pos;
diff --git a/src/core/display.c b/src/core/display.c
index 0c5f61d..25cf857 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -3470,6 +3470,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
#endif
display->grab_was_cancelled = FALSE;
display->grab_frame_action = frame_action;
+ display->grab_resize_unmaximize = 0;
if (display->grab_resize_timeout_id)
{
@@ -3700,11 +3701,20 @@ meta_display_end_grab_op (MetaDisplay *display,
display->grab_wireframe_rect.x,
display->grab_wireframe_rect.y);
if (meta_grab_op_is_resizing (display->grab_op))
- meta_window_resize_with_gravity (display->grab_window,
- TRUE,
- display->grab_wireframe_rect.width,
- display->grab_wireframe_rect.height,
- meta_resize_gravity_from_grab_op (display->grab_op));
+ {
+ if (display->grab_resize_unmaximize != 0)
+ meta_window_unmaximize_with_gravity (display->grab_window,
+ display->grab_resize_unmaximize,
+ display->grab_wireframe_rect.width,
+ display->grab_wireframe_rect.height,
+ meta_resize_gravity_from_grab_op (display->grab_op));
+ else
+ meta_window_resize_with_gravity (display->grab_window,
+ TRUE,
+ display->grab_wireframe_rect.width,
+ display->grab_wireframe_rect.height,
+ meta_resize_gravity_from_grab_op (display->grab_op));
+ }
}
meta_window_calc_showing (display->grab_window);
}
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 7cf5b04..2c07e85 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -412,6 +412,11 @@ void meta_window_maximize_internal (MetaWindow *window,
MetaRectangle *saved_rect);
void meta_window_unmaximize (MetaWindow *window,
MetaMaximizeFlags directions);
+void meta_window_unmaximize_with_gravity (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ int new_width,
+ int new_height,
+ int gravity);
void meta_window_make_above (MetaWindow *window);
void meta_window_unmake_above (MetaWindow *window);
void meta_window_shade (MetaWindow *window,
diff --git a/src/core/window.c b/src/core/window.c
index 897161e..427f91f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2693,9 +2693,11 @@ unmaximize_window_before_freeing (MetaWindow *window)
}
}
-void
-meta_window_unmaximize (MetaWindow *window,
- MetaMaximizeFlags directions)
+static void
+meta_window_unmaximize_internal (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ MetaRectangle *desired_rect,
+ int gravity)
{
/* At least one of the two directions ought to be set */
gboolean unmaximize_horizontally, unmaximize_vertically;
@@ -2729,13 +2731,13 @@ meta_window_unmaximize (MetaWindow *window,
meta_window_get_client_root_coords (window, &target_rect);
if (unmaximize_horizontally)
{
- target_rect.x = window->saved_rect.x;
- target_rect.width = window->saved_rect.width;
+ target_rect.x = desired_rect->x;
+ target_rect.width = desired_rect->width;
}
if (unmaximize_vertically)
{
- target_rect.y = window->saved_rect.y;
- target_rect.height = window->saved_rect.height;
+ target_rect.y = desired_rect->y;
+ target_rect.height = desired_rect->height;
}
/* Window's size hints may have changed while maximized, making
@@ -2754,12 +2756,13 @@ meta_window_unmaximize (MetaWindow *window,
window->display->grab_anchor_window_pos = target_rect;
}
- meta_window_move_resize (window,
- FALSE,
- target_rect.x,
- target_rect.y,
- target_rect.width,
- target_rect.height);
+ meta_window_move_resize_internal (window,
+ META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
+ gravity,
+ target_rect.x,
+ target_rect.y,
+ target_rect.width,
+ target_rect.height);
/* Make sure user_rect is current.
*/
@@ -2776,6 +2779,36 @@ meta_window_unmaximize (MetaWindow *window,
}
void
+meta_window_unmaximize (MetaWindow *window,
+ MetaMaximizeFlags directions)
+{
+ meta_window_unmaximize_internal (window, directions, &window->saved_rect,
+ NorthWestGravity);
+}
+
+/* Like meta_window_unmaximize(), but instead of unmaximizing to the
+ * saved position, we give the new desired size, and the gravity that
+ * determines the positioning relationship between the area occupied
+ * maximized and the new are. The arguments are similar to
+ * meta_window_resize_with_gravity().
+ */
+void
+meta_window_unmaximize_with_gravity (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ int new_width,
+ int new_height,
+ int gravity)
+{
+ MetaRectangle desired_rect;
+
+ meta_window_get_position (window, &desired_rect.x, &desired_rect.y);
+ desired_rect.width = new_width;
+ desired_rect.height = new_height;
+
+ meta_window_unmaximize_internal (window, directions, &desired_rect, gravity);
+}
+
+void
meta_window_make_above (MetaWindow *window)
{
window->wm_state_above = TRUE;
@@ -7124,6 +7157,112 @@ update_resize_timeout (gpointer data)
return FALSE;
}
+/* When resizing a maximized window by using alt-middle-drag (resizing
+ * with the grips or the menu for a maximized window is not enabled),
+ * the user can "break" out of the maximized state. This checks for
+ * that possibility. During such a break-out resize the user can also
+ * return to the previous maximization state by resizing back to near
+ * the original size.
+ */
+static MetaMaximizeFlags
+check_resize_unmaximize(MetaWindow *window,
+ int dx,
+ int dy)
+{
+ int threshold;
+ MetaMaximizeFlags new_unmaximize;
+
+#define DRAG_THRESHOLD_TO_RESIZE_THRESHOLD_FACTOR 3
+
+ threshold = meta_ui_get_drag_threshold (window->screen->ui) *
+ DRAG_THRESHOLD_TO_RESIZE_THRESHOLD_FACTOR;
+ new_unmaximize = 0;
+
+ if (window->maximized_horizontally ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0)
+ {
+ int x_amount;
+
+ /* We allow breaking out of maximization in either direction, to make
+ * the window larger than the monitor as well as smaller than the
+ * monitor. If we wanted to only allow resizing smaller than the
+ * monitor, we'd use - dx for NE/E/SE and dx for SW/W/NW.
+ */
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_NE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+ case META_GRAB_OP_RESIZING_E:
+ case META_GRAB_OP_KEYBOARD_RESIZING_E:
+ case META_GRAB_OP_RESIZING_SE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SE:
+ case META_GRAB_OP_RESIZING_SW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ case META_GRAB_OP_RESIZING_W:
+ case META_GRAB_OP_KEYBOARD_RESIZING_W:
+ case META_GRAB_OP_RESIZING_NW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+ x_amount = dx < 0 ? - dx : dx;
+ break;
+ default:
+ x_amount = 0;
+ break;
+ }
+
+ if (x_amount > threshold)
+ new_unmaximize |= META_MAXIMIZE_HORIZONTAL;
+ }
+
+ if (window->maximized_vertically ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0)
+ {
+ int y_amount;
+
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_N:
+ case META_GRAB_OP_KEYBOARD_RESIZING_N:
+ case META_GRAB_OP_RESIZING_NE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+ case META_GRAB_OP_RESIZING_NW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+ case META_GRAB_OP_RESIZING_SE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SE:
+ case META_GRAB_OP_RESIZING_S:
+ case META_GRAB_OP_KEYBOARD_RESIZING_S:
+ case META_GRAB_OP_RESIZING_SW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ y_amount = dy < 0 ? - dy : dy;
+ break;
+ default:
+ y_amount = 0;
+ break;
+ }
+
+ if (y_amount > threshold)
+ new_unmaximize |= META_MAXIMIZE_VERTICAL;
+ }
+
+ /* Metacity doesn't have a full user interface for only horizontally or
+ * vertically maximized, so while only unmaximizing in the direction drags
+ * has some advantages, it will also confuse the user. So, we always
+ * unmaximize both ways if possible.
+ */
+ if (new_unmaximize != 0)
+ {
+ new_unmaximize = 0;
+
+ if (window->maximized_horizontally ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0)
+ new_unmaximize |= META_MAXIMIZE_HORIZONTAL;
+ if (window->maximized_vertically ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0)
+ new_unmaximize |= META_MAXIMIZE_VERTICAL;
+ }
+
+ return new_unmaximize;
+}
+
static void
update_resize (MetaWindow *window,
gboolean snap,
@@ -7136,6 +7275,7 @@ update_resize (MetaWindow *window,
MetaRectangle old;
int new_x, new_y;
double remaining;
+ MetaMaximizeFlags new_unmaximize;
window->display->grab_latest_motion_x = x;
window->display->grab_latest_motion_y = y;
@@ -7200,7 +7340,9 @@ update_resize (MetaWindow *window,
meta_window_update_keyboard_resize (window, TRUE);
}
}
-
+
+ new_unmaximize = check_resize_unmaximize (window, dx, dy);
+
/* FIXME: This stupidity only needed because of wireframe mode and
* the fact that wireframe isn't making use of
* meta_rectangle_resize_with_gravity(). If we were to use that, we
@@ -7324,6 +7466,8 @@ update_resize (MetaWindow *window,
if (window->display->grab_wireframe_active)
{
+ MetaRectangle root_coords;
+
if ((new_x + new_w <= new_x) || (new_y + new_h <= new_y))
return;
@@ -7333,18 +7477,60 @@ update_resize (MetaWindow *window,
* wireframe, but still resize it; however, that probably
* confuses broken clients that have problems with opaque
* resize, they probably don't track their visibility.
+ *
+ * We handle the basic constraints on maximized windows here
+ * to give the user feedback.
*/
+
+ if (window->maximized_horizontally && (new_unmaximize & META_MAXIMIZE_HORIZONTAL) == 0)
+ {
+ meta_window_get_client_root_coords (window, &root_coords);
+ new_x = root_coords.x;
+ new_w = root_coords.width;
+ }
+ if (window->maximized_vertically && (new_unmaximize & META_MAXIMIZE_VERTICAL) == 0)
+ {
+ meta_window_get_client_root_coords (window, &root_coords);
+ new_y = root_coords.y;
+ new_h = root_coords.height;
+ }
+
meta_window_update_wireframe (window, new_x, new_y, new_w, new_h);
}
else
{
- /* We don't need to update unless the specified width and height
- * are actually different from what we had before.
- */
- if (old.width != new_w || old.height != new_h)
- meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
+ if (new_unmaximize == window->display->grab_resize_unmaximize)
+ {
+ /* We don't need to update unless the specified width and height
+ * are actually different from what we had before.
+ */
+ if (old.width != new_w || old.height != new_h)
+ {
+ if ((window->display->grab_resize_unmaximize == new_unmaximize))
+ meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
+ }
+ }
+ else
+ {
+ if ((new_unmaximize & ~window->display->grab_resize_unmaximize) != 0)
+ {
+ meta_window_unmaximize_with_gravity (window,
+ (new_unmaximize & ~window->display->grab_resize_unmaximize),
+ new_w, new_h, gravity);
+ }
+
+ if ((window->display->grab_resize_unmaximize & ~new_unmaximize))
+ {
+ MetaRectangle saved_rect = window->saved_rect;
+ meta_window_maximize (window,
+ (window->display->grab_resize_unmaximize & ~new_unmaximize));
+ window->saved_rect = saved_rect;
+ }
+ }
}
+ window->display->grab_resize_unmaximize = new_unmaximize;
+
/* Store the latest resize time, if we actually resized. */
if (window->rect.width != old.width || window->rect.height != old.height)
g_get_current_time (&window->display->grab_last_moveresize_time);
--
1.7.9

View File

@ -1,113 +0,0 @@
From 2bd938c957b27c1055f7f235939c9b8b338d5cbf Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 23 Jun 2010 19:45:05 -0400
Subject: [PATCH] Apply new-windows-always-on-top to newly
raised/activated windows
A window that raises itself or activates itself is in many ways
like a completely new window. (Once a window is out of the user's
site, they really have no idea if it's mapped or has been withdrawn
by the user.)
If the user has set the new-windows-always-on-top key to make the
behavior for a focus-stealing-prevented *new* window "raise but not
focus", then they'll want the same behavior in the case of
windows that attempt to raise or activate themselves as well.
https://bugzilla.gnome.org/show_bug.cgi?id=599261
---
src/core/window.c | 35 +++++++++++++++++++++++++++++---
src/org.gnome.metacity.gschema.xml.in | 6 +++++
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/src/core/window.c b/src/core/window.c
index b6a69b0..897161e 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2970,6 +2970,8 @@ window_activate (MetaWindow *window,
MetaWorkspace *workspace)
{
gboolean can_ignore_outdated_timestamps;
+ gboolean only_raise = FALSE;
+
meta_topic (META_DEBUG_FOCUS,
"_NET_ACTIVE_WINDOW message sent for %s at time %u "
"by client type %u.\n",
@@ -2991,8 +2993,28 @@ window_activate (MetaWindow *window,
"last_user_time (%u) is more recent; ignoring "
" _NET_ACTIVE_WINDOW message.\n",
window->display->last_user_time);
- meta_window_set_demands_attention(window);
- return;
+ if (meta_prefs_get_new_windows_always_on_top () &&
+ meta_prefs_get_raise_on_click ())
+ {
+ /* The new_windows_only_on_top preference causes new
+ * focus-denied windows to get raised but not focused
+ * instead of set to demands attention. For consistency, we
+ * do the same here with windows that are "new to the user"
+ * - that self activate and are focus-stealing prevented. We
+ * can't just raise the window and return here because the
+ * window might be on a different workspace, so we need the
+ * handling below. The check for meta_prefs_get_raise_on_click ()
+ * is because that preference, if off, somewhat unexpectedl
+ * akes windows not raise on self-activation. If that is changed
+ * than the test should be removed here.
+ */
+ only_raise = TRUE;
+ }
+ else
+ {
+ meta_window_set_demands_attention (window);
+ return;
+ }
}
/* For those stupid pagers, get a valid timestamp and show a warning */
@@ -3041,7 +3063,8 @@ window_activate (MetaWindow *window,
meta_topic (META_DEBUG_FOCUS,
"Focusing window %s due to activation\n",
window->desc);
- meta_window_focus (window, timestamp);
+ if (!only_raise)
+ meta_window_focus (window, timestamp);
}
/* This function exists since most of the functionality in window_activate
@@ -4759,11 +4782,15 @@ meta_window_configure_request (MetaWindow *window,
"broken behavior and the request is being ignored.\n",
window->desc);
}
+ /* the new_windows_always_on_top check is because a window that
+ * spontaneously restacks itself to the top is a lot like a new
+ * window that doesn't get focus */
else if (active_window &&
!meta_window_same_application (window, active_window) &&
!meta_window_same_client (window, active_window) &&
XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,
- active_window->net_wm_user_time))
+ active_window->net_wm_user_time) &&
+ !meta_prefs_get_new_windows_always_on_top ())
{
meta_topic (META_DEBUG_STACK,
"Ignoring xconfigure stacking request from %s (with "
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index d69d525..edc1b70 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -66,6 +66,12 @@
invariant in the 'click' focus mode that the topmost window always
has focus, so its most suitable for use with the 'mouse' and
'sloppy' focus modes.
+
+ This key also affects windows that try to activate or raise themselves
+ themselves but don't succeed in getting the the focus. Without
+ this key being set, such windows are flashed in the taskbar. With
+ this key set they, like entirely new windows, are raised but not
+ focused.
</_description>
</key>
</schema>
--
1.7.9

View File

@ -1,69 +0,0 @@
From 3a8164d5ddf688db9cb00657861351febf013e72 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 23 Jun 2010 16:49:37 -0400
Subject: [PATCH] Exclude the current application from no-focus-windows
setting
The idea of the no-focus-windows setting is to allow identifying
legacy application windows that are stealing focus from other
applications and suppress that behavior. Sometimes its not possible to
identify specific problem windows of an application and its
necessary to blanket add all windows of the application. In this
case no-focus-windows can disrupt the internal flow of focus
within the application.
On the assumption that apps internally handle focus correctly
and have been tested not to steal focus from themselves at
annoying times, we exclude windows of the the current application
from no-focus-windows.
https://bugzilla.gnome.org/show_bug.cgi?id=599248
---
src/core/window.c | 11 ++++++++++-
src/org.gnome.metacity.gschema.xml.in | 3 +++
2 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/src/core/window.c b/src/core/window.c
index 5440160..6f5c280 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1980,12 +1980,21 @@ window_state_on_map (MetaWindow *window,
gboolean *places_on_top)
{
gboolean intervening_events;
+ MetaWindow *focus_window;
/* A 'no focus' window is a window that has been configured in GConf
* to never take focus on map; typically it will be a notification
* window from a legacy app that doesn't support _NET_WM_USER_TIME.
+ *
+ * This doesn't apply to applications taking focus from themselves;
+ * the assumption is applications have been properly tested to internally
+ * handle focus properly.
*/
- if (meta_prefs_window_is_no_focus (window->title, window->res_class))
+ focus_window = window->display->focus_window;
+ if (focus_window &&
+ !meta_window_same_application (window, focus_window) &&
+ !meta_window_same_client (window, focus_window) &&
+ meta_prefs_window_is_no_focus (window->title, window->res_class))
intervening_events = TRUE;
else
intervening_events = intervening_user_event_occurred (window);
diff --git a/src/org.gnome.metacity.gschema.xml.in b/src/org.gnome.metacity.gschema.xml.in
index 6900fa6..e4f86bd 100644
--- a/src/org.gnome.metacity.gschema.xml.in
+++ b/src/org.gnome.metacity.gschema.xml.in
@@ -41,6 +41,9 @@
WM_CLASS matches the shell-style glob pattern &lt;glob&gt;.
(and &lt;expr&gt; &lt;expr&gt;) (or &lt;expr&gt; &lt;expr&gt;) (not &lt;expr): Boolean combinations
of expressions.
+
+ New windows from the current active application are unaffected by
+ this setting.
</_description>
</key>
</schema>
--
1.7.9

View File

@ -1,396 +0,0 @@
From a24b336303c50e74f7d5e8582049dfae0d70329d Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Tue, 20 Oct 2009 15:13:45 -0400
Subject: [PATCH] For mouse and sloppy focus, return to "mouse mode" on
motion
For mouse and sloppy focus, there are various cases where the focus
window can be moved away from the focus window. Mostly these relate
to "display->mouse_mode = FALSE", which we enter when the user
starts keynav'ing, but it can also occur if a window is focus-denied
mapped and mapped under the pointer.
Prior to this patch, there was no fast way for the user to start
interacting with the window - if they just clicked on the window,
the click would be passed through, and could disturb the windows
contents, so the user had to either mouse out and then mouse back
in, or go up and click on the titlebar.
With this patch, when we get into this state, we add a timeout
and poll for pointer motion with XQueryPointer. If the user then
moves the pointer (more than a single pixel to handle jitter),
we focus the window under the pointer and return to mouse mode.
https://bugzilla.gnome.org/show_bug.cgi?id=599097
---
src/core/display-private.h | 11 ++
src/core/display.c | 239 +++++++++++++++++++++++++++++++++++--------
src/core/keybindings.c | 10 +-
3 files changed, 210 insertions(+), 50 deletions(-)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index feee851..fee321c 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -150,6 +150,14 @@ struct _MetaDisplay
guint autoraise_timeout_id;
MetaWindow* autoraise_window;
+ /* When we ignore an enter due to !display->mouse_mode, a timeout
+ * to check if the mouse is moved, in which case we should focus
+ * the pointer window and return to mouse mode */
+ guint focus_on_motion_timeout_id;
+ Window focus_on_motion_start_root_window;
+ int focus_on_motion_start_x;
+ int focus_on_motion_start_y;
+
/* Alt+click button grabs */
unsigned int window_grab_modifiers;
@@ -501,4 +509,7 @@ void meta_display_remove_autoraise_callback (MetaDisplay *display);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
+void meta_display_disable_mouse_mode (MetaDisplay *display);
+void meta_display_enable_mouse_mode (MetaDisplay *display);
+
#endif
diff --git a/src/core/display.c b/src/core/display.c
index 2e959b6..5bcf025 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -165,6 +165,9 @@ static void sanity_check_timestamps (MetaDisplay *display,
MetaGroup* get_focussed_group (MetaDisplay *display);
+static void start_focus_on_motion (MetaDisplay *display);
+static void stop_focus_on_motion (MetaDisplay *display);
+
/**
* Destructor for MetaPingData structs. Will destroy the
* event source for the struct as well.
@@ -876,6 +879,7 @@ meta_display_close (MetaDisplay *display,
meta_prefs_remove_listener (prefs_changed_callback, display);
meta_display_remove_autoraise_callback (display);
+ stop_focus_on_motion (display);
if (display->grab_old_window_stacking)
g_list_free (display->grab_old_window_stacking);
@@ -1778,67 +1782,86 @@ event_callback (XEvent *event,
if (window && !serial_is_ignored (display, event->xany.serial) &&
event->xcrossing.mode != NotifyGrab &&
event->xcrossing.mode != NotifyUngrab &&
- event->xcrossing.detail != NotifyInferior &&
- meta_display_focus_sentinel_clear (display))
+ event->xcrossing.detail != NotifyInferior)
{
switch (meta_prefs_get_focus_mode ())
{
case G_DESKTOP_FOCUS_MODE_SLOPPY:
case G_DESKTOP_FOCUS_MODE_MOUSE:
- display->mouse_mode = TRUE;
- if (window->type != META_WINDOW_DOCK &&
- window->type != META_WINDOW_DESKTOP)
+ if (!meta_display_focus_sentinel_clear (display))
{
- meta_topic (META_DEBUG_FOCUS,
- "Focusing %s due to enter notify with serial %lu "
- "at time %lu, and setting display->mouse_mode to "
- "TRUE.\n",
- window->desc,
- event->xany.serial,
- event->xcrossing.time);
-
- meta_window_focus (window, event->xcrossing.time);
-
- /* stop ignoring stuff */
- reset_ignores (display);
-
- if (meta_prefs_get_auto_raise ())
+ /* There was an enter event that we want to ignore because
+ * we're in "keynav mode" or because we are mapping
+ * a focus-denied window; the next time the mouse is moved
+ * we want to focus the window so the user doesn't have
+ * to click (possibly messing up window contents) or
+ * enter/leave to get focus to the window.
+ *
+ * (This check will also trigger for visual bell flashes
+ * but it doesn't really do any harm to check for motion
+ * in that case, since the next motion will just result in
+ * the current window being focused.)
+ */
+ start_focus_on_motion (display);
+ }
+ else
+ {
+ meta_display_enable_mouse_mode (display);
+ if (window->type != META_WINDOW_DOCK &&
+ window->type != META_WINDOW_DESKTOP)
{
- meta_display_queue_autoraise_callback (display, window);
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to enter notify with serial %lu "
+ "at time %lu, and setting display->mouse_mode to "
+ "TRUE.\n",
+ window->desc,
+ event->xany.serial,
+ event->xcrossing.time);
+
+ meta_window_focus (window, event->xcrossing.time);
+
+ /* stop ignoring stuff */
+ reset_ignores (display);
+
+ if (meta_prefs_get_auto_raise ())
+ {
+ meta_display_queue_autoraise_callback (display, window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Auto raise is disabled\n");
+ }
}
- else
+ /* In mouse focus mode, we defocus when the mouse *enters*
+ * the DESKTOP window, instead of defocusing on LeaveNotify.
+ * This is because having the mouse enter override-redirect
+ * child windows unfortunately causes LeaveNotify events that
+ * we can't distinguish from the mouse actually leaving the
+ * toplevel window as we expect. But, since we filter out
+ * EnterNotify events on override-redirect windows, this
+ * alternative mechanism works great.
+ */
+ if (window->type == META_WINDOW_DESKTOP &&
+ meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE &&
+ display->expected_focus_window != NULL)
{
meta_topic (META_DEBUG_FOCUS,
- "Auto raise is disabled\n");
+ "Unsetting focus from %s due to mouse entering "
+ "the DESKTOP window\n",
+ display->expected_focus_window->desc);
+ meta_display_focus_the_no_focus_window (display,
+ window->screen,
+ event->xcrossing.time);
}
}
- /* In mouse focus mode, we defocus when the mouse *enters*
- * the DESKTOP window, instead of defocusing on LeaveNotify.
- * This is because having the mouse enter override-redirect
- * child windows unfortunately causes LeaveNotify events that
- * we can't distinguish from the mouse actually leaving the
- * toplevel window as we expect. But, since we filter out
- * EnterNotify events on override-redirect windows, this
- * alternative mechanism works great.
- */
- if (window->type == META_WINDOW_DESKTOP &&
- meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE &&
- display->expected_focus_window != NULL)
- {
- meta_topic (META_DEBUG_FOCUS,
- "Unsetting focus from %s due to mouse entering "
- "the DESKTOP window\n",
- display->expected_focus_window->desc);
- meta_display_focus_the_no_focus_window (display,
- window->screen,
- event->xcrossing.time);
- }
break;
case G_DESKTOP_FOCUS_MODE_CLICK:
break;
}
-
- if (window->type == META_WINDOW_DOCK)
+
+ if (window->type == META_WINDOW_DOCK &&
+ meta_display_focus_sentinel_clear (display))
meta_window_raise (window);
}
break;
@@ -5095,6 +5118,132 @@ meta_display_remove_autoraise_callback (MetaDisplay *display)
}
}
+#define FOCUS_ON_MOTION_CHECK_INTERVAL 200 /* 0.2 seconds */
+#define FOCUS_ON_MOTION_THRESHOLD 2 /* Must move 2 pixels */
+
+static gboolean
+check_focus_on_motion (gpointer data)
+{
+ MetaDisplay *display = data;
+ Window root, child;
+ int root_x, root_y;
+ int window_x, window_y;
+ guint mask;
+
+ XQueryPointer (display->xdisplay,
+ DefaultRootWindow (display->xdisplay),
+ &root, &child,
+ &root_x, &root_y,
+ &window_x, &window_y,
+ &mask);
+
+ if (root != display->focus_on_motion_start_root_window ||
+ MAX (ABS (root_x - display->focus_on_motion_start_x),
+ ABS (root_y - display->focus_on_motion_start_y)) >= FOCUS_ON_MOTION_THRESHOLD)
+ {
+ MetaScreen *screen;
+
+ meta_topic (META_DEBUG_FOCUS,
+ "Returning to mouse mode on mouse motion\n");
+
+ meta_display_enable_mouse_mode (display);
+
+ screen = meta_display_screen_for_root (display, root);
+ if (screen != NULL)
+ {
+ MetaWindow *window = meta_screen_get_mouse_window (screen, NULL);
+ guint32 timestamp = meta_display_get_current_time_roundtrip (display);
+
+ if (window &&
+ window->type != META_WINDOW_DOCK &&
+ window->type != META_WINDOW_DESKTOP)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing mouse window %s\n", window->desc);
+
+ meta_window_focus (window, timestamp);
+
+ if (display->autoraise_window != window &&
+ meta_prefs_get_auto_raise ())
+ {
+ meta_display_queue_autoraise_callback (display, window);
+ }
+ }
+ else if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_MOUSE)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Setting focus to no_focus_windowm, since no mouse window.\n");
+ meta_display_focus_the_no_focus_window (display, screen, timestamp);
+ }
+
+ /* for G_DESKTOP_FOCUS_MODE_SLOPPY, if the pointer isn't over a window, we just
+ * leave the last window focused */
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+start_focus_on_motion (MetaDisplay *display)
+{
+ if (!display->focus_on_motion_timeout_id)
+ {
+ Window child;
+ guint mask;
+ int window_x, window_y;
+
+ XQueryPointer (display->xdisplay,
+ DefaultRootWindow (display->xdisplay),
+ &display->focus_on_motion_start_root_window,
+ &child,
+ &display->focus_on_motion_start_x,
+ &display->focus_on_motion_start_y,
+ &window_x, &window_y,
+ &mask);
+
+ display->focus_on_motion_timeout_id =
+ g_timeout_add (FOCUS_ON_MOTION_CHECK_INTERVAL,
+ check_focus_on_motion,
+ display);
+ }
+}
+
+static void
+stop_focus_on_motion (MetaDisplay *display)
+{
+ if (display->focus_on_motion_timeout_id)
+ {
+ g_source_remove (display->focus_on_motion_timeout_id);
+ display->focus_on_motion_timeout_id = 0;
+ }
+}
+
+void
+meta_display_disable_mouse_mode (MetaDisplay *display)
+{
+ display->mouse_mode = FALSE;
+
+ /* mouse_mode disabled means that we are now allowing the
+ * mouse window to be different from the focus window;
+ * that discrepancy might not come until we ignore some
+ * enter event, but in a case like tabbing away from the
+ * mouse window, it occurs immediately, so we need to
+ * start checking for motion events to see if we should
+ * focus the mouse window and return to mouse mode.
+ */
+ if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK)
+ start_focus_on_motion (display);
+}
+
+void
+meta_display_enable_mouse_mode (MetaDisplay *display)
+{
+ display->mouse_mode = TRUE;
+
+ stop_focus_on_motion (display);
+}
+
#ifdef HAVE_COMPOSITE_EXTENSIONS
void
meta_display_get_compositor_version (MetaDisplay *display,
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 08d861e..3c0ef95 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -2082,7 +2082,7 @@ process_tab_grab (MetaDisplay *display,
meta_topic (META_DEBUG_FOCUS, "Activating %s due to tab popup "
"selection and turning mouse_mode off\n",
target_window->desc);
- display->mouse_mode = FALSE;
+ meta_display_disable_mouse_mode (display);
meta_window_activate (target_window, event->xkey.time);
meta_topic (META_DEBUG_KEYBINDINGS,
@@ -2686,7 +2686,7 @@ handle_panel (MetaDisplay *display,
meta_topic (META_DEBUG_KEYBINDINGS,
"Sending panel message with timestamp %lu, and turning mouse_mode "
"off due to keybinding press\n", event->xkey.time);
- display->mouse_mode = FALSE;
+ meta_display_disable_mouse_mode (display);
meta_error_trap_push (display);
@@ -2809,7 +2809,7 @@ do_choose_window (MetaDisplay *display,
"Activating %s and turning off mouse_mode due to "
"switch/cycle windows with no modifiers\n",
initial_selection->desc);
- display->mouse_mode = FALSE;
+ meta_display_disable_mouse_mode (display);
meta_window_activate (initial_selection, event->xkey.time);
}
else if (meta_display_begin_grab_op (display,
@@ -2838,7 +2838,7 @@ do_choose_window (MetaDisplay *display,
"modifier was released prior to grab\n",
initial_selection->desc);
meta_display_end_grab_op (display, event->xkey.time);
- display->mouse_mode = FALSE;
+ meta_display_disable_mouse_mode (display);
meta_window_activate (initial_selection, event->xkey.time);
}
else
@@ -3079,7 +3079,7 @@ handle_move_to_workspace (MetaDisplay *display,
meta_topic (META_DEBUG_FOCUS,
"Resetting mouse_mode to FALSE due to "
"handle_move_to_workspace() call with flip set.\n");
- workspace->screen->display->mouse_mode = FALSE;
+ meta_display_disable_mouse_mode (display);
meta_workspace_activate_with_focus (workspace,
window,
event->xkey.time);
--
1.7.9

View File

@ -1,200 +0,0 @@
From ab0428a82f8233829c36e2a3ac0ed0848571c59d Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 9 Jun 2010 19:38:35 -0400
Subject: [PATCH] Stop confusing GDK's grab tracking
With client side windows, mixing GDK event delivery with explicit calls
to XUngrabPointer() can result in GDK losing button release events
it expects to get. This means that GDK thinks there is an implicit
grab in effect when there is none and send events to the wrong window.
Avoid this by bypassing GDK's event handling for most mouse events.
We do a simplified conversion of the X event into a GdkEvent and send
it to directly to libgtk for delivery.
We make an exception when a GDK grab is already in effect - this is
needed for the correct operation of menus.
http://bugzilla.gnome.org/show_bug.cgi?id=599181
---
src/core/display-private.h | 7 ++
src/core/display.c | 131 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 0 deletions(-)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index fee321c..7f779fd 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -232,6 +232,13 @@ struct _MetaDisplay
/* Closing down the display */
int closing;
+ /* To detect double clicks */
+ guint button_click_number;
+ Window button_click_window;
+ int button_click_x;
+ int button_click_y;
+ guint32 button_click_time;
+
/* Managed by group.c */
GHashTable *groups_by_leader;
diff --git a/src/core/display.c b/src/core/display.c
index 5bcf025..0c5f61d 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -77,6 +77,7 @@
#include <X11/extensions/Xfixes.h>
#endif
#include <string.h>
+#include <gtk/gtk.h>
#define GRAB_OP_IS_WINDOW_SWITCH(g) \
(g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \
@@ -1362,6 +1363,133 @@ meta_display_queue_autoraise_callback (MetaDisplay *display,
display->autoraise_window = window;
}
+/* We do some of our event handling in core/frames.c, which expects
+ * GDK events delivered by GTK+. However, since the transition to
+ * client side windows, we can't let GDK see button events, since the
+ * client-side tracking of implicit and explicit grabs it does will
+ * get confused by our direct use of X grabs.
+ *
+ * So we do a very minimal GDK => GTK event conversion here and send on the
+ * events we care about, and then filter them out so they don't go
+ * through the normal GDK event handling.
+ *
+ * To reduce the amount of code, the only events fields filled out
+ * below are the ones that frames.c uses. If frames.c is modified to
+ * use more fields, more fields need to be filled out below.
+ */
+
+static gboolean
+maybe_send_event_to_gtk (MetaDisplay *display,
+ XEvent *xevent)
+{
+ /* We're always using the default display */
+ GdkDisplay *gdk_display = gdk_display_get_default ();
+ GdkEvent gdk_event;
+ GdkWindow *gdk_window;
+ Window window;
+
+ switch (xevent->type)
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ window = xevent->xbutton.window;
+ break;
+ case MotionNotify:
+ window = xevent->xmotion.window;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ window = xevent->xcrossing.window;
+ break;
+ default:
+ return FALSE;
+ }
+
+ gdk_window = gdk_window_lookup_for_display (gdk_display, window);
+ if (gdk_window == NULL)
+ return FALSE;
+
+ /* If GDK already things it has a grab, we better let it see events; this
+ * is the menu-navigation case and events need to get sent to the appropriate
+ * (client-side) subwindow for individual menu items.
+ */
+ if (gdk_display_pointer_is_grabbed (gdk_display))
+ return FALSE;
+
+ memset (&gdk_event, 0, sizeof (gdk_event));
+
+ switch (xevent->type)
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ if (xevent->type == ButtonPress)
+ {
+ GtkSettings *settings = gtk_settings_get_default ();
+ int double_click_time;
+ int double_click_distance;
+
+ g_object_get (settings,
+ "gtk-double-click-time", &double_click_time,
+ "gtk-double-click-distance", &double_click_distance,
+ NULL);
+
+ if (xevent->xbutton.button == display->button_click_number &&
+ xevent->xbutton.window == display->button_click_window &&
+ xevent->xbutton.time < display->button_click_time + double_click_time &&
+ ABS (xevent->xbutton.x - display->button_click_x) <= double_click_distance &&
+ ABS (xevent->xbutton.y - display->button_click_y) <= double_click_distance)
+ {
+ gdk_event.button.type = GDK_2BUTTON_PRESS;
+
+ display->button_click_number = 0;
+ }
+ else
+ {
+ gdk_event.button.type = GDK_BUTTON_PRESS;
+ display->button_click_number = xevent->xbutton.button;
+ display->button_click_window = xevent->xbutton.window;
+ display->button_click_time = xevent->xbutton.time;
+ display->button_click_x = xevent->xbutton.x;
+ display->button_click_y = xevent->xbutton.y;
+ }
+ }
+ else
+ {
+ gdk_event.button.type = GDK_BUTTON_RELEASE;
+ }
+
+ gdk_event.button.window = gdk_window;
+ gdk_event.button.button = xevent->xbutton.button;
+ gdk_event.button.time = xevent->xbutton.time;
+ gdk_event.button.x = xevent->xbutton.x;
+ gdk_event.button.y = xevent->xbutton.y;
+ gdk_event.button.x_root = xevent->xbutton.x_root;
+ gdk_event.button.y_root = xevent->xbutton.y_root;
+
+ break;
+ case MotionNotify:
+ gdk_event.motion.type = GDK_MOTION_NOTIFY;
+ gdk_event.motion.window = gdk_window;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ gdk_event.crossing.type = xevent->type == EnterNotify ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
+ gdk_event.crossing.window = gdk_window;
+ gdk_event.crossing.x = xevent->xcrossing.x;
+ gdk_event.crossing.y = xevent->xcrossing.y;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* If we've gotten here, we've filled in the gdk_event and should send it on */
+
+ gtk_main_do_event (&gdk_event);
+
+ return TRUE;
+}
+
/**
* This is the most important function in the whole program. It is the heart,
* it is the nexus, it is the Grand Central Station of Metacity's world.
@@ -2387,6 +2515,9 @@ event_callback (XEvent *event,
event,
window);
}
+
+ if (maybe_send_event_to_gtk (display, event))
+ filter_out_event = TRUE;
display->current_time = CurrentTime;
return filter_out_event;
--
1.7.9

View File

@ -1,11 +0,0 @@
--- metacity-2.27.0/src/core/display.c 2009-06-07 21:35:13.623787399 -0400
+++ hacked/src/core/display.c 2009-06-06 00:20:58.889278832 -0400
@@ -3307,7 +3307,7 @@
meta_display_set_grab_op_cursor (display, screen, op, FALSE, grab_xwindow,
timestamp);
- if (!display->grab_have_pointer)
+ if (!display->grab_have_pointer && !grab_op_is_keyboard (op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"XGrabPointer() failed\n");

View File

@ -1,287 +0,0 @@
diff -up metacity-2.30.2/src/ui/fixedtip.c.fresh-tooltips metacity-2.30.2/src/ui/fixedtip.c
--- metacity-2.30.2/src/ui/fixedtip.c.fresh-tooltips 2010-09-04 12:09:53.000000000 -0400
+++ metacity-2.30.2/src/ui/fixedtip.c 2010-09-29 13:27:27.931194002 -0400
@@ -50,23 +50,214 @@ static int screen_right_edge = 0;
*/
static int screen_bottom_edge = 0;
+static void
+draw_round_rect (cairo_t *cr,
+ gdouble aspect,
+ gdouble x,
+ gdouble y,
+ gdouble corner_radius,
+ gdouble width,
+ gdouble height)
+{
+ gdouble radius = corner_radius / aspect;
+
+ cairo_move_to (cr, x + radius, y);
+
+ /* top-right, left of the corner */
+ cairo_line_to (cr, x + width - radius, y);
+
+ /* top-right, below the corner */
+ cairo_arc (cr,
+ x + width - radius, y + radius, radius,
+ -90.0f * G_PI / 180.0f, 0.0f * G_PI / 180.0f);
+
+ /* bottom-right, above the corner */
+ cairo_line_to (cr, x + width, y + height - radius);
+
+ /* bottom-right, left of the corner */
+ cairo_arc (cr,
+ x + width - radius, y + height - radius, radius,
+ 0.0f * G_PI / 180.0f, 90.0f * G_PI / 180.0f);
+
+ /* bottom-left, right of the corner */
+ cairo_line_to (cr, x + radius, y + height);
+
+ /* bottom-left, above the corner */
+ cairo_arc (cr,
+ x + radius, y + height - radius, radius,
+ 90.0f * G_PI / 180.0f, 180.0f * G_PI / 180.0f);
+
+ /* top-left, below the corner */
+ cairo_line_to (cr, x, y + radius);
+
+ /* top-left, right of the corner */
+ cairo_arc (cr,
+ x + radius, y + radius, radius,
+ 180.0f * G_PI / 180.0f, 270.0f * G_PI / 180.0f);
+
+ cairo_close_path (cr);
+}
+
+
+static void
+fill_background (GtkWidget *widget,
+ cairo_t *cr)
+{
+ GdkColor color;
+ gdouble r, g, b;
+ gint radius;
+ gdouble background_alpha;
+
+ if (gdk_screen_is_composited (gtk_widget_get_screen (widget)))
+ background_alpha = 0.90;
+ else
+ background_alpha = 1.0;
+
+ radius = MIN (widget->style->xthickness, widget->style->ythickness);
+ radius = MAX (radius, 1);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ draw_round_rect (cr,
+ 1.0, 0.5, 0.5, radius,
+ widget->allocation.width - 1,
+ widget->allocation.height - 1);
+
+ color = widget->style->bg [GTK_STATE_NORMAL];
+ r = (float)color.red / 65535.0;
+ g = (float)color.green / 65535.0;
+ b = (float)color.blue / 65535.0;
+ cairo_set_source_rgba (cr, r, g, b, background_alpha);
+ cairo_fill_preserve (cr);
+
+ color = widget->style->bg [GTK_STATE_SELECTED];
+ r = (float) color.red / 65535.0;
+ g = (float) color.green / 65535.0;
+ b = (float) color.blue / 65535.0;
+
+ cairo_set_source_rgba (cr, r, g, b, background_alpha);
+ cairo_set_line_width (cr, 1.0);
+ cairo_stroke (cr);
+}
+
+static void
+update_shape (GtkWidget *window)
+{
+ GdkBitmap *mask;
+ cairo_t *cr;
+ gint width, height;
+ gint radius;
+ gboolean new_style;
+
+ gtk_widget_style_get (window, "new-tooltip-style", &new_style, NULL);
+
+ if (!new_style)
+ {
+ gtk_widget_shape_combine_mask (window, NULL, 0, 0);
+ return;
+ }
+
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+
+ if (gdk_screen_is_composited (gtk_widget_get_screen (window)))
+ {
+ gtk_widget_shape_combine_mask (window, NULL, 0, 0);
+ return;
+ }
+
+ radius = MIN (window->style->xthickness, window->style->ythickness);
+ radius = MAX (radius, 1);
+
+ mask = (GdkBitmap *) gdk_pixmap_new (NULL, width, height, 1);
+ cr = gdk_cairo_create (mask);
+ if (cairo_status (cr) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ draw_round_rect (cr, 1.0, 0, 0, radius + 1, width, height);
+ cairo_fill (cr);
+
+ gtk_widget_shape_combine_mask (window, mask, 0, 0);
+ }
+ cairo_destroy (cr);
+
+ g_object_unref (mask);
+}
+
static gint
-expose_handler (GtkTooltip *tooltips)
+expose_handler (GtkWidget *window)
{
- gtk_paint_flat_box (gtk_widget_get_style (tip), gtk_widget_get_window (tip),
- GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- NULL, tip, "tooltip",
- 0, 0, -1, -1);
+ cairo_t *context;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ gboolean new_style;
+
+ gtk_widget_style_get (window, "new-tooltip-style", &new_style, NULL);
+
+ if (new_style)
+ {
+ context = gdk_cairo_create (window->window);
+
+ cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
+ surface = cairo_surface_create_similar (cairo_get_target (context),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ window->allocation.width,
+ window->allocation.height);
+ cr = cairo_create (surface);
+
+ fill_background (window, cr);
+
+ cairo_destroy (cr);
+ cairo_set_source_surface (context, surface, 0, 0);
+ cairo_paint (context);
+ cairo_surface_destroy (surface);
+ cairo_destroy (context);
+
+ update_shape (window);
+ }
+ else
+ {
+ gtk_paint_flat_box (window->style,
+ window->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL,
+ window,
+ "tooltip",
+ 0, 0,
+ window->allocation.width,
+ window->allocation.height);
+ }
return FALSE;
}
+static void
+on_style_set (GtkWidget *widget, GtkStyle *prev)
+{
+ GtkWidget *alignment;
+
+ alignment = gtk_bin_get_child (GTK_BIN (widget));
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ widget->style->ythickness,
+ widget->style->ythickness,
+ widget->style->xthickness,
+ widget->style->xthickness);
+ gtk_widget_queue_draw (widget);
+}
+
void
meta_fixed_tip_show (Display *xdisplay, int screen_number,
int root_x, int root_y,
const char *markup_text)
{
int w, h;
+ GtkWidget *alignment;
if (tip == NULL)
{
@@ -77,6 +268,7 @@ meta_fixed_tip_show (Display *xdisplay,
GdkScreen *gdk_screen;
GdkRectangle monitor;
gint mon_num;
+ GdkColormap *rgba;
gdk_screen = gdk_display_get_screen (gdk_display_get_default (),
screen_number);
@@ -86,25 +278,47 @@ meta_fixed_tip_show (Display *xdisplay,
gdk_screen_get_monitor_geometry (gdk_screen, mon_num, &monitor);
screen_right_edge = monitor.x + monitor.width;
screen_bottom_edge = monitor.y + monitor.height;
+
+ rgba = gdk_screen_get_rgba_colormap (gdk_screen);
+ if (rgba)
+ gtk_widget_set_colormap (tip, rgba);
+
+#if 0
+ g_signal_connect (tip, "composited-changed",
+ G_CALLBACK (on_composited_changed), NULL);
+ g_signal_connect (tip, "realize",
+ G_CALLBACK (on_realized), NULL);
+#endif
}
-
+
gtk_widget_set_app_paintable (tip, TRUE);
gtk_window_set_resizable (GTK_WINDOW (tip), FALSE);
- gtk_widget_set_name (tip, "gtk-tooltips");
- gtk_container_set_border_width (GTK_CONTAINER (tip), 4);
+ gtk_widget_set_name (tip, "gtk-tooltip");
+ gtk_widget_realize (tip);
- g_signal_connect_swapped (tip, "expose_event",
- G_CALLBACK (expose_handler), NULL);
+ g_signal_connect (tip, "expose_event",
+ G_CALLBACK (expose_handler), NULL);
+
+ alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ tip->style->ythickness,
+ tip->style->ythickness,
+ tip->style->xthickness,
+ tip->style->xthickness);
+ gtk_widget_show (alignment);
+ gtk_container_add (GTK_CONTAINER (tip), alignment);
label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
- gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
gtk_widget_show (label);
-
- gtk_container_add (GTK_CONTAINER (tip), label);
+
+ gtk_container_add (GTK_CONTAINER (alignment), label);
g_signal_connect (tip, "destroy",
G_CALLBACK (gtk_widget_destroyed), &tip);
+
+ g_signal_connect (tip, "style-set",
+ G_CALLBACK (on_style_set), NULL);
}
gtk_label_set_markup (GTK_LABEL (label), markup_text);

View File

@ -1,58 +0,0 @@
From 04f775d77d53bca92faee883258d787b89255ef8 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Fri, 20 Nov 2009 10:42:07 -0500
Subject: [PATCH] Handle XError and XIOError for unknown displays
The atk-bridge GTK+ module opens its own display; if we get an
XIOError on that display, we shouldn't abort with a meta_bug()
but just exit normally. Also fix a segfault if we got an XError
for that display.
---
src/core/errors.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/src/core/errors.c b/src/core/errors.c
index 8de4608..59f9c71 100644
--- a/src/core/errors.c
+++ b/src/core/errors.c
@@ -222,10 +222,10 @@ x_error_handler (Display *xdisplay,
display = meta_display_for_x_display (xdisplay);
- /* Display can be NULL here because the compositing manager
- * has its own Display, but Xlib only has one global error handler
+ /* Display can be NULL here Xlib only has one global error handler; and
+ * there might be other displays open in the process.
*/
- if (display->error_traps > 0)
+ if (display && display->error_traps > 0)
{
/* we're in an error trap, chain to the trap handler
* saved from GDK
@@ -264,21 +264,18 @@ x_io_error_handler (Display *xdisplay)
display = meta_display_for_x_display (xdisplay);
- if (display == NULL)
- meta_bug ("IO error received for unknown display?\n");
-
if (errno == EPIPE)
{
meta_warning (_("Lost connection to the display '%s';\n"
"most likely the X server was shut down or you killed/destroyed\n"
"the window manager.\n"),
- display->name);
+ display ? display->name : DisplayString (xdisplay));
}
else
{
meta_warning (_("Fatal IO error %d (%s) on display '%s'.\n"),
errno, g_strerror (errno),
- display->name);
+ display ? display->name : DisplayString (xdisplay));
}
/* Xlib would force an exit anyhow */
--
1.7.9

View File

@ -1,37 +1,16 @@
Summary: Unobtrusive window manager
Name: metacity
Version: 2.34.13
Release: 7%{?dist}
Version: 3.12.0
Release: 1%{?dist}
URL: http://download.gnome.org/sources/metacity/
Source0: http://download.gnome.org/sources/metacity/2.34/metacity-%{version}.tar.xz
Source0: http://download.gnome.org/sources/metacity/3.12/metacity-%{version}.tar.xz
# http://bugzilla.gnome.org/show_bug.cgi?id=558723
Patch4: stop-spamming-xsession-errors.patch
# http://bugzilla.gnome.org/show_bug.cgi?id=135056
Patch5: dnd-keynav.patch
# fedora specific patches
Patch12: fresh-tooltips.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=598995
Patch16: Dont-focus-ancestor-window-on-a-different-workspac.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=599097
Patch18: For-mouse-and-sloppy-focus-return-to-mouse-mode-on.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=599248
Patch19: Add-nofocuswindows-preference-to-list-windows-that.patch
Patch119: Exclude-the-current-application-from-no_focus_window.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=599261
Patch20: Add-a-newwindowsalwaysontop-preference.patch
Patch120: Apply-new_windows_always_on_top-to-newly-raised-acti.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=559816
Patch24: metacity-2.28-empty-keybindings.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=604319
Patch25: metacity-2.28-xioerror-unknown-display.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=599181
Patch28: Stop-confusing-GDK-s-grab-tracking.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=622517
Patch29: Allow-breaking-out-from-maximization-during-mouse.patch
Patch40: 0001-doc-Update-man-pages.patch
License: GPLv2+
Group: User Interface/Desktops
@ -86,20 +65,9 @@ API. This package exists purely for technical reasons.
%prep
%setup -q
%patch4 -p1 -b .stop-spamming-xsession-errors
%patch5 -p1 -b .dnd-keynav
%patch12 -p1 -b .fresh-tooltips
%patch16 -p1 -b .focus-different-workspace
%patch18 -p1 -b .focus-on-motion
%patch19 -p1 -b .no-focus-windows
%patch119 -p1 -b .no-focus-windows-current-app
%patch20 -p1 -b .always-on-top
%patch120 -p1 -b .always-on-top-activate
%patch24 -p1 -b .empty-keybindings
%patch25 -p1 -b .xioerror-unknown-display
%patch28 -p1 -b .grab-tracking
%patch29 -p1 -b .mouse-unmaximize
%patch40 -p1 -b .man-page
# force regeneration
rm -f src/org.gnome.metacity.gschema.valid
@ -177,6 +145,9 @@ fi
%{_mandir}/man1/metacity-window-demo.1.gz
%changelog
* Wed Jun 18 2014 Richard Hughes <rhughes@redhat.com> - 3.12.0-1
- Update to 3.12.0
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.34.13-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild

View File

@ -1 +1 @@
6d89b71672d4fa49fc87f83d610d0ef6 metacity-2.34.13.tar.xz
30637f6e564ef66db9bbc31fce99652c metacity-3.12.0.tar.xz