not using CurrentTime anywhere

This commit is contained in:
Dana Jansens 2003-03-26 15:02:08 +00:00
parent 1d5fa24e4b
commit f29dd7e0cd
11 changed files with 19 additions and 1074 deletions

View file

@ -1934,7 +1934,7 @@ gboolean client_focus(Client *self)
if (self->can_focus) if (self->can_focus)
XSetInputFocus(ob_display, self->window, RevertToNone, XSetInputFocus(ob_display, self->window, RevertToNone,
CurrentTime); event_lasttime);
if (self->focus_notify) { if (self->focus_notify) {
XEvent ce; XEvent ce;
@ -1944,7 +1944,7 @@ gboolean client_focus(Client *self)
ce.xclient.window = self->window; ce.xclient.window = self->window;
ce.xclient.format = 32; ce.xclient.format = 32;
ce.xclient.data.l[0] = prop_atoms.wm_take_focus; ce.xclient.data.l[0] = prop_atoms.wm_take_focus;
ce.xclient.data.l[1] = CurrentTime; ce.xclient.data.l[1] = event_lasttime;
ce.xclient.data.l[2] = 0l; ce.xclient.data.l[2] = 0l;
ce.xclient.data.l[3] = 0l; ce.xclient.data.l[3] = 0l;
ce.xclient.data.l[4] = 0l; ce.xclient.data.l[4] = 0l;
@ -1972,6 +1972,7 @@ void client_set_focused(Client *self, gboolean focused)
if (focus_client != self) if (focus_client != self)
focus_set_client(self); focus_set_client(self);
} else { } else {
event_unfocustime = event_lasttime;
if (focus_client == self) if (focus_client == self)
focus_set_client(NULL); focus_set_client(NULL);
} }

View file

@ -24,6 +24,7 @@ static void event_handle_root(XEvent *e);
static void event_handle_client(Client *c, XEvent *e); static void event_handle_client(Client *c, XEvent *e);
Time event_lasttime = 0; Time event_lasttime = 0;
Time event_unfocustime = 0;
/*! The value of the mask for the NumLock modifier */ /*! The value of the mask for the NumLock modifier */
unsigned int NumLockMask; unsigned int NumLockMask;

View file

@ -5,6 +5,9 @@
/*! Time at which the last event with a timestamp occured. */ /*! Time at which the last event with a timestamp occured. */
extern Time event_lasttime; extern Time event_lasttime;
/*! Time at which the last event with a timestamp occured before we tried to
unfocus a window. */
extern Time event_unfocustime;
/*! The value of the mask for the NumLock modifier */ /*! The value of the mask for the NumLock modifier */
extern unsigned int NumLockMask; extern unsigned int NumLockMask;

View file

@ -62,7 +62,8 @@ void focus_set_client(Client *client)
if (client == NULL) { if (client == NULL) {
/* when nothing will be focused, send focus to the backup target */ /* when nothing will be focused, send focus to the backup target */
XSetInputFocus(ob_display, focus_backup, RevertToNone, event_lasttime); XSetInputFocus(ob_display, focus_backup, RevertToNone,
event_unfocustime);
} }
old = focus_client; old = focus_client;

View file

@ -17,13 +17,13 @@ void grab_keyboard(gboolean grab)
if (kgrabs++ == 0) { if (kgrabs++ == 0) {
g_message("GRABBING KEYBOARD %d", kgrabs); g_message("GRABBING KEYBOARD %d", kgrabs);
XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync, GrabModeSync, XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync, GrabModeSync,
CurrentTime); event_lasttime);
} else } else
g_message("NOT GRABBING KEYBOARD %d", kgrabs); g_message("NOT GRABBING KEYBOARD %d", kgrabs);
} else if (kgrabs > 0) { } else if (kgrabs > 0) {
if (--kgrabs == 0) { if (--kgrabs == 0) {
g_message("UNGRABBING KEYBOARD %d", kgrabs); g_message("UNGRABBING KEYBOARD %d", kgrabs);
XUngrabKeyboard(ob_display, CurrentTime); XUngrabKeyboard(ob_display, event_lasttime);
} else } else
g_message("NOT UNGRABBING KEYBOARD %d", kgrabs); g_message("NOT UNGRABBING KEYBOARD %d", kgrabs);
} }
@ -34,10 +34,10 @@ void grab_pointer(gboolean grab, Cursor cur)
if (grab) { if (grab) {
if (pgrabs++ == 0) if (pgrabs++ == 0)
XGrabPointer(ob_display, ob_root, False, 0, GrabModeAsync, XGrabPointer(ob_display, ob_root, False, 0, GrabModeAsync,
GrabModeAsync, FALSE, cur, CurrentTime); GrabModeAsync, FALSE, cur, event_lasttime);
} else if (pgrabs > 0) { } else if (pgrabs > 0) {
if (--pgrabs == 0) if (--pgrabs == 0)
XUngrabPointer(ob_display, CurrentTime); XUngrabPointer(ob_display, event_lasttime);
} }
} }

View file

@ -1,297 +0,0 @@
#include "focus.h"
#include "openbox.h"
#include "keyboard.h"
#include "clientwrap.h"
#include <Python.h>
#include <glib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif
typedef struct KeyBindingTree {
guint state;
guint key;
GList *keylist;
PyObject *func;
/* the next binding in the tree at the same level */
struct KeyBindingTree *next_sibling;
/* the first child of this binding (next binding in a chained sequence).*/
struct KeyBindingTree *first_child;
} KeyBindingTree;
static KeyBindingTree *firstnode, *curpos;
static guint reset_key, reset_state;
static gboolean grabbed, user_grabbed;
static PyObject *grab_func;
/***************************************************************************
Define the type 'KeyboardData'
***************************************************************************/
typedef struct KeyboardData {
PyObject_HEAD
PyObject *keychain;
guint state;
guint keycode;
gboolean press;
} KeyboardData;
staticforward PyTypeObject KeyboardDataType;
/***************************************************************************
Type methods/struct
***************************************************************************/
static PyObject *keybdata_new(PyObject *keychain, guint state,
guint keycode, gboolean press)
{
KeyboardData *data = PyObject_New(KeyboardData, &KeyboardDataType);
data->keychain = keychain;
Py_INCREF(keychain);
data->state = state;
data->keycode = keycode;
data->press = press;
return (PyObject*) data;
}
static void keybdata_dealloc(KeyboardData *self)
{
Py_DECREF(self->keychain);
PyObject_Del((PyObject*)self);
}
static PyObject *keybdata_getattr(KeyboardData *self, char *name)
{
if (!strcmp(name, "keychain")) {
Py_INCREF(self->keychain);
return self->keychain;
} else if (!strcmp(name, "state"))
return PyInt_FromLong(self->state);
else if (!strcmp(name, "keycode"))
return PyInt_FromLong(self->keycode);
else if (!strcmp(name, "press"))
return PyInt_FromLong(!!self->press);
PyErr_Format(PyExc_AttributeError, "no such attribute '%s'", name);
return NULL;
}
static PyTypeObject KeyboardDataType = {
PyObject_HEAD_INIT(NULL)
0,
"KeyboardData",
sizeof(KeyboardData),
0,
(destructor) keybdata_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc) keybdata_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
/***************************************************************************/
static gboolean grab_keyboard(gboolean grab)
{
gboolean ret = TRUE;
g_message("grab_keyboard(%s). grabbed: %d", (grab?"True":"False"),grabbed);
user_grabbed = grab;
if (!grabbed) {
if (grab)
ret = XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync,
GrabModeAsync, CurrentTime) == GrabSuccess;
else
XUngrabKeyboard(ob_display, CurrentTime);
}
return ret;
}
/***************************************************************************
Define the type 'Keyboard'
***************************************************************************/
#define IS_KEYBOARD(v) ((v)->ob_type == &KeyboardType)
#define CHECK_KEYBOARD(self, funcname) { \
if (!IS_KEYBOARD(self)) { \
PyErr_SetString(PyExc_TypeError, \
"descriptor '" funcname "' requires a 'Keyboard' " \
"object"); \
return NULL; \
} \
}
typedef struct Keyboard {
PyObject_HEAD
} Keyboard;
staticforward PyTypeObject KeyboardType;
static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
{
CHECK_KEYBOARD(self, "clearBinds");
if (!PyArg_ParseTuple(args, ":clearBinds"))
return NULL;
clearall();
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *keyb_grab(Keyboard *self, PyObject *args)
{
PyObject *func;
CHECK_KEYBOARD(self, "grab");
if (!PyArg_ParseTuple(args, "O:grab", &func))
return NULL;
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_ValueError, "expected a callable object");
return NULL;
}
if (!grab_keyboard(TRUE)) {
PyErr_SetString(PyExc_RuntimeError, "failed to grab keyboard");
return NULL;
}
grab_func = func;
Py_INCREF(grab_func);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *keyb_ungrab(Keyboard *self, PyObject *args)
{
CHECK_KEYBOARD(self, "ungrab");
if (!PyArg_ParseTuple(args, ":ungrab"))
return NULL;
grab_keyboard(FALSE);
Py_XDECREF(grab_func);
grab_func = NULL;
Py_INCREF(Py_None);
return Py_None;
}
#define METH(n, d) {#n, (PyCFunction)keyb_##n, METH_VARARGS, #d}
static PyMethodDef KeyboardMethods[] = {
METH(bind,
"bind(keychain, func)\n\n"
"Binds a key-chain to a function. The keychain is a tuple of strings "
"which define a chain of key presses. Each member of the tuple has "
"the format [Modifier-]...[Key]. Modifiers can be 'mod1', 'mod2', "
"'mod3', 'mod4', 'mod5', 'control', and 'shift'. The keys on your "
"keyboard that are bound to each of these modifiers can be found by "
"running 'xmodmap'. The Key can be any valid key definition. Key "
"definitions can be found by running 'xev', pressing the key while "
"its window is focused, and watching its output. Here are some "
"examples of valid keychains: ('a'), ('F7'), ('control-a', 'd'), "
"('control-mod1-x', 'control-mod4-g'), ('F1', 'space'). The func "
"must have a definition similar to 'def func(keydata, client)'. A "
"keychain cannot be bound to more than one function."),
METH(clearBinds,
"clearBinds()\n\n"
"Removes all bindings that were previously made by bind()."),
METH(grab,
"grab(func)\n\n"
"Grabs the entire keyboard, causing all possible keyboard events to "
"be passed to the given function. CAUTION: Be sure when you grab() "
"that you also have an ungrab() that will execute, or you will not "
"be able to type until you restart Openbox. The func must have a "
"definition similar to 'def func(keydata)'. The keyboard cannot be "
"grabbed if it is already grabbed."),
METH(ungrab,
"ungrab()\n\n"
"Ungrabs the keyboard. The keyboard cannot be ungrabbed if it is not "
"grabbed."),
{ NULL, NULL, 0, NULL }
};
/***************************************************************************
Type methods/struct
***************************************************************************/
static void keyb_dealloc(PyObject *self)
{
PyObject_Del(self);
}
static PyTypeObject KeyboardType = {
PyObject_HEAD_INIT(NULL)
0,
"Keyboard",
sizeof(Keyboard),
0,
(destructor) keyb_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
/**************************************************************************/
void keyboard_startup()
{
PyObject *input, *inputdict, *ptr;
gboolean b;
curpos = firstnode = NULL;
grabbed = user_grabbed = FALSE;
b = translate("C-G", &reset_state, &reset_key);
g_assert(b);
KeyboardType.ob_type = &PyType_Type;
KeyboardType.tp_methods = KeyboardMethods;
PyType_Ready(&KeyboardType);
PyType_Ready(&KeyboardDataType);
/* get the input module/dict */
input = PyImport_ImportModule("input"); /* new */
g_assert(input != NULL);
inputdict = PyModule_GetDict(input); /* borrowed */
g_assert(inputdict != NULL);
/* add a Keyboard instance to the input module */
ptr = (PyObject*) PyObject_New(Keyboard, &KeyboardType);
PyDict_SetItemString(inputdict, "Keyboard", ptr);
Py_DECREF(ptr);
Py_DECREF(input);
}
void keyboard_shutdown()
{
if (grabbed || user_grabbed) {
grabbed = FALSE;
grab_keyboard(FALSE);
}
grab_keys(FALSE);
destroytree(firstnode);
firstnode = NULL;
}

View file

@ -1,13 +0,0 @@
#ifndef __keyboard_h
#define __keyboard_h
#include <glib.h>
void keyboard_startup();
void keyboard_shutdown();
guint keyboard_translate_modifier(char *str);
void keyboard_event(XKeyEvent *e);
#endif

View file

@ -1,740 +0,0 @@
#include "pointer.h"
#include "keyboard.h"
#include "frame.h"
#include "engine.h"
#include "openbox.h"
#include "hooks.h"
#include "configwrap.h"
#include <glib.h>
#include <Python.h>
#include <structmember.h> /* for PyMemberDef stuff */
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
typedef enum {
Action_Press,
Action_Release,
Action_Click,
Action_DoubleClick,
Action_Motion,
NUM_ACTIONS
} Action;
/* GData of GSList*s of PointerBinding*s. */
static GData *bound_contexts;
static gboolean grabbed;
PyObject *grab_func;
struct foreach_grab_temp {
Client *client;
gboolean grab;
};
typedef struct {
guint state;
guint button;
Action action;
char *name;
GSList *funcs[NUM_ACTIONS];
} PointerBinding;
/***************************************************************************
Define the type 'ButtonData'
***************************************************************************/
typedef struct PointerData {
PyObject_HEAD
Action action;
GQuark context;
char *button;
guint state;
guint buttonnum;
int posx, posy;
int pressposx, pressposy;
int pcareax, pcareay, pcareaw, pcareah;
} PointerData;
staticforward PyTypeObject PointerDataType;
/***************************************************************************
Type methods/struct
***************************************************************************/
static PyObject *ptrdata_new(char *button, GQuark context, Action action,
guint state, guint buttonnum, int posx, int posy,
int pressposx, int pressposy, int pcareax,
int pcareay, int pcareaw, int pcareah)
{
PointerData *self = PyObject_New(PointerData, &PointerDataType);
self->button = g_strdup(button);
self->context = context;
self->action = action;
self->state = state;
self->buttonnum = buttonnum;
self->posx = posx;
self->posy = posy;
self->pressposx = pressposx;
self->pressposy = pressposy;
self->pcareax = pcareax;
self->pcareay = pcareay;
self->pcareaw = pcareaw;
self->pcareah = pcareah;
return (PyObject*) self;
}
static void ptrdata_dealloc(PointerData *self)
{
g_free(self->button);
PyObject_Del((PyObject*)self);
}
static PyObject *ptrdata_getattr(PointerData *self, char *name)
{
if (!strcmp(name, "button"))
return PyString_FromString(self->button);
if (!strcmp(name, "action"))
return PyInt_FromLong(self->action);
if (!strcmp(name, "context"))
return PyString_FromString(g_quark_to_string(self->context));
if (!strcmp(name, "state"))
return PyInt_FromLong(self->state);
if (!strcmp(name, "buttonnum"))
return PyInt_FromLong(self->buttonnum);
if (self->action == Action_Motion) { /* the rest are only for motions */
if (!strcmp(name, "pos")) {
PyObject *pos = PyTuple_New(2);
PyTuple_SET_ITEM(pos, 0, PyInt_FromLong(self->posx));
PyTuple_SET_ITEM(pos, 1, PyInt_FromLong(self->posy));
return pos;
}
if (!strcmp(name, "presspos")) {
PyObject *presspos = PyTuple_New(2);
PyTuple_SET_ITEM(presspos, 0, PyInt_FromLong(self->pressposx));
PyTuple_SET_ITEM(presspos, 1, PyInt_FromLong(self->pressposy));
return presspos;
}
if (!strcmp(name, "pressclientarea")) {
if (self->pcareaw < 0) { /* < 0 indicates no client */
Py_INCREF(Py_None);
return Py_None;
} else {
PyObject *ca = PyTuple_New(4);
PyTuple_SET_ITEM(ca, 0, PyInt_FromLong(self->pcareax));
PyTuple_SET_ITEM(ca, 1, PyInt_FromLong(self->pcareay));
PyTuple_SET_ITEM(ca, 2, PyInt_FromLong(self->pcareaw));
PyTuple_SET_ITEM(ca, 3, PyInt_FromLong(self->pcareah));
return ca;
}
}
}
PyErr_Format(PyExc_AttributeError, "no such attribute '%s'", name);
return NULL;
}
static PyTypeObject PointerDataType = {
PyObject_HEAD_INIT(NULL)
0,
"PointerData",
sizeof(PointerData),
0,
(destructor) ptrdata_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc) ptrdata_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
/***************************************************************************/
static gboolean translate(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 = keyboard_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;
}
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)
XGrabButton(ob_display, button, state, win, FALSE, mask, mode,
GrabModeAsync, None, None);
else
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) {
PointerBinding *b = it->data;
grab_button(d->client, b->state, b->button, key, d->grab);
}
}
void pointer_grab_all(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)
pointer_grab_all(it->data, grab);
}
static gboolean grab_pointer(gboolean grab)
{
gboolean ret = TRUE;
if (grab)
ret = XGrabPointer(ob_display, ob_root, FALSE, (ButtonPressMask |
ButtonReleaseMask |
ButtonMotionMask |
PointerMotionMask),
GrabModeAsync, GrabModeAsync, None, None,
CurrentTime) == GrabSuccess;
else
XUngrabPointer(ob_display, CurrentTime);
if (ret) grabbed = grab;
return ret;
}
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;
PointerBinding *b = it->data;
for (i = 0; i < NUM_ACTIONS; ++i)
while (b->funcs[i] != NULL) {
Py_DECREF((PyObject*)b->funcs[i]->data);
b->funcs[i] = g_slist_delete_link(b->funcs[i], b->funcs[i]);
}
g_free(b->name);
g_free(b);
}
g_slist_free(data);
}
static void clearall()
{
grab_all_clients(FALSE);
g_datalist_foreach(&bound_contexts, foreach_clear, NULL);
}
static void fire_event(char *button, GQuark context, Action action,
guint state, guint buttonnum, int posx, int posy,
int pressposx, int pressposy, int pcareax,
int pcareay, int pcareaw, int pcareah,
PyObject *client, GSList *functions)
{
PyObject *ptrdata, *args, *ret;
GSList *it;
ptrdata = ptrdata_new(button, context, action,
state, buttonnum, posx, posy, pressposx, pressposy,
pcareax, pcareay, pcareaw, pcareah);
args = Py_BuildValue("OO", ptrdata, client);
if (grabbed) {
ret = PyObject_CallObject(grab_func, args);
if (ret == NULL) PyErr_Print();
Py_XDECREF(ret);
} else {
for (it = functions; it != NULL; it = it->next) {
ret = PyObject_CallObject(it->data, args);
if (ret == NULL) PyErr_Print();
Py_XDECREF(ret);
}
}
Py_DECREF(args);
Py_DECREF(ptrdata);
}
void pointer_event(XEvent *e, Client *c)
{
static guint button = 0, lastbutton = 0;
static Time time = 0;
static Rect carea;
static guint pressx, pressy;
GQuark contextq;
gboolean click = FALSE, dblclick = FALSE;
PyObject *client;
GString *str = g_string_sized_new(0);
guint state;
GSList *it = NULL;
PointerBinding *b = NULL;
guint drag_threshold;
drag_threshold = configwrap_get_int("input", "drag_threshold");
contextq = engine_get_context(c, e->xany.window);
/* pick a button, figure out clicks/double clicks */
switch (e->type) {
case ButtonPress:
if (!button) {
button = e->xbutton.button;
if (c != NULL) carea = c->frame->area;
else carea.width = -1; /* indicates no client */
pressx = e->xbutton.x_root;
pressy = e->xbutton.y_root;
}
state = e->xbutton.state;
break;
case ButtonRelease:
state = e->xbutton.state;
break;
case MotionNotify:
state = e->xmotion.state;
break;
default:
g_assert_not_reached();
return;
}
if (!grabbed) {
for (it = g_datalist_id_get_data(&bound_contexts, contextq);
it != NULL; it = it->next) {
b = it->data;
if (b->state == state && b->button == button)
break;
}
/* if not grabbed and not bound, then nothing to do! */
if (it == NULL) return;
}
if (c) client = clientwrap_new(c);
else client = Py_None;
/* build the button string */
if (state & ControlMask) g_string_append(str, "C-");
if (state & ShiftMask) g_string_append(str, "S-");
if (state & Mod1Mask) g_string_append(str, "Mod1-");
if (state & Mod2Mask) g_string_append(str, "Mod2-");
if (state & Mod3Mask) g_string_append(str, "Mod3-");
if (state & Mod4Mask) g_string_append(str, "Mod4-");
if (state & Mod5Mask) g_string_append(str, "Mod5-");
g_string_append_printf(str, "%d", button);
/* figure out clicks/double clicks */
switch (e->type) {
case ButtonRelease:
if (button == e->xbutton.button) {
/* determine if this is a valid 'click'. Its not if the release is
not over the window, or if a drag occured. */
if (ABS(e->xbutton.x_root - pressx) < drag_threshold &&
ABS(e->xbutton.y_root - pressy) < drag_threshold &&
e->xbutton.x >= 0 && e->xbutton.y >= 0) {
int junk;
Window wjunk;
guint ujunk, w, h;
XGetGeometry(ob_display, e->xany.window, &wjunk, &junk, &junk,
&w, &h, &ujunk, &ujunk);
if (e->xbutton.x < (signed)w && e->xbutton.y < (signed)h)
click =TRUE;
}
/* determine if this is a valid 'double-click' */
if (click) {
if (lastbutton == button &&
e->xbutton.time -
configwrap_get_int("input", "double_click_rate") < time) {
dblclick = TRUE;
lastbutton = 0;
} else
lastbutton = button;
} else
lastbutton = 0;
time = e->xbutton.time;
pressx = pressy = 0;
button = 0;
carea.x = carea.y = carea.width = carea.height = 0;
}
break;
}
/* fire off the events */
switch (e->type) {
case ButtonPress:
fire_event(str->str, contextq, Action_Press,
state, button, 0, 0, 0, 0, 0, 0, 0, 0,
client, b == NULL ? NULL : b->funcs[Action_Press]);
break;
case ButtonRelease:
fire_event(str->str, contextq, Action_Release,
state, button, 0, 0, 0, 0, 0, 0, 0, 0,
client, b == NULL ? NULL : b->funcs[Action_Release]);
break;
case MotionNotify:
/* watch out for the drag threshold */
if (ABS(e->xmotion.x_root - pressx) < drag_threshold &&
ABS(e->xmotion.y_root - pressy) < drag_threshold)
break;
fire_event(str->str, contextq, Action_Motion,
state, button, e->xmotion.x_root,
e->xmotion.y_root, pressx, pressy,
carea.x, carea.y, carea.width, carea.height,
client, b == NULL ? NULL : b->funcs[Action_Motion]);
break;
}
if (click)
fire_event(str->str, contextq, Action_Click,
state, button, 0, 0, 0, 0, 0, 0, 0, 0,
client, b == NULL ? NULL : b->funcs[Action_Click]);
if (dblclick)
fire_event(str->str, contextq, Action_DoubleClick,
state, button, 0, 0, 0, 0, 0, 0, 0, 0,
client, b == NULL ? NULL : b->funcs[Action_DoubleClick]);
g_string_free(str, TRUE);
if (client != Py_None) { Py_DECREF(client); }
if (contextq == g_quark_try_string("client")) {
/* Replay the event, so it goes to the client*/
XAllowEvents(ob_display, ReplayPointer, CurrentTime);
/* generate a release event since we don't get real ones */
if (e->type == ButtonPress) {
e->type = ButtonRelease;
pointer_event(e, c);
}
}
}
/***************************************************************************
Define the type 'Pointer'
***************************************************************************/
#define IS_POINTER(v) ((v)->ob_type == &PointerType)
#define CHECK_POINTER(self, funcname) { \
if (!IS_POINTER(self)) { \
PyErr_SetString(PyExc_TypeError, \
"descriptor '" funcname "' requires a 'Pointer' " \
"object"); \
return NULL; \
} \
}
typedef struct Pointer {
PyObject_HEAD
Action press;
Action release;
Action click;
Action doubleclick;
Action motion;
} Pointer;
staticforward PyTypeObject PointerType;
static PyObject *ptr_bind(Pointer *self, PyObject *args)
{
char *buttonstr;
char *contextstr;
guint state, button;
PointerBinding *b;
GSList *it;
GQuark context;
PyObject *func;
Action action;
int i;
CHECK_POINTER(self, "grab");
if (!PyArg_ParseTuple(args, "ssiO:grab",
&buttonstr, &contextstr, &action, &func))
return NULL;
if (!translate(buttonstr, &state, &button)) {
PyErr_SetString(PyExc_ValueError, "invalid button");
return NULL;
}
context = g_quark_try_string(contextstr);
if (!context) {
PyErr_SetString(PyExc_ValueError, "invalid context");
return NULL;
}
if (action < 0 || action >= NUM_ACTIONS) {
PyErr_SetString(PyExc_ValueError, "invalid action");
return NULL;
}
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_ValueError, "expected a callable object");
return NULL;
}
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 */
b->funcs[action] = g_slist_append(b->funcs[action], func);
Py_INCREF(Py_None);
return Py_None;
}
}
grab_all_clients(FALSE);
/* add the binding */
b = g_new(PointerBinding, 1);
b->state = state;
b->button = button;
b->name = g_strdup(buttonstr);
for (i = 0; i < NUM_ACTIONS; ++i)
if (i != (signed)action) b->funcs[i] = NULL;
b->funcs[action] = g_slist_append(NULL, func);
g_datalist_id_set_data(&bound_contexts, context,
g_slist_append(g_datalist_id_get_data(&bound_contexts, context), b));
grab_all_clients(TRUE);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *ptr_clearBinds(Pointer *self, PyObject *args)
{
CHECK_POINTER(self, "clearBinds");
if (!PyArg_ParseTuple(args, ":clearBinds"))
return NULL;
clearall();
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *ptr_grab(Pointer *self, PyObject *args)
{
PyObject *func;
CHECK_POINTER(self, "grab");
if (!PyArg_ParseTuple(args, "O:grab", &func))
return NULL;
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_ValueError, "expected a callable object");
return NULL;
}
if (!grab_pointer(TRUE)) {
PyErr_SetString(PyExc_RuntimeError, "failed to grab pointer");
return NULL;
}
grab_func = func;
Py_INCREF(grab_func);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *ptr_ungrab(Pointer *self, PyObject *args)
{
CHECK_POINTER(self, "ungrab");
if (!PyArg_ParseTuple(args, ":ungrab"))
return NULL;
grab_pointer(FALSE);
Py_XDECREF(grab_func);
grab_func = NULL;
Py_INCREF(Py_None);
return Py_None;
}
#define METH(n, d) {#n, (PyCFunction)ptr_##n, METH_VARARGS, #d}
static PyMethodDef PointerMethods[] = {
METH(bind,
"bind(button, context, func)\n\n"
"Binds a pointer button for a context to a function. See the "
"Terminology section for a decription and list of common contexts. "
"The button is a string which defines a modifier and button "
"combination with the format [Modifier-]...[Button]. Modifiers can "
"be 'mod1', 'mod2', 'mod3', 'mod4', 'mod5', 'control', and 'shift'. "
"The keys on your keyboard that are bound to each of these modifiers "
"can be found by running 'xmodmap'. The button is the number of the "
"button. Button numbers can be found by running 'xev', pressing the "
"button with the pointer over its window, and watching its output. "
"Here are some examples of valid buttons: 'control-1', '2', "
"'mod1-shift-5'. The func must have a definition similar to "
"'def func(keydata, client)'. A button and context may be bound to "
"more than one function."),
METH(clearBinds,
"clearBinds()\n\n"
"Removes all bindings that were previously made by bind()."),
METH(grab,
"grab(func)\n\n"
"Grabs the pointer device, causing all possible pointer events to be "
"sent to the given function. CAUTION: Be sure when you grab() that "
"you also have an ungrab() that will execute, or you will not be "
"able to use the pointer device until you restart Openbox. The func "
"must have a definition similar to 'def func(keydata)'. The pointer "
"cannot be grabbed if it is already grabbed."),
METH(ungrab,
"ungrab()\n\n"
"Ungrabs the pointer. The pointer cannot be ungrabbed if it is not "
"grabbed."),
{ NULL, NULL, 0, NULL }
};
static PyMemberDef PointerMembers[] = {
{"Action_Press", T_INT, offsetof(Pointer, press), READONLY,
"a pointer button press"},
{"Action_Release", T_INT, offsetof(Pointer, release), READONLY,
"a pointer button release"},
{"Action_Click", T_INT, offsetof(Pointer, click), READONLY,
"a pointer button click (press-release)"},
{"Action_DoubleClick", T_INT, offsetof(Pointer, doubleclick), READONLY,
"a pointer button double-click"},
{"Action_Motion", T_INT, offsetof(Pointer, motion), READONLY,
"a pointer drag"},
{NULL}
};
/***************************************************************************
Type methods/struct
***************************************************************************/
static void ptr_dealloc(PyObject *self)
{
PyObject_Del(self);
}
static PyTypeObject PointerType = {
PyObject_HEAD_INIT(NULL)
0,
"Pointer",
sizeof(Pointer),
0,
(destructor) ptr_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
/**************************************************************************/
void pointer_startup()
{
PyObject *input, *inputdict;
Pointer *ptr;
grabbed = FALSE;
configwrap_add_int("input", "double_click_rate", "Double-Click Rate",
"An integer containing the number of milliseconds in "
"which 2 clicks must be received to cause a "
"double-click event.", 300);
configwrap_add_int("input", "drag_threshold", "Drag Threshold",
"An integer containing the number of pixels a drag "
"must go before motion events start getting generated. "
"Once a drag has begun, the button release will not "
"count as a click event.", 3);
g_datalist_init(&bound_contexts);
PointerType.ob_type = &PyType_Type;
PointerType.tp_methods = PointerMethods;
PointerType.tp_members = PointerMembers;
PyType_Ready(&PointerType);
PyType_Ready(&PointerDataType);
/* get the input module/dict */
input = PyImport_ImportModule("input"); /* new */
g_assert(input != NULL);
inputdict = PyModule_GetDict(input); /* borrowed */
g_assert(inputdict != NULL);
/* add a Pointer instance to the input module */
ptr = PyObject_New(Pointer, &PointerType);
ptr->press = Action_Press;
ptr->release = Action_Release;
ptr->click = Action_Click;
ptr->doubleclick = Action_DoubleClick;
ptr->motion = Action_Motion;
PyDict_SetItemString(inputdict, "Pointer", (PyObject*) ptr);
Py_DECREF(ptr);
Py_DECREF(input);
}
void pointer_shutdown()
{
if (grabbed)
grab_pointer(FALSE);
clearall();
g_datalist_clear(&bound_contexts);
}

View file

@ -1,14 +0,0 @@
#ifndef __pointer_h
#define __pointer_h
#include "client.h"
#include <glib.h>
void pointer_startup();
void pointer_shutdown();
void pointer_grab_all(Client *client, gboolean grab);
void pointer_event(XEvent *e, Client *c);
#endif

View file

@ -1,6 +1,7 @@
#include "../../kernel/focus.h" #include "../../kernel/focus.h"
#include "../../kernel/dispatch.h" #include "../../kernel/dispatch.h"
#include "../../kernel/openbox.h" #include "../../kernel/openbox.h"
#include "../../kernel/event.h"
#include "../../kernel/grab.h" #include "../../kernel/grab.h"
#include "../../kernel/action.h" #include "../../kernel/action.h"
#include "tree.h" #include "tree.h"
@ -40,7 +41,7 @@ static void reset_chains()
grabbed = FALSE; grabbed = FALSE;
grab_keyboard(FALSE); grab_keyboard(FALSE);
} else } else
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime); XAllowEvents(ob_display, AsyncKeyboard, event_lasttime);
} }
gboolean kbind(GList *keylist, Action *action) gboolean kbind(GList *keylist, Action *action)
@ -102,7 +103,8 @@ static void press(ObEvent *e, void *foo)
if (!grabbed) { if (!grabbed) {
grab_keyboard(TRUE); grab_keyboard(TRUE);
grabbed = TRUE; grabbed = TRUE;
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime); XAllowEvents(ob_display, AsyncKeyboard,
event_lasttime);
} }
curpos = p; curpos = p;
} else { } else {

View file

@ -1,6 +1,7 @@
#include "../../kernel/openbox.h" #include "../../kernel/openbox.h"
#include "../../kernel/dispatch.h" #include "../../kernel/dispatch.h"
#include "../../kernel/action.h" #include "../../kernel/action.h"
#include "../../kernel/event.h"
#include "../../kernel/client.h" #include "../../kernel/client.h"
#include "../../kernel/frame.h" #include "../../kernel/frame.h"
#include "../../kernel/grab.h" #include "../../kernel/grab.h"
@ -219,7 +220,7 @@ static void event(ObEvent *e, void *foo)
if (context == g_quark_try_string("client")) { if (context == g_quark_try_string("client")) {
/* Replay the event, so it goes to the client*/ /* Replay the event, so it goes to the client*/
XAllowEvents(ob_display, ReplayPointer, CurrentTime); XAllowEvents(ob_display, ReplayPointer, event_lasttime);
/* Fall through to the release case! */ /* Fall through to the release case! */
} else } else
break; break;