Asynchronously update the keyboard state

When the keyboard layout is modified via xmodmap, each single "change"
(line of input to xmodmap) causes an "the keyboard configuration
changed"-event to be sent. Awesome reacted to each of these events by
reloading the keyboard layout. Thus, awesome reloaded the keyboard
layout a lot and appeared to freeze.

Fix this by asynchronously update the keyboard state: When such an event
comes in, instead of reloading things immediately, we set a flag which
makes us update the state at the end of the main loop iteration. This
means that many events still cause only a single (or at least few)
re-quering of the layout. Thus, a lot of time is saved.

This commit removes the argument to the (undocumented!) signal
xkb::group_changed. Previously, the argument was the active group
number. Since this argument was unused and I'm lazy, I just removed it.
The alternative would be that it might be visible to Lua that some "the
active group changed"-events are dropped.

Fixes: https://github.com/awesomeWM/awesome/issues/1494
Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2017-03-28 10:23:09 +02:00
parent 686abd174f
commit 9f3a6757e9
5 changed files with 65 additions and 11 deletions

View File

@ -42,9 +42,13 @@ void client_destroy_later(void);
/* objects/screen.c */
void screen_refresh(void);
/* xkb.c */
void xkb_refresh(void);
static inline int
awesome_refresh(void)
{
xkb_refresh();
screen_refresh();
luaA_emit_refresh();
drawin_refresh();

View File

@ -186,6 +186,12 @@ typedef struct
struct xkb_context *xkb_ctx;
/* xkb state of dead keys on keyboard */
struct xkb_state *xkb_state;
/* Do we have a pending reload? */
bool xkb_reload_keymap;
/* Do we have a pending map change? */
bool xkb_map_changed;
/* Do we have a pending group change? */
bool xkb_group_changed;
/** The preferred size of client icons for this screen */
uint32_t preferred_icon_size;
/** Cached wallpaper information */

View File

@ -0,0 +1,29 @@
-- Test for bug #1494: Using xmodmap freezes awesome since it re-queries the
-- keyboard layout many, many times. (xmodmap applies each change on its own)
local runner = require("_runner")
local spawn = require("awful.spawn")
local GLib = require("lgi").GLib
local done
local timer = GLib.Timer()
local steps = {
function(count)
if count == 1 then
-- POSIX allows us to use awk
local cmd = "awk 'BEGIN { for(i=1; i<=1000;i++) print \"keycode 107 = parenleft\" }' | xmodmap -"
spawn.easy_async({"sh", "-c", cmd}, function()
awesome.sync()
done = true
end)
end
if done then
-- Apply some limit on how long awesome may need to process 'things'
return timer:elapsed() < 5
end
end
}
runner.run_steps(steps)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

36
xkb.c
View File

@ -297,13 +297,29 @@ xkb_reload_keymap(void)
}
}
void
xkb_refresh(void)
{
lua_State *L = globalconf_get_lua_State();
if (globalconf.xkb_reload_keymap)
xkb_reload_keymap();
if (globalconf.xkb_map_changed)
signal_object_emit(L, &global_signals, "xkb::map_changed", 0);
if (globalconf.xkb_group_changed)
signal_object_emit(L, &global_signals, "xkb::group_changed", 0);
globalconf.xkb_reload_keymap = false;
globalconf.xkb_map_changed = false;
globalconf.xkb_group_changed = false;
}
/** The xkb notify event handler.
* \param event The event.
*/
void
event_handle_xkb_notify(xcb_generic_event_t* event)
{
lua_State *L = globalconf_get_lua_State();
assert(globalconf.have_xkb);
/* The pad0 field of xcb_generic_event_t contains the event sub-type,
@ -315,18 +331,16 @@ event_handle_xkb_notify(xcb_generic_event_t* event)
{
xcb_xkb_new_keyboard_notify_event_t *new_keyboard_event = (void*)event;
xkb_reload_keymap();
globalconf.xkb_reload_keymap = true;
if (new_keyboard_event->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
{
signal_object_emit(L, &global_signals, "xkb::map_changed", 0);
}
globalconf.xkb_map_changed = true;
break;
}
case XCB_XKB_MAP_NOTIFY:
{
xkb_reload_keymap();
signal_object_emit(L, &global_signals, "xkb::map_changed", 0);
globalconf.xkb_reload_keymap = true;
globalconf.xkb_map_changed = true;
break;
}
case XCB_XKB_STATE_NOTIFY:
@ -342,10 +356,7 @@ event_handle_xkb_notify(xcb_generic_event_t* event)
state_notify_event->lockedGroup);
if (state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE)
{
lua_pushinteger(L, state_notify_event->group);
signal_object_emit(L, &global_signals, "xkb::group_changed", 1);
}
globalconf.xkb_group_changed = true;
break;
}
@ -358,6 +369,9 @@ event_handle_xkb_notify(xcb_generic_event_t* event)
void
xkb_init(void)
{
globalconf.xkb_reload_keymap = false;
globalconf.xkb_map_changed = false;
globalconf.xkb_group_changed = false;
int success_xkb = xkb_x11_setup_xkb_extension(globalconf.connection,
XKB_X11_MIN_MAJOR_XKB_VERSION,

1
xkb.h
View File

@ -26,6 +26,7 @@
#include <lua.h>
void event_handle_xkb_notify(xcb_generic_event_t* event);
void xkb_refresh(void);
void xkb_init(void);
void xkb_free(void);