diff --git a/include/mode-private.h b/include/mode-private.h index 935402e4..67d3ca9d 100644 --- a/include/mode-private.h +++ b/include/mode-private.h @@ -1,7 +1,8 @@ #ifndef ROFI_MODE_PRIVATE_H #define ROFI_MODE_PRIVATE_H -#define ABI_VERSION 0x00000002 +#include +#define ABI_VERSION 0x00000003 /** * @param data Pointer to #Mode object. @@ -149,5 +150,8 @@ struct rofi_mode _mode_free free; /** Extra fields for script */ void *ed; + + /** Module */ + GModule *module; }; #endif // ROFI_MODE_PRIVATE_H diff --git a/include/rofi.h b/include/rofi.h index 87e571e4..ee2d4ccd 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -41,6 +41,7 @@ const Mode * rofi_get_mode ( unsigned int index ); * Queue an error. */ void rofi_add_error_message ( GString *str ); + /** * @param code the code to return * @@ -48,6 +49,13 @@ void rofi_add_error_message ( GString *str ); * This function sets the code that rofi will return on exit. */ void rofi_set_return_code ( int code ); + +/** + * @param name Search for mode with this name. + * + * @return returns Mode * when found, NULL if not. + */ +Mode * rofi_collect_modi_search ( const char *name ); /** Reset terminal */ #define color_reset "\033[0m" /** Set terminal text bold */ diff --git a/source/dialogs/combi.c b/source/dialogs/combi.c index 33bed0ce..4699f151 100644 --- a/source/dialogs/combi.c +++ b/source/dialogs/combi.c @@ -68,48 +68,22 @@ static void combi_mode_parse_switchers ( Mode *sw ) pd->switchers = (CombiMode *) g_realloc ( pd->switchers, sizeof ( CombiMode ) * ( pd->num_switchers + 1 ) ); - // Window switcher. - #ifdef WINDOW_MODE - if ( strcasecmp ( token, "window" ) == 0 ) { + Mode *mode = rofi_collect_modi_search ( token ); + if ( mode ){ pd->switchers[pd->num_switchers].disable = FALSE; - pd->switchers[pd->num_switchers++].mode = &window_mode; - } - else if ( strcasecmp ( token, "windowcd" ) == 0 ) { - pd->switchers[pd->num_switchers].disable = FALSE; - pd->switchers[pd->num_switchers++].mode = &window_mode_cd; - } - else - #endif // WINDOW_MODE - // SSh dialog - if ( strcasecmp ( token, "ssh" ) == 0 ) { - pd->switchers[pd->num_switchers].disable = FALSE; - pd->switchers[pd->num_switchers++].mode = &ssh_mode; - } - // Run dialog - else if ( strcasecmp ( token, "run" ) == 0 ) { - pd->switchers[pd->num_switchers].disable = FALSE; - pd->switchers[pd->num_switchers++].mode = &run_mode; - } - #ifdef ENABLE_DRUN - else if ( strcasecmp ( token, "drun" ) == 0 ) { - pd->switchers[pd->num_switchers].disable = FALSE; - pd->switchers[pd->num_switchers++].mode = &drun_mode; - } -#endif // ENABLE_DRUN - else { + pd->switchers[pd->num_switchers++].mode = mode; + } else { // If not build in, use custom switchers. Mode *sw = script_switcher_parse_setup ( token ); if ( sw != NULL ) { pd->switchers[pd->num_switchers].disable = FALSE; pd->switchers[pd->num_switchers++].mode = sw; - } - else{ + } else { // Report error, don't continue. fprintf ( stderr, "Invalid script switcher: %s\n", token ); token = NULL; } } - // Keybinding. } // Free string that was modified by strtok_r g_free ( switcher_str ); diff --git a/source/rofi.c b/source/rofi.c index c933a742..fe952173 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -81,6 +81,7 @@ const char *cache_dir = NULL; /** List of error messages.*/ GList *list_of_error_msgs = NULL; +static void rofi_collect_modi_destroy ( void ); void rofi_add_error_message ( GString *str ) { list_of_error_msgs = g_list_append ( list_of_error_msgs, str ); @@ -397,6 +398,116 @@ static void cleanup () rofi_theme = NULL; } TIMINGS_STOP (); + rofi_collect_modi_destroy ( ); +} + +/** + * Collected modi + */ +// List of (possibly uninitialized) modi's +Mode ** available_modi = NULL; +unsigned int num_available_modi = 0; + +/** + * @param name Search for mode with this name. + * + * @return returns Mode * when found, NULL if not. + */ +Mode * rofi_collect_modi_search ( const char *name ) +{ + for ( unsigned int i = 0; i < num_available_modi; i++ ){ + if ( g_strcmp0 ( name, available_modi[i]->name ) == 0 ) { + return available_modi[i]; + } + } + return NULL; +} +/** + * @param mode Add mode to list. + * + * @returns TRUE when success. + */ +static gboolean rofi_collect_modi_add ( Mode *mode ) +{ + Mode *m = rofi_collect_modi_search ( mode->name ); + if ( m == NULL ) { + available_modi = g_realloc ( available_modi, sizeof(Mode *)*(num_available_modi+1)); + // Set mode. + available_modi[num_available_modi] = mode; + num_available_modi++; + return TRUE; + } + return FALSE; +} +/** + * Find all available modi. + */ +static void rofi_collect_modi ( void ) +{ +#ifdef WINDOW_MODE + rofi_collect_modi_add ( &window_mode ); + rofi_collect_modi_add ( &window_mode_cd ); +#endif + rofi_collect_modi_add ( &run_mode ); + rofi_collect_modi_add ( &ssh_mode ); +#ifdef ENABLE_DRUN + rofi_collect_modi_add ( &drun_mode ); +#endif + rofi_collect_modi_add ( &combi_mode ); + rofi_collect_modi_add ( &help_keys_mode ); + + GDir *dir = g_dir_open ( PLUGIN_PATH, 0, NULL ); + if ( dir ) { + const char *dn = NULL; + while ( ( dn = g_dir_read_name ( dir ) ) ) + { + if ( !g_str_has_suffix ( dn, G_MODULE_SUFFIX ) ) { + continue; + } + char *fn = g_build_filename ( PLUGIN_PATH, dn, NULL ); + GModule *mod = g_module_open ( fn, G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL ); + if ( mod ) { + Mode *m = NULL; + if ( g_module_symbol ( mod, "mode", (gpointer *)&m) ){ + if ( m->abi_version != ABI_VERSION ) { + fprintf(stderr, "ABI version of plugin does not match: %08X expecting: %08X\n", m->abi_version, ABI_VERSION); + g_module_close ( mod ); + } else { + m->module = mod; + if ( ! rofi_collect_modi_add ( m ) ) { + g_module_close ( mod ); + } + } + } else { + fprintf(stderr, "Symbol 'mode' not found in module: %s\n", fn); + g_module_close ( mod ); + } + } + g_free ( fn ); + } + g_dir_close ( dir ); + } +} + +/** + * Setup configuration for config. + */ +static void rofi_collect_modi_setup ( void ) +{ + for ( unsigned int i = 0; i < num_available_modi ; i++ ) { + mode_set_config ( available_modi[i] ); + } +} +static void rofi_collect_modi_destroy ( void ) +{ + for ( unsigned int i = 0; i < num_available_modi ; i++ ) { + if ( available_modi[i]->module ) { + g_module_close ( available_modi[i]->module ); + } + } + g_free ( available_modi ); + available_modi = NULL; + num_available_modi = 0; } /** @@ -412,85 +523,18 @@ static int add_mode ( const char * token ) // Resize and add entry. modi = (Mode * *) g_realloc ( modi, sizeof ( Mode* ) * ( num_modi + 1 ) ); - // Window switcher. -#ifdef WINDOW_MODE - if ( strcasecmp ( token, "window" ) == 0 ) { - modi[num_modi] = &window_mode; + Mode *mode = rofi_collect_modi_search ( token ); + if ( mode ) { + modi[num_modi] = mode; num_modi++; - } - else if ( strcasecmp ( token, "windowcd" ) == 0 ) { - modi[num_modi] = &window_mode_cd; - num_modi++; - } - else -#endif // WINDOW_MODE - // SSh dialog - if ( strcasecmp ( token, "ssh" ) == 0 ) { - modi[num_modi] = &ssh_mode; - num_modi++; - } - else if ( strcasecmp ( token, mode_get_name ( &help_keys_mode ) ) == 0 ) { - modi[num_modi] = &help_keys_mode; - num_modi++; - } - // Run dialog - else if ( strcasecmp ( token, "run" ) == 0 ) { - modi[num_modi] = &run_mode; - num_modi++; - } -#ifdef ENABLE_DRUN - else if ( strcasecmp ( token, "drun" ) == 0 ) { - modi[num_modi] = &drun_mode; - num_modi++; - } -#endif - // combi dialog - else if ( strcasecmp ( token, "combi" ) == 0 ) { - modi[num_modi] = &combi_mode; - num_modi++; - } - else if ( g_str_has_suffix ( token, G_MODULE_SUFFIX ) ) - { - gchar *fn; - if ( token[0] != G_DIR_SEPARATOR) { - fn = g_build_filename ( PLUGIN_PATH, token, NULL ); - } else { - fn = g_strdup ( token ); - } - TICK_N("Loading module"); - // Load module. - GModule *mod = g_module_open ( fn, G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL ); - if ( mod ) { - Mode *m = NULL; - if ( g_module_symbol ( mod, "mode", (gpointer *)&m) ){ - // Simple abi check. - if ( m->abi_version != ABI_VERSION ){ - fprintf(stderr, "ABI version of plugin does not match: %08X expecting: %08X\n", m->abi_version, ABI_VERSION); - g_module_close ( mod ); - } else { - modi[num_modi] = m; - num_modi++; - } - } else { - fprintf(stderr, "Symbol 'mode' not found in module: %s\n", token); - g_module_close ( mod ); - } - - } else { - fprintf ( stderr, "Failed to open module: %s\n", token); - } - g_free(fn); - TICK_N("Loading module done"); - } - else { + } else { // If not build in, use custom modi. Mode *sw = script_switcher_parse_setup ( token ); if ( sw != NULL ) { modi[num_modi] = sw; mode_set_config ( sw ); num_modi++; - } - else{ + } else { // Report error, don't continue. fprintf ( stderr, "Invalid script switcher: %s\n", token ); } @@ -509,19 +553,7 @@ static void setup_modi ( void ) } // Free string that was modified by strtok_r g_free ( switcher_str ); - // We cannot do this in main loop, as we create pointer to string, - // and re-alloc moves that pointer. - mode_set_config ( &ssh_mode ); - mode_set_config ( &run_mode ); -#ifdef ENABLE_DRUN - mode_set_config ( &drun_mode ); -#endif - -#ifdef WINDOW_MODE - mode_set_config ( &window_mode ); - mode_set_config ( &window_mode_cd ); -#endif // WINDOW_MODE - mode_set_config ( &combi_mode ); + rofi_collect_modi_setup (); } /** @@ -892,7 +924,10 @@ int main ( int argc, char *argv[] ) fprintf ( stderr, "Failed to open display: %s", display_str ); return EXIT_FAILURE; } + TICK_N ( "Open Display" ); + rofi_collect_modi (); + TICK_N ( "Collect MODI" ); xcb->screen = xcb_aux_get_screen ( xcb->connection, xcb->screen_nbr );