mouse and key bindings plugins work. segfault somewhere still on shutdown
authorDana Jansens <danakj@orodu.net>
Wed, 19 Mar 2003 04:16:19 +0000 (04:16 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 19 Mar 2003 04:16:19 +0000 (04:16 +0000)
15 files changed:
openbox/action.c
openbox/action.h
openbox/grab.c
plugins/keyboard/Makefile.am
plugins/keyboard/keyboard.c
plugins/keyboard/keyboard.h
plugins/keyboard/translate.c
plugins/keyboard/translate.h
plugins/keyboard/tree.c
plugins/mouse/.cvsignore
plugins/mouse/Makefile.am
plugins/mouse/mouse.c
plugins/mouse/mouse.h [new file with mode: 0644]
plugins/mouse/translate.c [new file with mode: 0644]
plugins/mouse/translate.h [new file with mode: 0644]

index 9f97957..b976a84 100644 (file)
 #include "client.h"
 #include "stacking.h"
+#include "frame.h"
 #include "screen.h"
+#include "action.h"
 
 #include <glib.h>
 
-void action_execute(char *path)
+Action *action_new(void (*func)(union ActionData *data))
+{
+    Action *a = g_new(Action, 1);
+    a->func = func;
+
+    /* deal with pointers */
+    if (func == action_execute)
+        a->data.execute.path = NULL;
+
+    return a;
+}
+
+void action_free(Action *a)
+{
+    /* deal with pointers */
+    if (a->func == action_execute)
+        g_free(a->data.execute.path);
+
+    g_free(a);
+}
+
+void action_execute(union ActionData *data)
 {
     GError *e;
-    if (!g_spawn_command_line_async(path, &e)) {
-        g_warning("failed to execute '%s': %s", path, e->message);
+    if (!g_spawn_command_line_async(data->execute.path, &e)) {
+        g_warning("failed to execute '%s': %s",
+                  data->execute.path, e->message);
     }
 }
 
-void action_iconify(Client *c)
+void action_iconify(union ActionData *data)
 {
-    client_iconify(c, TRUE, TRUE);
+    client_iconify(data->client.c, TRUE, TRUE);
 }
 
-void action_raise(Client *c)
+void action_raise(union ActionData *data)
 {
-    stacking_raise(c);
+    stacking_raise(data->client.c);
 }
 
-void action_lower(Client *c)
+void action_lower(union ActionData *data)
 {
-    stacking_lower(c);
+    stacking_lower(data->client.c);
 }
 
-void action_close(Client *c)
+void action_close(union ActionData *data)
 {
-    client_close(c);
+    client_close(data->client.c);
 }
 
-void action_shade(Client *c)
+void action_shade(union ActionData *data)
 {
-    client_shade(c, TRUE);
+    client_shade(data->client.c, TRUE);
 }
 
-void action_unshade(Client *c)
+void action_unshade(union ActionData *data)
 {
-    client_shade(c, FALSE);
+    client_shade(data->client.c, FALSE);
 }
 
-void action_toggle_shade(Client *c)
+void action_toggle_shade(union ActionData *data)
 {
-    client_shade(c, !c->shaded);
+    client_shade(data->client.c, !data->client.c->shaded);
 }
 
-void action_toggle_omnipresent(Client *c)
+void action_toggle_omnipresent(union ActionData *data)
 {
-    client_set_desktop(c, c->desktop == DESKTOP_ALL ?
+    client_set_desktop(data->client.c, data->client.c->desktop == DESKTOP_ALL ?
                        screen_desktop : DESKTOP_ALL);
 }
 
-void action_move_relative(Client *c, int dx, int dy)
+void action_move_relative(union ActionData *data)
 {
-    client_configure(c, Corner_TopLeft, c->area.x + dx, c->area.y + dy,
+    Client *c = data->relative.c;
+    client_configure(c, Corner_TopLeft,
+                     c->area.x + data->relative.dx,
+                     c->area.y + data->relative.dy,
                      c->area.width, c->area.height, TRUE, TRUE);
 }
 
-void action_resize_relative(Client *c, int dx, int dy)
+void action_resize_relative(union ActionData *data)
 {
+    Client *c = data->relative.c;
     client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
-                     c->area.width + dx, c->area.height + dy, TRUE, TRUE);
+                     c->area.width + data->relative.dx,
+                     c->area.height + data->relative.dy, TRUE, TRUE);
 }
 
-void action_maximize_full(Client *c)
+void action_maximize_full(union ActionData *data)
 {
-    client_maximize(c, TRUE, 0, TRUE);
+    client_maximize(data->client.c, TRUE, 0, TRUE);
 }
 
-void action_unmaximize_full(Client *c)
+void action_unmaximize_full(union ActionData *data)
 {
-    client_maximize(c, FALSE, 0, TRUE);
+    client_maximize(data->client.c, FALSE, 0, TRUE);
 }
 
-void action_toggle_maximize_full(Client *c)
+void action_toggle_maximize_full(union ActionData *data)
 {
-    client_maximize(c, !(c->max_horz || c->max_vert), 0, TRUE);
+    client_maximize(data->client.c,
+                    !(data->client.c->max_horz || data->client.c->max_vert),
+                    0, TRUE);
 }
 
-void action_maximize_horz(Client *c)
+void action_maximize_horz(union ActionData *data)
 {
-    client_maximize(c, TRUE, 1, TRUE);
+    client_maximize(data->client.c, TRUE, 1, TRUE);
 }
 
-void action_unmaximize_horz(Client *c)
+void action_unmaximize_horz(union ActionData *data)
 {
-    client_maximize(c, FALSE, 1, TRUE);
+    client_maximize(data->client.c, FALSE, 1, TRUE);
 }
 
-void action_toggle_maximize_horz(Client *c)
+void action_toggle_maximize_horz(union ActionData *data)
 {
-    client_maximize(c, !c->max_horz, 1, TRUE);
+    client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
 }
 
-void action_maximize_vert(Client *c)
+void action_maximize_vert(union ActionData *data)
 {
-    client_maximize(c, TRUE, 2, TRUE);
+    client_maximize(data->client.c, TRUE, 2, TRUE);
 }
 
-void action_unmaximize_vert(Client *c)
+void action_unmaximize_vert(union ActionData *data)
 {
-    client_maximize(c, FALSE, 2, TRUE);
+    client_maximize(data->client.c, FALSE, 2, TRUE);
 }
 
-void action_toggle_maximize_vert(Client *c)
+void action_toggle_maximize_vert(union ActionData *data)
 {
-    client_maximize(c, !c->max_vert, 2, TRUE);
+    client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
 }
 
-void action_send_to_desktop(Client *c, guint desktop)
+void action_send_to_desktop(union ActionData *data)
 {
-    if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
-        client_set_desktop(c, desktop);
+    if (data->sendto.desktop < screen_num_desktops ||
+        data->sendto.desktop == DESKTOP_ALL)
+        client_set_desktop(data->sendto.c, data->sendto.desktop);
 }
 
-void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow)
+void action_send_to_next_desktop(union ActionData *data)
 {
     guint d;
 
     d = screen_desktop + 1;
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->sendtonextprev.wrap) return;
         d = 0;
     }
-    client_set_desktop(c, d);
-    if (follow) screen_set_desktop(d);
+    client_set_desktop(data->sendtonextprev.c, d);
+    if (data->sendtonextprev.follow) screen_set_desktop(d);
 }
 
-void action_send_to_previous_desktop(Client *c, gboolean wrap, gboolean follow)
+void action_send_to_previous_desktop(union ActionData *data)
 {
     guint d;
 
     d = screen_desktop - 1;
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->sendtonextprev.wrap) return;
         d = screen_num_desktops - 1;
     }
-    client_set_desktop(c, d);
-    if (follow) screen_set_desktop(d);
+    client_set_desktop(data->sendtonextprev.c, d);
+    if (data->sendtonextprev.follow) screen_set_desktop(d);
 }
 
-void action_desktop(guint desktop)
+void action_desktop(union ActionData *data)
 {
-    if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
-        screen_set_desktop(desktop);
+    if (data->desktop.desk < screen_num_desktops ||
+        data->desktop.desk == DESKTOP_ALL)
+        screen_set_desktop(data->desktop.desk);
 }
 
-void action_next_desktop(gboolean wrap)
+void action_next_desktop(union ActionData *data)
 {
     guint d;
 
     d = screen_desktop + 1;
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         d = 0;
     }
     screen_set_desktop(d);
 }
 
-void action_previous_desktop(gboolean wrap)
+void action_previous_desktop(union ActionData *data)
 {
     guint d;
 
     d = screen_desktop - 1;
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         d = screen_num_desktops - 1;
     }
     screen_set_desktop(d);
@@ -267,7 +300,7 @@ static guint translate_row_col(guint r, guint c)
     return 0;
 }
 
-void action_next_desktop_column(gboolean wrap)
+void action_next_desktop_column(union ActionData *data)
 {
     guint r, c, d;
 
@@ -275,7 +308,7 @@ void action_next_desktop_column(gboolean wrap)
     ++c;
     d = translate_row_col(r, c);
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         c = 0;
     }
     if (d >= screen_num_desktops)
@@ -285,7 +318,7 @@ void action_next_desktop_column(gboolean wrap)
         screen_set_desktop(d);
 }
 
-void action_previous_desktop_column(gboolean wrap)
+void action_previous_desktop_column(union ActionData *data)
 {
     guint r, c, d;
 
@@ -293,7 +326,7 @@ void action_previous_desktop_column(gboolean wrap)
     --c;
     d = translate_row_col(r, c);
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         c = screen_desktop_layout.columns - 1;
     }
     if (d >= screen_num_desktops)
@@ -303,7 +336,7 @@ void action_previous_desktop_column(gboolean wrap)
         screen_set_desktop(d);
 }
 
-void action_next_desktop_row(gboolean wrap)
+void action_next_desktop_row(union ActionData *data)
 {
     guint r, c, d;
 
@@ -311,7 +344,7 @@ void action_next_desktop_row(gboolean wrap)
     ++r;
     d = translate_row_col(r, c);
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         r = 0;
     }
     if (d >= screen_num_desktops)
@@ -321,7 +354,7 @@ void action_next_desktop_row(gboolean wrap)
         screen_set_desktop(d);
 }
 
-void action_previous_desktop_row(gboolean wrap)
+void action_previous_desktop_row(union ActionData *data)
 {
     guint r, c, d;
 
@@ -329,7 +362,7 @@ void action_previous_desktop_row(gboolean wrap)
     --r;
     d = translate_row_col(r, c);
     if (d >= screen_num_desktops) {
-        if (!wrap) return;
+        if (!data->nextprevdesktop.wrap) return;
         c = screen_desktop_layout.rows - 1;
     }
     if (d >= screen_num_desktops)
@@ -339,8 +372,29 @@ void action_previous_desktop_row(gboolean wrap)
         screen_set_desktop(d);
 }
 
-void action_toggle_decorations(Client *c)
+void action_toggle_decorations(union ActionData *data)
 {
+    Client *c = data->client.c;
     c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
     client_setup_decor_and_functions(c);
 }
+
+void action_move(union ActionData *data)
+{
+    Client *c = data->move.c;
+    int x = data->move.x;
+    int y = data->move.y;
+
+    client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
+                     TRUE, data->move.final);
+}
+
+void action_resize(union ActionData *data)
+{
+    Client *c = data->resize.c;
+    int w = data->resize.x - c->frame->size.left - c->frame->size.right;
+    int h = data->resize.y - c->frame->size.top - c->frame->size.bottom;
+
+    client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
+                     TRUE, data->resize.final);
+}
index 2a6ed8a..10fa177 100644 (file)
 
 #include "client.h"
 
-typedef enum {
-    Action_Execute,
-    Action_Iconify,
-    Action_Raise,
-    Action_Lower,
-    Action_Close,
-    Action_Shade,
-    Action_Unshade,
-    Action_ToggleShade,
-    Action_ToggleOmnipresent,
-    Action_MoveRelative,
-    Action_ResizeRelative,
-    Action_MaximizeFull,
-    Action_UnmaximizeFull,
-    Action_ToggleMaximizeFull,
-    Action_MaximizeHorz,
-    Action_UnmaximizeHorz,
-    Action_ToggleMaximizeHorz,
-    Action_MaximizeVert,
-    Action_UnmaximizeVert,
-    Action_ToggleMaximizeVert,
-    Action_SendToDesktop,
-    Action_SendToNextDesktop,
-    Action_SendToPreviousDesktop,
-    Action_Desktop,
-    Action_NextDesktop,
-    Action_PreviousDesktop,
-    Action_NextDesktopColumn,
-    Action_PreviousDesktopColumn,
-    Action_NextDesktopRow,
-    Action_PreviousDesktopRow,
-    Action_ToggleDecorations
+/* These have to all have a Client* at the top even if they don't use it, so
+   that I can set it blindly later on. So every function will have a Client*
+   available (possibly NULL though) if it wants it.
+*/
+
+struct AnyAction {
+    Client *c;
+};
+
+struct Execute {
+    Client *c;
+    char *path;
+};
+
+struct ClientAction {
+    Client *c;
+};
+
+struct MoveResizeRelative {
+    Client *c;
+    int dx;
+    int dy;
+};
+
+struct SendToDesktop {
+    Client *c;
+    guint desktop;
+};
+
+struct SendToNextPreviousDesktop {
+    Client *c;
+    gboolean wrap;
+    gboolean follow;
+};
+
+struct Desktop {
+    Client *c;
+    guint desk;
+};
+
+struct NextPreviousDesktop {
+    Client *c;
+    gboolean wrap;
+};
+
+struct Move {
+    Client *c;
+    int x;
+    int y;
+    gboolean final;
+};
+
+struct Resize {
+    Client *c;
+    int x;
+    int y;
+    gboolean final;
+    Corner corner;
+};
+
+union ActionData {
+    struct AnyAction any;
+    struct Execute execute;
+    struct ClientAction client;
+    struct MoveResizeRelative relative;
+    struct SendToDesktop sendto;
+    struct SendToNextPreviousDesktop sendtonextprev;
+    struct Desktop desktop;
+    struct NextPreviousDesktop nextprevdesktop;
+    struct Move move;
+    struct Resize resize;
+};
+
+typedef struct {
+    /* The func member acts like an enum to tell which one of the structs in
+       the data union are valid.
+    */
+    void (*func)(union ActionData *data);
+    union ActionData data;
 } Action;
 
-void action_execute(char *path);
-void action_iconify(Client *c);
-void action_raise(Client *c);
-void action_lower(Client *c);
-void action_close(Client *c);
-void action_shade(Client *c);
-void action_unshade(Client *c);
-void action_toggle_shade(Client *c);
-void action_toggle_omnipresent(Client *c);
-void action_move_relative(Client *c, int dx, int dy);
-void action_resize_relative(Client *c, int dx, int dy);
-void action_maximize_full(Client *c);
-void action_unmaximize_full(Client *c);
-void action_toggle_maximize_full(Client *c);
-void action_maximize_horz(Client *c);
-void action_unmaximize_horz(Client *c);
-void action_toggle_maximize_horz(Client *c);
-void action_maximize_vert(Client *c);
-void action_unmaximize_vert(Client *c);
-void action_toggle_maximize_vert(Client *c);
-void action_send_to_desktop(Client *c, guint desktop);
-void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow);
-void action_send_to_previous_desktop(Client *c, gboolean wrap,gboolean follow);
-void action_desktop(guint desktop);
-void action_next_desktop(gboolean wrap);
-void action_previous_desktop(gboolean wrap);
-void action_next_desktop_column(gboolean wrap);
-void action_previous_desktop_column(gboolean wrap);
-void action_next_desktop_row(gboolean wrap);
-void action_previous_desktop_row(gboolean wrap);
-void action_toggle_decorations(Client *c);
+Action *action_new(void (*func)(union ActionData *data));
+void action_free(Action *a);
+
+/* Execute */
+void action_execute(union ActionData *data);
+/* ClientAction */
+void action_iconify(union ActionData *data);
+/* ClientAction */
+void action_raise(union ActionData *data);
+/* ClientAction */
+void action_lower(union ActionData *data);
+/* ClientAction */
+void action_close(union ActionData *data);
+/* ClientAction */
+void action_shade(union ActionData *data);
+/* ClientAction */
+void action_unshade(union ActionData *data);
+/* ClientAction */
+void action_toggle_shade(union ActionData *data);
+/* ClientAction */
+void action_toggle_omnipresent(union ActionData *data);
+/* MoveResizeRelative */
+void action_move_relative(union ActionData *data);
+/* MoveResizeRelative */
+void action_resize_relative(union ActionData *data);
+/* ClientAction */
+void action_maximize_full(union ActionData *data);
+/* ClientAction */
+void action_unmaximize_full(union ActionData *data);
+/* ClientAction */
+void action_toggle_maximize_full(union ActionData *data);
+/* ClientAction */
+void action_maximize_horz(union ActionData *data);
+/* ClientAction */
+void action_unmaximize_horz(union ActionData *data);
+/* ClientAction */
+void action_toggle_maximize_horz(union ActionData *data);
+/* ClientAction */
+void action_maximize_vert(union ActionData *data);
+/* ClientAction */
+void action_unmaximize_vert(union ActionData *data);
+/* ClientAction */
+void action_toggle_maximize_vert(union ActionData *data);
+/* SendToDesktop */
+void action_send_to_desktop(union ActionData *data);
+/* SendToNextPreviousDesktop */
+void action_send_to_next_desktop(union ActionData *data);
+/* SendToNextPreviousDesktop */
+void action_send_to_previous_desktop(union ActionData *data);
+/* Desktop */
+void action_desktop(union ActionData *data);
+/* NextPreviousDesktop */
+void action_next_desktop(union ActionData *data);
+/* NextPreviousDesktop */
+void action_previous_desktop(union ActionData *data);
+/* NextPreviousDesktop */
+void action_next_desktop_column(union ActionData *data);
+/* NextPreviousDesktop */
+void action_previous_desktop_column(union ActionData *data);
+/* NextPreviousDesktop */
+void action_next_desktop_row(union ActionData *data);
+/* NextPreviousDesktop */
+void action_previous_desktop_row(union ActionData *data);
+/* ClientAction */
+void action_toggle_decorations(union ActionData *data);
+/* Move */
+void action_move(union ActionData *data);
+/* Resize */
+void action_resize(union ActionData *data);
 
 #endif
index c6beee7..6312711 100644 (file)
@@ -21,7 +21,7 @@ void grab_pointer(gboolean grab, Cursor cur)
     if (grab) {
         if (pgrabs++ == 0)
             XGrabPointer(ob_display, ob_root, False, 0, GrabModeAsync,
-                         GrabModeSync, FALSE, cur, CurrentTime);
+                         GrabModeAsync, FALSE, cur, CurrentTime);
     } else if (pgrabs > 0) {
         if (--pgrabs == 0)
             XUngrabPointer(ob_display, CurrentTime);
index 983fd39..b5ab415 100644 (file)
@@ -7,9 +7,9 @@ CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
 plugin_LTLIBRARIES=keyboard.la
 
 keyboard_la_LDFLAGS=-module -avoid-version
-keyboard_la_SOURCES=keyboard.c tree.c translate.c keyaction.c
+keyboard_la_SOURCES=keyboard.c tree.c translate.c
 
-noinst_HEADERS=keyboard.h tree.h translate.h keyaction.h
+noinst_HEADERS=keyboard.h tree.h translate.h
 
 MAINTAINERCLEANFILES= Makefile.in
 
index 05481b5..141bb5b 100644 (file)
@@ -5,7 +5,6 @@
 #include "../../kernel/action.h"
 #include "tree.h"
 #include "keyboard.h"
-#include "keyaction.h"
 #include <glib.h>
 
 KeyBindingTree *firstnode;
@@ -21,6 +20,7 @@ static void grab_keys(gboolean grab)
     } else {
        KeyBindingTree *p = firstnode;
        while (p) {
+            /* XXX grab all lock keys too */
            XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
                     GrabModeAsync, GrabModeSync);
            p = p->next_sibling;
@@ -38,56 +38,43 @@ static void reset_chains()
     }
 }
 
-static void clearall()
-{
-    grab_keys(FALSE);
-    tree_destroy(firstnode);
-    firstnode = NULL;
-    grab_keys(TRUE);
-}
-
-static gboolean bind(GList *keylist, KeyAction *action)
+static gboolean kbind(GList *keylist, Action *action)
 {
     KeyBindingTree *tree, *t;
     gboolean conflict;
 
+    g_assert(keylist != NULL);
+    g_assert(action != NULL);
+
     if (!(tree = tree_build(keylist))) {
         g_warning("invalid binding");
         return FALSE;
     }
-
-    t = tree_find(tree, &conflict);
-    if (conflict) {
-        g_warning("conflict with binding");
+    if ((t = tree_find(tree, &conflict)) != NULL) {
+       /* already bound to something */
+       g_warning("keychain is already bound");
         tree_destroy(tree);
         return FALSE;
     }
-    if (t != NULL) {
-       /* already bound to something */
-       g_warning("keychain is already bound");
+    if (conflict) {
+        g_warning("conflict with binding");
         tree_destroy(tree);
         return FALSE;
     }
 
-    /* grab the server here to make sure no key pressed go missed */
+    /* grab the server here to make sure no key presses go missed */
     grab_server(TRUE);
-
     grab_keys(FALSE);
 
-    /* set the function */
+    /* set the action */
     t = tree;
     while (t->first_child) t = t->first_child;
-    t->action.action = action->action;
-    t->action.type[0] = action->type[0];
-    t->action.type[1] = action->type[1];
-    t->action.data[0] = action->data[0];
-    t->action.data[1] = action->data[1];
-
-    /* assimilate this built tree into the main tree */
-    tree_assimilate(tree); /* assimilation destroys/uses the tree */
+    t->action = action;
+    /* assimilate this built tree into the main tree. assimilation
+       destroys/uses the tree */
+    tree_assimilate(tree);
 
     grab_keys(TRUE); 
-
     grab_server(FALSE);
 
     return TRUE;
@@ -117,7 +104,14 @@ static void press(ObEvent *e, void *foo)
                     }
                     curpos = p;
                 } else {
-                    keyaction_do(&p->action, focus_client);
+                    if (p->action->func != NULL) {
+                        p->action->data.any.c = focus_client;
+
+                        g_assert(!(p->action->func == action_move ||
+                                   p->action->func == action_resize));
+
+                        p->action->func(&p->action->data);
+                    }
 
                     XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
                     reset_chains();
@@ -132,49 +126,47 @@ static void press(ObEvent *e, void *foo)
 static void binddef()
 {
     GList *list = g_list_append(NULL, NULL);
-    KeyAction a;
+    Action *a;
+
+    /* When creating an Action struct, all of the data elements in the
+       appropriate struct need to be set, except the Client*, which will be set
+       at call-time when then action function is used.
+    */
 
     list->data = "C-Right";
-    a.action = Action_NextDesktop;
-    keyaction_set_bool(&a, 0, TRUE);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_next_desktop);
+    a->data.nextprevdesktop.wrap = TRUE;
+    kbind(list, a);
 
     list->data = "C-Left";
-    a.action = Action_PreviousDesktop;
-    keyaction_set_bool(&a, 0, TRUE);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_previous_desktop);
+    a->data.nextprevdesktop.wrap = TRUE;
+    kbind(list, a);
 
     list->data = "C-1";
-    a.action = Action_Desktop;
-    keyaction_set_uint(&a, 0, 0);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_desktop);
+    a->data.desktop.desk = 0;
+    kbind(list, a);
 
-    list->data = "C-2";
-    a.action = Action_Desktop;
-    keyaction_set_uint(&a, 0, 1);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    list->data = "C-2"; 
+    a = action_new(action_desktop);
+    a->data.desktop.desk = 1;
+    kbind(list, a);
 
     list->data = "C-3";
-    a.action = Action_Desktop;
-    keyaction_set_uint(&a, 0, 2);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_desktop);
+    a->data.desktop.desk = 2;
+    kbind(list, a);
 
     list->data = "C-4";
-    a.action = Action_Desktop;
-    keyaction_set_uint(&a, 0, 3);
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_desktop);
+    a->data.desktop.desk = 3;
+    kbind(list, a);
 
     list->data = "C-space";
-    a.action = Action_Execute;
-    keyaction_set_string(&a, 0, "xterm");
-    keyaction_set_none(&a, 1);
-    bind(list, &a);
+    a = action_new(action_execute);
+    a->data.execute.path = g_strdup("xterm");
+    kbind(list, a);
 }
 
 void plugin_startup()
@@ -188,6 +180,10 @@ void plugin_startup()
 void plugin_shutdown()
 {
     dispatch_register(0, (EventHandler)press, NULL);
-    clearall();
+
+    grab_keys(FALSE);
+    tree_destroy(firstnode);
+    firstnode = NULL;
+    grab_keys(TRUE);
 }
 
index b183fa3..e2406d9 100644 (file)
@@ -1,14 +1,15 @@
 #ifndef __plugin_keyboard_keybaord_h
 #define __plugin_keyboard_keybaord_h
 
-#include "keyaction.h"
 #include <glib.h>
 
+#include "../../kernel/action.h"
+
 typedef struct KeyBindingTree {
     guint state;
     guint key;
     GList *keylist;
-    KeyAction action;
+    Action *action;
 
     /* the next binding in the tree at the same level */
     struct KeyBindingTree *next_sibling; 
index 75c077f..d18c604 100644 (file)
@@ -1,9 +1,8 @@
 #include "../../kernel/openbox.h"
-#include "keyboard.h"
 #include <glib.h>
 #include <string.h>
 
-guint keyboard_translate_modifier(char *str)
+static guint translate_modifier(char *str)
 {
     if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
     else if (!strcmp("Mod2", str)) return Mod2Mask;
@@ -36,7 +35,7 @@ gboolean translate_key(char *str, guint *state, guint *keycode)
     /* figure out the mod mask */
     *state = 0;
     for (i = 0; parsed[i] != l; ++i) {
-       guint m = keyboard_translate_modifier(parsed[i]);
+       guint m = translate_modifier(parsed[i]);
        if (!m) goto translation_fail;
        *state |= m;
     }
index e0d0bae..4dae901 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <glib.h>
 
-guint translate_modifier(char *str);
 gboolean translate_key(char *str, guint *state, guint *keycode);
 
 #endif
index b7f5188..ab52837 100644 (file)
@@ -1,6 +1,5 @@
 #include "keyboard.h"
 #include "translate.h"
-#include "keyaction.h"
 #include <glib.h>
 
 void tree_destroy(KeyBindingTree *tree)
@@ -15,7 +14,7 @@ void tree_destroy(KeyBindingTree *tree)
            for (it = tree->keylist; it != NULL; it = it->next)
                g_free(it->data);
            g_list_free(tree->keylist);
-            keyaction_free(&tree->action);
+            action_free(tree->action);
        }
        g_free(tree);
        tree = c;
index e76ce20..0acc4c5 100644 (file)
@@ -4,3 +4,4 @@ Makefile
 Makefile.in
 .libs
 .deps
+translate.lo
index d2ead23..dabf853 100644 (file)
@@ -7,9 +7,9 @@ CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
 plugin_LTLIBRARIES=mouse.la
 
 mouse_la_LDFLAGS=-module -avoid-version
-mouse_la_SOURCES=mouse.c
+mouse_la_SOURCES=mouse.c translate.c
 
-noinst_HEADERS=
+noinst_HEADERS=mouse.h translate.h
 
 MAINTAINERCLEANFILES= Makefile.in
 
index 7b129c8..5dd39db 100644 (file)
+#include "../../kernel/openbox.h"
 #include "../../kernel/dispatch.h"
+#include "../../kernel/action.h"
+#include "../../kernel/client.h"
+#include "../../kernel/frame.h"
+#include "../../kernel/engine.h"
+#include "translate.h"
+#include "mouse.h"
 #include <glib.h>
 
-void my_powerful_function() {}
+/* GData of GSList*s of PointerBinding*s. */
+static GData *bound_contexts;
+
+struct foreach_grab_temp {
+    Client *client;
+    gboolean grab;
+};
+
+static void grab_button(Client *client, guint state, guint button,
+                       GQuark context, gboolean grab)
+{
+    Window win;
+    int mode = GrabModeAsync;
+    unsigned int mask;
+
+    if (context == g_quark_try_string("frame")) {
+       win = client->frame->window;
+       mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
+    } else if (context == g_quark_try_string("client")) {
+       win = client->frame->plate;
+       mode = GrabModeSync; /* this is handled in pointer_event */
+       mask = ButtonPressMask; /* can't catch more than this with Sync mode
+                                  the release event is manufactured in
+                                  pointer_fire */
+    } else return;
+
+    if (grab)
+        /* XXX grab all lock keys */
+       XGrabButton(ob_display, button, state, win, FALSE, mask, mode,
+                   GrabModeAsync, None, None);
+    else
+        /* XXX ungrab all lock keys */
+       XUngrabButton(ob_display, button, state, win);
+}
+
+static void foreach_grab(GQuark key, gpointer data, gpointer user_data)
+{
+    struct foreach_grab_temp *d = user_data;
+    GSList *it;
+    for (it = data; it != NULL; it = it->next) {
+       MouseBinding *b = it->data;
+       grab_button(d->client, b->state, b->button, key, d->grab);
+    }
+}
+  
+static void grab_for_client(Client *client, gboolean grab)
+{
+    struct foreach_grab_temp bt;
+    bt.client = client;
+    bt.grab = grab;
+    g_datalist_foreach(&bound_contexts, foreach_grab, &bt);
+}
+
+static void grab_all_clients(gboolean grab)
+{
+    GSList *it;
+
+    for (it = client_list; it != NULL; it = it->next)
+       grab_for_client(it->data, grab);
+}
+
+static void foreach_clear(GQuark key, gpointer data, gpointer user_data)
+{
+    GSList *it;
+    user_data = user_data;
+    for (it = data; it != NULL; it = it->next) {
+       int i;
+
+        MouseBinding *b = it->data;
+       for (i = 0; i < NUM_MOUSEACTION; ++i)
+            action_free(b->action[i]);
+        g_free(b);
+    }
+    g_slist_free(data);
+}
+
+static void fire_button(MouseAction a, GQuark context, Client *c, guint state,
+                        guint button)
+{
+    GSList *it;
+    MouseBinding *b;
+
+    for (it = g_datalist_id_get_data(&bound_contexts, context);
+         it != NULL; it = it->next) {
+        b = it->data;
+        if (b->state == state && b->button == button)
+            break;
+    }
+    /* if not bound, then nothing to do! */
+    if (it == NULL) return;
+
+    if (b->action[a] != NULL && b->action[a]->func != NULL) {
+        b->action[a]->data.any.c = c;
+
+        g_assert(!(b->action[a]->func == action_move ||
+                   b->action[a]->func == action_resize));
+
+        b->action[a]->func(&b->action[a]->data);
+    }
+}
+
+/* corner should be the opposite corner of the window in which the pointer
+   clicked, Corner_TopLeft if a good default if there is no client */
+static void fire_motion(MouseAction a, GQuark context, Client *c, guint state,
+                        guint button, int cx, int cy, int cw, int ch,
+                        int dx, int dy, gboolean final, Corner corner)
+{
+    GSList *it;
+    MouseBinding *b;
+
+    for (it = g_datalist_id_get_data(&bound_contexts, context);
+         it != NULL; it = it->next) {
+        b = it->data;
+        if (b->state == state && b->button == button)
+               break;
+    }
+    /* if not bound, then nothing to do! */
+    if (it == NULL) return;
+
+    if (b->action[a] != NULL && b->action[a]->func != NULL) {
+        b->action[a]->data.any.c = c;
+
+        if (b->action[a]->func == action_move) {
+            b->action[a]->data.move.x = cx + dx;
+            b->action[a]->data.move.y = cy + dy;
+            b->action[a]->data.move.final = final;
+        } else if (b->action[a]->func == action_resize) {
+            b->action[a]->data.resize.corner = corner;
+            switch (corner) {
+            case Corner_TopLeft:
+                b->action[a]->data.resize.x = cw + dx;
+                b->action[a]->data.resize.y = ch + dy;
+                break;
+            case Corner_TopRight:
+                b->action[a]->data.resize.x = cw - dx;
+                b->action[a]->data.resize.y = ch + dy;
+                break;
+            case Corner_BottomLeft:
+                b->action[a]->data.resize.x = cw + dx;
+                b->action[a]->data.resize.y = ch - dy;
+                break;
+            case Corner_BottomRight:
+                b->action[a]->data.resize.x = cw - dx;
+                b->action[a]->data.resize.y = ch - dy;
+                break;
+            }
+            b->action[a]->data.resize.final = final;
+        }
+        b->action[a]->func(&b->action[a]->data);
+    }
+}
+
+static Corner pick_corner(int x, int y, int cx, int cy, int cw, int ch)
+{
+    if (x - cx < cw / 2) {
+        if (y - cy < ch / 2)
+            return Corner_BottomRight;
+        else
+            return Corner_TopRight;
+    } else {
+        if (y - cy < ch / 2)
+            return Corner_BottomLeft;
+        else
+            return Corner_TopLeft;
+    }
+}
 
 static void event(ObEvent *e, void *foo)
 {
+    static Time ltime;
+    static int px, py, cx, cy, cw, ch, dx, dy;
+    static guint button = 0, lbutton = 0;
+    static gboolean drag = FALSE;
+    static Corner corner = Corner_TopLeft;
+    gboolean click = FALSE;
+    gboolean dclick = FALSE;
+
     switch (e->type) {
+    case Event_Client_Mapped:
+        grab_for_client(e->data.c.client, TRUE);
+        break;
+
+    case Event_Client_Destroy:
+        grab_for_client(e->data.c.client, FALSE);
+        break;
+
     case Event_X_ButtonPress:
+        if (!button) {
+            if (e->data.x.client == NULL)
+                corner = Corner_TopLeft;
+            else {
+                cx = e->data.x.client->frame->area.x;
+                cy = e->data.x.client->frame->area.y;
+                cw = e->data.x.client->frame->area.width;
+                ch = e->data.x.client->frame->area.height;
+                px = e->data.x.e->xbutton.x_root;
+                py = e->data.x.e->xbutton.y_root;
+                corner = pick_corner(px, py, cx, cy, cw, ch);
+                button = e->data.x.e->xbutton.button;
+            }
+        }
+        fire_button(MouseAction_Press,
+                    engine_get_context(e->data.x.client,
+                                       e->data.x.e->xbutton.window),
+                    e->data.x.client, e->data.x.e->xbutton.state,
+                    e->data.x.e->xbutton.button);
         break;
+
     case Event_X_ButtonRelease:
+        if (e->data.x.e->xbutton.button == button) {
+            /* end drags */
+            if (drag) {
+                fire_motion(MouseAction_Motion,
+                            engine_get_context(e->data.x.client,
+                                               e->data.x.e->xbutton.window),
+                            e->data.x.client, e->data.x.e->xbutton.state,
+                            e->data.x.e->xbutton.button,
+                            cx, cy, cw, ch, dx, dy, TRUE, corner);
+            }
+
+            /* clicks are only valid if its released over the window */
+           if (e->data.x.e->xbutton.x >= 0 && e->data.x.e->xbutton.y >= 0) {
+               int junk;
+               Window wjunk;
+               guint ujunk, w, h;
+               XGetGeometry(ob_display, e->data.x.e->xbutton.window,
+                             &wjunk, &junk, &junk, &w, &h, &ujunk, &ujunk);
+               if (e->data.x.e->xbutton.x < (signed)w &&
+                    e->data.x.e->xbutton.y < (signed)h) {
+                   click =TRUE;
+                    /* double clicks happen if there were 2 in a row! */
+                    if (lbutton == button &&
+                        e->data.x.e->xbutton.time - 300 <= ltime)
+                        dclick = TRUE;
+                }
+                lbutton = button;
+           } else
+                lbutton = 0;
+
+            button = 0;
+            ltime = e->data.x.e->xbutton.time;
+        }
+        fire_button(MouseAction_Press,
+                    engine_get_context(e->data.x.client,
+                                       e->data.x.e->xbutton.window),
+                    e->data.x.client, e->data.x.e->xbutton.state,
+                    e->data.x.e->xbutton.button);
+        if (click)
+            fire_button(MouseAction_Click,
+                        engine_get_context(e->data.x.client,
+                                           e->data.x.e->xbutton.window),
+                        e->data.x.client, e->data.x.e->xbutton.state,
+                        e->data.x.e->xbutton.button);
+        if (dclick)
+            fire_button(MouseAction_DClick,
+                        engine_get_context(e->data.x.client,
+                                           e->data.x.e->xbutton.window),
+                        e->data.x.client, e->data.x.e->xbutton.state,
+                        e->data.x.e->xbutton.button);
         break;
+
     case Event_X_MotionNotify:
+        if (button) {
+            drag = TRUE;
+            dx = e->data.x.e->xmotion.x_root - px;
+            dy = e->data.x.e->xmotion.y_root - py;
+            fire_motion(MouseAction_Motion,
+                        engine_get_context(e->data.x.client,
+                                           e->data.x.e->xbutton.window),
+                        e->data.x.client, e->data.x.e->xmotion.state,
+                        button, cx, cy, cw, ch, dx, dy, FALSE, corner);
+        }
         break;
+
     default:
         g_assert_not_reached();
     }
 }
 
+static gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
+                      Action *action)
+{
+    guint state, button;
+    GQuark context;
+    MouseBinding *b;
+    GSList *it;
+    guint i;
+
+    if (!translate_button(buttonstr, &state, &button)) {
+        g_warning("invalid button");
+        return FALSE;
+    }
+
+    context = g_quark_try_string(contextstr);
+    if (!context) {
+        g_warning("invalid context");
+        return FALSE;
+    }
+
+    for (it = g_datalist_id_get_data(&bound_contexts, context);
+        it != NULL; it = it->next){
+       b = it->data;
+       if (b->state == state && b->button == button) {
+           /* already bound */
+            if (b->action[mact] != NULL) {
+                g_warning("duplicate binding");
+                return FALSE;
+            }
+            b->action[mact] = action;
+            return TRUE;
+       }
+    }
+
+    grab_all_clients(FALSE);
+
+    /* add the binding */
+    b = g_new(MouseBinding, 1);
+    b->state = state;
+    b->button = button;
+    for (i = 0; i < NUM_MOUSEACTION; ++i)
+        if (i != mact)
+            b->action[i] = NULL;
+    b->action[mact] = action;
+    g_datalist_id_set_data(&bound_contexts, context, 
+        g_slist_append(g_datalist_id_get_data(&bound_contexts, context), b));
+
+    grab_all_clients(TRUE);
+
+    return TRUE;
+}
+
+static void binddef()
+{
+    Action *a;
+
+    /* When creating an Action struct, all of the data elements in the
+       appropriate struct need to be set, except the Client*, which will be set
+       at call-time when then action function is used.
+
+       For action_move and action_resize, the 'x', 'y', and 'final' data
+       elements should not be set, as they are set at call-time.       
+    */
+
+    a = action_new(action_move);
+    mbind("1", "titlebar", MouseAction_Motion, a);
+    a = action_new(action_move);
+    mbind("1", "handle", MouseAction_Motion, a);
+    a = action_new(action_move);
+    mbind("A-1", "frame", MouseAction_Motion, a);
+
+    a = action_new(action_resize);
+    mbind("1", "blcorner", MouseAction_Motion, a);
+    a = action_new(action_resize);
+    mbind("1", "brcorner", MouseAction_Motion, a);
+    a = action_new(action_resize);
+    mbind("A-3", "frame", MouseAction_Motion, a);
+}
+
 void plugin_startup()
 {
-    dispatch_register(Event_X_ButtonPress | Event_X_ButtonRelease |
+    dispatch_register(Event_Client_Mapped | Event_Client_Destroy |
+                      Event_X_ButtonPress | Event_X_ButtonRelease |
                       Event_X_MotionNotify, (EventHandler)event, NULL);
+
+    /* XXX parse a config */
+    binddef();
 }
 
 void plugin_shutdown()
 {
     dispatch_register(0, (EventHandler)event, NULL);
+
+    grab_all_clients(FALSE);
+    g_datalist_foreach(&bound_contexts, foreach_clear, NULL);
 }
diff --git a/plugins/mouse/mouse.h b/plugins/mouse/mouse.h
new file mode 100644 (file)
index 0000000..0498488
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __plugin_mouse_mouse_h
+#define __plugin_mouse_mouse_h
+
+#include "../../kernel/action.h"
+
+typedef enum {
+    MouseAction_Press,
+    MouseAction_Release,
+    MouseAction_Click,
+    MouseAction_DClick,
+    MouseAction_Motion,
+    NUM_MOUSEACTION
+} MouseAction;
+
+typedef struct {
+    guint state;
+    guint button;
+    Action *action[NUM_MOUSEACTION];
+} MouseBinding;
+
+#endif
diff --git a/plugins/mouse/translate.c b/plugins/mouse/translate.c
new file mode 100644 (file)
index 0000000..8d4b0d4
--- /dev/null
@@ -0,0 +1,55 @@
+#include "../../kernel/openbox.h"
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+
+static guint translate_modifier(char *str)
+{
+    if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
+    else if (!strcmp("Mod2", str)) return Mod2Mask;
+    else if (!strcmp("Mod3", str)) return Mod3Mask;
+    else if (!strcmp("Mod4", str) || !strcmp("W", str)) return Mod4Mask;
+    else if (!strcmp("Mod5", str)) return Mod5Mask;
+    else if (!strcmp("C", str)) return ControlMask;
+    else if (!strcmp("S", str)) return ShiftMask;
+    g_warning("Invalid modifier '%s' in binding.", str);
+    return 0;
+}
+
+gboolean translate_button(char *str, guint *state, guint *button)
+{
+    char **parsed;
+    char *l;
+    int i;
+    gboolean ret = FALSE;
+
+    parsed = g_strsplit(str, "-", -1);
+    
+    /* first, find the button (last token) */
+    l = NULL;
+    for (i = 0; parsed[i] != NULL; ++i)
+       l = parsed[i];
+    if (l == NULL)
+       goto translation_fail;
+
+    /* figure out the mod mask */
+    *state = 0;
+    for (i = 0; parsed[i] != l; ++i) {
+       guint m = translate_modifier(parsed[i]);
+       if (!m) goto translation_fail;
+       *state |= m;
+    }
+
+    /* figure out the button */
+    *button = atoi(l);
+    if (!*button) {
+       g_warning("Invalid button '%s' in pointer binding.", l);
+       goto translation_fail;
+    }
+
+    ret = TRUE;
+
+translation_fail:
+    g_strfreev(parsed);
+    return ret;
+}
diff --git a/plugins/mouse/translate.h b/plugins/mouse/translate.h
new file mode 100644 (file)
index 0000000..a2fcfc9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __plugin_mouse_translate_h
+#define __plugin_mouse_translate_h
+
+#include <glib.h>
+
+gboolean translate_button(char *str, guint *state, guint *keycode);
+
+#endif