Fix #65, Fix #63 Allow user to select list of modi's

* Add script_dialog, so user can add dialogs using a script.
    * Add a way to disable modi's
    * Add -show <modi> option.
This commit is contained in:
QC 2014-07-21 21:39:24 +02:00
parent d584987c81
commit cd4888a5cf
17 changed files with 544 additions and 73 deletions

View File

@ -0,0 +1,22 @@
#!/bin/bash
if [ -z $@ ]
then
function gen_workspaces()
{
i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | sed 's/"name":"\(.*\)"/\1/g' | sort -n
}
echo empty; gen_workspaces
else
WORKSPACE=$@
if [ x"empty" = x"${WORKSPACE}" ]
then
i3_empty_workspace.sh >/dev/null
elif [ -n "${WORKSPACE}" ]
then
i3-msg workspace "${WORKSPACE}" >/dev/null
fi
fi

View File

@ -26,12 +26,14 @@ rofi_SOURCES=\
source/dmenu-dialog.c\
source/run-dialog.c\
source/ssh-dialog.c\
source/script-dialog.c\
source/history.c\
config/config.c\
include/rofi.h\
include/run-dialog.h\
include/ssh-dialog.h\
include/dmenu-dialog.h\
include/script-dialog.h\
include/xrmoptions.h\
include/history.h\
include/textbox.h
@ -66,6 +68,7 @@ EXTRA_DIST=\
$(man1_MANS)\
$(markdown_FILES)\
$(markdown_SC_FILES)\
Examples/i3_switch_workspaces.sh\
INSTALL.md
##

View File

@ -29,6 +29,9 @@
#include "rofi.h"
Settings config = {
// List of enabled switchers.
// -switchers
.switchers = "window,run,ssh",
// Set the default window opacity.
// This option only works when running a composite manager.
// -o

View File

@ -14,11 +14,11 @@ SYNOPSIS
[ -terminal *terminal* ] [ -loc *position* ] [ -hmode ] [ -fixed-num-lines ] [ -padding *padding* ]
[ -opacity *opacity%* ] [ -display *display* ] [ -bc *color* ] [ -bw *width* ] [ -dmenu [ -p *prompt* ] ]
[ -ssh-set-title *true|false* ] [ -now ] [ -rnow ] [ -snow ] [ -version ] [ -help] [ -dump-xresources ]
[ -disable-history ] [ -levenshtein-sort ]
[ -disable-history ] [ -levenshtein-sort ] [ -show *mode* ] [ -switcher *mode1,mode2* ]
DESCRIPTION
-----------
`rofi` is an X11 popup window switcher. A list is displayed center-screen showing open window titles, WM_CLASS, and desktop number.
`rofi` is an X11 popup window switcher. A list is displayed center-screen showing open window titles, WM_CLASS, and desktop number.
The user may filter the list by typing, navigate with Up/Down or Tab keys, and select a window with Return (Enter). Escape cancels.
License
@ -219,11 +219,38 @@ OPTIONS
When searching sort the result based on levenshtein distance.
`-show` *mode*
Open rofi in a certain mode.
For example to show the run-dialog:
rofi -show run
This function deprecates -rnow,-snow and -now
`-switchers` *mode1,mode1*
Give a comma separated list of modes to enable, in what order.
For example to only show the run and ssh dialog (in that order):
rofi -switchers "run,ssh" -show run
Custom modes can be added using the internal 'script' mode. Each mode has two parameters:
<name>:<script>
So to have a mode 'Workspaces' using the `i3_switch_workspace.sh` script type:
rofi -switchers "window,run,ssh,Workspaces:i3_switch_workspaces.sh" -show Workspaces
Switch between modi
-------------------
Type '?' *enter* to switch between window list, run and ssh mode.
Type '?' *enter* to switch between window list, run and ssh mode. The list can be customized with
the `-switchers` argument.
WEBSITE
-------

View File

@ -9,10 +9,10 @@ rofi \- A window switcher, run dialog and dmenu replacement
[ \-terminal \fIterminal\fP ] [ \-loc \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\-set\-title \fItrue|false\fP ] [ \-now ] [ \-rnow ] [ \-snow ] [ \-version ] [ \-help] [ \-dump\-xresources ]
[ \-disable\-history ] [ \-levenshtein\-sort ]
[ \-disable\-history ] [ \-levenshtein\-sort ] [ \-show \fImode\fP ] [ \-switcher \fImode1,mode2\fP ]
.SH DESCRIPTION
.PP
\fB\fCrofi\fR is an X11 popup window switcher. A list is displayed center\-screen showing open window titles, WM_CLASS, and desktop number.
\fB\fCrofi\fR is an X11 popup window switcher. A list is displayed center\-screen showing open window titles, WM_CLASS, and desktop number.
The user may filter the list by typing, navigate with Up/Down or Tab keys, and select a window with Return (Enter). Escape cancels.
.SH License
.PP
@ -262,9 +262,52 @@ Disable history
\fB\fC\-levenshtein\-sort\fR
.IP
When searching sort the result based on levenshtein distance.
.PP
\fB\fC\-show\fR \fImode\fP
.IP
Open rofi in a certain mode.
.IP
For example to show the run\-dialog:
.PP
.RS
.nf
rofi \-show run
.fi
.RE
.IP
This function deprecates \-rnow,\-snow and \-now
.PP
\fB\fC\-switchers\fR \fImode1,mode1\fP
.IP
Give a comma separated list of modes to enable, in what order.
.IP
For example to only show the run and ssh dialog (in that order):
.PP
.RS
.nf
rofi \-switchers "run,ssh" \-show run
.fi
.RE
.IP
Custom modes can be added using the internal 'script' mode. Each mode has two parameters:
.PP
.RS
.nf
<name>:<script>
.fi
.RE
.IP
So to have a mode 'Workspaces' using the \fB\fCi3_switch_workspace.sh\fR script type:
.PP
.RS
.nf
rofi \-switchers "window,run,ssh,Workspaces:i3_switch_workspaces.sh" \-show Workspaces
.fi
.RE
.SH Switch between modi
.PP
Type '?' \fIenter\fP to switch between window list, run and ssh mode.
Type '?' \fIenter\fP to switch between window list, run and ssh mode. The list can be customized with
the \fB\fC\-switchers\fR argument.
.SH WEBSITE
.PP
\fB\fCrofi\fR website can be found at here

View File

@ -2,6 +2,6 @@
#define __DMENU_DIALOG_H__
extern char *dmenu_prompt;
SwitcherMode dmenu_switcher_dialog ( char **input );
SwitcherMode dmenu_switcher_dialog ( char **input, void *data );
#endif

View File

@ -19,27 +19,24 @@
extern const char *cache_dir;
/**
* Enum used to sum the possible states of ROFI.
*/
typedef enum
{
/** Show the window switcher */
WINDOW_SWITCHER,
/** Show the run dialog */
RUN_DIALOG,
/** Show the ssh dialog */
SSH_DIALOG,
/** Number of cycle-able dialogs */
NUM_DIALOGS,
/** Dmenu mode */
DMENU_DIALOG,
DMENU_DIALOG = 999,
/** Exit. */
MODE_EXIT,
MODE_EXIT = 1000,
/** Skip to the next cycle-able dialog. */
NEXT_DIALOG
NEXT_DIALOG = 1001,
/** Reload current DIALOG */
RELOAD_DIALOG = 1002
} SwitcherMode;
// switcher callback
typedef SwitcherMode ( *switcher_callback )( char **input, void *data );
/**
* State returned by the rofi window.
@ -105,6 +102,7 @@ typedef enum _WindowLocation
typedef struct _Settings
{
char *switchers;
// Window settings
unsigned int window_opacity;
// Menu settings

View File

@ -3,6 +3,6 @@
SwitcherMode run_switcher_dialog ( char **input );
SwitcherMode run_switcher_dialog ( char **input, void *data );
#endif

28
include/script-dialog.h Normal file
View File

@ -0,0 +1,28 @@
#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;
SwitcherMode script_switcher_dialog ( char **input, void *data );
/**
* Parse an argument string into the right ScriptOptions data object.
* This is off format: <Name>:<Script>
* Return NULL when it fails.
*/
ScriptOptions *script_switcher_parse_setup ( const char *str );
/**
* Free the ScriptOptions block.
*/
void script_switcher_free_options ( ScriptOptions *sw );
#endif

View File

@ -3,6 +3,6 @@
SwitcherMode ssh_switcher_dialog ( char **input );
SwitcherMode ssh_switcher_dialog ( char **input, void *data );
#endif

View File

@ -19,12 +19,12 @@ typedef struct
typedef enum
{
TB_AUTOHEIGHT = 1 << 0,
TB_AUTOWIDTH = 1 << 1,
TB_LEFT = 1 << 16,
TB_RIGHT = 1 << 17,
TB_CENTER = 1 << 18,
TB_EDITABLE = 1 << 19,
TB_AUTOHEIGHT = 1 << 0,
TB_AUTOWIDTH = 1 << 1,
TB_LEFT = 1 << 16,
TB_RIGHT = 1 << 17,
TB_CENTER = 1 << 18,
TB_EDITABLE = 1 << 19,
} TextboxFlags;
typedef enum

View File

@ -65,7 +65,7 @@ static char **get_dmenu ( unsigned int *length )
return retv;
}
SwitcherMode dmenu_switcher_dialog ( char **input )
SwitcherMode dmenu_switcher_dialog ( char **input, void *data )
{
int selected_line = 0;
SwitcherMode retv = MODE_EXIT;
@ -76,7 +76,7 @@ SwitcherMode dmenu_switcher_dialog ( char **input )
token_match, NULL, &selected_line );
if ( mretv == MENU_NEXT ) {
retv = DMENU_DIALOG;
retv = RELOAD_DIALOG;
}
else if ( mretv == MENU_OK && list[selected_line] != NULL ) {
fputs ( list[selected_line], stdout );

View File

@ -65,6 +65,7 @@
#include "run-dialog.h"
#include "ssh-dialog.h"
#include "dmenu-dialog.h"
#include "script-dialog.h"
#include "xrmoptions.h"
@ -85,6 +86,48 @@ char *active_font = NULL;
unsigned int NumlockMask = 0;
Display *display = NULL;
typedef struct _Switcher
{
char name[32];
switcher_callback cb;
void *cb_data;
} Switcher;
Switcher *switchers = NULL;
int num_switchers = 0;
int switcher_get ( const char *name )
{
for ( int i = 0; i < num_switchers; i++ ) {
if ( strcmp ( switchers[i].name, name ) == 0 ) {
return i;
}
}
return -1;
}
/**
* Not every platform has strlcpy. (Why god why?)
* So a quick implementation to fix this.
*/
static size_t copy_string ( char *dest, const char *src, size_t len )
{
size_t size;
if ( !len ) {
return 0;
}
size = strlen ( src );
if ( size >= len ) {
size = len - 1;
}
memcpy ( dest, src, size );
dest[size] = '\0';
return size;
}
/**
* Shared 'token_match' function.
* Matches tokenized.
@ -219,22 +262,26 @@ static int find_arg ( const int argc, char * const argv[], const char * const ke
return i < argc ? i : -1;
}
static void find_arg_str ( int argc, char *argv[], char *key, char** val )
static int find_arg_str ( int argc, char *argv[], char *key, char** val )
{
int i = find_arg ( argc, argv, key );
if ( val != NULL && i > 0 && i < argc - 1 ) {
*val = argv[i + 1];
return TRUE;
}
return FALSE;
}
static void find_arg_int ( int argc, char *argv[], char *key, unsigned int *val )
static int find_arg_int ( int argc, char *argv[], char *key, unsigned int *val )
{
int i = find_arg ( argc, argv, key );
if ( val != NULL && i > 0 && i < ( argc - 1 ) ) {
*val = strtol ( argv[i + 1], NULL, 10 );
return TRUE;
}
return FALSE;
}
@ -1333,8 +1380,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
if ( shift != NULL ) {
( *shift ) = ( ( ev.xkey.state & ShiftMask ) == ShiftMask );
}
if ( filtered && filtered[selected] ) {
if ( filtered[selected] != NULL ) {
retv = MENU_OK;
*selected_line = line_map[selected];
}
@ -1490,7 +1536,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
return retv;
}
SwitcherMode run_switcher_window ( char **input )
SwitcherMode run_switcher_window ( char **input, void *data )
{
Screen *screen = DefaultScreenOfDisplay ( display );
Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) );
@ -1662,31 +1708,29 @@ static void run_switcher ( int do_fork, SwitcherMode mode )
config.menu_hlbg,
config.menu_hlfg );
char *input = NULL;
// Dmenu is a special mode. You can cycle away from it.
if ( mode == DMENU_DIALOG ) {
dmenu_switcher_dialog ( &input, NULL );
}
// Otherwise check if requested mode is enabled.
else if ( switchers[mode].cb != NULL ) {
do {
SwitcherMode retv = MODE_EXIT;
do {
SwitcherMode retv = MODE_EXIT;
if ( mode == WINDOW_SWITCHER ) {
retv = run_switcher_window ( &input );
}
else if ( mode == RUN_DIALOG ) {
retv = run_switcher_dialog ( &input );
}
else if ( mode == SSH_DIALOG ) {
retv = ssh_switcher_dialog ( &input );
}
else if ( mode == DMENU_DIALOG ) {
retv = dmenu_switcher_dialog ( &input );
}
if ( retv == NEXT_DIALOG ) {
mode = ( mode + 1 ) % NUM_DIALOGS;
}
else{
mode = retv;
}
} while ( mode != MODE_EXIT );
retv = switchers[mode].cb ( &input, switchers[mode].cb_data );
// Find next enabled
if ( retv == NEXT_DIALOG ) {
mode = ( mode + 1 ) % num_switchers;
}
else if ( retv == RELOAD_DIALOG ) {
// do nothing.
}
else {
mode = retv;
}
} while ( mode != MODE_EXIT );
}
free ( input );
// Cleanup font setup.
@ -1704,17 +1748,26 @@ static void handle_keypress ( XEvent *ev )
if ( ( windows_modmask == AnyModifier || ev->xkey.state & windows_modmask ) &&
key == windows_keysym ) {
run_switcher ( TRUE, WINDOW_SWITCHER );
int index = switcher_get ( "window" );
if ( index >= 0 ) {
run_switcher ( TRUE, index );
}
}
if ( ( rundialog_modmask == AnyModifier || ev->xkey.state & rundialog_modmask ) &&
key == rundialog_keysym ) {
run_switcher ( TRUE, RUN_DIALOG );
int index = switcher_get ( "run" );
if ( index >= 0 ) {
run_switcher ( TRUE, index );
}
}
if ( ( sshdialog_modmask == AnyModifier || ev->xkey.state & sshdialog_modmask ) &&
key == sshdialog_keysym ) {
run_switcher ( TRUE, SSH_DIALOG );
int index = switcher_get ( "ssh" );
if ( index >= 0 ) {
run_switcher ( TRUE, index );
}
}
}
@ -1836,6 +1889,7 @@ static void parse_cmd_options ( int argc, char ** argv )
exit ( EXIT_SUCCESS );
}
find_arg_str ( argc, argv, "-switchers", &( config.switchers ) );
// Parse commandline arguments about the looks.
find_arg_int ( argc, argv, "-opacity", &( config.window_opacity ) );
@ -1933,6 +1987,14 @@ static void cleanup ()
xdgWipeHandle ( &xdg_handle );
free ( active_font );
for ( unsigned int i = 0; i < num_switchers; i++ ) {
// only used for script dialog.
if ( switchers[i].cb_data != NULL ) {
script_switcher_free_options ( switchers[i].cb_data );
}
}
free ( switchers );
}
/**
@ -1966,6 +2028,51 @@ static void config_sanity_check ( void )
}
}
static void setup_switchers ( void )
{
char *switcher_str = strdup ( config.switchers );
char *token;
for ( token = strtok ( switcher_str, "," ); token != NULL; token = strtok ( NULL, "," ) ) {
if ( strcasecmp ( token, "window" ) == 0 ) {
switchers = (Switcher *) realloc ( switchers, sizeof ( Switcher ) * ( num_switchers + 1 ) );
copy_string ( switchers[num_switchers].name, "window", 32 );
switchers[num_switchers].cb = run_switcher_window;
switchers[num_switchers].cb_data = NULL;
num_switchers++;
}
else if ( strcasecmp ( token, "ssh" ) == 0 ) {
switchers = (Switcher *) realloc ( switchers, sizeof ( Switcher ) * ( num_switchers + 1 ) );
copy_string ( switchers[num_switchers].name, "ssh", 32 );
switchers[num_switchers].cb = ssh_switcher_dialog;
switchers[num_switchers].cb_data = NULL;
num_switchers++;
}
else if ( strcasecmp ( token, "run" ) == 0 ) {
switchers = (Switcher *) realloc ( switchers, sizeof ( Switcher ) * ( num_switchers + 1 ) );
copy_string ( switchers[num_switchers].name, "run", 32 );
switchers[num_switchers].cb = run_switcher_dialog;
switchers[num_switchers].cb_data = NULL;
num_switchers++;
}
else {
ScriptOptions *sw = script_switcher_parse_setup ( token );
if ( sw != NULL ) {
switchers = (Switcher *) realloc ( switchers, sizeof ( Switcher ) * ( num_switchers + 1 ) );
copy_string ( switchers[num_switchers].name, sw->name, 32 );
switchers[num_switchers].cb = script_switcher_dialog;
switchers[num_switchers].cb_data = sw;
num_switchers++;
}
else{
fprintf ( stderr, "Invalid script switcher: %s\n", token );
token = NULL;
}
}
}
free ( switcher_str );
}
int main ( int argc, char *argv[] )
{
@ -1999,6 +2106,9 @@ int main ( int argc, char *argv[] )
// Sanity check
config_sanity_check ();
// setup_switchers
setup_switchers ();
// Generate the font string for the line that indicates a selected item.
if ( asprintf ( &active_font, "%s:slant=italic", config.menu_font ) < 0 ) {
fprintf ( stderr, "Failed to construct active string: %s\n", strerror ( errno ) );
@ -2043,14 +2153,43 @@ int main ( int argc, char *argv[] )
// flags to run immediately and exit
if ( find_arg ( argc, argv, "-now" ) >= 0 ) {
run_switcher ( FALSE, WINDOW_SWITCHER );
char *sname = NULL;
if ( find_arg_str ( argc, argv, "-show", &sname ) == TRUE ) {
int index = switcher_get ( sname );
if ( index >= 0 ) {
run_switcher ( FALSE, index );
}
else {
fprintf ( stderr, "The %s switcher has not been enabled\n", sname );
}
}
// Old modi.
else if ( find_arg ( argc, argv, "-now" ) >= 0 ) {
int index = switcher_get ( "window" );
if ( index >= 0 ) {
run_switcher ( FALSE, index );
}
else {
fprintf ( stderr, "The window switcher has not been enabled\n" );
}
}
else if ( find_arg ( argc, argv, "-rnow" ) >= 0 ) {
run_switcher ( FALSE, RUN_DIALOG );
int index = switcher_get ( "run" );
if ( index >= 0 ) {
run_switcher ( FALSE, index );
}
else {
fprintf ( stderr, "The run dialog has not been enabled\n" );
}
}
else if ( find_arg ( argc, argv, "-snow" ) >= 0 ) {
run_switcher ( FALSE, SSH_DIALOG );
int index = switcher_get ( "ssh" );
if ( index >= 0 ) {
run_switcher ( FALSE, index );
}
else {
fprintf ( stderr, "The ssh dialog has not been enabled\n" );
}
}
else if ( find_arg ( argc, argv, "-dmenu" ) >= 0 ) {
find_arg_str ( argc, argv, "-p", &dmenu_prompt );
@ -2058,14 +2197,20 @@ int main ( int argc, char *argv[] )
}
else{
// Daemon mode, Listen to key presses..
parse_key ( display, config.window_key, &windows_modmask, &windows_keysym );
grab_key ( display, windows_modmask, windows_keysym );
if ( switcher_get ( "window" ) >= 0 ) {
parse_key ( display, config.window_key, &windows_modmask, &windows_keysym );
grab_key ( display, windows_modmask, windows_keysym );
}
parse_key ( display, config.run_key, &rundialog_modmask, &rundialog_keysym );
grab_key ( display, rundialog_modmask, rundialog_keysym );
if ( switcher_get ( "run" ) >= 0 ) {
parse_key ( display, config.run_key, &rundialog_modmask, &rundialog_keysym );
grab_key ( display, rundialog_modmask, rundialog_keysym );
}
parse_key ( display, config.ssh_key, &sshdialog_modmask, &sshdialog_keysym );
grab_key ( display, sshdialog_modmask, sshdialog_keysym );
if ( switcher_get ( "ssh" ) >= 0 ) {
parse_key ( display, config.ssh_key, &sshdialog_modmask, &sshdialog_keysym );
grab_key ( display, sshdialog_modmask, sshdialog_keysym );
}
// Main loop
for (;; ) {

View File

@ -198,7 +198,7 @@ static char ** get_apps ( unsigned int *length )
return retv;
}
SwitcherMode run_switcher_dialog ( char **input )
SwitcherMode run_switcher_dialog ( char **input, void *data )
{
int shift = 0;
int selected_line = 0;
@ -226,7 +226,7 @@ SwitcherMode run_switcher_dialog ( char **input )
}
else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] ) {
delete_entry ( cmd_list[selected_line] );
retv = RUN_DIALOG;
retv = RELOAD_DIALOG;
}
for ( int i = 0; cmd_list != NULL && cmd_list[i] != NULL; i++ ) {

201
source/script-dialog.c Normal file
View File

@ -0,0 +1,201 @@
/**
* rofi
*
* MIT/X11 License
* Copyright 2013-2014 Qball Cow <qball@gmpclient.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "rofi.h"
#include "script-dialog.h"
pid_t execute_generator ( char * cmd )
{
int filedes[2];
pid_t pid;
if ( -1 == pipe ( filedes ) ) {
perror ( "pipe failed" );
return 0;
}
switch ( pid = fork () )
{
case -1:
perror ( "Failed to fork, executing generator failed" );
pid = 0;
break;
case 0: /* child */
close ( 1 );
dup ( filedes[1] );
close ( filedes[1] );
execlp ( "/bin/sh", "sh", "-c", cmd, NULL );
perror ( cmd );
break;
default: /* parent */
close ( 0 );
dup ( filedes[0] );
close ( filedes[0] );
close ( filedes[1] );
break;
}
return pid;
}
static char **get_script_output ( char *command, unsigned int *length )
{
char buffer[1024];
char **retv = NULL;
*length = 0;
execute_generator ( command );
while ( fgets ( buffer, 1024, stdin ) != NULL ) {
char **tr = realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) );
if ( tr == NULL ) {
return retv;
}
retv = tr;
retv[( *length )] = strdup ( buffer );
retv[( *length ) + 1] = NULL;
// Filter out line-end.
if ( retv[( *length )][strlen ( buffer ) - 1] == '\n' ) {
retv[( *length )][strlen ( buffer ) - 1] = '\0';
}
( *length )++;
}
return retv;
}
char **execute_executor ( ScriptOptions *options, const char *result, unsigned int *length )
{
char **retv = NULL;
char *command;
if ( asprintf ( &command, "%s %s", options->script_path, result ) > 0 ) {
retv = get_script_output ( command, length );
free ( command );
}
return retv;
}
SwitcherMode script_switcher_dialog ( char **input, void *data )
{
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 );
do {
unsigned int new_length = 0;
char **new_list = NULL;
int mretv = menu ( list, length, input, options->name, NULL, NULL,
token_match, NULL, &selected_line );
if ( mretv == MENU_NEXT ) {
retv = NEXT_DIALOG;
}
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.
for ( unsigned int i = 0; i < length; i++ ) {
free ( list[i] );
}
if ( list != NULL ) {
free ( list );
list = NULL;
}
// If a new list was generated, use that an loop around.
if ( new_list != NULL ) {
list = new_list;
length = new_length;
free ( *input );
*input = NULL;
}
} while ( list != NULL );
return retv;
}
void script_switcher_free_options ( ScriptOptions *sw )
{
if ( sw == NULL ) {
return;
}
free ( sw->name );
free ( sw->script_path );
free ( sw );
}
ScriptOptions *script_switcher_parse_setup ( const char *str )
{
ScriptOptions *sw = calloc ( 1, sizeof ( *sw ) );
char *endp = NULL;
char *parse = strdup ( str );
unsigned int index = 0;
// TODO: This is naive and can be improved.
for ( char *token = strtok_r ( parse, ":", &endp ); token != NULL; token = strtok_r ( NULL, ":", &endp ) ) {
if ( index == 0 ) {
sw->name = strdup ( token );
}
else if ( index == 1 ) {
sw->script_path = strdup ( token );
}
index++;
}
free ( parse );
if ( index == 2 ) {
return sw;
}
fprintf ( stderr, "The script command '%s' has %d options, but needs 2: <name>:<script>.\n",
str, index );
script_switcher_free_options ( sw );
return NULL;
}

View File

@ -215,7 +215,7 @@ static char ** get_ssh ( unsigned int *length )
return retv;
}
SwitcherMode ssh_switcher_dialog ( char **input )
SwitcherMode ssh_switcher_dialog ( char **input, void *data )
{
SwitcherMode retv = MODE_EXIT;
// act as a launcher
@ -244,7 +244,7 @@ SwitcherMode ssh_switcher_dialog ( char **input )
else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] ) {
delete_ssh ( cmd_list[selected_line] );
// Stay
retv = SSH_DIALOG;
retv = RELOAD_DIALOG;
}
for ( int i = 0; cmd_list[i] != NULL; i++ ) {

View File

@ -58,6 +58,7 @@ typedef struct
* Currently supports string and number.
*/
static XrmOption xrmOptions[] = {
{ xrm_String, "switchers", { .str = &config.switchers }, NULL },
{ xrm_Number, "opacity", { .num = &config.window_opacity }, NULL },
{ xrm_Number, "width", { .num = &config.menu_width }, NULL },