From a9199e3e1762182ddd8a19514a75f6c78c14481a Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Sun, 28 May 2017 02:18:09 +0200 Subject: Use libnkutils for keybindings Signed-off-by: Quentin Glidic --- source/dialogs/ssh.c | 2 +- source/helper.c | 6 +- source/keyb.c | 288 ++++++++++++++++++--------------------------- source/rofi.c | 103 +++++----------- source/view.c | 191 ++++++++++++------------------ source/widgets/box.c | 23 ++-- source/widgets/container.c | 25 ++-- source/widgets/listview.c | 125 ++++++++++++-------- source/widgets/scrollbar.c | 81 ++++++++----- source/widgets/textbox.c | 31 ++++- source/widgets/widget.c | 47 ++++++-- source/x11-helper.c | 164 +------------------------- source/xrmoptions.c | 3 - 13 files changed, 448 insertions(+), 641 deletions(-) (limited to 'source') diff --git a/source/dialogs/ssh.c b/source/dialogs/ssh.c index 36392da4..96230bf8 100644 --- a/source/dialogs/ssh.c +++ b/source/dialogs/ssh.c @@ -206,7 +206,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length ) // Reading one line per time. while ( getline ( &buffer, &buffer_length, fd ) > 0 ) { // Evaluate one line. - unsigned int index = 0, ti = 0; + unsigned int index = 0, ti = 0; char *token = buffer; // Tokenize it. diff --git a/source/helper.c b/source/helper.c index 7fa07478..f6b3b74d 100644 --- a/source/helper.c +++ b/source/helper.c @@ -256,7 +256,7 @@ GRegex **tokenize ( const char *input, int case_sensitive ) } char *saveptr = NULL, *token; - GRegex **retv = NULL; + GRegex **retv = NULL; if ( !config.tokenize ) { retv = g_malloc0 ( sizeof ( GRegex* ) * 2 ); retv[0] = (GRegex *) create_regex ( input, case_sensitive ); @@ -885,8 +885,8 @@ int rofi_scorer_fuzzy_evaluate ( const char *pattern, glong plen, const char *st // uleft: value of the upper left cell; ulefts: maximum value of uleft and cells on the left. The arbitrary initial // values suppress warnings. int uleft = 0, ulefts = 0, left, lefts; - const gchar *pit = pattern, *sit; - enum CharClass prev = NON_WORD; + const gchar *pit = pattern, *sit; + enum CharClass prev = NON_WORD; for ( si = 0, sit = str; si < slen; si++, sit = g_utf8_next_char ( sit ) ) { enum CharClass cur = rofi_scorer_get_character_class ( g_utf8_get_char ( sit ) ); score[si] = rofi_scorer_get_score_for ( prev, cur ); diff --git a/source/keyb.c b/source/keyb.c index 1c5163f0..a9331d6a 100644 --- a/source/keyb.c +++ b/source/keyb.c @@ -28,146 +28,136 @@ #include #include #include "rofi.h" -#include "x11-helper.h" +#include "xkb.h" +#include "xkb-internal.h" +#include "nkutils-bindings.h" #include "xrmoptions.h" typedef struct { - unsigned int modmask; - xkb_keysym_t keysym; - gboolean release; -} KeyBinding; - -typedef struct -{ - const char *name; - char *keystr; - int num_bindings; - KeyBinding *kb; + guint id; + guint scope; + char *name; + char *binding; + char *comment; } ActionBindingEntry; -typedef struct -{ - KeyBindingAction id; - char *name; - char *keybinding; - char *comment; -} DefaultBinding; - /** * Data structure holding all the action keybinding. */ -ActionBindingEntry abe[NUM_ABE]; - -/** - * LIST OF DEFAULT SETTINGS - */ -DefaultBinding bindings[NUM_ABE] = +ActionBindingEntry rofi_bindings[] = { - { .id = PASTE_PRIMARY, .name = "kb-primary-paste", .keybinding = "Control+V,Shift+Insert", .comment = "Paste primary selection" }, - { .id = PASTE_SECONDARY, .name = "kb-secondary-paste", .keybinding = "Control+v,Insert", .comment = "Paste clipboard" }, - { .id = CLEAR_LINE, .name = "kb-clear-line", .keybinding = "Control+w", .comment = "Clear input line" }, - { .id = MOVE_FRONT, .name = "kb-move-front", .keybinding = "Control+a", .comment = "Beginning of line" }, - { .id = MOVE_END, .name = "kb-move-end", .keybinding = "Control+e", .comment = "End of line" }, - { .id = MOVE_WORD_BACK, .name = "kb-move-word-back", .keybinding = "Alt+b", .comment = "Move back one word" }, - { .id = MOVE_WORD_FORWARD, .name = "kb-move-word-forward", .keybinding = "Alt+f", .comment = "Move forward one word" }, - { .id = MOVE_CHAR_BACK, .name = "kb-move-char-back", .keybinding = "Left,Control+b", .comment = "Move back one char" }, - { .id = MOVE_CHAR_FORWARD, .name = "kb-move-char-forward", .keybinding = "Right,Control+f", .comment = "Move forward one char" }, - { .id = REMOVE_WORD_BACK, .name = "kb-remove-word-back", .keybinding = "Control+Alt+h,Control+BackSpace", .comment = "Delete previous word" }, - { .id = REMOVE_WORD_FORWARD, .name = "kb-remove-word-forward", .keybinding = "Control+Alt+d", .comment = "Delete next word" }, - { .id = REMOVE_CHAR_FORWARD, .name = "kb-remove-char-forward", .keybinding = "Delete,Control+d", .comment = "Delete next char" }, - { .id = REMOVE_CHAR_BACK, .name = "kb-remove-char-back", .keybinding = "BackSpace,Control+h", .comment = "Delete previous char" }, - { .id = REMOVE_TO_EOL, .name = "kb-remove-to-eol", .keybinding = "Control+k", .comment = "Delete till the end of line" }, - { .id = REMOVE_TO_SOL, .name = "kb-remove-to-sol", .keybinding = "Control+u", .comment = "Delete till the start of line" }, - { .id = ACCEPT_ENTRY, .name = "kb-accept-entry", .keybinding = "Control+j,Control+m,Return,KP_Enter", .comment = "Accept entry" }, - { .id = ACCEPT_CUSTOM, .name = "kb-accept-custom", .keybinding = "Control+Return", .comment = "Use entered text as command (in ssh/run modi)" }, - { .id = ACCEPT_ALT, .name = "kb-accept-alt", .keybinding = "Shift+Return", .comment = "Use alternate accept command." }, - { .id = DELETE_ENTRY, .name = "kb-delete-entry", .keybinding = "Shift+Delete", .comment = "Delete entry from history" }, - { .id = MODE_NEXT, .name = "kb-mode-next", .keybinding = "Shift+Right,Control+Tab", .comment = "Switch to the next mode." }, - { .id = MODE_PREVIOUS, .name = "kb-mode-previous", .keybinding = "Shift+Left,Control+ISO_Left_Tab", .comment = "Switch to the previous mode." }, - { .id = ROW_LEFT, .name = "kb-row-left", .keybinding = "Control+Page_Up", .comment = "Go to the previous column" }, - { .id = ROW_RIGHT, .name = "kb-row-right", .keybinding = "Control+Page_Down", .comment = "Go to the next column" }, - { .id = ROW_UP, .name = "kb-row-up", .keybinding = "Up,Control+p,ISO_Left_Tab", .comment = "Select previous entry" }, - { .id = ROW_DOWN, .name = "kb-row-down", .keybinding = "Down,Control+n", .comment = "Select next entry" }, - { .id = ROW_TAB, .name = "kb-row-tab", .keybinding = "Tab", .comment = "Go to next row, if one left, accept it, if no left next mode." }, - { .id = PAGE_PREV, .name = "kb-page-prev", .keybinding = "Page_Up", .comment = "Go to the previous page" }, - { .id = PAGE_NEXT, .name = "kb-page-next", .keybinding = "Page_Down", .comment = "Go to the next page" }, - { .id = ROW_FIRST, .name = "kb-row-first", .keybinding = "Home,KP_Home", .comment = "Go to the first entry" }, - { .id = ROW_LAST, .name = "kb-row-last", .keybinding = "End,KP_End", .comment = "Go to the last entry" }, - { .id = ROW_SELECT, .name = "kb-row-select", .keybinding = "Control+space", .comment = "Set selected item as input text" }, - { .id = SCREENSHOT, .name = "kb-screenshot", .keybinding = "Alt+S", .comment = "Take a screenshot of the rofi window" }, - { .id = TOGGLE_CASE_SENSITIVITY, .name = "kb-toggle-case-sensitivity", .keybinding = "grave,dead_grave", .comment = "Toggle case sensitivity" }, - { .id = TOGGLE_SORT, .name = "kb-toggle-sort", .keybinding = "Alt+grave", .comment = "Toggle sort" }, - { .id = CANCEL, .name = "kb-cancel", .keybinding = "Escape,Control+g,Control+bracketleft", .comment = "Quit rofi" }, - { .id = CUSTOM_1, .name = "kb-custom-1", .keybinding = "Alt+1", .comment = "Custom keybinding 1" }, - { .id = CUSTOM_2, .name = "kb-custom-2", .keybinding = "Alt+2", .comment = "Custom keybinding 2" }, - { .id = CUSTOM_3, .name = "kb-custom-3", .keybinding = "Alt+3", .comment = "Custom keybinding 3" }, - { .id = CUSTOM_4, .name = "kb-custom-4", .keybinding = "Alt+4", .comment = "Custom keybinding 4" }, - { .id = CUSTOM_5, .name = "kb-custom-5", .keybinding = "Alt+5", .comment = "Custom Keybinding 5" }, - { .id = CUSTOM_6, .name = "kb-custom-6", .keybinding = "Alt+6", .comment = "Custom keybinding 6" }, - { .id = CUSTOM_7, .name = "kb-custom-7", .keybinding = "Alt+7", .comment = "Custom Keybinding 7" }, - { .id = CUSTOM_8, .name = "kb-custom-8", .keybinding = "Alt+8", .comment = "Custom keybinding 8" }, - { .id = CUSTOM_9, .name = "kb-custom-9", .keybinding = "Alt+9", .comment = "Custom keybinding 9" }, - { .id = CUSTOM_10, .name = "kb-custom-10", .keybinding = "Alt+0", .comment = "Custom keybinding 10" }, - { .id = CUSTOM_11, .name = "kb-custom-11", .keybinding = "Alt+exclam", .comment = "Custom keybinding 11" }, - { .id = CUSTOM_12, .name = "kb-custom-12", .keybinding = "Alt+at", .comment = "Custom keybinding 12" }, - { .id = CUSTOM_13, .name = "kb-custom-13", .keybinding = "Alt+numbersign", .comment = "Csutom keybinding 13" }, - { .id = CUSTOM_14, .name = "kb-custom-14", .keybinding = "Alt+dollar", .comment = "Custom keybinding 14" }, - { .id = CUSTOM_15, .name = "kb-custom-15", .keybinding = "Alt+percent", .comment = "Custom keybinding 15" }, - { .id = CUSTOM_16, .name = "kb-custom-16", .keybinding = "Alt+dead_circumflex", .comment = "Custom keybinding 16" }, - { .id = CUSTOM_17, .name = "kb-custom-17", .keybinding = "Alt+ampersand", .comment = "Custom keybinding 17" }, - { .id = CUSTOM_18, .name = "kb-custom-18", .keybinding = "Alt+asterisk", .comment = "Custom keybinding 18" }, - { .id = CUSTOM_19, .name = "kb-custom-19", .keybinding = "Alt+parenleft", .comment = "Custom Keybinding 19" }, - { .id = SELECT_ELEMENT_1, .name = "kb-select-1", .keybinding = "Super+1", .comment = "Select row 1" }, - { .id = SELECT_ELEMENT_2, .name = "kb-select-2", .keybinding = "Super+2", .comment = "Select row 2" }, - { .id = SELECT_ELEMENT_3, .name = "kb-select-3", .keybinding = "Super+3", .comment = "Select row 3" }, - { .id = SELECT_ELEMENT_4, .name = "kb-select-4", .keybinding = "Super+4", .comment = "Select row 4" }, - { .id = SELECT_ELEMENT_5, .name = "kb-select-5", .keybinding = "Super+5", .comment = "Select row 5" }, - { .id = SELECT_ELEMENT_6, .name = "kb-select-6", .keybinding = "Super+6", .comment = "Select row 6" }, - { .id = SELECT_ELEMENT_7, .name = "kb-select-7", .keybinding = "Super+7", .comment = "Select row 7" }, - { .id = SELECT_ELEMENT_8, .name = "kb-select-8", .keybinding = "Super+8", .comment = "Select row 8" }, - { .id = SELECT_ELEMENT_9, .name = "kb-select-9", .keybinding = "Super+9", .comment = "Select row 9" }, - { .id = SELECT_ELEMENT_10, .name = "kb-select-10", .keybinding = "Super+0", .comment = "Select row 10" }, + { .id = PASTE_PRIMARY, .name = "kb-primary-paste", .binding = "Control+V,Shift+Insert", .comment = "Paste primary selection" }, + { .id = PASTE_SECONDARY, .name = "kb-secondary-paste", .binding = "Control+v,Insert", .comment = "Paste clipboard" }, + { .id = CLEAR_LINE, .name = "kb-clear-line", .binding = "Control+w", .comment = "Clear input line" }, + { .id = MOVE_FRONT, .name = "kb-move-front", .binding = "Control+a", .comment = "Beginning of line" }, + { .id = MOVE_END, .name = "kb-move-end", .binding = "Control+e", .comment = "End of line" }, + { .id = MOVE_WORD_BACK, .name = "kb-move-word-back", .binding = "Alt+b", .comment = "Move back one word" }, + { .id = MOVE_WORD_FORWARD, .name = "kb-move-word-forward", .binding = "Alt+f", .comment = "Move forward one word" }, + { .id = MOVE_CHAR_BACK, .name = "kb-move-char-back", .binding = "Left,Control+b", .comment = "Move back one char" }, + { .id = MOVE_CHAR_FORWARD, .name = "kb-move-char-forward", .binding = "Right,Control+f", .comment = "Move forward one char" }, + { .id = REMOVE_WORD_BACK, .name = "kb-remove-word-back", .binding = "Control+Alt+h,Control+BackSpace", .comment = "Delete previous word" }, + { .id = REMOVE_WORD_FORWARD, .name = "kb-remove-word-forward", .binding = "Control+Alt+d", .comment = "Delete next word" }, + { .id = REMOVE_CHAR_FORWARD, .name = "kb-remove-char-forward", .binding = "Delete,Control+d", .comment = "Delete next char" }, + { .id = REMOVE_CHAR_BACK, .name = "kb-remove-char-back", .binding = "BackSpace,Control+h", .comment = "Delete previous char" }, + { .id = REMOVE_TO_EOL, .name = "kb-remove-to-eol", .binding = "Control+k", .comment = "Delete till the end of line" }, + { .id = REMOVE_TO_SOL, .name = "kb-remove-to-sol", .binding = "Control+u", .comment = "Delete till the start of line" }, + { .id = ACCEPT_ENTRY, .name = "kb-accept-entry", .binding = "Control+j,Control+m,Return,KP_Enter", .comment = "Accept entry" }, + { .id = ACCEPT_CUSTOM, .name = "kb-accept-custom", .binding = "Control+Return", .comment = "Use entered text as command (in ssh/run modi)" }, + { .id = ACCEPT_ALT, .name = "kb-accept-alt", .binding = "Shift+Return", .comment = "Use alternate accept command." }, + { .id = DELETE_ENTRY, .name = "kb-delete-entry", .binding = "Shift+Delete", .comment = "Delete entry from history" }, + { .id = MODE_NEXT, .name = "kb-mode-next", .binding = "Shift+Right,Control+Tab", .comment = "Switch to the next mode." }, + { .id = MODE_PREVIOUS, .name = "kb-mode-previous", .binding = "Shift+Left,Control+ISO_Left_Tab", .comment = "Switch to the previous mode." }, + { .id = ROW_LEFT, .name = "kb-row-left", .binding = "Control+Page_Up", .comment = "Go to the previous column" }, + { .id = ROW_RIGHT, .name = "kb-row-right", .binding = "Control+Page_Down", .comment = "Go to the next column" }, + { .id = ROW_UP, .name = "kb-row-up", .binding = "Up,Control+p,ISO_Left_Tab", .comment = "Select previous entry" }, + { .id = ROW_DOWN, .name = "kb-row-down", .binding = "Down,Control+n", .comment = "Select next entry" }, + { .id = ROW_TAB, .name = "kb-row-tab", .binding = "Tab", .comment = "Go to next row, if one left, accept it, if no left next mode." }, + { .id = PAGE_PREV, .name = "kb-page-prev", .binding = "Page_Up", .comment = "Go to the previous page" }, + { .id = PAGE_NEXT, .name = "kb-page-next", .binding = "Page_Down", .comment = "Go to the next page" }, + { .id = ROW_FIRST, .name = "kb-row-first", .binding = "Home,KP_Home", .comment = "Go to the first entry" }, + { .id = ROW_LAST, .name = "kb-row-last", .binding = "End,KP_End", .comment = "Go to the last entry" }, + { .id = ROW_SELECT, .name = "kb-row-select", .binding = "Control+space", .comment = "Set selected item as input text" }, + { .id = SCREENSHOT, .name = "kb-screenshot", .binding = "Alt+S", .comment = "Take a screenshot of the rofi window" }, + { .id = TOGGLE_CASE_SENSITIVITY, .name = "kb-toggle-case-sensitivity", .binding = "grave,dead_grave", .comment = "Toggle case sensitivity" }, + { .id = TOGGLE_SORT, .name = "kb-toggle-sort", .binding = "Alt+grave", .comment = "Toggle sort" }, + { .id = CANCEL, .name = "kb-cancel", .binding = "Escape,Control+g,Control+bracketleft", .comment = "Quit rofi" }, + { .id = CUSTOM_1, .name = "kb-custom-1", .binding = "Alt+1", .comment = "Custom keybinding 1" }, + { .id = CUSTOM_2, .name = "kb-custom-2", .binding = "Alt+2", .comment = "Custom keybinding 2" }, + { .id = CUSTOM_3, .name = "kb-custom-3", .binding = "Alt+3", .comment = "Custom keybinding 3" }, + { .id = CUSTOM_4, .name = "kb-custom-4", .binding = "Alt+4", .comment = "Custom keybinding 4" }, + { .id = CUSTOM_5, .name = "kb-custom-5", .binding = "Alt+5", .comment = "Custom Keybinding 5" }, + { .id = CUSTOM_6, .name = "kb-custom-6", .binding = "Alt+6", .comment = "Custom keybinding 6" }, + { .id = CUSTOM_7, .name = "kb-custom-7", .binding = "Alt+7", .comment = "Custom Keybinding 7" }, + { .id = CUSTOM_8, .name = "kb-custom-8", .binding = "Alt+8", .comment = "Custom keybinding 8" }, + { .id = CUSTOM_9, .name = "kb-custom-9", .binding = "Alt+9", .comment = "Custom keybinding 9" }, + { .id = CUSTOM_10, .name = "kb-custom-10", .binding = "Alt+0", .comment = "Custom keybinding 10" }, + { .id = CUSTOM_11, .name = "kb-custom-11", .binding = "Alt+exclam", .comment = "Custom keybinding 11" }, + { .id = CUSTOM_12, .name = "kb-custom-12", .binding = "Alt+at", .comment = "Custom keybinding 12" }, + { .id = CUSTOM_13, .name = "kb-custom-13", .binding = "Alt+numbersign", .comment = "Csutom keybinding 13" }, + { .id = CUSTOM_14, .name = "kb-custom-14", .binding = "Alt+dollar", .comment = "Custom keybinding 14" }, + { .id = CUSTOM_15, .name = "kb-custom-15", .binding = "Alt+percent", .comment = "Custom keybinding 15" }, + { .id = CUSTOM_16, .name = "kb-custom-16", .binding = "Alt+dead_circumflex", .comment = "Custom keybinding 16" }, + { .id = CUSTOM_17, .name = "kb-custom-17", .binding = "Alt+ampersand", .comment = "Custom keybinding 17" }, + { .id = CUSTOM_18, .name = "kb-custom-18", .binding = "Alt+asterisk", .comment = "Custom keybinding 18" }, + { .id = CUSTOM_19, .name = "kb-custom-19", .binding = "Alt+parenleft", .comment = "Custom Keybinding 19" }, + { .id = SELECT_ELEMENT_1, .name = "kb-select-1", .binding = "Super+1", .comment = "Select row 1" }, + { .id = SELECT_ELEMENT_2, .name = "kb-select-2", .binding = "Super+2", .comment = "Select row 2" }, + { .id = SELECT_ELEMENT_3, .name = "kb-select-3", .binding = "Super+3", .comment = "Select row 3" }, + { .id = SELECT_ELEMENT_4, .name = "kb-select-4", .binding = "Super+4", .comment = "Select row 4" }, + { .id = SELECT_ELEMENT_5, .name = "kb-select-5", .binding = "Super+5", .comment = "Select row 5" }, + { .id = SELECT_ELEMENT_6, .name = "kb-select-6", .binding = "Super+6", .comment = "Select row 6" }, + { .id = SELECT_ELEMENT_7, .name = "kb-select-7", .binding = "Super+7", .comment = "Select row 7" }, + { .id = SELECT_ELEMENT_8, .name = "kb-select-8", .binding = "Super+8", .comment = "Select row 8" }, + { .id = SELECT_ELEMENT_9, .name = "kb-select-9", .binding = "Super+9", .comment = "Select row 9" }, + { .id = SELECT_ELEMENT_10, .name = "kb-select-10", .binding = "Super+0", .comment = "Select row 10" }, + + /* Mouse-aware bindings */ + + { .id = SCROLL_LEFT, .scope = SCOPE_MOUSE_LISTVIEW, .name = "ml-row-left", .binding = "Mouse6", .comment = "Go to the previous column" }, + { .id = SCROLL_RIGHT, .scope = SCOPE_MOUSE_LISTVIEW, .name = "ml-row-right", .binding = "Mouse7", .comment = "Go to the next column" }, + { .id = SCROLL_UP, .scope = SCOPE_MOUSE_LISTVIEW, .name = "ml-row-up", .binding = "Mouse4", .comment = "Select previous entry" }, + { .id = SCROLL_DOWN, .scope = SCOPE_MOUSE_LISTVIEW, .name = "ml-row-down", .binding = "Mouse5", .comment = "Select next entry" }, + + { .id = SELECT_HOVERED_ENTRY, .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT, .name = "me-select-entry", .binding = "Mouse1", .comment = "Select hovered row" }, + { .id = ACCEPT_HOVERED_ENTRY, .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT, .name = "me-accept-entry", .binding = "MouseD1", .comment = "Accept hovered row" }, + { .id = ACCEPT_HOVERED_CUSTOM, .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT, .name = "me-accept-custom", .binding = "Control+MouseD1", .comment = "Accept hovered row with custom action" }, + + /* Sentinel */ + { .id = 0 } +}; + +static const gchar *mouse_default_bindings[] = { + [MOUSE_CLICK_DOWN] = "Mouse1", + [MOUSE_CLICK_UP] = "!Mouse1", + [MOUSE_DCLICK_DOWN] = "MouseD1", + [MOUSE_DCLICK_UP] = "!MouseD1", }; void setup_abe ( void ) { - for ( int iter = 0; iter < NUM_ABE; iter++ ) { - int id = bindings[iter].id; - // set pointer to name. - abe[id].name = bindings[iter].name; - abe[id].keystr = g_strdup ( bindings[iter].keybinding ); - abe[id].num_bindings = 0; - abe[id].kb = NULL; - - config_parser_add_option ( xrm_String, abe[id].name, (void * *) &( abe[id].keystr ), bindings[iter].comment ); + for ( gsize i = 0; i < G_N_ELEMENTS ( rofi_bindings ); ++i ) { + ActionBindingEntry *b = &rofi_bindings[i]; + b->binding = g_strdup ( b->binding ); + config_parser_add_option ( xrm_String, b->name, (void * *) &( b->binding ), b->comment ); } } -gboolean parse_keys_abe ( void ) +gboolean parse_keys_abe ( NkBindings *bindings ) { + GError *error = NULL; GString *error_msg = g_string_new ( "" ); - for ( int iter = 0; iter < NUM_ABE; iter++ ) { - char *keystr = g_strdup ( abe[iter].keystr ); - char *sp = NULL; - - g_free ( abe[iter].kb ); - abe[iter].kb = NULL; - abe[iter].num_bindings = 0; + for ( gsize i = 0; i < G_N_ELEMENTS ( rofi_bindings ); ++i ) { + ActionBindingEntry *b = &rofi_bindings[i]; + char *keystr = g_strdup ( b->binding ); + char *sp = NULL; // Iter over bindings. const char *const sep = ","; for ( char *entry = strtok_r ( keystr, sep, &sp ); entry != NULL; entry = strtok_r ( NULL, sep, &sp ) ) { - abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) ); - KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] ); - memset ( kb, 0, sizeof ( KeyBinding ) ); - if ( x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ), &( kb->release ), error_msg ) ) { - abe[iter].num_bindings++; - } - else { - char *name = g_markup_escape_text ( abe[iter].name, -1 ); - g_string_append_printf ( error_msg, "Failed to set binding for: %s\n\n", name ); - g_free ( name ); + if ( !nk_bindings_add_binding ( bindings, b->scope, entry, rofi_view_trigger_action, GUINT_TO_POINTER ( b->id ), NULL, &error ) ) { + g_string_append_c ( g_string_append ( error_msg, error->message ), '\n' ); + g_clear_error ( &error ); } } @@ -178,67 +168,13 @@ gboolean parse_keys_abe ( void ) g_string_free ( error_msg, TRUE ); return FALSE; } - g_string_free ( error_msg, TRUE ); - return TRUE; -} - -void cleanup_abe ( void ) -{ - for ( int iter = 0; iter < NUM_ABE; iter++ ) { - g_free ( abe[iter].kb ); - abe[iter].kb = NULL; - abe[iter].num_bindings = 0; - } -} - -/** - * Array holding actions that should be trigger on release. - */ -static gboolean _abe_trigger_on_release[NUM_ABE] = { 0 }; - -static gboolean abe_test_action ( KeyBindingAction action, unsigned int mask, xkb_keysym_t key ) -{ - ActionBindingEntry *akb = &( abe[action] ); - - for ( int iter = 0; iter < akb->num_bindings; iter++ ) { - const KeyBinding * const kb = &( akb->kb[iter] ); - if ( ( kb->keysym == key ) && ( kb->modmask == mask ) ) { - if ( kb->release ) { - _abe_trigger_on_release[action] = TRUE; - } - else { - return TRUE; - } - } - } - - return FALSE; -} -KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key ) -{ - KeyBindingAction action; - - for ( action = 0; action < NUM_ABE; ++action ) { - if ( abe_test_action ( action, mask, key ) ) { - break; + for ( gsize i = SCOPE_MIN_FIXED; i <= SCOPE_MAX_FIXED; ++i ) { + for ( gsize j = 1; j < G_N_ELEMENTS ( mouse_default_bindings ); ++j ) { + nk_bindings_add_binding ( bindings, i, mouse_default_bindings[j], rofi_view_trigger_action, GSIZE_TO_POINTER ( j ), NULL, NULL ); } } - return action; -} - -void abe_trigger_release ( void ) -{ - RofiViewState *state; - - state = rofi_view_get_active ( ); - if ( state ) { - for ( KeyBindingAction action = 0; action < NUM_ABE; ++action ) { - if ( _abe_trigger_on_release[action] ) { - rofi_view_trigger_action ( state, action ); - _abe_trigger_on_release[action] = FALSE; - } - } - } + g_string_free ( error_msg, TRUE ); + return TRUE; } diff --git a/source/rofi.c b/source/rofi.c index 1fe17c27..441edebf 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -91,19 +90,13 @@ void rofi_add_error_message ( GString *str ) /** global structure holding the keyboard status */ struct xkb_stuff xkb = { .xcb_connection = NULL, - .context = NULL, - .keymap = NULL, - .state = NULL, - .compose = { - .table = NULL, - .state = NULL - } + .bindings = NULL, }; /** Path to the configuration file */ G_MODULE_EXPORT char *config_path = NULL; /** Array holding all activated modi. */ -Mode **modi = NULL; +Mode **modi = NULL; /** List of (possibly uninitialized) modi's */ Mode ** available_modi = NULL; @@ -441,26 +434,7 @@ static void cleanup () } // XKB Cleanup // - if ( xkb.compose.state != NULL ) { - xkb_compose_state_unref ( xkb.compose.state ); - xkb.compose.state = NULL; - } - if ( xkb.compose.table != NULL ) { - xkb_compose_table_unref ( xkb.compose.table ); - xkb.compose.table = NULL; - } - if ( xkb.state != NULL ) { - xkb_state_unref ( xkb.state ); - xkb.state = NULL; - } - if ( xkb.keymap != NULL ) { - xkb_keymap_unref ( xkb.keymap ); - xkb.keymap = NULL; - } - if ( xkb.context != NULL ) { - xkb_context_unref ( xkb.context ); - xkb.context = NULL; - } + nk_bindings_free ( xkb.bindings ); // Cleanup xcb_stuff_wipe ( xcb ); @@ -472,9 +446,6 @@ static void cleanup () } g_free ( modi ); - // Cleanup the custom keybinding - cleanup_abe (); - g_free ( config_path ); if ( list_of_error_msgs ) { @@ -558,8 +529,9 @@ static void rofi_collect_modi_dir ( const char *base_dir ) g_warning ( "Symbol 'mode' not found in module: %s", dn ); g_module_close ( mod ); } - } else { - g_warning ( "Failed to open 'mode' plugin: '%s', error: %s", dn, g_module_error()); + } + else { + g_warning ( "Failed to open 'mode' plugin: '%s', error: %s", dn, g_module_error () ); } g_free ( fn ); } @@ -694,32 +666,27 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN switch ( ev->pad0 ) { case XCB_XKB_MAP_NOTIFY: - xkb_state_unref ( xkb.state ); - xkb_keymap_unref ( xkb.keymap ); - xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, 0 ); - xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id ); + { + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_get_context ( xkb.bindings ), xcb->connection, xkb.device_id, 0 ); + struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xkb.device_id ); + nk_bindings_update_keymap ( xkb.bindings, 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; - guint modmask; - xkb_state_update_mask ( xkb.state, - ksne->baseMods, - ksne->latchedMods, - ksne->lockedMods, - ksne->baseGroup, - ksne->latchedGroup, - ksne->lockedGroup ); - modmask = x11_get_current_mask ( &xkb ); - if ( modmask == 0 ) { - abe_trigger_release ( ); - - // Because of abe_trigger, state of rofi can be changed. handle this! - // Run mainloop on dummy event. - xcb_generic_event_t dev; - dev.response_type = 0; - main_loop_x11_event_handler_view ( &dev ); - } + nk_bindings_update_mask ( xkb.bindings, + 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; } } @@ -830,7 +797,7 @@ static gboolean startup ( G_GNUC_UNUSED gpointer data ) __create_window ( window_flags ); TICK_N ( "Create Window" ); // Parse the keybindings. - if ( !parse_keys_abe () ) { + if ( !parse_keys_abe ( xkb.bindings ) ) { // Error dialog return G_SOURCE_REMOVE; } @@ -1032,8 +999,8 @@ int main ( int argc, char *argv[] ) return EXIT_FAILURE; } - xkb.context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ); - if ( xkb.context == NULL ) { + struct xkb_context *xkb_context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ); + if ( xkb_context == NULL ) { g_warning ( "cannot create XKB context!" ); cleanup (); return EXIT_FAILURE; @@ -1083,33 +1050,27 @@ int main ( int argc, char *argv[] ) required_map_parts, /* map */ &details ); - xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); - if ( xkb.keymap == NULL ) { + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( xkb_context, 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; } - xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id ); - if ( xkb.state == NULL ) { + 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; } - xkb.compose.table = xkb_compose_table_new_from_locale ( xkb.context, setlocale ( LC_CTYPE, NULL ), 0 ); - if ( xkb.compose.table != NULL ) { - xkb.compose.state = xkb_compose_state_new ( xkb.compose.table, 0 ); - } - else { - g_warning ( "Failed to get keyboard compose table. Trying to limp on." ); - } + xkb.bindings = nk_bindings_new ( xkb_context, keymap, state ); if ( xcb_connection_has_error ( xcb->connection ) ) { g_warning ( "Connection has error" ); cleanup (); return EXIT_FAILURE; } - x11_setup ( &xkb ); + x11_setup (); TICK_N ( "Setup xkb" ); if ( xcb_connection_has_error ( xcb->connection ) ) { g_warning ( "Connection has error" ); diff --git a/source/view.c b/source/view.c index 416bad7d..e6264704 100644 --- a/source/view.c +++ b/source/view.c @@ -69,10 +69,6 @@ #include "xcb.h" -#ifdef XkBCOMMON_HAS_CONSUMED2 -#define xkb_state_key_get_consumed_mods( s, k ) xkb_state_key_get_consumed_mods2 ( s, k, XKB_CONSUMED_MODE_GTK ) -#endif - /** * @param state The handle to the view * @param qr Indicate if queue_redraw should be called on changes. @@ -1008,31 +1004,6 @@ static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t } } -static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_event_t *xbe ) -{ - // Scroll event - if ( xbe->detail > 3 ) { - if ( xbe->detail == 4 ) { - listview_nav_up ( state->list_view ); - } - else if ( xbe->detail == 5 ) { - listview_nav_down ( state->list_view ); - } - else if ( xbe->detail == 6 ) { - listview_nav_left ( state->list_view ); - } - else if ( xbe->detail == 7 ) { - listview_nav_right ( state->list_view ); - } - return; - } - else { - xcb_button_press_event_t rel = *xbe; - if ( widget_clicked ( WIDGET ( state->main_window ), &rel ) ) { - return; - } - } -} static void _rofi_view_reload_row ( RofiViewState *state ) { g_free ( state->line_map ); @@ -1152,9 +1123,9 @@ void rofi_view_finalize ( RofiViewState *state ) } } -gboolean rofi_view_trigger_action ( RofiViewState *state, KeyBindingAction action ) +static void rofi_view_trigger_global_action ( KeyBindingAction action ) { - gboolean ret = TRUE; + RofiViewState *state = rofi_view_get_active (); switch ( action ) { // Handling of paste @@ -1207,9 +1178,6 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, KeyBindingAction actio state->retv = MENU_ENTRY_DELETE; state->quit = TRUE; } - else { - ret = FALSE; - } break; } case SELECT_ELEMENT_1: @@ -1372,65 +1340,34 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, KeyBindingAction actio state->quit = TRUE; break; } - case NUM_ABE: - ret = FALSE; - break; } - - return ret; } -static void rofi_view_handle_keypress ( RofiViewState *state, xkb_stuff *xkb, xcb_key_press_event_t *xkpe ) +gboolean rofi_view_trigger_action ( guint scope, gpointer user_data ) { - xcb_keysym_t key; - char pad[32]; - int len = 0; - - key = xkb_state_key_get_one_sym ( xkb->state, xkpe->detail ); - - if ( xkb->compose.state != NULL ) { - if ( ( key != XKB_KEY_NoSymbol ) && ( xkb_compose_state_feed ( xkb->compose.state, key ) == XKB_COMPOSE_FEED_ACCEPTED ) ) { - switch ( xkb_compose_state_get_status ( xkb->compose.state ) ) - { - case XKB_COMPOSE_CANCELLED: - /* Eat the keysym that cancelled the compose sequence. - * This is default behaviour with Xlib */ - case XKB_COMPOSE_COMPOSING: - key = XKB_KEY_NoSymbol; - break; - case XKB_COMPOSE_COMPOSED: - key = xkb_compose_state_get_one_sym ( xkb->compose.state ); - len = xkb_compose_state_get_utf8 ( xkb->compose.state, pad, sizeof ( pad ) ); - break; - case XKB_COMPOSE_NOTHING: - break; - } - if ( ( key == XKB_KEY_NoSymbol ) && ( len == 0 ) ) { - return; - } + RofiViewState *state = rofi_view_get_active (); + g_print ( "TRY ACTION scope %u\n", scope ); + switch ( (BindingsScope) scope ) + { + case SCOPE_GLOBAL: + rofi_view_trigger_global_action ( GPOINTER_TO_UINT ( user_data ) ); + return TRUE; + case SCOPE_MOUSE_LISTVIEW: + case SCOPE_MOUSE_LISTVIEW_ELEMENT: + case SCOPE_MOUSE_EDITBOX: + case SCOPE_MOUSE_SCROLLBAR: + case SCOPE_MOUSE_SIDEBAR_MODI: + { + gint x = state->mouse.x, y = state->mouse.y; + widget *target = widget_find_mouse_target ( WIDGET ( state->main_window ), scope, &x, &y ); + if ( target == NULL ) { + return FALSE; } - } - if ( len == 0 ) { - len = xkb_state_key_get_utf8 ( xkb->state, xkpe->detail, pad, sizeof ( pad ) ); + return widget_trigger_action ( target, GPOINTER_TO_UINT ( user_data ), x, y ); } - - xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods ( xkb->state, xkpe->detail ); - - unsigned int modstate = x11_canonalize_mask ( xkpe->state & ( ~consumed ) ); - - if ( key != XKB_KEY_NoSymbol ) { - KeyBindingAction action; - action = abe_find_action ( modstate, key ); - if ( rofi_view_trigger_action ( state, action ) ) { - return; - } - } - - if ( ( len > 0 ) && ( textbox_append_char ( state->text, pad, len ) ) ) { - state->refilter = TRUE; - return; } + return FALSE; } void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb_stuff *xkb ) @@ -1472,18 +1409,27 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb state->mouse_seen = TRUE; } xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) event ); + state->mouse.x = xme.event_x; + state->mouse.y = xme.event_y; if ( widget_motion_notify ( WIDGET ( state->main_window ), &xme ) ) { return; } break; } case XCB_BUTTON_PRESS: - rofi_view_mouse_navigation ( state, (xcb_button_press_event_t *) event ); + { + 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_handle_button ( xkb->bindings, 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_handle_button ( xkb->bindings, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time ); if ( config.click_to_exit == TRUE ) { if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) { - xcb_button_release_event_t *bre = (xcb_button_release_event_t *) event; if ( ( state->mouse_seen == FALSE ) && ( bre->event != CacheState.main_window ) ) { state->quit = TRUE; state->retv = MENU_CANCEL; @@ -1492,35 +1438,39 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb state->mouse_seen = FALSE; } break; + } // Paste event. case XCB_SELECTION_NOTIFY: rofi_view_paste ( state, (xcb_selection_notify_event_t *) event ); break; case XCB_KEYMAP_NOTIFY: { - xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *) event; - guint modstate = x11_get_current_mask ( xkb ); + xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *) event; for ( gint32 by = 0; by < 31; ++by ) { for ( gint8 bi = 0; bi < 7; ++bi ) { if ( kne->keys[by] & ( 1 << bi ) ) { // X11 keycodes starts at 8 - xkb_keysym_t key = xkb_state_key_get_one_sym ( xkb->state, ( 8 * by + bi ) + 8 ); - abe_find_action ( modstate, key ); + nk_bindings_handle_key ( xkb->bindings, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED ); } } } break; } case XCB_KEY_PRESS: - rofi_view_handle_keypress ( state, xkb, (xcb_key_press_event_t *) event ); + { + xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) event; + gchar *text; + + text = nk_bindings_handle_key ( xkb->bindings, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS ); + if ( ( text != NULL ) && ( textbox_append_char ( state->text, text, strlen ( text ) ) ) ) { + state->refilter = TRUE; + } break; + } case XCB_KEY_RELEASE: { - xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event; - unsigned int modstate = x11_canonalize_mask ( xkre->state ); - if ( modstate == 0 ) { - abe_trigger_release ( ); - } + xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event; + nk_bindings_handle_key ( xkb->bindings, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE ); break; } default: @@ -1550,26 +1500,41 @@ static int rofi_view_calculate_height ( RofiViewState *state ) return height; } -static gboolean rofi_view_modi_clicked_cb ( widget *textbox, G_GNUC_UNUSED xcb_button_press_event_t *xbe, void *udata ) +static gboolean textbox_sidebar_modi_trigger_action ( widget *wid, MouseBindingMouseDefaultAction action, gint x, gint y, G_GNUC_UNUSED void *user_data ) { - RofiViewState *state = ( RofiViewState *) udata; - for ( unsigned int i = 0; i < state->num_modi; i++ ) { - if ( WIDGET ( state->modi[i] ) == textbox ) { - state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK ); - state->quit = TRUE; - state->skip_absorb = TRUE; - return TRUE; + g_print ( "CLICK ON SIDEBAR\n" ); + RofiViewState *state = ( RofiViewState *) user_data; + unsigned int i; + for ( i = 0; i < state->num_modi; i++ ) { + if ( WIDGET ( state->modi[i] ) == wid ) { + break; } } + if ( i == state->num_modi ) { + return FALSE; + } + + switch ( action ) + { + case MOUSE_CLICK_DOWN: + state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK ); + state->quit = TRUE; + state->skip_absorb = TRUE; + return TRUE; + case MOUSE_CLICK_UP: + case MOUSE_DCLICK_DOWN: + case MOUSE_DCLICK_UP: + break; + } return FALSE; } + // @TODO don't like this construction. -static void rofi_view_listview_mouse_activated_cb ( listview *lv, xcb_button_press_event_t *xce, void *udata ) +static void rofi_view_listview_mouse_activated_cb ( listview *lv, gboolean custom, void *udata ) { - RofiViewState *state = (RofiViewState *) udata; - int control = x11_modifier_active ( xce->state, X11MOD_CONTROL ); + RofiViewState *state = (RofiViewState *) udata; state->retv = MENU_OK; - if ( control ) { + if ( custom ) { state->retv |= MENU_CUSTOM_ACTION; } ( state->selected_line ) = state->line_map[listview_get_selected ( lv )]; @@ -1619,10 +1584,10 @@ RofiViewState *rofi_view_create ( Mode *sw, state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) ); for ( unsigned int j = 0; j < state->num_modi; j++ ) { const Mode * mode = rofi_get_mode ( j ); - state->modi[j] = textbox_create ( "window.mainbox.sidebar.button", TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL, - mode_get_display_name ( mode ) ); + state->modi[j] = textbox_create_full ( WIDGET_TYPE_SIDEBAR_MODI, "window.mainbox.sidebar.button", TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL, + mode_get_display_name ( mode ) ); box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j ); - widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state ); + widget_set_trigger_action_handler ( WIDGET ( state->modi[j] ), textbox_sidebar_modi_trigger_action, state ); } } @@ -1642,7 +1607,7 @@ RofiViewState *rofi_view_create ( Mode *sw, // Entry box TextboxFlags tfl = TB_EDITABLE; tfl |= ( ( menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0; - state->text = textbox_create ( "window.mainbox.inputbar.entry", tfl | TB_AUTOHEIGHT, NORMAL, input ); + state->text = textbox_create_full ( WIDGET_TYPE_EDITBOX, "window.mainbox.inputbar.entry", tfl | TB_AUTOHEIGHT, NORMAL, input ); box_add ( state->input_bar, WIDGET ( state->text ), TRUE, 2 ); diff --git a/source/widgets/box.c b/source/widgets/box.c index faeba226..2224858a 100644 --- a/source/widgets/box.c +++ b/source/widgets/box.c @@ -277,7 +277,7 @@ static void box_resize ( widget *widget, short w, short h ) } } -static gboolean box_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC_UNUSED void *udata ) +static widget *box_find_mouse_target ( widget *wid, WidgetType type, gint *x, gint *y ) { box *b = (box *) wid; for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { @@ -285,15 +285,20 @@ static gboolean box_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC if ( !child->enabled ) { continue; } - if ( widget_intersect ( child, xbe->event_x, xbe->event_y ) ) { - xcb_button_press_event_t rel = *xbe; - rel.event_x -= child->x; - rel.event_y -= child->y; - return widget_clicked ( child, &rel ); + if ( widget_intersect ( child, *x, *y ) ) { + gint rx = *x - child->x; + gint ry = *y - child->y; + widget *target = widget_find_mouse_target ( child, type, &rx, &ry ); + if ( target != NULL ) { + *x = rx; + *y = ry; + return target; + } } } - return FALSE; + return NULL; } + static gboolean box_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ) { box *b = (box *) wid; @@ -316,13 +321,13 @@ box * box_create ( const char *name, boxType type ) { box *b = g_malloc0 ( sizeof ( box ) ); // Initialize widget. - widget_init ( WIDGET ( b ), name ); + widget_init ( WIDGET ( b ), WIDGET_TYPE_UNKNOWN, name ); b->type = type; b->widget.draw = box_draw; b->widget.free = box_free; b->widget.resize = box_resize; b->widget.update = box_update; - b->widget.clicked = box_clicked; + b->widget.find_mouse_target = box_find_mouse_target; b->widget.motion_notify = box_motion_notify; b->widget.get_desired_height = box_get_desired_height; b->widget.enabled = rofi_theme_get_boolean ( WIDGET ( b ), "enabled", TRUE ); diff --git a/source/widgets/container.c b/source/widgets/container.c index c175d073..a7f16652 100644 --- a/source/widgets/container.c +++ b/source/widgets/container.c @@ -88,16 +88,23 @@ static void container_resize ( widget *widget, short w, short h ) } } -static gboolean container_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC_UNUSED void *udata ) +static widget *container_find_mouse_target ( widget *wid, WidgetType type, gint *x, gint *y ) { container *b = (container *) wid; - if ( widget_intersect ( b->child, xbe->event_x, xbe->event_y ) ) { - xcb_button_press_event_t rel = *xbe; - rel.event_x -= b->child->x; - rel.event_y -= b->child->y; - return widget_clicked ( b->child, &rel ); + if ( !widget_intersect ( b->child, *x, *y ) ) { + return NULL; } - return FALSE; + + gint rx = *x - b->child->x; + gint ry = *y - b->child->y; + widget *target = widget_find_mouse_target ( b->child, type, &rx, &ry ); + if ( target == NULL ) { + return NULL; + } + + *x = rx; + *y = ry; + return target; } static gboolean container_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ) { @@ -115,12 +122,12 @@ container * container_create ( const char *name ) { container *b = g_malloc0 ( sizeof ( container ) ); // Initialize widget. - widget_init ( WIDGET ( b ), name ); + widget_init ( WIDGET ( b ), WIDGET_TYPE_UNKNOWN, name ); b->widget.draw = container_draw; b->widget.free = container_free; b->widget.resize = container_resize; b->widget.update = container_update; - b->widget.clicked = container_clicked; + b->widget.find_mouse_target = container_find_mouse_target; b->widget.motion_notify = container_motion_notify; b->widget.get_desired_height = container_get_desired_height; b->widget.enabled = rofi_theme_get_boolean ( WIDGET ( b ), "enabled", TRUE ); diff --git a/source/widgets/listview.c b/source/widgets/listview.c index 8113d8f5..d121988d 100644 --- a/source/widgets/listview.c +++ b/source/widgets/listview.c @@ -78,8 +78,6 @@ struct _listview listview_update_callback callback; void *udata; - gboolean scrollbar_scroll; - xcb_timestamp_t last_click; listview_mouse_activated_cb mouse_activated; void *mouse_activated_data; @@ -221,6 +219,8 @@ static void listview_draw ( widget *wid, cairo_t *draw ) widget_draw ( WIDGET ( lv->scrollbar ), draw ); } +static gboolean listview_element_trigger_action ( widget *wid, MouseBindingListviewElementAction action, gint x, gint y, void *user_data ); + static void listview_recompute_elements ( listview *lv ) { unsigned int newne = 0; @@ -243,7 +243,8 @@ static void listview_recompute_elements ( listview *lv ) char *name = g_strjoin ( ".", lv->listview_name, "element", NULL ); for ( unsigned int i = lv->cur_elements; i < newne; i++ ) { TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0; - lv->boxes[i] = textbox_create ( name, flags, NORMAL, "" ); + lv->boxes[i] = textbox_create_full ( WIDGET_TYPE_LISTVIEW_ELEMENT, name, flags, NORMAL, "" ); + widget_set_trigger_action_handler ( WIDGET ( lv->boxes[i] ), listview_element_trigger_action, lv ); } g_free ( name ); } @@ -301,74 +302,97 @@ static void listview_resize ( widget *wid, short w, short h ) widget_queue_redraw ( wid ); } -static gboolean listview_scrollbar_clicked ( widget *sb, xcb_button_press_event_t * xce, void *udata ) -{ - listview *lv = (listview *) udata; - - unsigned int sel = scrollbar_clicked ( (scrollbar *) sb, xce->event_y ); - listview_set_selected ( lv, sel ); - - return TRUE; -} - -static gboolean listview_clicked ( widget *wid, xcb_button_press_event_t *xce, G_GNUC_UNUSED void *udata ) +static widget *listview_find_mouse_target ( widget *wid, WidgetType type, gint *x, gint *y ) { + widget *target = NULL; + gint rx, ry; listview *lv = (listview *) wid; - lv->scrollbar_scroll = FALSE; - if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) && widget_intersect ( WIDGET ( lv->scrollbar ), xce->event_x, xce->event_y ) ) { - // Forward to handler of scrollbar. - xcb_button_press_event_t xce2 = *xce; - xce->event_x -= widget_get_x_pos ( WIDGET ( lv->scrollbar ) ); - xce->event_y -= widget_get_y_pos ( WIDGET ( lv->scrollbar ) ); - lv->scrollbar_scroll = TRUE; - return widget_clicked ( WIDGET ( lv->scrollbar ), &xce2 ); - } - // Handle the boxes. + if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) && widget_intersect ( WIDGET ( lv->scrollbar ), *x, *y ) ) { + rx = *x - widget_get_x_pos ( WIDGET ( lv->scrollbar ) ); + ry = *y - widget_get_y_pos ( WIDGET ( lv->scrollbar ) ); + target = widget_find_mouse_target ( WIDGET ( lv->scrollbar ), type, &rx, &ry ); + } + unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset ); - for ( unsigned int i = 0; i < max; i++ ) { + unsigned int i; + for ( i = 0; i < max && target == NULL; i++ ) { widget *w = WIDGET ( lv->boxes[i] ); - if ( widget_intersect ( w, xce->event_x, xce->event_y ) ) { - if ( ( lv->last_offset + i ) == lv->selected ) { - if ( ( xce->time - lv