diff --git a/config/config.c b/config/config.c index a6c809b8..53a19eab 100644 --- a/config/config.c +++ b/config/config.c @@ -63,6 +63,8 @@ Settings config = { .ssh_command = "{terminal} -e {ssh-client} {host}", /** Command when running */ .run_command = "{cmd}", + /** Command used to list executable commands. empty -> internal */ + .run_list_command = "", /** Command executed when running application in terminal */ .run_shell_command = "{terminal} -e {cmd}", /** Key binding */ diff --git a/doc/rofi-manpage.markdown b/doc/rofi-manpage.markdown index da8f5f6c..7339190c 100644 --- a/doc/rofi-manpage.markdown +++ b/doc/rofi-manpage.markdown @@ -6,13 +6,14 @@ rofi - A window switcher, run dialog and dmenu replacement ## SYNOPSIS -**rofi** [ -width *pct_scr* ] [ -lines *lines* ] [ -columns *columns* ] [ -font *pangofont* ] [ -fg *color* ] -[ -bg *color* ] [ -hlfg *color* ] [ -hlbg *color* ] [ -key *combo* ] [ -dkey *comdo* ] [ -rkey *comdo* ] -[ -terminal *terminal* ] [ -location *position* ] [ -hmode ] [ -fixed-num-lines ] [ -padding *padding* ] -[ -opacity *opacity%* ] [ -display *display* ] [ -bc *color* ] [ -bw *width* ] [ -dmenu [ -p *prompt* ] ] -[ -ssh-client *client* ] [ -ssh-command *command* ] [ -now ] [ -rnow ] [ -snow ] [ -version ] -[ -help] [ -dump-xresources ] [ -disable-history ] [ -levenshtein-sort ] [ -show *mode* ] [ -switcher -*mode1,mode2* ] [ -e *message*] [ -sep *separator* ] [ -eh *element height* ] [ -l *selected line* ] +**rofi** [ -width *pct_scr* ] [ -lines *lines* ] [ -columns *columns* ] [ -font *pangofont* ] [ -fg +*color* ] [ -bg *color* ] [ -hlfg *color* ] [ -hlbg *color* ] [ -key *combo* ] [ -dkey *comdo* ] [ +-rkey *comdo* ] [ -terminal *terminal* ] [ -location *position* ] [ -hmode ] [ -fixed-num-lines ] [ +-padding *padding* ] [ -opacity *opacity%* ] [ -display *display* ] [ -bc *color* ] [ -bw *width* ] +[ -dmenu [ -p *prompt* ] ] [ -ssh-client *client* ] [ -ssh-command *command* ] [ -now ] [ -rnow ] [ +-snow ] [ -version ] [ -help] [ -dump-xresources ] [ -disable-history ] [ -levenshtein-sort ] [ +-show *mode* ] [ -switcher *mode1,mode2* ] [ -e *message*] [ -sep *separator* ] [ -eh *element +height* ] [ -l *selected line* ] [ -run-list-command *cmd* ] ## DESCRIPTION @@ -281,6 +282,10 @@ The default key combinations are: Set the command to execute when running an application in a shell. See *PATTERN*. +`-run-list-command` *cmd* + + If set, use an external tool to generate list of executable commands. Uses 'run-command' + ### History and Sorting `-disable-history` diff --git a/doc/rofi.1 b/doc/rofi.1 index 20e910c2..d8d7030e 100644 --- a/doc/rofi.1 +++ b/doc/rofi.1 @@ -4,13 +4,14 @@ rofi \- A window switcher, run dialog and dmenu replacement .SH SYNOPSIS .PP -\fBrofi\fP [ \-width \fIpct_scr\fP ] [ \-lines \fIlines\fP ] [ \-columns \fIcolumns\fP ] [ \-font \fIpangofont\fP ] [ \-fg \fIcolor\fP ] -[ \-bg \fIcolor\fP ] [ \-hlfg \fIcolor\fP ] [ \-hlbg \fIcolor\fP ] [ \-key \fIcombo\fP ] [ \-dkey \fIcomdo\fP ] [ \-rkey \fIcomdo\fP ] -[ \-terminal \fIterminal\fP ] [ \-location \fIposition\fP ] [ \-hmode ] [ \-fixed\-num\-lines ] [ \-padding \fIpadding\fP ] -[ \-opacity \fIopacity%\fP ] [ \-display \fIdisplay\fP ] [ \-bc \fIcolor\fP ] [ \-bw \fIwidth\fP ] [ \-dmenu [ \-p \fIprompt\fP ] ] -[ \-ssh\-client \fIclient\fP ] [ \-ssh\-command \fIcommand\fP ] [ \-now ] [ \-rnow ] [ \-snow ] [ \-version ] -[ \-help] [ \-dump\-xresources ] [ \-disable\-history ] [ \-levenshtein\-sort ] [ \-show \fImode\fP ] [ \-switcher -\fImode1,mode2\fP ] [ \-e \fImessage\fP] [ \-sep \fIseparator\fP ] [ \-eh \fIelement height\fP ] [ \-l \fIselected line\fP ] +\fBrofi\fP [ \-width \fIpct_scr\fP ] [ \-lines \fIlines\fP ] [ \-columns \fIcolumns\fP ] [ \-font \fIpangofont\fP ] [ \-fg +\fIcolor\fP ] [ \-bg \fIcolor\fP ] [ \-hlfg \fIcolor\fP ] [ \-hlbg \fIcolor\fP ] [ \-key \fIcombo\fP ] [ \-dkey \fIcomdo\fP ] [ +\-rkey \fIcomdo\fP ] [ \-terminal \fIterminal\fP ] [ \-location \fIposition\fP ] [ \-hmode ] [ \-fixed\-num\-lines ] [ +\-padding \fIpadding\fP ] [ \-opacity \fIopacity%\fP ] [ \-display \fIdisplay\fP ] [ \-bc \fIcolor\fP ] [ \-bw \fIwidth\fP ] +[ \-dmenu [ \-p \fIprompt\fP ] ] [ \-ssh\-client \fIclient\fP ] [ \-ssh\-command \fIcommand\fP ] [ \-now ] [ \-rnow ] [ +\-snow ] [ \-version ] [ \-help] [ \-dump\-xresources ] [ \-disable\-history ] [ \-levenshtein\-sort ] [ +\-show \fImode\fP ] [ \-switcher \fImode1,mode2\fP ] [ \-e \fImessage\fP] [ \-sep \fIseparator\fP ] [ \-eh \fIelement +height\fP ] [ \-l \fIselected line\fP ] [ \-run\-list\-command \fIcmd\fP ] .SH DESCRIPTION .PP \fBrofi\fP is an X11 popup window switcher. A list is displayed center\-screen showing open window titles, WM_CLASS, and desktop number. @@ -354,6 +355,10 @@ See \fIPATTERN\fP\&. .IP Set the command to execute when running an application in a shell. See \fIPATTERN\fP\&. +.PP +\fB\fC\-run\-list\-command\fR \fIcmd\fP +.IP +If set, use an external tool to generate list of executable commands. Uses 'run\-command' .SS History and Sorting .PP \fB\fC\-disable\-history\fR @@ -516,18 +521,14 @@ Check quotes used on the commandline: e.g. used “ instead of ". .SH WEBSITE .PP \fBrofi\fP website can be found at here -.UR https://davedavenport.github.io/rofi/ -.UE +\[la]https://davedavenport.github.io/rofi/\[ra] .PP \fBrofi\fP bugtracker can be found here -.UR https://github.com/DaveDavenport/rofi/issues -.UE +\[la]https://github.com/DaveDavenport/rofi/issues\[ra] .SH AUTHOR .PP Qball Cow -.MT qball@gmpclient.org -.ME +\[la]qball@gmpclient.org\[ra] .PP Original code based on work by: Sean Pringle -.MT sean.pringle@gmail.com -.ME +\[la]sean.pringle@gmail.com\[ra] diff --git a/include/helper.h b/include/helper.h index 5e615f32..45c7ae28 100644 --- a/include/helper.h +++ b/include/helper.h @@ -103,4 +103,13 @@ int token_match ( char **tokens, const char *input, __attribute__( ( unused ) ) int index, __attribute__( ( unused ) ) void *data ); +/** + * @param cmd The command to execute. + * + * Execute cmd using config.run_command and outputs the result (stdout) to the opened file + * descriptor. + * + * @returns a valid file descriptor on success, or -1 on failure. + */ +int execute_generator ( char * cmd ) __attribute__( ( nonnull ) ); #endif // __HELPER_H__ diff --git a/include/rofi.h b/include/rofi.h index 0ffe53f6..d1e4f7b4 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -169,6 +169,8 @@ typedef struct _Settings char * run_command; /** Command for executing an application in a terminal */ char * run_shell_command; + /** Command for listing executables */ + char * run_list_command; /** Key to open window switcher */ char * window_key; diff --git a/source/helper.c b/source/helper.c index 0c23fcdd..01b3b864 100644 --- a/source/helper.c +++ b/source/helper.c @@ -2,9 +2,9 @@ #include #include #include -#include #include #include +#include /** * `fgets` implementation with custom separator. @@ -276,3 +276,38 @@ int token_match ( char **tokens, const char *input, g_free ( compk ); return match; } + +int execute_generator ( char * cmd ) +{ + char **args = NULL; + int argv = 0; + helper_parse_setup ( config.run_command, &args, &argv, "{cmd}", cmd, NULL ); + + int fd = -1; + GError *error = NULL; + g_spawn_async_with_pipes ( NULL, + args, + NULL, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + NULL, + NULL, &fd, NULL, + &error ); + + if ( error != NULL ) { + char *msg = g_strdup_printf ( "Failed to execute: '%s'\nError: '%s'", cmd, + error->message ); +#ifdef error_dialog + error_dialog ( msg ); +#else + fputs ( msg, stderr ); +#endif + g_free ( msg ); + // print error. + g_error_free ( error ); + fd = -1; + } + g_strfreev ( args ); + return fd; +} diff --git a/source/rofi.c b/source/rofi.c index afacd5fa..a92981df 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -2188,6 +2188,7 @@ static void parse_cmd_options ( int argc, char ** argv ) find_arg_str ( argc, argv, "-ssh-client", &( config.ssh_client ) ); find_arg_str ( argc, argv, "-ssh-command", &( config.ssh_command ) ); find_arg_str ( argc, argv, "-run-command", &( config.run_command ) ); + find_arg_str ( argc, argv, "-run-list-command", &( config.run_list_command ) ); find_arg_str ( argc, argv, "-run-shell-command", &( config.run_shell_command ) ); // Keybindings @@ -2425,17 +2426,14 @@ int main ( int argc, char *argv[] ) // determine numlock mask so we can bind on keys with and without it XModifierKeymap *modmap = XGetModifierMapping ( display ); - + KeyCode kc = XKeysymToKeycode ( display, XK_Num_Lock ); for ( int i = 0; i < 8; i++ ) { for ( int j = 0; j < ( int ) modmap->max_keypermod; j++ ) { - if ( modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode ( display, XK_Num_Lock ) ) { + if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc ) { NumlockMask = ( 1 << i ); } } } - - - XFreeModifiermap ( modmap ); cache_client = winlist_new (); diff --git a/source/run-dialog.c b/source/run-dialog.c index 3a41be49..68ca6b6a 100644 --- a/source/run-dialog.c +++ b/source/run-dialog.c @@ -124,6 +124,38 @@ static int sort_func ( const void *a, const void *b ) } return strcasecmp ( astr, bstr ); } + +/** + * External spider to get list of executables. + */ +static char ** get_apps_external ( char **retv, unsigned int *length ) +{ + int fd = execute_generator ( config.run_list_command ); + if ( fd >= 0 ) { + FILE *inp = fdopen ( fd, "r" ); + if ( inp ) { + char buffer[1024]; + while ( fgets ( buffer, 1024, inp ) != NULL ) { + retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) ); + retv[( *length )] = g_strdup ( buffer ); + retv[( *length ) + 1] = NULL; + + // Filter out line-end. + if ( retv[( *length )][strlen ( buffer ) - 1] == '\n' ) { + retv[( *length )][strlen ( buffer ) - 1] = '\0'; + } + + ( *length )++; + } + fclose ( inp ); + } + } + return retv; +} + +/** + * Internal spider used to get list of executables. + */ static char ** get_apps ( unsigned int *length ) { unsigned int num_favorites = 0; @@ -247,7 +279,11 @@ SwitcherMode run_switcher_dialog ( char **input, G_GNUC_UNUSED void *data ) SwitcherMode retv = MODE_EXIT; // act as a launcher unsigned int cmd_list_length = 0; - char **cmd_list = get_apps ( &cmd_list_length ); + char **cmd_list = NULL; + cmd_list = get_apps ( &cmd_list_length ); + if ( config.run_list_command != NULL && config.run_list_command[0] != '\0' ) { + cmd_list = get_apps_external ( cmd_list, &cmd_list_length ); + } if ( cmd_list == NULL ) { cmd_list = g_malloc_n ( 2, sizeof ( char * ) ); diff --git a/source/script-dialog.c b/source/script-dialog.c index 5cd7d1ce..e9234949 100644 --- a/source/script-dialog.c +++ b/source/script-dialog.c @@ -40,35 +40,6 @@ -pid_t execute_generator ( char * cmd ) -{ - char **args = NULL; - int argv = 0; - helper_parse_setup ( config.run_command, &args, &argv, "{cmd}", cmd, NULL ); - - int fd = -1; - GError *error = NULL; - g_spawn_async_with_pipes ( NULL, - args, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - NULL, &fd, NULL, - &error ); - - if ( error != NULL ) { - char *msg = g_strdup_printf ( "Failed to execute: '%s'\nError: '%s'", cmd, - error->message ); - error_dialog ( msg ); - g_free ( msg ); - // print error. - g_error_free ( error ); - } - g_strfreev ( args ); - return fd; -} static char **get_script_output ( char *command, unsigned int *length ) diff --git a/source/xrmoptions.c b/source/xrmoptions.c index 3119d3f6..9e35e912 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -101,6 +101,7 @@ static XrmOption xrmOptions[] = { { xrm_String, "ssh-client", { .str = &config.ssh_client }, NULL }, { xrm_String, "ssh-command", { .str = &config.ssh_command }, NULL }, { xrm_String, "run-command", { .str = &config.run_command }, NULL }, + { xrm_String, "run-list-command", { .str = &config.run_list_command }, NULL }, { xrm_String, "run-shell-command", { .str = &config.run_shell_command }, NULL }, { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL },