diff --git a/Changelog b/Changelog index 9584b77b..89cb7b7b 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ - Improve rendering of boxes (fixed height and margins) - Fix modi switcher boxes size+layout. - Reduce work on redraws (do not always calculate new size/position), set text, etc. + - OO-ify the switchers. Cleanup: - Do not lug argc,argv around everywhere. diff --git a/include/dialogs/run.h b/include/dialogs/run.h index 49701705..c95944f4 100644 --- a/include/dialogs/run.h +++ b/include/dialogs/run.h @@ -1,14 +1,5 @@ #ifndef __RUN_DIALOG_H__ #define __RUN_DIALOG_H__ -/** - * @param input Pointer to the user-input string. - * @param data Custom data pointer for callback. - * - * Run the run dialog - * - * @returns SwitcherMode selected by user. - */ -SwitcherMode run_switcher_dialog ( char **input, void *data ); - +extern Switcher run_mode; #endif diff --git a/include/dialogs/script.h b/include/dialogs/script.h index effc8177..fed5189b 100644 --- a/include/dialogs/script.h +++ b/include/dialogs/script.h @@ -1,27 +1,6 @@ #ifndef __SCRIPT_DIALOG_H__ #define __SCRIPT_DIALOG_H__ -/** - * Structure holds the arguments for the script_switcher. - */ -typedef struct -{ - /** Prompt to display. */ - char *name; - /** The script */ - char *script_path; -} ScriptOptions; - - -/** - * @param input Pointer to the user-input string. - * @param data Custom data pointer for callback. - * - * Run the script dialog - * - * @returns SwitcherMode selected by user. - */ -SwitcherMode script_switcher_dialog ( char **input, void *data ); /** * @param str The input string to parse @@ -31,12 +10,5 @@ SwitcherMode script_switcher_dialog ( char **input, void *data ); * * @returns NULL when it fails, a newly allocated ScriptOptions when successful. */ -ScriptOptions *script_switcher_parse_setup ( const char *str ); - -/** - * @param sw Handle to the ScriptOption - * - * Free the ScriptOptions block. - */ -void script_switcher_free_options ( void *data ); +Switcher *script_switcher_parse_setup ( const char *str ); #endif diff --git a/include/dialogs/ssh.h b/include/dialogs/ssh.h index dac52006..d6fbe572 100644 --- a/include/dialogs/ssh.h +++ b/include/dialogs/ssh.h @@ -1,14 +1,5 @@ #ifndef __SSH_DIALOG_H__ #define __SSH_DIALOG_H__ -/** - * @param input Pointer to the user-input string. - * @param data Custom data pointer for callback. - * - * Run the ssh dialog - * - * @returns SwitcherMode selected by user. - */ -SwitcherMode ssh_switcher_dialog ( char **input, void *data ); - +extern Switcher ssh_mode; #endif diff --git a/include/dialogs/window.h b/include/dialogs/window.h index e6b6f727..af582596 100644 --- a/include/dialogs/window.h +++ b/include/dialogs/window.h @@ -1,6 +1,5 @@ #ifndef __WINDOW_DIALOG_H__ #define __WINDOW_DIALOG_H__ -SwitcherMode run_switcher_window ( char **input, G_GNUC_UNUSED void *data ); - +extern Switcher window_mode; #endif // __WINDOW_DIALOG_H__ diff --git a/include/helper.h b/include/helper.h index bd76d9a3..f6cdba7f 100644 --- a/include/helper.h +++ b/include/helper.h @@ -1,6 +1,6 @@ #ifndef __HELPER_H__ #define __HELPER_H__ - +#include "rofi.h" /** * @param string The input string. * @param output Pointer to 2 dimensional array with parsed string. @@ -105,7 +105,7 @@ int find_arg ( const char * const key ); */ int token_match ( char **tokens, const char *input, int case_sensitive, __attribute__( ( unused ) ) int index, - __attribute__( ( unused ) ) void *data ); + __attribute__( ( unused ) ) Switcher * data ); /** * @param cmd The command to execute. @@ -115,7 +115,7 @@ int token_match ( char **tokens, const char *input, int case_sensitive, * * @returns a valid file descriptor on success, or -1 on failure. */ -int execute_generator ( char * cmd ) __attribute__( ( nonnull ) ); +int execute_generator ( const char * cmd ) __attribute__( ( nonnull ) ); /** * @param pidfile The pidfile to create. diff --git a/include/rofi.h b/include/rofi.h index 74999a4a..83480a44 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -2,6 +2,7 @@ #define __SIMPLESWITCHER_H__ #include #include +#include /** @@ -9,7 +10,7 @@ */ extern const char *cache_dir; - +typedef struct _Switcher Switcher; /** * Enum used to sum the possible states of ROFI. */ @@ -34,7 +35,7 @@ typedef enum * @returns SwitcherMode */ typedef SwitcherMode ( *switcher_callback )( char **input, void *data ); -typedef void ( *switcher_callback_free_data )( void *data ); +typedef void ( *switcher_free )( Switcher *data ); /** * State returned by the rofi window. @@ -42,19 +43,21 @@ typedef void ( *switcher_callback_free_data )( void *data ); typedef enum { /** Entry is selected. */ - MENU_OK = 0, + MENU_OK = 0x1, /** User canceled the operation. (e.g. pressed escape) */ - MENU_CANCEL = -1, + MENU_CANCEL = 0x2, /** User requested a mode switch */ - MENU_NEXT = -2, + MENU_NEXT = 0x4, /** Custom (non-matched) input was entered. */ - MENU_CUSTOM_INPUT = -3, + MENU_CUSTOM_INPUT = 0x8, /** User wanted to delete entry from history. */ - MENU_ENTRY_DELETE = -4, + MENU_ENTRY_DELETE = 0x10, /** User wants to jump to another switcher. */ - MENU_QUICK_SWITCH = -5, + MENU_QUICK_SWITCH = 0x20, /** Go to the previous menu. */ - MENU_PREVIOUS = -6 + MENU_PREVIOUS = 0x40, + /** Modifiers */ + MENU_SHIFT = 0x1000 } MenuReturn; @@ -69,7 +72,7 @@ typedef enum * * @returns 1 when it matches, 0 if not. */ -typedef int ( *menu_match_cb )( char **tokens, const char *input, int case_sensitive, int index, void *data ); +typedef int ( *menu_match_cb )( char **tokens, const char *input, int case_sensitive, int index, Switcher *data ); /** * @param lines An array of strings to display. @@ -87,9 +90,9 @@ typedef int ( *menu_match_cb )( char **tokens, const char *input, int case_sensi * @returns The command issued (see MenuReturn) */ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prompt, - Time *time, int *shift, + Time *time, menu_match_cb mmc, void *mmc_data, - int *selected_line, int sorting ) __attribute__ ( ( nonnull ( 1, 3, 4, 9 ) ) ); + int *selected_line, int sorting ) __attribute__ ( ( nonnull ( 1, 3, 4, 8 ) ) ); /** * @param sig The caught signal * @@ -212,4 +215,42 @@ extern Settings config; */ void error_dialog ( const char *msg ); +/** + * Structure defining a switcher. + * It consists of a name, callback and if enabled + * a textbox for the sidebar-mode. + */ +struct _Switcher +{ + // Name (max 31 char long) + char name[32]; + // Textbox used in the sidebar-mode. + textbox *tb; + // Keybindings (keysym and modmask) + char * keycfg; + char * keystr; + KeySym keysym; + unsigned int modmask; + + + /** + * A switcher normally consists of the following parts: + */ + void ( *init )( struct _Switcher *sw ); + char ** ( *get_data )( unsigned int *length, struct _Switcher *pd ); + int ( *match )( char **tokens, const char *input, int case_sensitive, int index, struct _Switcher *data ); + SwitcherMode ( *result )( int menu_retv, char **input, unsigned int selected_line, struct _Switcher *pd ); + void ( *destroy )( struct _Switcher *pd ); + // Token match. + menu_match_cb token_match; + + // Pointer to private data. + void *private_data; + + // Extra fields for script + void *ed; + // Free SWitcher + switcher_free free; +}; + #endif diff --git a/source/dialogs/dmenu.c b/source/dialogs/dmenu.c index b79c56d4..35f32273 100644 --- a/source/dialogs/dmenu.c +++ b/source/dialogs/dmenu.c @@ -83,13 +83,12 @@ int dmenu_switcher_dialog ( char **input ) find_arg_int ( "-l", &selected_line ); do { - int shift = 0; - int mretv = menu ( list, length, input, dmenu_prompt, NULL, &shift, + int mretv = menu ( list, length, input, dmenu_prompt, NULL, token_match, NULL, &selected_line, FALSE ); // We normally do not want to restart the loop. restart = FALSE; - if ( mretv == MENU_OK && list[selected_line] != NULL ) { + if ( ( mretv & MENU_OK ) && list[selected_line] != NULL ) { if ( number_mode ) { fprintf ( stdout, "%d", selected_line ); } @@ -98,20 +97,20 @@ int dmenu_switcher_dialog ( char **input ) } fputc ( '\n', stdout ); fflush ( stdout ); - if ( shift ) { + if ( ( mretv & MENU_SHIFT ) ) { restart = TRUE; // Move to next line. selected_line = MIN ( selected_line + 1, length - 1 ); } retv = TRUE; } - else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) { + else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) { if ( !number_mode ) { fputs ( *input, stdout ); fputc ( '\n', stdout ); fflush ( stdout ); } - if ( shift ) { + if ( ( mretv & MENU_SHIFT ) ) { restart = TRUE; // Move to next line. selected_line = MIN ( selected_line + 1, length - 1 ); diff --git a/source/dialogs/run.c b/source/dialogs/run.c index 946fe334..fc3cd039 100644 --- a/source/dialogs/run.c +++ b/source/dialogs/run.c @@ -152,9 +152,8 @@ static char ** get_apps_external ( char **retv, unsigned int *length, unsigned i } // No duplicate, add it. - retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) ); - retv[( *length )] = g_strdup ( buffer ); - retv[( *length ) + 1] = NULL; + retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) ); + retv[( *length )] = g_strdup ( buffer ); ( *length )++; @@ -162,14 +161,16 @@ static char ** get_apps_external ( char **retv, unsigned int *length, unsigned i fclose ( inp ); } } + retv[( *length ) ] = NULL; return retv; } /** * Internal spider used to get list of executables. */ -static char ** get_apps ( char **retv, unsigned int *length ) +static char ** get_apps ( unsigned int *length ) { + char **retv = NULL; unsigned int num_favorites = 0; char *path; @@ -263,47 +264,85 @@ static char ** get_apps ( char **retv, unsigned int *length ) return retv; } -SwitcherMode run_switcher_dialog ( char **input, G_GNUC_UNUSED void *data ) +typedef struct _RunModePrivateData { - int shift = 0; - int selected_line = 0; - SwitcherMode retv = MODE_EXIT; - // act as a launcher - unsigned int cmd_list_length = 0; - char **cmd_list = NULL; - cmd_list = get_apps ( cmd_list, &cmd_list_length ); + unsigned int id; + char **cmd_list; + unsigned int cmd_list_length; +} RunModePrivateData; - if ( cmd_list == NULL ) { - cmd_list = g_malloc_n ( 2, sizeof ( char * ) ); - cmd_list[0] = g_strdup ( "No applications found" ); - cmd_list[1] = NULL; + +static void run_mode_init ( Switcher *sw ) +{ + if ( sw->private_data == NULL ) { + RunModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) ); + sw->private_data = (void *) pd; } +} - int mretv = menu ( cmd_list, cmd_list_length, input, "run:", - NULL, &shift, token_match, NULL, &selected_line, - config.levenshtein_sort ); +static char ** run_mode_get_data ( unsigned int *length, Switcher *sw ) +{ + RunModePrivateData *rmpd = (RunModePrivateData *) sw->private_data; + if ( rmpd->cmd_list == NULL ) { + rmpd->cmd_list_length = 0; + rmpd->cmd_list = get_apps ( &( rmpd->cmd_list_length ) ); + } + *length = rmpd->cmd_list_length; + return rmpd->cmd_list; +} - if ( mretv == MENU_NEXT ) { +static SwitcherMode run_mode_result ( int mretv, char **input, unsigned int selected_line, Switcher *sw ) +{ + RunModePrivateData *rmpd = (RunModePrivateData *) sw->private_data; + SwitcherMode retv = MODE_EXIT; + + int shift = ( ( mretv & MENU_SHIFT ) == MENU_SHIFT ); + + if ( mretv & MENU_NEXT ) { retv = NEXT_DIALOG; } - else if ( mretv == MENU_PREVIOUS ) { + else if ( mretv & MENU_PREVIOUS ) { retv = PREVIOUS_DIALOG; } - else if ( mretv == MENU_QUICK_SWITCH ) { + else if ( mretv & MENU_QUICK_SWITCH ) { retv = selected_line; } - else if ( mretv == MENU_OK && cmd_list[selected_line] != NULL ) { - exec_cmd ( cmd_list[selected_line], shift ); + else if ( ( mretv & MENU_OK ) && rmpd->cmd_list[selected_line] != NULL ) { + exec_cmd ( rmpd->cmd_list[selected_line], shift ); } - else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) { + else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) { exec_cmd ( *input, shift ); } - else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] ) { - delete_entry ( cmd_list[selected_line] ); + else if ( ( mretv & MENU_ENTRY_DELETE ) && rmpd->cmd_list[selected_line] ) { + delete_entry ( rmpd->cmd_list[selected_line] ); retv = RELOAD_DIALOG; } - - g_strfreev ( cmd_list ); - return retv; } + + +static void run_mode_destroy ( Switcher *sw ) +{ + RunModePrivateData *rmpd = (RunModePrivateData *) sw->private_data; + if ( rmpd != NULL ) { + g_strfreev ( rmpd->cmd_list ); + g_free ( rmpd ); + sw->private_data = NULL; + } +} + +Switcher run_mode = +{ + .name = "run", + .tb = NULL, + .keycfg = NULL, + .keystr = NULL, + .modmask = AnyModifier, + .init = run_mode_init, + .get_data = run_mode_get_data, + .result = run_mode_result, + .destroy = run_mode_destroy, + .token_match = token_match, + .private_data = NULL, + .free = NULL +}; diff --git a/source/dialogs/script.c b/source/dialogs/script.c index 946f7be6..96334ed1 100644 --- a/source/dialogs/script.c +++ b/source/dialogs/script.c @@ -42,7 +42,7 @@ -static char **get_script_output ( char *command, unsigned int *length ) +static char **get_script_output ( const char *command, unsigned int *length ) { char **retv = NULL; @@ -70,101 +70,131 @@ static char **get_script_output ( char *command, unsigned int *length ) return retv; } -static char **execute_executor ( ScriptOptions *options, const char *result, unsigned int *length ) +static char **execute_executor ( Switcher *sw, const char *result, unsigned int *length ) { char **retv = NULL; char *arg = g_shell_quote ( result ); - char *command = g_strdup_printf ( "%s %s", options->script_path, arg ); + char *command = g_strdup_printf ( "%s %s", (const char *) sw->ed, arg ); retv = get_script_output ( command, length ); g_free ( command ); g_free ( arg ); return retv; } -SwitcherMode script_switcher_dialog ( char **input, void *data ) +static void script_switcher_free ( Switcher *sw ) { - ScriptOptions *options = (ScriptOptions *) data; - assert ( options != NULL ); - int selected_line = 0; - SwitcherMode retv = MODE_EXIT; - unsigned int length = 0; - char **list = get_script_output ( options->script_path, &length ); - char *prompt = g_strdup_printf ( "%s:", options->name ); - - do { - unsigned int new_length = 0; - char **new_list = NULL; - int mretv = menu ( list, length, input, prompt, NULL, NULL, - token_match, NULL, &selected_line, FALSE ); - - if ( mretv == MENU_NEXT ) { - retv = NEXT_DIALOG; - } - else if ( mretv == MENU_PREVIOUS ) { - retv = PREVIOUS_DIALOG; - } - else if ( mretv == MENU_QUICK_SWITCH ) { - retv = selected_line; - } - else if ( mretv == MENU_OK && list[selected_line] != NULL ) { - new_list = execute_executor ( options, list[selected_line], &new_length ); - } - else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) { - new_list = execute_executor ( options, *input, &new_length ); - } - - // Free old list. - g_strfreev ( list ); - list = NULL; - - // If a new list was generated, use that an loop around. - if ( new_list != NULL ) { - list = new_list; - length = new_length; - g_free ( *input ); - *input = NULL; - } - } while ( list != NULL ); - - g_free ( prompt ); - return retv; -} - -void script_switcher_free_options ( void *data ) -{ - ScriptOptions *sw = (ScriptOptions *) data; if ( sw == NULL ) { return; } - g_free ( sw->name ); - g_free ( sw->script_path ); + g_free ( sw->ed ); g_free ( sw ); } - -ScriptOptions *script_switcher_parse_setup ( const char *str ) +typedef struct _ScriptModePrivateData { - ScriptOptions *sw = g_malloc0 ( sizeof ( *sw ) ); - char *endp = NULL; - char *parse = g_strdup ( str ); - unsigned int index = 0; + unsigned int id; + char **cmd_list; + unsigned int cmd_list_length; +} ScriptModePrivateData; + + +static void script_mode_init ( Switcher *sw ) +{ + if ( sw->private_data == NULL ) { + ScriptModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) ); + sw->private_data = (void *) pd; + } +} +static char ** script_mode_get_data ( unsigned int *length, Switcher *sw ) +{ + ScriptModePrivateData *rmpd = (ScriptModePrivateData *) sw->private_data; + if ( rmpd->cmd_list == NULL ) { + rmpd->cmd_list_length = 0; + rmpd->cmd_list = get_script_output ( (const char *) sw->ed, &( rmpd->cmd_list_length ) ); + } + *length = rmpd->cmd_list_length; + return rmpd->cmd_list; +} + +static SwitcherMode script_mode_result ( int mretv, char **input, unsigned int selected_line, Switcher *sw ) +{ + ScriptModePrivateData *rmpd = (ScriptModePrivateData *) sw->private_data; + SwitcherMode retv = MODE_EXIT; + char **new_list = NULL; + unsigned int new_length = 0; + + if ( ( mretv & MENU_NEXT ) ) { + retv = NEXT_DIALOG; + } + else if ( ( mretv & MENU_PREVIOUS ) ) { + retv = PREVIOUS_DIALOG; + } + else if ( ( mretv & MENU_QUICK_SWITCH ) ) { + retv = selected_line; + } + else if ( ( mretv & MENU_OK ) && rmpd->cmd_list[selected_line] != NULL ) { + new_list = execute_executor ( sw, rmpd->cmd_list[selected_line], &new_length ); + } + else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) { + new_list = execute_executor ( sw, *input, &new_length ); + } + + + // If a new list was generated, use that an loop around. + if ( new_list != NULL ) { + g_strfreev ( rmpd->cmd_list ); + + rmpd->cmd_list = new_list; + rmpd->cmd_list_length = new_length; + g_free ( *input ); + *input = NULL; + retv = RELOAD_DIALOG; + } + return retv; +} + +static void script_mode_destroy ( Switcher *sw ) +{ + ScriptModePrivateData *rmpd = (ScriptModePrivateData *) sw->private_data; + if ( rmpd != NULL ) { + g_strfreev ( rmpd->cmd_list ); + g_free ( rmpd ); + sw->private_data = NULL; + } +} + +Switcher *script_switcher_parse_setup ( const char *str ) +{ + Switcher *sw = g_malloc0 ( sizeof ( *sw ) ); + char *endp = NULL; + char *parse = g_strdup ( str ); + unsigned int index = 0; for ( char *token = strtok_r ( parse, ":", &endp ); token != NULL; token = strtok_r ( NULL, ":", &endp ) ) { if ( index == 0 ) { - sw->name = g_strdup ( token ); + g_strlcpy ( sw->name, token, 32 ); } else if ( index == 1 ) { - sw->script_path = g_strdup ( token ); + sw->ed = (void *) g_strdup ( token ); } index++; } g_free ( parse ); if ( index == 2 ) { + sw->free = script_switcher_free; + sw->keysym = None; + sw->modmask = AnyModifier; + sw->init = script_mode_init; + sw->get_data = script_mode_get_data; + sw->result = script_mode_result; + sw->destroy = script_mode_destroy; + sw->token_match = token_match; + return sw; } fprintf ( stderr, "The script command '%s' has %u options, but needs 2: :