allow multiple contexts separated by space in a mouse binding
authorDana Jansens <danakj@orodu.net>
Fri, 14 May 2010 02:16:44 +0000 (22:16 -0400)
committerDana Jansens <danakj@orodu.net>
Mon, 17 May 2010 23:31:51 +0000 (19:31 -0400)
example: context="Top Left Right Bottom"

openbox/config.c
openbox/frame.c
openbox/frame.h
openbox/mouse.c
openbox/mouse.h

index 00309d8..93ba3cb 100644 (file)
@@ -459,7 +459,7 @@ static void parse_mouse(xmlNodePtr node, gpointer d)
 {
     xmlNodePtr n, nbut, nact;
     gchar *buttonstr;
-    gchar *contextstr;
+    gchar *cxstr;
     ObMouseAction mact;
 
     mouse_unbind_all();
@@ -482,37 +482,52 @@ static void parse_mouse(xmlNodePtr node, gpointer d)
 
     n = obt_xml_find_node(node, "context");
     while (n) {
-        if (!obt_xml_attr_string(n, "name", &contextstr))
+        gchar *modcxstr;
+        ObFrameContext cx;
+
+        if (!obt_xml_attr_string(n, "name", &cxstr))
             goto next_n;
-        nbut = obt_xml_find_node(n->children, "mousebind");
-        while (nbut) {
-            if (!obt_xml_attr_string(nbut, "button", &buttonstr))
-                goto next_nbut;
-            if (obt_xml_attr_contains(nbut, "action", "press")) {
-                mact = OB_MOUSE_ACTION_PRESS;
-            } else if (obt_xml_attr_contains(nbut, "action", "release")) {
-                mact = OB_MOUSE_ACTION_RELEASE;
-            } else if (obt_xml_attr_contains(nbut, "action", "click")) {
-                mact = OB_MOUSE_ACTION_CLICK;
-            } else if (obt_xml_attr_contains(nbut, "action","doubleclick")) {
-                mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
-            } else if (obt_xml_attr_contains(nbut, "action", "drag")) {
-                mact = OB_MOUSE_ACTION_MOTION;
-            } else
-                goto next_nbut;
-            nact = obt_xml_find_node(nbut->children, "action");
-            while (nact) {
-                ObActionsAct *action;
-
-                if ((action = actions_parse(nact)))
-                    mouse_bind(buttonstr, contextstr, mact, action);
-                nact = obt_xml_find_node(nact->next, "action");
+
+        modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
+        while (frame_next_context_from_string(modcxstr, &cx)) {
+            if (!cx) {
+                g_message(_("Invalid context \"%s\" in mouse binding"),
+                          cxstr);
+                break;
             }
+
+            nbut = obt_xml_find_node(n->children, "mousebind");
+            while (nbut) {
+                if (!obt_xml_attr_string(nbut, "button", &buttonstr))
+                    goto next_nbut;
+                if (obt_xml_attr_contains(nbut, "action", "press"))
+                    mact = OB_MOUSE_ACTION_PRESS;
+                else if (obt_xml_attr_contains(nbut, "action", "release"))
+                    mact = OB_MOUSE_ACTION_RELEASE;
+                else if (obt_xml_attr_contains(nbut, "action", "click"))
+                    mact = OB_MOUSE_ACTION_CLICK;
+                else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
+                    mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
+                else if (obt_xml_attr_contains(nbut, "action", "drag"))
+                    mact = OB_MOUSE_ACTION_MOTION;
+                else
+                    goto next_nbut;
+
+                nact = obt_xml_find_node(nbut->children, "action");
+                while (nact) {
+                    ObActionsAct *action;
+
+                    if ((action = actions_parse(nact)))
+                        mouse_bind(buttonstr, cx, mact, action);
+                    nact = obt_xml_find_node(nact->next, "action");
+                }
+            next_nbut:
             g_free(buttonstr);
-        next_nbut:
             nbut = obt_xml_find_node(nbut->next, "mousebind");
+            }
         }
-        g_free(contextstr);
+        g_free(modcxstr);
+        g_free(cxstr);
     next_n:
         n = obt_xml_find_node(n->next, "context");
     }
@@ -959,8 +974,8 @@ static void bind_default_mouse(void)
     };
 
     for (it = binds; it->button; ++it)
-        mouse_bind(it->button, it->context, it->mact,
-                   actions_parse_string(it->actname));
+        mouse_bind(it->button, frame_context_from_string(it->context),
+                   it->mact, actions_parse_string(it->actname));
 }
 
 void config_startup(ObtXmlInst *i)
index 6c3ee6f..571ddc0 100644 (file)
@@ -1281,6 +1281,50 @@ static void layout_title(ObFrame *self)
         XUnmapWindow(obt_display, self->label);
 }
 
+gboolean frame_next_context_from_string(gchar *names, ObFrameContext *cx)
+{
+    gchar *p, *n;
+
+    if (!*names) /* empty string */
+        return FALSE;
+
+    /* find the first space */
+    for (p = names; *p; p = g_utf8_next_char(p)) {
+        const gunichar c = g_utf8_get_char(p);
+        if (g_unichar_isspace(c)) break;
+    }
+
+    if (p == names) {
+        /* leading spaces in the string */
+        n = g_utf8_next_char(names);
+        if (!frame_next_context_from_string(n, cx))
+            return FALSE;
+    } else {
+        n = p;
+        if (*p) {
+            /* delete the space with null zero(s) */
+            while (n < g_utf8_next_char(p))
+                *(n++) = '\0';
+        }
+
+        *cx = frame_context_from_string(names);
+
+        /* find the next non-space */
+        for (; *n; n = g_utf8_next_char(n)) {
+            const gunichar c = g_utf8_get_char(n);
+            if (!g_unichar_isspace(c)) break;
+        }
+    }
+
+    /* delete everything we just read (copy everything at n to the start of
+       the string */
+    for (p = names; *n; ++p, ++n)
+        *p = *n;
+    *p = *n;
+
+    return TRUE;
+}
+
 ObFrameContext frame_context_from_string(const gchar *name)
 {
     if (!g_ascii_strcasecmp("Desktop", name))
index 1130709..8f1ed91 100644 (file)
@@ -221,6 +221,16 @@ void frame_release_client(ObFrame *self);
 
 ObFrameContext frame_context_from_string(const gchar *name);
 
+/*! Parses a ObFrameContext from a string of space-separated context names.
+  @names The list of context names, the first of which is removed from the
+         string.
+  @cx The ObFrameContext is returned here.  If an invalid name is found, this
+      is set to OB_FRAME_CONTEXT_NONE.
+  @return TRUE if there was something to read in @names, FALSE if it was an
+          empty input.
+*/
+gboolean frame_next_context_from_string(gchar *names, ObFrameContext *cx);
+
 ObFrameContext frame_context(struct _ObClient *self, Window win,
                              gint x, gint y);
 
index 2f8604e..567ec4d 100644 (file)
@@ -362,25 +362,20 @@ gboolean mouse_event(ObClient *client, XEvent *e)
     return used;
 }
 
-gboolean mouse_bind(const gchar *buttonstr, const gchar *contextstr,
+gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context,
                     ObMouseAction mact, ObActionsAct *action)
 {
     guint state, button;
-    ObFrameContext context;
     ObMouseBinding *b;
     GSList *it;
 
+    g_assert(context != OB_FRAME_CONTEXT_NONE);
+
     if (!translate_button(buttonstr, &state, &button)) {
         g_message(_("Invalid button \"%s\" in mouse binding"), buttonstr);
         return FALSE;
     }
 
-    context = frame_context_from_string(contextstr);
-    if (!context) {
-        g_message(_("Invalid context \"%s\" in mouse binding"), contextstr);
-        return FALSE;
-    }
-
     for (it = bound_contexts[context]; it; it = g_slist_next(it)) {
         b = it->data;
         if (b->state == state && b->button == button) {
index 3effcc4..de4c0ec 100644 (file)
@@ -29,7 +29,7 @@ struct _ObActionsAct;
 void mouse_startup(gboolean reconfig);
 void mouse_shutdown(gboolean reconfig);
 
-gboolean mouse_bind(const gchar *buttonstr, const gchar *contextstr,
+gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context,
                     ObMouseAction mact, struct _ObActionsAct *action);
 void mouse_unbind_all(void);