diff --git a/include/view.h b/include/view.h index 6dd82230..e9a437c1 100644 --- a/include/view.h +++ b/include/view.h @@ -28,7 +28,6 @@ #ifndef ROFI_VIEW_H #define ROFI_VIEW_H #include "mode.h" -#include "xkb.h" /** * @defgroup View View @@ -99,7 +98,7 @@ unsigned int rofi_view_get_next_position ( const RofiViewState *state ); * * Process an Xevent. */ -void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb_stuff *xkb ); +void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, NkBindingsSeat *seat ); /** * @param state the Menu handle * diff --git a/include/xcb-internal.h b/include/xcb-internal.h index 0e6a6382..ef151a79 100644 --- a/include/xcb-internal.h +++ b/include/xcb-internal.h @@ -34,6 +34,8 @@ #include #include +#include "nkutils-bindings.h" + /** * Structure to keep xcb stuff around. */ @@ -46,6 +48,15 @@ struct _xcb_stuff SnDisplay *sndisplay; SnLauncheeContext *sncontext; struct _workarea *monitors; + struct + { + /** Flag indicating first event */ + uint8_t first_event; + /** Keyboard device id */ + int32_t device_id; + } xkb; + NkBindings *bindings; + NkBindingsSeat *bindings_seat; }; #endif diff --git a/include/xcb.h b/include/xcb.h index e7743a45..47906170 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -40,6 +40,8 @@ typedef struct _xcb_stuff xcb_stuff; */ extern xcb_stuff *xcb; +gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data ); + /** * @param xcb the xcb data structure * @@ -55,7 +57,6 @@ xcb_window_t xcb_stuff_get_root_window ( xcb_stuff *xcb ); */ void xcb_stuff_wipe ( xcb_stuff *xcb ); - /** * @param w The xcb_window_t to read property from. * @param atom The property identifier @@ -192,7 +193,7 @@ int take_pointer ( xcb_window_t w, int iters ); * * Numlock detection * * Cache */ -void x11_setup ( void ); +gboolean x11_setup ( void ); /** * Depth of visual diff --git a/include/xkb-internal.h b/include/xkb-internal.h deleted file mode 100644 index 861d4462..00000000 --- a/include/xkb-internal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * rofi - * - * MIT/X11 License - * Copyright © 2013-2017 Qball Cow - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ROFI_XKB_INTERNAL_H -#define ROFI_XKB_INTERNAL_H - -#include "nkutils-bindings.h" -#include - -struct xkb_stuff -{ - /** connection to the X server*/ - xcb_connection_t *xcb_connection; - /** Flag indicating first event */ - uint8_t first_event; - /** Keyboard device id */ - int32_t device_id; - NkBindings *bindings; - NkBindingsSeat *bindings_seat; -}; - -#endif diff --git a/include/xkb.h b/include/xkb.h deleted file mode 100644 index 52202c18..00000000 --- a/include/xkb.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * rofi - * - * MIT/X11 License - * Copyright © 2013-2017 Qball Cow - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ROFI_XKB_H -#define ROFI_XKB_H - -/** - * Structure holding xkb related state. - */ -typedef struct xkb_stuff xkb_stuff; -#endif diff --git a/meson.build b/meson.build index df39486d..d852d148 100644 --- a/meson.build +++ b/meson.build @@ -197,8 +197,6 @@ rofi_sources = files( 'include/dialogs/window.h', 'include/dialogs/dialogs.h', 'include/dialogs/help-keys.h', - 'include/xkb.h', - 'include/xkb-internal.h', ) theme_lexer_sources = files('lexer/theme-lexer.l') theme_parser_sources = files('lexer/theme-parser.y') diff --git a/source/keyb.c b/source/keyb.c index 394be6eb..a5a7ceb0 100644 --- a/source/keyb.c +++ b/source/keyb.c @@ -28,8 +28,6 @@ #include #include #include "rofi.h" -#include "xkb.h" -#include "xkb-internal.h" #include "nkutils-bindings.h" #include "xrmoptions.h" diff --git a/source/rofi.c b/source/rofi.c index 38c5cd12..1bea2436 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -39,11 +39,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include @@ -51,7 +46,6 @@ #include #include "xcb-internal.h" -#include "xkb-internal.h" #include "settings.h" #include "mode.h" @@ -86,12 +80,6 @@ void rofi_add_error_message ( GString *str ) { list_of_error_msgs = g_list_append ( list_of_error_msgs, str ); } -/** global structure holding the keyboard status */ -struct xkb_stuff xkb = { - .xcb_connection = NULL, - .bindings = NULL, - .bindings_seat = NULL, -}; /** Path to the configuration file */ G_MODULE_EXPORT char *config_path = NULL; @@ -432,10 +420,6 @@ static void cleanup () g_main_loop_unref ( main_loop ); main_loop = NULL; } - // XKB Cleanup - // - nk_bindings_free ( xkb.bindings ); - // Cleanup xcb_stuff_wipe ( xcb ); @@ -629,76 +613,6 @@ static gboolean setup_modi ( void ) return FALSE; } -/** - * Process X11 events in the main-loop (gui-thread) of the application. - */ -static void main_loop_x11_event_handler_view ( xcb_generic_event_t *ev ) -{ - RofiViewState *state = rofi_view_get_active (); - if ( state != NULL ) { - rofi_view_itterrate ( state, ev, &xkb ); - if ( rofi_view_get_completed ( state ) ) { - // This menu is done. - rofi_view_finalize ( state ); - // cleanup - if ( rofi_view_get_active () == NULL ) { - g_main_loop_quit ( main_loop ); - } - } - } -} -static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data ) -{ - if ( ev == NULL ) { - int status = xcb_connection_has_error ( xcb->connection ); - if ( status > 0 ) { - g_warning ( "The XCB connection to X server had a fatal error: %d", status ); - g_main_loop_quit ( main_loop ); - return G_SOURCE_REMOVE; - } - else { - g_warning ( "main_loop_x11_event_handler: ev == NULL, status == %d", status ); - return G_SOURCE_CONTINUE; - } - } - uint8_t type = ev->response_type & ~0x80; - if ( type == xkb.first_event ) { - switch ( ev->pad0 ) - { - case XCB_XKB_MAP_NOTIFY: - { - struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xkb.bindings_seat ), xcb->connection, xkb.device_id, 0 ); - struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xkb.device_id ); - nk_bindings_seat_update_keymap ( xkb.bindings_seat, keymap, state ); - xkb_keymap_unref ( keymap ); - xkb_state_unref ( state ); - break; - } - case XCB_XKB_STATE_NOTIFY: - { - xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev; - nk_bindings_seat_update_mask ( xkb.bindings_seat, - ksne->baseMods, - ksne->latchedMods, - ksne->lockedMods, - ksne->baseGroup, - ksne->latchedGroup, - ksne->lockedGroup ); - xcb_generic_event_t dev; - dev.response_type = 0; - main_loop_x11_event_handler_view ( &dev ); - break; - } - } - return G_SOURCE_CONTINUE; - } - if ( xcb->sndisplay != NULL ) { - sn_xcb_display_process_event ( xcb->sndisplay, ev ); - } - main_loop_x11_event_handler_view ( ev ); - return G_SOURCE_CONTINUE; -} - static gboolean main_loop_signal_handler_int ( G_GNUC_UNUSED gpointer data ) { // Break out of loop. @@ -706,23 +620,6 @@ static gboolean main_loop_signal_handler_int ( G_GNUC_UNUSED gpointer data ) return G_SOURCE_CONTINUE; } -/** X server error depth. to handle nested errors. */ -static int error_trap_depth = 0; -static void error_trap_push ( G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED xcb_connection_t *xdisplay ) -{ - ++error_trap_depth; -} - -static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, xcb_connection_t *xdisplay ) -{ - if ( error_trap_depth == 0 ) { - g_warning ( "Error trap underflow!" ); - exit ( EXIT_FAILURE ); - } - - xcb_flush ( xdisplay ); - --error_trap_depth; -} /** Retry count of grabbing keyboard. */ unsigned int lazy_grab_retry_count_kb = 0; /** Retry count of grabbing pointer. */ @@ -797,10 +694,6 @@ static gboolean startup ( G_GNUC_UNUSED gpointer data ) __create_window ( window_flags ); TICK_N ( "Create Window" ); // Parse the keybindings. - if ( !parse_keys_abe ( xkb.bindings ) ) { - // Error dialog - return G_SOURCE_REMOVE; - } TICK_N ( "Parse ABE" ); // Sanity check config_sanity_check ( ); @@ -960,138 +853,21 @@ int main ( int argc, char *argv[] ) return EXIT_FAILURE; } - // Get DISPLAY, first env, then argument. - // We never modify display_str content. - char *display_str = ( char *) g_getenv ( "DISPLAY" ); - find_arg_str ( "-display", &display_str ); - - xcb->connection = xcb_connect ( display_str, &xcb->screen_nbr ); - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Failed to open display: %s", display_str ); - cleanup (); - return EXIT_FAILURE; - } - - TICK_N ( "Open Display" ); rofi_collect_modi (); rofi_collect_modi_setup (); TICK_N ( "Collect MODI" ); - xcb->screen = xcb_aux_get_screen ( xcb->connection, xcb->screen_nbr ); - - x11_build_monitor_layout (); - - xcb_intern_atom_cookie_t *ac = xcb_ewmh_init_atoms ( xcb->connection, &xcb->ewmh ); - xcb_generic_error_t *errors = NULL; - xcb_ewmh_init_atoms_replies ( &xcb->ewmh, ac, &errors ); - if ( errors ) { - g_warning ( "Failed to create EWMH atoms" ); - free ( errors ); - } - // Discover the current active window manager. - x11_helper_discover_window_manager (); - TICK_N ( "Setup XCB" ); - - if ( xkb_x11_setup_xkb_extension ( xcb->connection, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, - XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, NULL, NULL, &xkb.first_event, NULL ) < 0 ) { - g_warning ( "cannot setup XKB extension!" ); - cleanup (); - return EXIT_FAILURE; - } - - xkb.xcb_connection = xcb->connection; - - xkb.device_id = xkb_x11_get_core_keyboard_device_id ( xcb->connection ); - - enum - { - required_events = - ( XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | - XCB_XKB_EVENT_TYPE_MAP_NOTIFY | - XCB_XKB_EVENT_TYPE_STATE_NOTIFY ), - - required_nkn_details = - ( XCB_XKB_NKN_DETAIL_KEYCODES ), - - required_map_parts = - ( XCB_XKB_MAP_PART_KEY_TYPES | - XCB_XKB_MAP_PART_KEY_SYMS | - XCB_XKB_MAP_PART_MODIFIER_MAP | - XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | - XCB_XKB_MAP_PART_KEY_ACTIONS | - XCB_XKB_MAP_PART_VIRTUAL_MODS | - XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP ), - - required_state_details = - ( XCB_XKB_STATE_PART_MODIFIER_BASE | - XCB_XKB_STATE_PART_MODIFIER_LATCH | - XCB_XKB_STATE_PART_MODIFIER_LOCK | - XCB_XKB_STATE_PART_GROUP_BASE | - XCB_XKB_STATE_PART_GROUP_LATCH | - XCB_XKB_STATE_PART_GROUP_LOCK ), - }; - - static const xcb_xkb_select_events_details_t details = { - .affectNewKeyboard = required_nkn_details, - .newKeyboardDetails = required_nkn_details, - .affectState = required_state_details, - .stateDetails = required_state_details, - }; - xcb_xkb_select_events ( xcb->connection, xkb.device_id, required_events, /* affectWhich */ - 0, /* clear */ - required_events, /* selectAll */ - required_map_parts, /* affectMap */ - required_map_parts, /* map */ - &details ); - - xkb.bindings = nk_bindings_new (); - xkb.bindings_seat = nk_bindings_seat_new ( xkb.bindings, XKB_CONTEXT_NO_FLAGS ); - struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xkb.bindings_seat ), xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); - if ( keymap == NULL ) { - g_warning ( "Failed to get Keymap for current keyboard device." ); - cleanup (); - return EXIT_FAILURE; - } - struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xkb.device_id ); - if ( state == NULL ) { - g_warning ( "Failed to get state object for current keyboard device." ); - cleanup (); - return EXIT_FAILURE; - } - - nk_bindings_seat_update_keymap ( xkb.bindings_seat, keymap, state ); - - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Connection has error" ); - cleanup (); - return EXIT_FAILURE; - } - x11_setup (); - TICK_N ( "Setup xkb" ); - if ( xcb_connection_has_error ( xcb->connection ) ) { + if ( !x11_setup () ) { g_warning ( "Connection has error" ); cleanup (); return EXIT_FAILURE; } + TICK_N ( "Setup X11" ); + main_loop = g_main_loop_new ( NULL, FALSE ); TICK_N ( "Setup mainloop" ); - // startup not. - xcb->sndisplay = sn_xcb_display_new ( xcb->connection, error_trap_push, error_trap_pop ); - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Connection has error" ); - cleanup (); - return EXIT_FAILURE; - } - if ( xcb->sndisplay != NULL ) { - xcb->sncontext = sn_launchee_context_new_from_environment ( xcb->sndisplay, xcb->screen_nbr ); - } - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Connection has error" ); - cleanup (); - return EXIT_FAILURE; - } TICK_N ( "Startup Notification" ); // Setup keybinding setup_abe (); @@ -1180,7 +956,7 @@ int main ( int argc, char *argv[] ) if ( find_arg_uint ( "-record-screenshots", &interval ) ) { g_timeout_add ( 1000 / (double) interval, record, NULL ); } - main_loop_source = g_water_xcb_source_new_for_connection ( NULL, xcb->connection, main_loop_x11_event_handler, NULL, NULL ); + main_loop_source = g_water_xcb_source_new_for_connection ( NULL, xcb->connection, main_loop_x11_event_handler, main_loop, NULL ); TICK_N ( "X11 Setup " ); diff --git a/source/view.c b/source/view.c index f3569532..47adad17 100644 --- a/source/view.c +++ b/source/view.c @@ -55,7 +55,6 @@ #include "rofi.h" #include "mode.h" #include "xcb-internal.h" -#include "xkb-internal.h" #include "helper.h" #include "helper-theme.h" #include "xrmoptions.h" @@ -1383,7 +1382,7 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, BindingsScope scope, g return FALSE; } -void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb_stuff *xkb ) +void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, NkBindingsSeat *seat ) { switch ( event->response_type & ~0x80 ) { @@ -1437,13 +1436,13 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb xcb_button_press_event_t *bpe = (xcb_button_press_event_t *) event; state->mouse.x = bpe->event_x; state->mouse.y = bpe->event_y; - nk_bindings_seat_handle_button ( xkb->bindings_seat, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time ); + nk_bindings_seat_handle_button ( seat, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time ); break; } case XCB_BUTTON_RELEASE: { xcb_button_release_event_t *bre = (xcb_button_release_event_t *) event; - nk_bindings_seat_handle_button ( xkb->bindings_seat, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time ); + nk_bindings_seat_handle_button ( seat, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time ); if ( config.click_to_exit == TRUE ) { if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) { if ( ( state->mouse_seen == FALSE ) && ( bre->event != CacheState.main_window ) ) { @@ -1466,7 +1465,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb for ( gint8 bi = 0; bi < 7; ++bi ) { if ( kne->keys[by] & ( 1 << bi ) ) { // X11 keycodes starts at 8 - nk_bindings_seat_handle_key ( xkb->bindings_seat, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED ); + nk_bindings_seat_handle_key ( seat, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED ); } } } @@ -1477,7 +1476,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) event; gchar *text; - text = nk_bindings_seat_handle_key ( xkb->bindings_seat, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS ); + text = nk_bindings_seat_handle_key ( seat, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS ); if ( ( text != NULL ) && ( textbox_append_char ( state->text, text, strlen ( text ) ) ) ) { state->refilter = TRUE; } @@ -1486,7 +1485,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb case XCB_KEY_RELEASE: { xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event; - nk_bindings_seat_handle_key ( xkb->bindings_seat, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE ); + nk_bindings_seat_handle_key ( seat, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE ); break; } default: diff --git a/source/xcb.c b/source/xcb.c index e9a300a2..e9414058 100644 --- a/source/xcb.c +++ b/source/xcb.c @@ -46,15 +46,18 @@ #include #include #include +#include +#include +#include #include "xcb-internal.h" #include "xcb.h" #include "settings.h" #include "helper.h" +#include "timings.h" #include /** Checks if the if x and y is inside rectangle. */ #define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) ) -#include "xkb-internal.h" WindowManager current_window_manager = WM_EWHM; /** @@ -614,6 +617,24 @@ void release_pointer ( void ) xcb_ungrab_pointer ( xcb->connection, XCB_CURRENT_TIME ); } +/** X server error depth. to handle nested errors. */ +static int error_trap_depth = 0; +static void error_trap_push ( G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED xcb_connection_t *xdisplay ) +{ + ++error_trap_depth; +} + +static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, xcb_connection_t *xdisplay ) +{ + if ( error_trap_depth == 0 ) { + g_warning ( "Error trap underflow!" ); + exit ( EXIT_FAILURE ); + } + + xcb_flush ( xdisplay ); + --error_trap_depth; +} + /** * Fill in the list of frequently used X11 Atoms. */ @@ -630,10 +651,129 @@ static void x11_create_frequently_used_atoms ( void ) } } -void x11_setup ( void ) +gboolean x11_setup ( void ) { + // Get DISPLAY, first env, then argument. + // We never modify display_str content. + char *display_str = ( char *) g_getenv ( "DISPLAY" ); + find_arg_str ( "-display", &display_str ); + + xcb->connection = xcb_connect ( display_str, &xcb->screen_nbr ); + if ( xcb_connection_has_error ( xcb->connection ) ) { + g_warning ( "Failed to open display: %s", display_str ); + return FALSE; + } + + TICK_N ( "Open Display" ); + + xcb->screen = xcb_aux_get_screen ( xcb->connection, xcb->screen_nbr ); + + x11_build_monitor_layout (); + + xcb_intern_atom_cookie_t *ac = xcb_ewmh_init_atoms ( xcb->connection, &xcb->ewmh ); + xcb_generic_error_t *errors = NULL; + xcb_ewmh_init_atoms_replies ( &xcb->ewmh, ac, &errors ); + if ( errors ) { + g_warning ( "Failed to create EWMH atoms" ); + free ( errors ); + } + // Discover the current active window manager. + x11_helper_discover_window_manager (); + TICK_N ( "Setup XCB" ); + + if ( xkb_x11_setup_xkb_extension ( xcb->connection, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, + XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, NULL, NULL, &xcb->xkb.first_event, NULL ) < 0 ) { + g_warning ( "cannot setup XKB extension!" ); + return FALSE; + } + + xcb->xkb.device_id = xkb_x11_get_core_keyboard_device_id ( xcb->connection ); + + enum + { + required_events = + ( XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | + XCB_XKB_EVENT_TYPE_MAP_NOTIFY | + XCB_XKB_EVENT_TYPE_STATE_NOTIFY ), + + required_nkn_details = + ( XCB_XKB_NKN_DETAIL_KEYCODES ), + + required_map_parts = + ( XCB_XKB_MAP_PART_KEY_TYPES | + XCB_XKB_MAP_PART_KEY_SYMS | + XCB_XKB_MAP_PART_MODIFIER_MAP | + XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | + XCB_XKB_MAP_PART_KEY_ACTIONS | + XCB_XKB_MAP_PART_VIRTUAL_MODS | + XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP ), + + required_state_details = + ( XCB_XKB_STATE_PART_MODIFIER_BASE | + XCB_XKB_STATE_PART_MODIFIER_LATCH | + XCB_XKB_STATE_PART_MODIFIER_LOCK | + XCB_XKB_STATE_PART_GROUP_BASE | + XCB_XKB_STATE_PART_GROUP_LATCH | + XCB_XKB_STATE_PART_GROUP_LOCK ), + }; + + static const xcb_xkb_select_events_details_t details = { + .affectNewKeyboard = required_nkn_details, + .newKeyboardDetails = required_nkn_details, + .affectState = required_state_details, + .stateDetails = required_state_details, + }; + xcb_xkb_select_events ( xcb->connection, xcb->xkb.device_id, required_events, /* affectWhich */ + 0, /* clear */ + required_events, /* selectAll */ + required_map_parts, /* affectMap */ + required_map_parts, /* map */ + &details ); + + xcb->bindings = nk_bindings_new (); + xcb->bindings_seat = nk_bindings_seat_new ( xcb->bindings, XKB_CONTEXT_NO_FLAGS ); + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xcb->bindings_seat ), xcb->connection, xcb->xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); + if ( keymap == NULL ) { + g_warning ( "Failed to get Keymap for current keyboard device." ); + return FALSE; + } + struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xcb->xkb.device_id ); + if ( state == NULL ) { + g_warning ( "Failed to get state object for current keyboard device." ); + return FALSE; + } + + nk_bindings_seat_update_keymap ( xcb->bindings_seat, keymap, state ); + + if ( !parse_keys_abe ( xcb->bindings ) ) { + // Error dialog + return FALSE; + } + // determine numlock mask so we can bind on keys with and without it x11_create_frequently_used_atoms ( ); + + if ( xcb_connection_has_error ( xcb->connection ) ) { + g_warning ( "Connection has error" ); + return FALSE; + } + + // startup not. + xcb->sndisplay = sn_xcb_display_new ( xcb->connection, error_trap_push, error_trap_pop ); + if ( xcb_connection_has_error ( xcb->connection ) ) { + g_warning ( "Connection has error" ); + return FALSE; + } + + if ( xcb->sndisplay != NULL ) { + xcb->sncontext = sn_launchee_context_new_from_environment ( xcb->sndisplay, xcb->screen_nbr ); + } + if ( xcb_connection_has_error ( xcb->connection ) ) { + g_warning ( "Connection has error" ); + return FALSE; + } + + return TRUE; } void x11_create_visual_and_colormap ( void ) @@ -676,6 +816,77 @@ void x11_create_visual_and_colormap ( void ) } } +/** + * Process X11 events in the main-loop (gui-thread) of the application. + */ +static void main_loop_x11_event_handler_view ( xcb_generic_event_t *ev, GMainLoop *main_loop ) +{ + RofiViewState *state = rofi_view_get_active (); + if ( state != NULL ) { + rofi_view_itterrate ( state, ev, xcb->bindings_seat ); + if ( rofi_view_get_completed ( state ) ) { + // This menu is done. + rofi_view_finalize ( state ); + // cleanup + if ( rofi_view_get_active () == NULL ) { + g_main_loop_quit ( main_loop ); + } + } + } +} + +gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, gpointer user_data ) +{ + if ( ev == NULL ) { + int status = xcb_connection_has_error ( xcb->connection ); + if ( status > 0 ) { + g_warning ( "The XCB connection to X server had a fatal error: %d", status ); + g_main_loop_quit ( user_data ); + return G_SOURCE_REMOVE; + } + else { + g_warning ( "main_loop_x11_event_handler: ev == NULL, status == %d", status ); + return G_SOURCE_CONTINUE; + } + } + uint8_t type = ev->response_type & ~0x80; + if ( type == xcb->xkb.first_event ) { + switch ( ev->pad0 ) + { + case XCB_XKB_MAP_NOTIFY: + { + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xcb->bindings_seat ), xcb->connection, xcb->xkb.device_id, 0 ); + struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xcb->xkb.device_id ); + nk_bindings_seat_update_keymap ( xcb->bindings_seat, keymap, state ); + xkb_keymap_unref ( keymap ); + xkb_state_unref ( state ); + break; + } + case XCB_XKB_STATE_NOTIFY: + { + xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev; + nk_bindings_seat_update_mask ( xcb->bindings_seat, + ksne->baseMods, + ksne->latchedMods, + ksne->lockedMods, + ksne->baseGroup, + ksne->latchedGroup, + ksne->lockedGroup ); + xcb_generic_event_t dev; + dev.response_type = 0; + main_loop_x11_event_handler_view ( &dev, user_data ); + break; + } + } + return G_SOURCE_CONTINUE; + } + if ( xcb->sndisplay != NULL ) { + sn_xcb_display_process_event ( xcb->sndisplay, ev ); + } + main_loop_x11_event_handler_view ( ev, user_data ); + return G_SOURCE_CONTINUE; +} + xcb_window_t xcb_stuff_get_root_window ( xcb_stuff *xcb ) { return xcb->screen->root; @@ -683,6 +894,9 @@ xcb_window_t xcb_stuff_get_root_window ( xcb_stuff *xcb ) void xcb_stuff_wipe ( xcb_stuff *xcb ) { + nk_bindings_seat_free ( xcb->bindings_seat ); + nk_bindings_free ( xcb->bindings ); + if ( xcb->connection != NULL ) { g_debug ( "Cleaning up XCB and XKB" ); if ( xcb->sncontext != NULL ) {