X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=plugins%2Fmouse%2Fmouse.c;h=1ef0ee8772a77813e632d2877733f5c401583643;hb=49eea4715faa55a0da670112619f22da6e20f5aa;hp=5dd39db39d59597a02200e02ed929c06b92ec97e;hpb=4bcd03b2d0904e2b5443a2383b66055422240255;p=chaz%2Fopenbox diff --git a/plugins/mouse/mouse.c b/plugins/mouse/mouse.c index 5dd39db3..1ef0ee87 100644 --- a/plugins/mouse/mouse.c +++ b/plugins/mouse/mouse.c @@ -1,13 +1,22 @@ #include "../../kernel/openbox.h" #include "../../kernel/dispatch.h" #include "../../kernel/action.h" +#include "../../kernel/event.h" #include "../../kernel/client.h" #include "../../kernel/frame.h" +#include "../../kernel/grab.h" #include "../../kernel/engine.h" #include "translate.h" #include "mouse.h" +#include "mouserc_parse.h" #include +void plugin_setup_config() +{ +} + +static int drag_threshold = 3; + /* GData of GSList*s of PointerBinding*s. */ static GData *bound_contexts; @@ -16,40 +25,33 @@ struct foreach_grab_temp { 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) { + /* grab/ungrab the button */ MouseBinding *b = it->data; - grab_button(d->client, b->state, b->button, key, d->grab); + Window win; + int mode; + unsigned int mask; + + if (key == g_quark_try_string("frame")) { + win = d->client->frame->window; + mode = GrabModeAsync; + mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask; + } else if (key == g_quark_try_string("client")) { + win = d->client->frame->plate; + mode = GrabModeSync; /* this is handled in event */ + mask = ButtonPressMask; /* can't catch more than this with Sync + mode the release event is manufactured + in event */ + } else return; + + if (d->grab) + grab_button(b->button, b->state, win, mask, mode); + else + ungrab_button(b->button, b->state, win); } } @@ -78,7 +80,8 @@ static void foreach_clear(GQuark key, gpointer data, gpointer user_data) MouseBinding *b = it->data; for (i = 0; i < NUM_MOUSEACTION; ++i) - action_free(b->action[i]); + if (b->action[i] != NULL) + action_free(b->action[i]); g_free(b); } g_slist_free(data); @@ -110,10 +113,13 @@ static void fire_button(MouseAction a, GQuark context, Client *c, guint state, } /* 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) + clicked, Corner_TopLeft if a good default if there is no client + Returns True or False for if a binding existed for the action or not. +*/ +static gboolean 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; @@ -125,7 +131,7 @@ static void fire_motion(MouseAction a, GQuark context, Client *c, guint state, break; } /* if not bound, then nothing to do! */ - if (it == NULL) return; + if (it == NULL) return FALSE; if (b->action[a] != NULL && b->action[a]->func != NULL) { b->action[a]->data.any.c = c; @@ -157,7 +163,9 @@ static void fire_motion(MouseAction a, GQuark context, Client *c, guint state, b->action[a]->data.resize.final = final; } b->action[a]->func(&b->action[a]->data); + return TRUE; } + return FALSE; } static Corner pick_corner(int x, int y, int cx, int cy, int cw, int ch) @@ -180,10 +188,11 @@ 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 gboolean drag = FALSE, drag_used = FALSE; static Corner corner = Corner_TopLeft; gboolean click = FALSE; gboolean dclick = FALSE; + GQuark context; switch (e->type) { case Event_Client_Mapped: @@ -196,89 +205,106 @@ static void event(ObEvent *e, void *foo) case Event_X_ButtonPress: if (!button) { - if (e->data.x.client == NULL) - corner = Corner_TopLeft; - else { + if (e->data.x.client != NULL) { 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; + /* use the client size because the frame can be differently + sized (shaded windows) and we want this based on the clients + size */ + cw = e->data.x.client->area.width + + e->data.x.client->frame->size.left + + e->data.x.client->frame->size.right; + ch = e->data.x.client->area.height + + e->data.x.client->frame->size.top + + e->data.x.client->frame->size.bottom; 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; } + button = e->data.x.e->xbutton.button; } - fire_button(MouseAction_Press, - engine_get_context(e->data.x.client, - e->data.x.e->xbutton.window), + context = engine_get_context(e->data.x.client, + e->data.x.e->xbutton.window); + + fire_button(MouseAction_Press, context, e->data.x.client, e->data.x.e->xbutton.state, e->data.x.e->xbutton.button); - break; + + if (context == g_quark_try_string("client")) { + /* Replay the event, so it goes to the client*/ + XAllowEvents(ob_display, ReplayPointer, event_lasttime); + /* Fall through to the release case! */ + } else + break; case Event_X_ButtonRelease: + context = engine_get_context(e->data.x.client, + e->data.x.e->xbutton.window); 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), + if (drag_used) { + fire_motion(MouseAction_Motion, context, 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; + drag = drag_used = FALSE; + + lbutton = 0; + } else { + /* clicks are only valid if its released over the window */ + int junk; + Window wjunk; + guint ujunk, b, w, h; + XGetGeometry(ob_display, e->data.x.e->xbutton.window, + &wjunk, &junk, &junk, &w, &h, &b, &ujunk); + if (e->data.x.e->xbutton.x >= (signed)-b && + e->data.x.e->xbutton.y >= (signed)-b && + e->data.x.e->xbutton.x < (signed)(w+b) && + e->data.x.e->xbutton.y < (signed)(h+b)) { + click = TRUE; /* double clicks happen if there were 2 in a row! */ if (lbutton == button && - e->data.x.e->xbutton.time - 300 <= ltime) + e->data.x.e->xbutton.time - 300 <= ltime) { dclick = TRUE; - } - lbutton = button; - } else - lbutton = 0; + lbutton = 0; + } else + 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), + fire_button(MouseAction_Release, context, 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), + fire_button(MouseAction_Click, context, 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), + fire_button(MouseAction_DClick, context, 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); + if (!drag && + (ABS(dx) >= drag_threshold || ABS(dy) >= drag_threshold)) + drag = TRUE; + if (drag) { + context = engine_get_context(e->data.x.client, + e->data.x.e->xbutton.window); + drag_used = fire_motion(MouseAction_Motion, context, + e->data.x.client, + e->data.x.e->xmotion.state, + button, cx, cy, cw, ch, dx, dy, + FALSE, corner); + } } break; @@ -287,25 +313,27 @@ static void event(ObEvent *e, void *foo) } } -static gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact, - Action *action) +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"); + g_warning("invalid button '%s'", buttonstr); return FALSE; } + contextstr = g_ascii_strdown(contextstr, -1); context = g_quark_try_string(contextstr); if (!context) { - g_warning("invalid context"); + g_warning("invalid context '%s'", contextstr); + g_free(contextstr); return FALSE; } + g_free(contextstr); for (it = g_datalist_id_get_data(&bound_contexts, context); it != NULL; it = it->next){ @@ -324,12 +352,9 @@ static gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact, grab_all_clients(FALSE); /* add the binding */ - b = g_new(MouseBinding, 1); + b = g_new0(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)); @@ -339,41 +364,13 @@ static gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact, 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_Client_Mapped | Event_Client_Destroy | Event_X_ButtonPress | Event_X_ButtonRelease | Event_X_MotionNotify, (EventHandler)event, NULL); - /* XXX parse a config */ - binddef(); + mouserc_parse(); } void plugin_shutdown()