use simple pattern matching for per-app settings. all rules that match are applied...
authorDana Jansens <danakj@orodu.net>
Mon, 21 May 2007 03:42:25 +0000 (03:42 +0000)
committerDana Jansens <danakj@orodu.net>
Mon, 21 May 2007 03:42:25 +0000 (03:42 +0000)
data/rc.xml
data/rc.xsd
openbox/client.c
openbox/client.h
openbox/config.c
openbox/config.h

index 42d629f..fa673c8 100644 (file)
      want to use it -->
 <applications>
   <!-- the name or the class can be set, or both. this is used to match
-       windows when they appear
+       windows when they appear. role can optionally be set as well, to
+       further restrict your matches
 
-       role can optionally be set, and only as much as you provide will be 
-       checked to see if it matches, eg. if you set role="abc" and the window's
-       role is actually "abcde" it would match.
+       the name, class, and role use simple globbing rules such as those
+       used by a shell. you can use * to match any characters and ? to match
+       any single character.
+
+       when multiple rules match a window, they will all be applied, in the
+       order that they appear in this list
  -->
   <application name="first element of window's WM_CLASS property (see xprop)"
               class="second element of window's WM_CLASS property (see xprop)"
          change that attribute of the window -->
 
     <decor>yes</decor>
+    <!-- enable or disable window decorations -->
 
     <shade>no</shade>
 
index ca99419..64cbb98 100644 (file)
     <xsd:complexType name="window_position">
         <xsd:element name="x" type="ob:center_or_int"/>
         <xsd:element name="y" type="ob:center_or_int"/>
+       <xsd:element name="monitor" type="ob:mouse_or_int"/>    
         <xsd:element minOccurs="0" name="head" type="xsd:string"/>
     </xsd:complexType>
     <xsd:complexType name="application">
             <xsd:pattern value="center|0|[1-9][0-9]*"/>
         </xsd:restriction>
     </xsd:simpleType>
+    <xsd:simpleType name="mouse_or_int">
+        <xsd:restriction base="xsd:string">
+            <!-- ob: atoi($_) unless $_ eq 'center'; -->
+            <!-- I think the regexp DTRT WRT atoi. -->
+            <xsd:pattern value="mouse|0|[1-9][0-9]*"/>
+        </xsd:restriction>
+    </xsd:simpleType>
     <xsd:simpleType name="contextname">
         <xsd:restriction base="xsd:string">
             <xsd:enumeration value="Desktop"/>
index e77a4ea..9b89b10 100644 (file)
@@ -314,7 +314,8 @@ void client_manage(Window window)
     grab_server(FALSE);
 
     /* per-app settings override stuff from client_get_all, and return the
-       settings for other uses too */
+       settings for other uses too. the returned settings is a shallow copy,
+       that needs to be freed with g_free(). */
     settings = client_get_settings_state(self);
     /* the session should get the last say thought */
     client_restore_session_state(self);
@@ -506,6 +507,9 @@ void client_manage(Window window)
     /* update the list hints */
     client_set_list();
 
+    /* free the ObAppSettings shallow copy */
+    g_free(settings);
+
     ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
              window, self->frame->plate, self->class);
 
@@ -527,7 +531,7 @@ ObClient *client_fake_manage(Window window)
 
     client_get_all(self, FALSE);
     /* per-app settings override stuff, and return the settings for other
-       uses too */
+       uses too. this returns a shallow copy that needs to be freed */
     settings = client_get_settings_state(self);
 
     client_setup_decor_and_functions(self);
@@ -535,6 +539,10 @@ ObClient *client_fake_manage(Window window)
     /* create the decoration frame for the client window and adjust its size */
     self->frame = frame_new(self);
     frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+
+    /* free the ObAppSettings shallow copy */
+    g_free(settings);
+
     return self;
 }
 
@@ -694,30 +702,39 @@ void client_fake_unmanage(ObClient *self)
     g_free(self);
 }
 
+/*! Returns a new structure containing the per-app settings for this client.
+  The returned structure needs to be freed with g_free. */
 static ObAppSettings *client_get_settings_state(ObClient *self)
 {
-    ObAppSettings *settings = NULL;
+    ObAppSettings *settings;
     GSList *it;
 
+    settings = config_create_app_settings();
+
     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
         ObAppSettings *app = it->data;
-        
-        if ((app->name && !app->class && !strcmp(app->name, self->name))
-            || (app->class && !app->name && !strcmp(app->class, self->class))
-            || (app->class && app->name && !strcmp(app->class, self->class)
-                && !strcmp(app->name, self->name)))
-        {
-            /* Match if no role was specified in the per app setting, or if the
-             * string matches the beginning of the role, since apps like to set
-             * the role to things like browser-window-23c4b2f */
-            if (!app->role
-                || !strncmp(app->role, self->role, strlen(app->role)))
-            {
-                ob_debug("Window matching: %s\n", app->name);
-                /* use this one */
-                settings = app;
-                break;
-            }
+        gboolean match = TRUE;
+
+        g_assert(app->name != NULL || app->class != NULL);
+
+        /* we know that either name or class is not NULL so it will have to
+           match to use the rule */
+        if (app->name &&
+            !g_pattern_match(app->name, strlen(self->name), self->name, NULL))
+            match = FALSE;
+        if (app->class &&
+            !g_pattern_match(app->class, strlen(self->class),self->class,NULL))
+            match = FALSE;
+        if (app->role &&
+            !g_pattern_match(app->role, strlen(self->role), self->role, NULL))
+            match = FALSE;
+
+        if (match) {
+            ob_debug("Window matching: %s\n", app->name);
+
+            /* copy the settings to our struct, overriding the existing
+               settings if they are not defaults */
+            config_app_settings_copy_non_defaults(app, settings);
         }
     }
 
index 1467ecd..e66cf9e 100644 (file)
@@ -35,7 +35,6 @@ struct _ObSessionState;
 
 typedef struct _ObClient      ObClient;
 typedef struct _ObClientIcon  ObClientIcon;
-typedef struct _ObAppSettings ObAppSettings;
 
 /* The value in client.transient_for indicating it is a transient for its
    group instead of for a single window */
index c007de5..480308b 100644 (file)
@@ -89,6 +89,54 @@ gint     config_resist_edge;
 
 GSList *config_per_app_settings;
 
+ObAppSettings* config_create_app_settings()
+{
+    ObAppSettings *settings = g_new0(ObAppSettings, 1);
+    settings->decor = -1;
+    settings->shade = -1;
+    settings->monitor = -1;
+    settings->focus = -1;
+    settings->desktop = 0;
+    settings->layer = -2;
+    settings->iconic = -1;
+    settings->skip_pager = -1;
+    settings->skip_taskbar = -1;
+    settings->fullscreen = -1;
+    settings->max_horz = -1;
+    settings->max_vert = -1;
+    return settings;
+}
+
+#define copy_if(setting, default) \
+  if (src->setting != default) dst->setting = src->setting
+void config_app_settings_copy_non_defaults(const ObAppSettings *src,
+                                           ObAppSettings *dst)
+{
+    g_assert(src != NULL);
+    g_assert(dst != NULL);
+
+    copy_if(decor, -1);
+    copy_if(shade, -1);
+    copy_if(focus, -1);
+    copy_if(desktop, 0);
+    copy_if(layer, -2);
+    copy_if(iconic, -1);
+    copy_if(skip_pager, -1);
+    copy_if(skip_taskbar, -1);
+    copy_if(fullscreen, -1);
+    copy_if(max_horz, -1);
+    copy_if(max_vert, -1);
+
+    if (src->pos_given) {
+        dst->pos_given = TRUE;
+        dst->center_x = src->center_x;
+        dst->center_y = src->center_y;
+        dst->position.x = src->position.x;
+        dst->position.y = src->position.y;
+        dst->monitor = src->monitor;
+    }
+}
+
 /*
   <applications>
     <application name="aterm">
@@ -121,7 +169,7 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
                                    xmlNodePtr node, gpointer d)
 {
     xmlNodePtr app = parse_find_node("application", node->children);
-    gchar *name, *class;
+    gchar *name = NULL, *class = NULL, *role = NULL;
     gboolean name_set, class_set;
     gboolean x_pos_given;
 
@@ -132,33 +180,25 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
         name_set = parse_attr_string("name", app, &name);
         if (class_set || name_set) {
             xmlNodePtr n, c;
-            ObAppSettings *settings = g_new0(ObAppSettings, 1);
+            ObAppSettings *settings = config_create_app_settings();;
             
             if (name_set)
-                settings->name = name;
-            else
-                settings->name = NULL;
+                settings->name = g_pattern_spec_new(name);
 
             if (class_set)
-                settings->class = class;
-            else
-                settings->class = NULL;
+                settings->class = g_pattern_spec_new(class);
 
-            if (!parse_attr_string("role", app, &settings->role))
-                settings->role = NULL;
+            if (parse_attr_string("role", app, &role))
+                settings->role = g_pattern_spec_new(role);
 
-            settings->decor = -1;
             if ((n = parse_find_node("decor", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->decor = parse_bool(doc, n);
 
-            settings->shade = -1;
             if ((n = parse_find_node("shade", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->shade = parse_bool(doc, n);
 
-            settings->position.x = settings->position.y = 0;
-            settings->pos_given = FALSE;
             if ((n = parse_find_node("position", app->children))) {
                 if ((c = parse_find_node("x", n->children)))
                     if (!parse_contains("default", doc, c)) {
@@ -198,7 +238,6 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
                     }
             }
 
-            settings->focus = -1;
             if ((n = parse_find_node("focus", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->focus = parse_bool(doc, n);
@@ -214,11 +253,9 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
                             settings->desktop = i;
                     }
                     g_free(s);
-                } else
-                    settings->desktop = 0;
+                }
             }
 
-            settings->layer = -2;
             if ((n = parse_find_node("layer", app->children)))
                 if (!parse_contains("default", doc, n)) {
                     gchar *s = parse_string(doc, n);
@@ -231,28 +268,22 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
                     g_free(s);
                 }
 
-            settings->iconic = -1;
             if ((n = parse_find_node("iconic", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->iconic = parse_bool(doc, n);
 
-            settings->skip_pager = -1;
             if ((n = parse_find_node("skip_pager", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->skip_pager = parse_bool(doc, n);
 
-            settings->skip_taskbar = -1;
             if ((n = parse_find_node("skip_taskbar", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->skip_taskbar = parse_bool(doc, n);
 
-            settings->fullscreen = -1;
             if ((n = parse_find_node("fullscreen", app->children)))
                 if (!parse_contains("default", doc, n))
                     settings->fullscreen = parse_bool(doc, n);
 
-            settings->max_horz = -1;
-            settings->max_vert = -1;
             if ((n = parse_find_node("maximized", app->children)))
                 if (!parse_contains("default", doc, n)) {
                     gchar *s = parse_string(doc, n);
@@ -274,6 +305,10 @@ static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
         
         app = parse_find_node("application", app->next);
     }
+
+    g_free(name);
+    g_free(class);
+    g_free(role);
 }
 
 /*
@@ -917,9 +952,9 @@ void config_shutdown()
 
     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
         ObAppSettings *itd = (ObAppSettings *)it->data;
-        g_free(itd->name);
-        g_free(itd->role);
-        g_free(itd->class);
+        if (itd->name)  g_pattern_spec_free(itd->name);
+        if (itd->role)  g_pattern_spec_free(itd->role);
+        if (itd->class) g_pattern_spec_free(itd->class);
         g_free(it->data);
     }
     g_slist_free(config_per_app_settings);
index a1598b8..6a064ff 100644 (file)
 
 struct _ObParseInst;
 
+typedef struct _ObAppSettings ObAppSettings;
+
 struct _ObAppSettings
 {
-    gchar *class;
-    gchar *name;
-    gchar *role;
+    GPatternSpec *class;
+    GPatternSpec *name;
+    GPatternSpec *role;
 
     Point position;
     gboolean center_x;
@@ -166,4 +168,12 @@ extern GSList *config_per_app_settings;
 void config_startup(struct _ObParseInst *i);
 void config_shutdown();
 
+/*! Create an ObAppSettings structure with the default values */
+ObAppSettings* config_create_app_settings();
+/*! Copies any settings in src to dest, if they are their default value in
+  src. */
+void config_app_settings_copy_non_defaults(const ObAppSettings *src,
+                                           ObAppSettings *dest);
+
+
 #endif