From fe7ca2079d97172980f0bc725f532019fc9b7eb5 Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Fri, 19 Feb 2016 22:43:53 +0100 Subject: [PATCH] rofi: Convert to XCB events Signed-off-by: Quentin Glidic --- .gitmodules | 3 + Makefile.am | 7 + configure.ac | 9 +- include/rofi.h | 1 + include/textbox.h | 2 +- include/view-internal.h | 2 +- include/view.h | 2 +- libgwater | 1 + libgwater-xcb-nolibtool.mk | 20 ++ source/rofi.c | 82 +++---- source/textbox.c | 31 +-- source/view.c | 489 ++++++++++++++++++------------------- 12 files changed, 331 insertions(+), 318 deletions(-) create mode 100644 .gitmodules create mode 160000 libgwater create mode 100644 libgwater-xcb-nolibtool.mk diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2034529a2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libgwater"] + path = libgwater + url = git://github.com/sardemff7/libgwater diff --git a/Makefile.am b/Makefile.am index bdfff8e92..62e42824f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,11 @@ # Specify automake version. AUTOMAKE_OPTIONS = 1.11.3 +ACLOCAL_AMFLAGS = -I libgwater ${ACLOCAL_FLAGS} + +noinst_LIBRARIES = +include $(top_srcdir)/libgwater-xcb-nolibtool.mk + ## # Rofi the program ## @@ -60,6 +65,7 @@ rofi_SOURCES=\ rofi_CFLAGS=\ $(AM_CFLAGS)\ $(glib_CFLAGS)\ + $(GW_XCB_CFLAGS)\ $(x11_CFLAGS)\ $(xinerama_CFLAGS)\ $(pango_CFLAGS)\ @@ -73,6 +79,7 @@ rofi_CFLAGS=\ rofi_LDADD=\ $(glib_LIBS)\ + $(GW_XCB_LIBS)\ $(x11_LIBS)\ $(xinerama_LIBS)\ $(libsn_LIBS)\ diff --git a/configure.ac b/configure.ac index 0fa89fd68..d7f711fcb 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,12 @@ dnl System extensions dnl --------------------------------------------------------------------- AC_USE_SYSTEM_EXTENSIONS +dnl --------------------------------------------------------------------- +dnl Static libraries programs +dnl --------------------------------------------------------------------- +AC_PROG_RANLIB +AM_PROG_AR + dnl --------------------------------------------------------------------- dnl Base CFLAGS dnl --------------------------------------------------------------------- @@ -77,7 +83,8 @@ dnl --------------------------------------------------------------------- dnl X11, Glib, Xinerama, Pango, Cairo, libstartup notification dnl --------------------------------------------------------------------- PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40]) -PKG_CHECK_MODULES([x11], [x11]) +GW_CHECK_XCB([xcb-aux xkbcommon xkbcommon-x11]) +PKG_CHECK_MODULES([x11], [x11 x11-xcb]) PKG_CHECK_MODULES([xinerama], [xinerama]) PKG_CHECK_MODULES([pango], [pango pangocairo]) PKG_CHECK_MODULES([cairo], [cairo cairo-xlib]) diff --git a/include/rofi.h b/include/rofi.h index ef717cbcd..411acb375 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -1,5 +1,6 @@ #ifndef ROFI_MAIN_H #define ROFI_MAIN_H +#include #include #include #include diff --git a/include/textbox.h b/include/textbox.h index 757b1c625..c4caa7ca6 100644 --- a/include/textbox.h +++ b/include/textbox.h @@ -113,7 +113,7 @@ void textbox_draw ( textbox *tb, cairo_t *draw ); * * @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1) */ -int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym key, Status stat ); +int textbox_keypress ( textbox *tb, xcb_key_press_event_t *ev, char *pad, int pad_len, KeySym key, Status stat ); /** * @param tb Handle to the textbox diff --git a/include/view-internal.h b/include/view-internal.h index 27ee8a001..6dd61ba21 100644 --- a/include/view-internal.h +++ b/include/view-internal.h @@ -69,7 +69,7 @@ struct RofiViewState MenuFlags menu_flags; // Handlers. - void ( *x11_event_loop )( struct RofiViewState *state, XEvent *ev ); + void ( *x11_event_loop )( struct RofiViewState *state, xcb_generic_event_t *ev ); void ( *finalize )( struct RofiViewState *state ); }; /** @} */ diff --git a/include/view.h b/include/view.h index f9763b830..d6a3aa19f 100644 --- a/include/view.h +++ b/include/view.h @@ -47,7 +47,7 @@ void rofi_view_finalize ( RofiViewState *state ); MenuReturn rofi_view_get_return_value ( const RofiViewState *state ); unsigned int rofi_view_get_next_position ( const RofiViewState *state ); -void rofi_view_itterrate ( RofiViewState *state, XEvent *event ); +void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event ); unsigned int rofi_view_get_completed ( const RofiViewState *state ); const char * rofi_view_get_user_input ( const RofiViewState *state ); diff --git a/libgwater b/libgwater new file mode 160000 index 000000000..50a0f8a4b --- /dev/null +++ b/libgwater @@ -0,0 +1 @@ +Subproject commit 50a0f8a4bc2d762c412b6dd1823a14949de583aa diff --git a/libgwater-xcb-nolibtool.mk b/libgwater-xcb-nolibtool.mk new file mode 100644 index 000000000..e4e07eb7c --- /dev/null +++ b/libgwater-xcb-nolibtool.mk @@ -0,0 +1,20 @@ +noinst_LIBRARIES += \ + libgwater/libgwater-xcb.a + +libgwater_libgwater_xcb_a_SOURCES = \ + libgwater/xcb/libgwater-xcb.c \ + libgwater/xcb/libgwater-xcb.h + +libgwater_libgwater_xcb_a_CFLAGS = \ + $(AM_CFLAGS) \ + $(GW_XCB_INTERNAL_CFLAGS) + + +GW_XCB_CFLAGS = \ + -I$(srcdir)/libgwater/xcb \ + $(GW_XCB_INTERNAL_CFLAGS) + +GW_XCB_LIBS = \ + libgwater/libgwater-xcb.a \ + $(GW_XCB_INTERNAL_LIBS) + diff --git a/source/rofi.c b/source/rofi.c index 66b10f32c..f3e2557e5 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -34,9 +34,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include #include #include @@ -45,6 +49,8 @@ #include +#include + #define SN_API_NOT_YET_FROZEN #include @@ -63,13 +69,15 @@ gboolean daemon_mode = FALSE; // Pidfile. -char *pidfile = NULL; -const char *cache_dir = NULL; -SnDisplay *sndisplay = NULL; -SnLauncheeContext *sncontext = NULL; -Display *display = NULL; -char *display_str = NULL; -char *config_path = NULL; +char *pidfile = NULL; +const char *cache_dir = NULL; +SnDisplay *sndisplay = NULL; +SnLauncheeContext *sncontext = NULL; +xcb_connection_t *xcb_connection = NULL; +xcb_screen_t *xcb_screen = NULL; +Display *display = NULL; +char *display_str = NULL; +char *config_path = NULL; // Array of modi. Mode **modi = NULL; unsigned int num_modi = 0; @@ -77,7 +85,7 @@ unsigned int num_modi = 0; unsigned int curr_switcher = 0; GMainLoop *main_loop = NULL; -GSource *main_loop_source = NULL; +GWaterXcbSource *main_loop_source = NULL; gboolean quiet = FALSE; static int dmenu_mode = FALSE; @@ -277,19 +285,19 @@ int show_error_message ( const char *msg, int markup ) * Function that listens for global key-presses. * This is only used when in daemon mode. */ -static void handle_keypress ( XEvent *ev ) +static void handle_keypress ( xcb_key_press_event_t *ev ) { int index; - KeySym key = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 ); - index = locate_switcher ( key, ev->xkey.state ); + KeySym key = XkbKeycodeToKeysym ( display, ev->detail, 0, 0 ); + index = locate_switcher ( key, ev->state ); if ( index >= 0 ) { run_switcher ( index ); } else { fprintf ( stderr, "Warning: Unhandled keypress in global keyhandler, keycode = %u mask = %u\n", - ev->xkey.keycode, - ev->xkey.state ); + ev->detail, + ev->state ); } } @@ -354,7 +362,7 @@ static void cleanup () rofi_view_workers_finalize (); if ( main_loop != NULL ) { if ( main_loop_source ) { - g_source_destroy ( main_loop_source ); + g_water_xcb_source_unref ( main_loop_source ); } g_main_loop_unref ( main_loop ); main_loop = NULL; @@ -542,19 +550,14 @@ static void reload_configuration () /** * Process X11 events in the main-loop (gui-thread) of the application. */ -static gboolean main_loop_x11_event_handler ( G_GNUC_UNUSED gpointer data ) +static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data ) { RofiViewState *state = rofi_view_get_active (); + if ( sndisplay != NULL ) { + sn_xcb_display_process_event ( sndisplay, ev ); + } if ( state != NULL ) { - while ( XPending ( display ) ) { - XEvent ev; - // Read event, we know this won't block as we checked with XPending. - XNextEvent ( display, &ev ); - if ( sndisplay != NULL ) { - sn_display_process_event ( sndisplay, &ev ); - } - rofi_view_itterrate ( state, &ev ); - } + rofi_view_itterrate ( state, ev ); if ( rofi_view_get_completed ( state ) ) { // This menu is done. rofi_view_finalize ( state ); @@ -566,24 +569,14 @@ static gboolean main_loop_x11_event_handler ( G_GNUC_UNUSED gpointer data ) } } } - return G_SOURCE_CONTINUE; } - // X11 produced an event. Consume them. - while ( XPending ( display ) ) { - XEvent ev; - // Read event, we know this won't block as we checked with XPending. - XNextEvent ( display, &ev ); - if ( sndisplay != NULL ) { - sn_display_process_event ( sndisplay, &ev ); - } + else { + // X11 produced an event. Consume them. // If we get an event that does not belong to a window: // Ignore it. - if ( ev.xany.window == None ) { - continue; - } // If keypress, handle it. - if ( ev.type == KeyPress ) { - handle_keypress ( &ev ); + if ( ( ev->response_type & ~0x80 ) == XCB_KEY_PRESS ) { + handle_keypress ( (xcb_key_press_event_t *) ev ); } } return G_SOURCE_CONTINUE; @@ -606,7 +599,7 @@ static gboolean main_loop_signal_handler_hup ( G_GNUC_UNUSED gpointer data ) // Grab the possibly new keybindings. grab_global_keybindings (); // We need to flush, otherwise the first key presses are not caught. - XFlush ( display ); + xcb_flush ( xcb_connection ); return G_SOURCE_CONTINUE; } @@ -722,8 +715,9 @@ static gboolean startup ( G_GNUC_UNUSED gpointer data ) sn_launchee_context_complete ( sncontext ); } daemon_mode = TRUE; - XSelectInput ( display, DefaultRootWindow ( display ), KeyPressMask ); - XFlush ( display ); + uint32_t mask[] = { XCB_EVENT_MASK_KEY_PRESS }; + xcb_change_window_attributes ( xcb_connection, xcb_screen->root, XCB_CW_EVENT_MASK, mask ); + xcb_flush ( xcb_connection ); } return G_SOURCE_REMOVE; @@ -807,6 +801,9 @@ int main ( int argc, char *argv[] ) } TICK_N ( "Open Display" ); + xcb_connection = XGetXCBConnection ( display ); + xcb_screen = xcb_aux_get_screen ( xcb_connection, DefaultScreen ( display ) ); + main_loop = g_main_loop_new ( NULL, FALSE ); TICK_N ( "Setup mainloop" ); @@ -856,8 +853,7 @@ int main ( int argc, char *argv[] ) } x11_setup ( display ); - main_loop_source = x11_event_source_new ( display ); - x11_event_source_set_callback ( main_loop_source, main_loop_x11_event_handler ); + main_loop_source = g_water_xcb_source_new_for_connection ( NULL, xcb_connection, main_loop_x11_event_handler, NULL, NULL ); TICK_N ( "X11 Setup " ); diff --git a/source/textbox.c b/source/textbox.c index 4a456a569..bb784eb8f 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -532,7 +533,7 @@ static void textbox_cursor_del_word ( textbox *tb ) // 0 = unhandled // 1 = handled // -1 = handled and return pressed (finished) -int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym key, Status stat ) +int textbox_keypress ( textbox *tb, xcb_key_press_event_t *ev, char *pad, int pad_len, KeySym key, Status stat ) { if ( !( tb->flags & TB_EDITABLE ) ) { return 0; @@ -541,67 +542,67 @@ int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym k tb->blink = 2; if ( stat == XLookupKeySym || stat == XLookupBoth ) { // Left or Ctrl-b - if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { + if ( abe_test_action ( MOVE_CHAR_BACK, ev->state, key ) ) { textbox_cursor_dec ( tb ); return 2; } // Right or Ctrl-F - else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { + else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->state, key ) ) { textbox_cursor_inc ( tb ); return 2; } // Ctrl-U: Kill from the beginning to the end of the line. - else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { + else if ( abe_test_action ( CLEAR_LINE, ev->state, key ) ) { textbox_text ( tb, "" ); return 1; } // Ctrl-A - else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { + else if ( abe_test_action ( MOVE_FRONT, ev->state, key ) ) { textbox_cursor ( tb, 0 ); return 2; } // Ctrl-E - else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { + else if ( abe_test_action ( MOVE_END, ev->state, key ) ) { textbox_cursor_end ( tb ); return 2; } // Ctrl-Alt-h - else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) { + else if ( abe_test_action ( REMOVE_WORD_BACK, ev->state, key ) ) { textbox_cursor_bkspc_word ( tb ); return 1; } // Ctrl-Alt-d - else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) { + else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->state, key ) ) { textbox_cursor_del_word ( tb ); return 1; } // Delete or Ctrl-D - else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { + else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->state, key ) ) { textbox_cursor_del ( tb ); return 1; } // Alt-B - else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) { + else if ( abe_test_action ( MOVE_WORD_BACK, ev->state, key ) ) { textbox_cursor_dec_word ( tb ); return 2; } // Alt-F - else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) { + else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->state, key ) ) { textbox_cursor_inc_word ( tb ); return 2; } // BackSpace, Ctrl-h - else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) { + else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->state, key ) ) { textbox_cursor_bkspc ( tb ); return 1; } - else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) { + else if ( abe_test_action ( ACCEPT_CUSTOM, ev->state, key ) ) { return -2; } - else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) { + else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->state, key ) ) { return -3; } - else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) { + else if ( abe_test_action ( ACCEPT_ENTRY, ev->state, key ) ) { return -1; } } diff --git a/source/view.c b/source/view.c index d9aeaf86e..c5ef9b84a 100644 --- a/source/view.c +++ b/source/view.c @@ -308,9 +308,95 @@ unsigned int rofi_view_get_completed ( const RofiViewState *state ) return state->quit; } -void rofi_view_itterrate ( RofiViewState *state, XEvent *event ) +static void rofi_view_resize ( RofiViewState *state ) +{ + unsigned int sbw = config.line_margin + 8; + widget_move ( WIDGET ( state->scrollbar ), state->w - state->border - sbw, state->top_offset ); + if ( config.sidebar_mode == TRUE ) { + int width = ( state->w - ( 2 * ( state->border ) + ( state->num_modi - 1 ) * config.line_margin ) ) / state->num_modi; + for ( unsigned int j = 0; j < state->num_modi; j++ ) { + textbox_moveresize ( state->modi[j], + state->border + j * ( width + config.line_margin ), state->h - state->line_height - state->border, + width, state->line_height ); + textbox_draw ( state->modi[j], draw ); + } + } + int entrybox_width = state->w - ( 2 * ( state->border ) ) - textbox_get_width ( state->prompt_tb ) + - textbox_get_width ( state->case_indicator ); + textbox_moveresize ( state->text, state->text->widget.x, state->text->widget.y, entrybox_width, state->line_height ); + widget_move ( WIDGET ( state->case_indicator ), state->w - state->border - textbox_get_width ( state->case_indicator ), state->border ); + /** + * Resize in Height + */ + { + unsigned int last_length = state->max_elements; + int element_height = state->line_height * config.element_height + config.line_margin; + // Calculated new number of boxes. + int h = ( state->h - state->top_offset - config.padding ); + if ( config.sidebar_mode == TRUE ) { + h -= state->line_height + config.line_margin; + } + if ( h < 0 ) { + fprintf ( stderr, "Current padding %u (on each side) does not fit within visible window %u.\n", config.padding, state->h ); + h = ( state->h - state->top_offset - state->h / 3 ); + if ( config.sidebar_mode == TRUE ) { + h -= state->line_height + config.line_margin; + } + } + state->max_rows = MAX ( 1, ( h / element_height ) ); + state->menu_lines = state->max_rows; + state->max_elements = state->max_rows * config.menu_columns; + // Free boxes no longer needed. + for ( unsigned int i = state->max_elements; i < last_length; i++ ) { + textbox_free ( state->boxes[i] ); + } + // resize array. + state->boxes = g_realloc ( state->boxes, state->max_elements * sizeof ( textbox* ) ); + + int y_offset = state->top_offset; + int x_offset = state->border; + // Add newly added boxes. + for ( unsigned int i = last_length; i < state->max_elements; i++ ) { + state->boxes[i] = textbox_create ( 0, x_offset, y_offset, + state->element_width, element_height, NORMAL, "" ); + } + scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin ); + } + + state->rchanged = TRUE; + state->update = TRUE; +} + +void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event ) { - state->x11_event_loop ( state, event ); + uint8_t type = event->response_type & ~0x80; + switch ( type ) + { + case XCB_EXPOSE: + state->update = TRUE; + break; + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *) event; + if ( xce->window == main_window ) { + if ( state->x != xce->x || state->y != xce->y ) { + state->x = xce->x; + state->y = xce->y; + state->update = TRUE; + } + if ( state->w != xce->width || state->h != xce->height ) { + state->w = xce->width; + state->h = xce->height; + cairo_xlib_surface_set_size ( surface, state->w, state->h ); + rofi_view_resize ( state ); + } + } + } + break; + default: + state->x11_event_loop ( state, event, xkb ); + } + rofi_view_update ( state ); } const char * rofi_view_get_user_input ( const RofiViewState *state ) @@ -881,7 +967,7 @@ void rofi_view_update ( RofiViewState *state ) * * Handle paste event. */ -static void rofi_view_paste ( RofiViewState *state, XSelectionEvent *xse ) +static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t *xse ) { if ( xse->property == netatoms[UTF8_STRING] ) { gchar *text = window_get_text_prop ( display, main_window, netatoms[UTF8_STRING] ); @@ -903,65 +989,6 @@ static void rofi_view_paste ( RofiViewState *state, XSelectionEvent *xse ) } } -static void rofi_view_resize ( RofiViewState *state ) -{ - unsigned int sbw = config.line_margin + 8; - widget_move ( WIDGET ( state->scrollbar ), state->w - state->border - sbw, state->top_offset ); - if ( config.sidebar_mode == TRUE ) { - int width = ( state->w - ( 2 * ( state->border ) + ( state->num_modi - 1 ) * config.line_margin ) ) / state->num_modi; - for ( unsigned int j = 0; j < state->num_modi; j++ ) { - textbox_moveresize ( state->modi[j], - state->border + j * ( width + config.line_margin ), state->h - state->line_height - state->border, - width, state->line_height ); - textbox_draw ( state->modi[j], draw ); - } - } - int entrybox_width = state->w - ( 2 * ( state->border ) ) - textbox_get_width ( state->prompt_tb ) - - textbox_get_width ( state->case_indicator ); - textbox_moveresize ( state->text, state->text->widget.x, state->text->widget.y, entrybox_width, state->line_height ); - widget_move ( WIDGET ( state->case_indicator ), state->w - state->border - textbox_get_width ( state->case_indicator ), state->border ); - /** - * Resize in Height - */ - { - unsigned int last_length = state->max_elements; - int element_height = state->line_height * config.element_height + config.line_margin; - // Calculated new number of boxes. - int h = ( state->h - state->top_offset - config.padding ); - if ( config.sidebar_mode == TRUE ) { - h -= state->line_height + config.line_margin; - } - if ( h < 0 ) { - fprintf ( stderr, "Current padding %u (on each side) does not fit within visible window %u.\n", config.padding, state->h ); - h = ( state->h - state->top_offset - state->h / 3 ); - if ( config.sidebar_mode == TRUE ) { - h -= state->line_height + config.line_margin; - } - } - state->max_rows = MAX ( 1, ( h / element_height ) ); - state->menu_lines = state->max_rows; - state->max_elements = state->max_rows * config.menu_columns; - // Free boxes no longer needed. - for ( unsigned int i = state->max_elements; i < last_length; i++ ) { - textbox_free ( state->boxes[i] ); - } - // resize array. - state->boxes = g_realloc ( state->boxes, state->max_elements * sizeof ( textbox* ) ); - - int y_offset = state->top_offset; - int x_offset = state->border; - // Add newly added boxes. - for ( unsigned int i = last_length; i < state->max_elements; i++ ) { - state->boxes[i] = textbox_create ( 0, x_offset, y_offset, - state->element_width, element_height, NORMAL, "" ); - } - scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin ); - } - - state->rchanged = TRUE; - state->update = TRUE; -} - /** * @param state Internal state of the menu. * @param key the Key being pressed. @@ -1047,32 +1074,32 @@ static int rofi_view_keyboard_navigation ( RofiViewState *state, KeySym key, uns return 0; } -static void rofi_view_mouse_navigation ( RofiViewState *state, XButtonEvent *xbe ) +static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_event_t *xbe ) { // Scroll event - if ( xbe->button > 3 ) { - if ( xbe->button == 4 ) { + if ( xbe->detail > 3 ) { + if ( xbe->detail == 4 ) { rofi_view_nav_up ( state ); } - else if ( xbe->button == 5 ) { + else if ( xbe->detail == 5 ) { rofi_view_nav_down ( state ); } - else if ( xbe->button == 6 ) { + else if ( xbe->detail == 6 ) { rofi_view_nav_left ( state ); } - else if ( xbe->button == 7 ) { + else if ( xbe->detail == 7 ) { rofi_view_nav_right ( state ); } return; } else { - if ( state->scrollbar && widget_intersect ( &( state->scrollbar->widget ), xbe->x, xbe->y ) ) { - state->selected = scrollbar_clicked ( state->scrollbar, xbe->y ); + if ( state->scrollbar && widget_intersect ( &( state->scrollbar->widget ), xbe->event_x, xbe->event_y ) ) { + state->selected = scrollbar_clicked ( state->scrollbar, xbe->event_y ); state->update = TRUE; return; } for ( unsigned int i = 0; config.sidebar_mode == TRUE && i < state->num_modi; i++ ) { - if ( widget_intersect ( &( state->modi[i]->widget ), xbe->x, xbe->y ) ) { + if ( widget_intersect ( &( state->modi[i]->widget ), xbe->event_x, xbe->event_y ) ) { ( state->selected_line ) = 0; state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK ); state->quit = TRUE; @@ -1081,7 +1108,7 @@ static void rofi_view_mouse_navigation ( RofiViewState *state, XButtonEvent *xbe } } for ( unsigned int i = 0; i < state->max_elements; i++ ) { - if ( widget_intersect ( &( state->boxes[i]->widget ), xbe->x, xbe->y ) ) { + if ( widget_intersect ( &( state->boxes[i]->widget ), xbe->event_x, xbe->event_y ) ) { // Only allow items that are visible to be selected. if ( ( state->last_offset + i ) >= state->filtered_lines ) { break; @@ -1219,192 +1246,165 @@ void rofi_view_setup_fake_transparency ( Display *display, RofiViewState *state } } -static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev ) +static void rofi_view_mainloop_iter ( RofiViewState *state, xcb_generic_event_t *ev ) { - if ( ev->type == KeymapNotify ) { - XRefreshKeyboardMapping ( &( ev->xmapping ) ); - } - else if ( ev->type == ConfigureNotify ) { - XConfigureEvent xce = ev->xconfigure; - if ( xce.window == main_window ) { - if ( state->x != (int ) xce.x || state->y != (int) xce.y ) { - state->x = xce.x; - state->y = xce.y; - state->update = TRUE; - } - if ( state->w != (unsigned int) xce.width || state->h != (unsigned int ) xce.height ) { - state->w = xce.width; - state->h = xce.height; - cairo_xlib_surface_set_size ( surface, state->w, state->h ); - rofi_view_resize ( state ); - } - } - } - else if ( ev->type == FocusIn ) { + switch ( ev->response_type & ~0x80 ) + { + case XCB_FOCUS_IN: if ( ( state->menu_flags & MENU_NORMAL_WINDOW ) == 0 ) { take_keyboard ( display, main_window ); } - } - else if ( ev->type == FocusOut ) { + break; + case XCB_FOCUS_OUT: if ( ( state->menu_flags & MENU_NORMAL_WINDOW ) == 0 ) { release_keyboard ( display ); } - } - // Handle event. - else if ( ev->type == Expose ) { - while ( XCheckTypedEvent ( display, Expose, ev ) ) { - ; - } - state->update = TRUE; - } - else if ( ev->type == MotionNotify ) { - while ( XCheckTypedEvent ( display, MotionNotify, ev ) ) { - ; - } - XMotionEvent xme = ev->xmotion; - if ( xme.x >= state->scrollbar->widget.x && xme.x < ( state->scrollbar->widget.x + state->scrollbar->widget.w ) ) { - state->selected = scrollbar_clicked ( state->scrollbar, xme.y ); + break; + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t *xme = (xcb_motion_notify_event_t *) ev; + if ( xme->event_x >= state->scrollbar->widget.x && xme->event_x < ( state->scrollbar->widget.x + state->scrollbar->widget.w ) ) { + state->selected = scrollbar_clicked ( state->scrollbar, xme->event_y ); state->update = TRUE; } + break; } - // Button press event. - else if ( ev->type == ButtonPress ) { - while ( XCheckTypedEvent ( display, ButtonPress, ev ) ) { - ; - } - rofi_view_mouse_navigation ( state, &( ev->xbutton ) ); - } + case XCB_BUTTON_PRESS: + rofi_view_mouse_navigation ( state, (xcb_button_press_event_t *) ev ); + break; // Paste event. - else if ( ev->type == SelectionNotify ) { - do { - rofi_view_paste ( state, &( ev->xselection ) ); - } while ( XCheckTypedEvent ( display, SelectionNotify, ev ) ); - } - // Key press event. - else if ( ev->type == KeyPress ) { - do { - // This is needed for letting the Input Method handle combined keys. - // E.g. `e into è - if ( XFilterEvent ( ev, main_window ) ) { - continue; + case XCB_SELECTION_NOTIFY: + rofi_view_paste ( state, (xcb_selection_notify_event_t *) ev ); + break; + case XCB_KEY_PRESS: + { + xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) ev; + XEvent fake_event; + fake_event.type = KeyPress; + fake_event.xany.display = display; + fake_event.xany.window = xkpe->event; + fake_event.xkey.state = xkpe->state; + fake_event.xkey.keycode = xkpe->detail; + // This is needed for letting the Input Method handle combined keys. + // E.g. `e into è + Status stat; + char pad[32]; + KeySym key; // = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 ); + int len = Xutf8LookupString ( xic, &( fake_event.xkey ), pad, sizeof ( pad ), &key, &stat ); + pad[len] = 0; + if ( stat == XLookupKeySym || stat == XLookupBoth ) { + // Handling of paste + if ( abe_test_action ( PASTE_PRIMARY, xkpe->state, key ) ) { + XConvertSelection ( display, XA_PRIMARY, netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, CurrentTime ); } - Status stat; - char pad[32]; - KeySym key; // = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 ); - int len = Xutf8LookupString ( xic, &( ev->xkey ), pad, sizeof ( pad ), &key, &stat ); - pad[len] = 0; - if ( stat == XLookupKeySym || stat == XLookupBoth ) { - // Handling of paste - if ( abe_test_action ( PASTE_PRIMARY, ev->xkey.state, key ) ) { - XConvertSelection ( display, XA_PRIMARY, netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, CurrentTime ); - } - else if ( abe_test_action ( PASTE_SECONDARY, ev->xkey.state, key ) ) { - XConvertSelection ( display, netatoms[CLIPBOARD], netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, - CurrentTime ); - } - if ( abe_test_action ( SCREENSHOT, ev->xkey.state, key ) ) { - menu_capture_screenshot ( ); - break; - } - if ( abe_test_action ( TOGGLE_SORT, ev->xkey.state, key ) ) { - config.levenshtein_sort = !config.levenshtein_sort; - state->refilter = TRUE; - state->update = TRUE; - textbox_text ( state->case_indicator, get_matching_state () ); - break; - } - else if ( abe_test_action ( MODE_PREVIOUS, ev->xkey.state, key ) ) { - state->retv = MENU_PREVIOUS; - ( state->selected_line ) = 0; - state->quit = TRUE; - break; - } - // Menu navigation. - else if ( abe_test_action ( MODE_NEXT, ev->xkey.state, key ) ) { - state->retv = MENU_NEXT; - ( state->selected_line ) = 0; + else if ( abe_test_action ( PASTE_SECONDARY, xkpe->state, key ) ) { + XConvertSelection ( display, netatoms[CLIPBOARD], netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, + CurrentTime ); + } + if ( abe_test_action ( SCREENSHOT, xkpe->state, key ) ) { + menu_capture_screenshot ( ); + break; + } + if ( abe_test_action ( TOGGLE_SORT, xkpe->state, key ) ) { + config.levenshtein_sort = !config.levenshtein_sort; + state->refilter = TRUE; + state->update = TRUE; + textbox_text ( state->case_indicator, get_matching_state () ); + break; + } + else if ( abe_test_action ( MODE_PREVIOUS, xkpe->state, key ) ) { + state->retv = MENU_PREVIOUS; + ( state->selected_line ) = 0; + state->quit = TRUE; + break; + } + // Menu navigation. + else if ( abe_test_action ( MODE_NEXT, xkpe->state, key ) ) { + state->retv = MENU_NEXT; + ( state->selected_line ) = 0; + state->quit = TRUE; + break; + } + // Toggle case sensitivity. + else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, xkpe->state, key ) ) { + config.case_sensitive = !config.case_sensitive; + ( state->selected_line ) = 0; + state->refilter = TRUE; + state->update = TRUE; + textbox_text ( state->case_indicator, get_matching_state () ); + break; + } + // Special delete entry command. + else if ( abe_test_action ( DELETE_ENTRY, xkpe->state, key ) ) { + if ( state->selected < state->filtered_lines ) { + ( state->selected_line ) = state->line_map[state->selected]; + state->retv = MENU_ENTRY_DELETE; state->quit = TRUE; break; } - // Toggle case sensitivity. - else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, ev->xkey.state, key ) ) { - config.case_sensitive = !config.case_sensitive; - ( state->selected_line ) = 0; - state->refilter = TRUE; - state->update = TRUE; - textbox_text ( state->case_indicator, get_matching_state () ); - break; - } - // Special delete entry command. - else if ( abe_test_action ( DELETE_ENTRY, ev->xkey.state, key ) ) { + } + for ( unsigned int a = CUSTOM_1; a <= CUSTOM_19; a++ ) { + if ( abe_test_action ( a, xkpe->state, key ) ) { + state->selected_line = UINT32_MAX; if ( state->selected < state->filtered_lines ) { ( state->selected_line ) = state->line_map[state->selected]; - state->retv = MENU_ENTRY_DELETE; - state->quit = TRUE; - break; - } - } - for ( unsigned int a = CUSTOM_1; a <= CUSTOM_19; a++ ) { - if ( abe_test_action ( a, ev->xkey.state, key ) ) { - state->selected_line = UINT32_MAX; - if ( state->selected < state->filtered_lines ) { - ( state->selected_line ) = state->line_map[state->selected]; - } - state->retv = MENU_QUICK_SWITCH | ( ( a - CUSTOM_1 ) & MENU_LOWER_MASK ); - state->quit = TRUE; - break; } - } - if ( rofi_view_keyboard_navigation ( state, key, ev->xkey.state ) ) { - continue; + state->retv = MENU_QUICK_SWITCH | ( ( a - CUSTOM_1 ) & MENU_LOWER_MASK ); + state->quit = TRUE; + break; } } - { - // Skip if we detected key before. - if ( state->quit ) { - continue; - } + if ( rofi_view_keyboard_navigation ( state, key, xkpe->state ) ) { + break; + } + } + { + // Skip if we detected key before. + if ( state->quit ) { + break; + } - int rc = textbox_keypress ( state->text, ev, pad, len, key, stat ); - // Row is accepted. - if ( rc < 0 ) { - int shift = ( ( ev->xkey.state & ShiftMask ) == ShiftMask ); + int rc = textbox_keypress ( state->text, xkpe, pad, len, key, stat ); + // Row is accepted. + if ( rc < 0 ) { + int shift = ( ( xkpe->state & ShiftMask ) == ShiftMask ); - // If a valid item is selected, return that.. - state->selected_line = UINT32_MAX; - if ( state->selected < state->filtered_lines ) { - ( state->selected_line ) = state->line_map[state->selected]; - if ( strlen ( state->text->text ) > 0 && rc == -2 ) { - state->retv = MENU_CUSTOM_INPUT; - } - else { - state->retv = MENU_OK; - } - } - else if ( strlen ( state->text->text ) > 0 ) { - state->retv = MENU_CUSTOM_INPUT; - } - else{ - // Nothing entered and nothing selected. + // If a valid item is selected, return that.. + state->selected_line = UINT32_MAX; + if ( state->selected < state->filtered_lines ) { + ( state->selected_line ) = state->line_map[state->selected]; + if ( strlen ( state->text->text ) > 0 && rc == -2 ) { state->retv = MENU_CUSTOM_INPUT; } - if ( shift ) { - state->retv |= MENU_SHIFT; + else { + state->retv = MENU_OK; } - - state->quit = TRUE; } - // Key press is handled by entry box. - else if ( rc == 1 ) { - state->refilter = TRUE; - state->update = TRUE; + else if ( strlen ( state->text->text ) > 0 ) { + state->retv = MENU_CUSTOM_INPUT; } - else if ( rc == 2 ) { - // redraw. - state->update = TRUE; + else{ + // Nothing entered and nothing selected. + state->retv = MENU_CUSTOM_INPUT; } + if ( shift ) { + state->retv |= MENU_SHIFT; + } + + state->quit = TRUE; + } + // Key press is handled by entry box. + else if ( rc == 1 ) { + state->refilter = TRUE; + state->update = TRUE; } - } while ( XCheckTypedEvent ( display, KeyPress, ev ) ); + else if ( rc == 2 ) { + // redraw. + state->update = TRUE; + } + } + break; + } } // Update if requested. if ( state->refilter ) { @@ -1625,38 +1625,15 @@ RofiViewState *rofi_view_create ( Mode *sw, } return state; } -static void __error_dialog_event_loop ( RofiViewState *state, XEvent *ev ) +static void __error_dialog_event_loop ( RofiViewState *state, xcb_generic_event_t *ev ) { // Handle event. - if ( ev->type == Expose ) { - while ( XCheckTypedEvent ( display, Expose, ev ) ) { - ; - } - state->update = TRUE; - } - else if ( ev->type == ConfigureNotify ) { - XConfigureEvent xce = ev->xconfigure; - if ( xce.window == main_window ) { - if ( state->x != (int ) xce.x || state->y != (int) xce.y ) { - state->x = xce.x; - state->y = xce.y; - state->update = TRUE; - } - if ( state->w != (unsigned int) xce.width || state->h != (unsigned int ) xce.height ) { - state->w = xce.width; - state->h = xce.height; - cairo_xlib_surface_set_size ( surface, state->w, state->h ); - } - } - } + switch ( ev->response_type & ~0x80 ) + { // Key press event. - else if ( ev->type == KeyPress ) { - while ( XCheckTypedEvent ( display, KeyPress, ev ) ) { - ; - } + case XCB_KEY_PRESS: state->quit = TRUE; } - rofi_view_update ( state ); } void process_result_error ( RofiViewState *state ); void rofi_view_error_dialog ( const char *msg, int markup )