Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 601357 Details for
Bug 844165
Review Request: mate-window-manager - Unobtrusive window manager
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
https://bugzilla.gnome.org/show_bug.cgi?id=599248
Add-nofocuswindows-preference-to-list-windows-that.patch (text/plain), 26.49 KB, created by
Wolfgang Ulbrich
on 2012-07-30 23:43:19 UTC
(
hide
)
Description:
https://bugzilla.gnome.org/show_bug.cgi?id=599248
Filename:
MIME Type:
Creator:
Wolfgang Ulbrich
Created:
2012-07-30 23:43:19 UTC
Size:
26.49 KB
patch
obsolete
>From 88c66808ec5f2bfba425fc6d6f0b9ac43ed44696 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: > > /apps/marco/general/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 | 43 ++++ > src/core/window-matcher.c | 582 ++++++++++++++++++++++++++++++++++++++++++++ > src/core/window-matcher.h | 46 ++++ > src/core/window.c | 9 +- > src/include/prefs.h | 6 +- > src/marco.schemas.in.in | 28 ++ > 7 files changed, 714 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 bd3420f..3baf422 100644 >--- a/src/Makefile.am >+++ b/src/Makefile.am >@@ -65,6 +65,8 @@ marco_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 6e41b3c..e03c816 100644 >--- a/src/core/prefs.c >+++ b/src/core/prefs.c >@@ -25,6 +25,7 @@ > > #include <config.h> > #include "prefs.h" >+#include "window-matcher.h" > #include "ui.h" > #include "util.h" > #ifdef HAVE_GCONF >@@ -76,6 +77,7 @@ static PangoFontDescription *titlebar_font = NULL; > static MetaVirtualModifier mouse_button_mods = Mod1Mask; > static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK; > static MetaFocusNewWindows focus_new_windows = META_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; >@@ -147,6 +149,7 @@ static void maybe_give_disable_workarounds_warning (void); > > static void titlebar_handler (MetaPreference, const gchar*, gboolean*); > static void theme_name_handler (MetaPreference, const gchar*, gboolean*); >+static void no_focus_windows_handler (MetaPreference, const gchar*, gboolean*); > static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*); > static void button_layout_handler (MetaPreference, const gchar*, gboolean*); > >@@ -425,6 +428,11 @@ static MetaStringPreference preferences_string[] = > theme_name_handler, > NULL, > }, >+ { "/apps/marco/general/no_focus_windows", >+ META_PREF_NO_FOCUS_WINDOWS, >+ no_focus_windows_handler, >+ NULL >+ }, > { KEY_TITLEBAR_FONT, > META_PREF_TITLEBAR_FONT, > titlebar_handler, >@@ -1344,6 +1352,30 @@ theme_name_handler (MetaPreference pref, > } > > static void >+no_focus_windows_handler (MetaPreference pref, >+ const gchar *string_value, >+ gboolean *inform_listeners) >+{ >+ 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); >+ } >+ } >+} >+ >+static void > mouse_button_mods_handler (MetaPreference pref, > const gchar *string_value, > gboolean *inform_listeners) >@@ -1755,6 +1787,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)"; >@@ -2633,6 +2668,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..e2fd293 >--- /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 8d029a2..10da47a 100644 >--- a/src/core/window.c >+++ b/src/core/window.c >@@ -1965,7 +1965,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 a4193ff..6698dfe 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, >@@ -106,6 +107,9 @@ MetaActionTitlebar meta_prefs_get_action_double_click_titlebar (void); > MetaActionTitlebar meta_prefs_get_action_middle_click_titlebar (void); > MetaActionTitlebar 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/marco.schemas.in.in b/src/marco.schemas.in.in >index a9dd397..34cd7d6 100644 >--- a/src/marco.schemas.in.in >+++ b/src/marco.schemas.in.in >@@ -100,6 +100,34 @@ > </schema> > > <schema> >+ <key>/schemas/apps/marco/general/no_focus_windows</key> >+ <applyto>/apps/marco/general/no_focus_windows</applyto> >+ <owner>marco</owner> >+ <type>string</type> >+ <default></default> >+ <locale name="C"> >+ <short>New windows that shouldn't get focus</short> >+ <long> >+ 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] "<value>"): window name (title) or the class from >+ WM_CLASS matches <value> exactly. >+ (glob [name|class] "<glob>"): window name (title) or the class from >+ WM_CLASS matches the shell-style glob pattern <glob>. >+ (and <expr> <expr>) (or <expr> <expr>) (not <expr): Boolean combinations >+ of expressions. >+ </long> >+ </locale> >+ </schema> >+ >+ <schema> > <key>/schemas/apps/marco/general/raise_on_click</key> > <applyto>/apps/marco/general/raise_on_click</applyto> > <owner>marco</owner>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 844165
:
601356
| 601357 |
601358
|
601359
|
601360
|
601361
|
601362
|
601363
|
601364
|
601365
|
601366
|
601367