mousegrabber: import

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2008-11-13 16:08:34 +01:00
parent ffca477d5d
commit 0e972d4845
9 changed files with 242 additions and 17 deletions

View File

@ -46,6 +46,7 @@ set(AWE_SRCS
${SOURCE_DIR}/ewmh.c
${SOURCE_DIR}/keybinding.c
${SOURCE_DIR}/keygrabber.c
${SOURCE_DIR}/mousegrabber.c
${SOURCE_DIR}/layout.c
${SOURCE_DIR}/luaa.c
${SOURCE_DIR}/hooks.c

View File

@ -327,6 +327,7 @@ main(int argc, char **argv)
/* clear the globalconf structure */
p_clear(&globalconf, 1);
globalconf.keygrabber = LUA_REFNIL;
globalconf.mousegrabber = LUA_REFNIL;
/* save argv */
for(i = 0; i < argc; i++)

28
event.c
View File

@ -35,6 +35,7 @@
#include "titlebar.h"
#include "keybinding.h"
#include "keygrabber.h"
#include "mousegrabber.h"
#include "luaa.h"
#include "systray.h"
#include "screen.h"
@ -133,6 +134,29 @@ widget_getbycoords(position_t position, widget_node_array_t *widgets,
return NULL;
}
/** Handle an event with mouse grabber if needed
* \param x The x coordinate.
* \param y The y coordinate.
* \param mask The mask buttons.
*/
static void
event_handle_mousegrabber(int x, int y, uint16_t mask)
{
if(globalconf.mousegrabber != LUA_REFNIL)
{
lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, globalconf.mousegrabber);
mousegrabber_handleevent(globalconf.L, x, y, mask);
if(lua_pcall(globalconf.L, 1, 1, 0))
{
warn("error running function: %s", lua_tostring(globalconf.L, -1));
luaA_mousegrabber_stop(globalconf.L);
}
else if(!lua_isboolean(globalconf.L, -1) || !lua_toboolean(globalconf.L, -1))
luaA_mousegrabber_stop(globalconf.L);
lua_pop(globalconf.L, 1); /* pop returned value */
}
}
/** The button press event handler.
* \param data The type of mouse event.
* \param connection The connection to the X server.
@ -153,6 +177,8 @@ event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_e
* drop them */
ev->state &= 0x00ff;
event_handle_mousegrabber(ev->root_x, ev->root_y, ev->state);
if((wibox = wibox_getbywin(ev->event))
|| (wibox = wibox_getbywin(ev->child)))
{
@ -408,6 +434,8 @@ event_handle_motionnotify(void *data __attribute__ ((unused)),
wibox_t *wibox = wibox_getbywin(ev->event);
widget_t *w;
event_handle_mousegrabber(ev->root_x, ev->root_y, ev->state);
if(wibox
&& (w = widget_getbycoords(wibox->position, &wibox->widgets,
wibox->sw.geometry.width,

4
luaa.c
View File

@ -56,6 +56,7 @@ extern awesome_t globalconf;
extern const struct luaL_reg awesome_hooks_lib[];
extern const struct luaL_reg awesome_keygrabber_lib[];
extern const struct luaL_reg awesome_mousegrabber_lib[];
extern const struct luaL_reg awesome_button_methods[];
extern const struct luaL_reg awesome_button_meta[];
extern const struct luaL_reg awesome_image_methods[];
@ -769,6 +770,9 @@ luaA_init(void)
/* Export keygrabber lib */
luaL_register(L, "keygrabber", awesome_keygrabber_lib);
/* Export mousegrabber lib */
luaL_register(L, "mousegrabber", awesome_mousegrabber_lib);
/* Export otable lib */
luaA_openlib(L, "otable", otable_methods, otable_meta);

51
mouse.c
View File

@ -1320,6 +1320,37 @@ luaA_mouse_newindex(lua_State *L)
return 0;
}
/** Push a table with mouse status.
* \param L The Lua VM state.
* \param x The x coordinate.
* \param y The y coordinate.
* \param mask The button mask.
*/
int
luaA_mouse_pushstatus(lua_State *L, int x, int y, uint16_t mask)
{
lua_newtable(L);
lua_pushnumber(L, x);
lua_setfield(L, -2, "x");
lua_pushnumber(L, y);
lua_setfield(L, -2, "y");
lua_newtable(L);
int i = 1;
for(uint16_t maski = XCB_BUTTON_MASK_1; maski <= XCB_BUTTON_MASK_5; maski <<= 1)
{
if(mask & maski)
lua_pushboolean(L, true);
else
lua_pushboolean(L, false);
lua_rawseti(L, -2, i++);
}
lua_setfield(L, -2, "buttons");
return 1;
}
/** Get or set the mouse coords.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
@ -1330,8 +1361,8 @@ luaA_mouse_newindex(lua_State *L)
static int
luaA_mouse_coords(lua_State *L)
{
uint16_t mask, maski;
int screen, x, y, mouse_x, mouse_y, i = 1;
uint16_t mask;
int screen, x, y, mouse_x, mouse_y;
if(lua_gettop(L) == 1)
{
@ -1353,21 +1384,7 @@ luaA_mouse_coords(lua_State *L)
if(!mouse_query_pointer_root(&screen, &mouse_x, &mouse_y, &mask))
return 0;
lua_newtable(L);
lua_pushnumber(L, mouse_x);
lua_setfield(L, -2, "x");
lua_pushnumber(L, mouse_y);
lua_setfield(L, -2, "y");
lua_newtable(L);
for(maski = XCB_BUTTON_MASK_1; i <= XCB_BUTTON_MASK_5; maski <<= 1, i++)
if(mask & maski)
{
lua_pushboolean(L, true);
lua_rawseti(L, -2, i);
}
lua_setfield(L, -2, "buttons");
return 1;
return luaA_mouse_pushstatus(L, mouse_x, mouse_y, mask);
}
const struct luaL_reg awesome_mouse_methods[] =

View File

@ -42,6 +42,7 @@ struct button_t
void button_delete(button_t **);
bool mouse_query_pointer(xcb_window_t, int *, int *, uint16_t *);
int luaA_mouse_pushstatus(lua_State *, int, int, uint16_t);
DO_RCNT(button_t, button, button_delete)
ARRAY_FUNCS(button_t *, button, button_unref)

139
mousegrabber.c Normal file
View File

@ -0,0 +1,139 @@
/*
* mousegrabber.c - mouse pointer grabbing
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include "mouse.h"
#include "mousegrabber.h"
#include "common/xcursor.h"
extern awesome_t globalconf;
/** Grab the mouse.
* \param cursor The cursor to use while grabbing.
* \return True if mouse was grabbed.
*/
static bool
mousegrabber_grab(xcb_cursor_t cursor)
{
xcb_window_t root;
for(int screen = 0;
screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
screen++)
{
int x, y;
uint16_t mask;
root = xutil_screen_get(globalconf.connection, screen)->root;
if(mouse_query_pointer(root, &x, &y, &mask))
break;
}
for(int i = 1000; i; i--)
{
xcb_grab_pointer_reply_t *grab_ptr_r;
xcb_grab_pointer_cookie_t grab_ptr_c =
xcb_grab_pointer_unchecked(globalconf.connection, false, root,
XCB_EVENT_MASK_BUTTON_PRESS
| XCB_EVENT_MASK_BUTTON_RELEASE
| XCB_EVENT_MASK_POINTER_MOTION,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
root, cursor, XCB_CURRENT_TIME);
if((grab_ptr_r = xcb_grab_pointer_reply(globalconf.connection, grab_ptr_c, NULL)))
{
p_delete(&grab_ptr_r);
return true;
}
usleep(1000);
}
return false;
}
/** Handle mouse motion events.
* \param L Lua stack to push the pointer motion.
* \param ev Received mouse motion event.
*/
void
mousegrabber_handleevent(lua_State *L, int x, int y, uint16_t mask)
{
luaA_mouse_pushstatus(L, x, y, mask);
}
/** Grab the mouse pointer and list motions, calling callback function at each
* motion. The callback function must return a boolean value: true to
* continue grabbing, false to stop.
* The function is called with one argument:
* a table containing modifiers pointer coordinates.
*
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*
* \luastack
*
* \lparam A callback function as described above.
*/
static int
luaA_mousegrabber_run(lua_State *L)
{
if(globalconf.mousegrabber != LUA_REFNIL)
luaL_error(L, "mousegrabber already running");
uint16_t cfont = xcursor_font_fromstr(luaL_checkstring(L, 2));
if(cfont)
{
xcb_cursor_t cursor = xcursor_new(globalconf.connection, cfont);
luaA_registerfct(L, 1, &globalconf.mousegrabber);
if(!mousegrabber_grab(cursor))
{
luaA_unregister(L, &globalconf.mousegrabber);
luaL_error(L, "unable to grab mouse pointer");
}
}
else
luaA_warn(L, "invalid cursor");
return 0;
}
/** Stop grabbing the mouse pointer.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*/
int
luaA_mousegrabber_stop(lua_State *L)
{
xcb_ungrab_pointer(globalconf.connection, XCB_CURRENT_TIME);
luaA_unregister(L, &globalconf.mousegrabber);
return 0;
}
const struct luaL_reg awesome_mousegrabber_lib[] =
{
{ "run", luaA_mousegrabber_run },
{ "stop", luaA_mousegrabber_stop },
{ NULL, NULL }
};

32
mousegrabber.h Normal file
View File

@ -0,0 +1,32 @@
/*
* mousegrabber.h - mouse pointer grabbing header
*
* Copyright © 2008 Julien Danjou <julien@danjou.info>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_MOUSEGRABBER_H
#define AWESOME_MOUSEGRABBER_H
#include <lua.h>
#include <xcb/xcb.h>
int luaA_mousegrabber_stop(lua_State *);
void mousegrabber_handleevent(lua_State *, int, int, uint16_t);
#endif
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -361,6 +361,8 @@ struct awesome_t
struct ev_timer timer;
/** The key grabber function */
luaA_ref keygrabber;
/** The mouse pointer grabber function */
luaA_ref mousegrabber;
/** Focused screen */
screen_t *screen_focus;
};