Refactor to make dmenu use Switcher, and make menu func use this.

This commit is contained in:
Dave Davenport 2015-09-08 21:41:54 +02:00
parent ae26c13daf
commit 13203c9de7
3 changed files with 159 additions and 106 deletions

View File

@ -79,6 +79,7 @@ typedef enum
typedef int ( *menu_match_cb )( char **tokens, const char *input, int case_sensitive, unsigned int index, Switcher *data );
/**
* @param sw the Switcher to show.
* @param lines An array of strings to display.
* @param num_lines Length of the array with strings to display.
* @param input A pointer to a string where the inputted data is placed.
@ -93,10 +94,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,
menu_match_cb mmc, void *mmc_data, int *selected_line,
get_display_value mgrv, void *mgrv_data, int *next_pos, const char *message ) __attribute__ ( ( nonnull ( 1, 3,
4, 7 ) ) );
MenuReturn menu ( Switcher *sw, char **input, char *prompt,
int *selected_line,
unsigned int *next_pos, const char *message ) __attribute__ ( ( nonnull ( 1, 2, 3, 4 ) ) );
/**
* @param sig The caught signal
*

View File

@ -36,8 +36,28 @@
#include "dialogs/dmenu.h"
#include "helper.h"
struct range_pair
{
unsigned int start;
unsigned int stop;
};
typedef struct _DmenuModePrivateData
{
char *prompt;
int selected_line;
char *message;
char *format;
struct range_pair * urgent_list;
unsigned int num_urgent_list;
struct range_pair * active_list;
unsigned int num_active_list;
// List with entries.
char **cmd_list;
unsigned int cmd_list_length;
} DmenuModePrivateData;
static char **get_dmenu ( int *length )
static char **get_dmenu ( unsigned int *length )
{
char buffer[1024];
char **retv = NULL;
@ -64,16 +84,17 @@ static char **get_dmenu ( int *length )
return retv;
}
struct range_pair
static char ** dmenu_mode_get_data ( unsigned int *length, Switcher *sw )
{
unsigned int start;
unsigned int stop;
};
DmenuModePrivateData *rmpd = (DmenuModePrivateData *) sw->private_data;
if ( rmpd->cmd_list == NULL ) {
rmpd->cmd_list_length = 0;
rmpd->cmd_list = get_dmenu ( &( rmpd->cmd_list_length ) );
}
*length = rmpd->cmd_list_length;
return rmpd->cmd_list;
}
struct range_pair * urgent_list = NULL;
unsigned int num_urgent_list = 0;
struct range_pair * active_list = NULL;
unsigned int num_active_list = 0;
static void parse_pair ( char *input, struct range_pair *item )
{
@ -113,14 +134,16 @@ static void parse_ranges ( char *input, struct range_pair **list, unsigned int *
static const char *get_display_data ( unsigned int index, void *data, G_GNUC_UNUSED int *state )
{
char **retv = (char * *) data;
for ( unsigned int i = 0; i < num_active_list; i++ ) {
if ( index >= active_list[i].start && index <= active_list[i].stop ) {
Switcher *sw = (Switcher *) data;
DmenuModePrivateData *pd = (DmenuModePrivateData *) sw->private_data;
char **retv = (char * *) pd->cmd_list;
for ( unsigned int i = 0; i < pd->num_active_list; i++ ) {
if ( index >= pd->active_list[i].start && index <= pd->active_list[i].stop ) {
*state |= ACTIVE;
}
}
for ( unsigned int i = 0; i < num_urgent_list; i++ ) {
if ( index >= urgent_list[i].start && index <= urgent_list[i].stop ) {
for ( unsigned int i = 0; i < pd->num_urgent_list; i++ ) {
if ( index >= pd->urgent_list[i].start && index <= pd->urgent_list[i].stop ) {
*state |= URGENT;
}
}
@ -177,65 +200,57 @@ static void dmenu_output_formatted_line ( const char *format, const char *string
fputc ( '\n', stdout );
fflush ( stdout );
}
int dmenu_switcher_dialog ( void )
static void dmenu_mode_free ( Switcher *sw )
{
char *input = NULL;
char *dmenu_prompt = "dmenu ";
int selected_line = -1;
int retv = FALSE;
int length = 0;
char **list = get_dmenu ( &length );
int restart = FALSE;
char *message = NULL;
if ( sw->private_data == NULL ) {
return;
}
DmenuModePrivateData *pd = (DmenuModePrivateData *) sw->private_data;
find_arg_str ( "-mesg", &message );
g_strfreev ( pd->cmd_list );
g_free ( pd->urgent_list );
g_free ( pd->active_list );
g_free ( pd );
sw->private_data = NULL;
}
static void dmenu_mode_init ( Switcher *sw )
{
if ( sw->private_data != NULL ) {
return;
}
sw->private_data = g_malloc0 ( sizeof ( DmenuModePrivateData ) );
DmenuModePrivateData *pd = (DmenuModePrivateData *) sw->private_data;
pd->prompt = "dmenu ";
pd->selected_line = -1;
find_arg_str ( "-mesg", &( pd->message ) );
// Check prompt
find_arg_str ( "-p", &( pd->prompt ) );
find_arg_int ( "-selected-row", &( pd->selected_line ) );
// By default we print the unescaped line back.
char *format = "s";
pd->format = "s";
// Allow user to override the output format.
find_arg_str ( "-format", &format );
// Check prompt
find_arg_str ( "-p", &dmenu_prompt );
find_arg_int ( "-selected-row", &selected_line );
find_arg_str ( "-format", &( pd->format ) );
// Urgent.
char *str = NULL;
find_arg_str ( "-u", &str );
if ( str != NULL ) {
parse_ranges ( str, &urgent_list, &num_urgent_list );
parse_ranges ( str, &( pd->urgent_list ), &( pd->num_urgent_list ) );
}
// Active
str = NULL;
find_arg_str ( "-a", &str );
if ( str != NULL ) {
parse_ranges ( str, &active_list, &num_active_list );
}
int only_selected = FALSE;
if ( find_arg ( "-only-match" ) >= 0 || find_arg ( "-no-custom" ) >= 0 ) {
only_selected = TRUE;
if ( length == 0 ) {
return TRUE;
}
}
/* copy filter string */
input = g_strdup ( config.filter );
char *select = NULL;
find_arg_str ( "-select", &select );
if ( select != NULL ) {
char **tokens = tokenize ( select, config.case_sensitive );
int i = 0;
for ( i = 0; i < length; i++ ) {
if ( token_match ( tokens, list[i], config.case_sensitive, 0, NULL ) ) {
selected_line = i;
break;
}
}
g_strfreev ( tokens );
parse_ranges ( str, &( pd->active_list ), &( pd->num_active_list ) );
}
// DMENU COMPATIBILITY
find_arg_uint ( "-l", &( config.menu_lines ) );
/**
@ -250,11 +265,63 @@ int dmenu_switcher_dialog ( void )
if ( find_arg ( "-i" ) >= 0 ) {
config.case_sensitive = FALSE;
}
}
Switcher dmenu_mode =
{
.name = "dmenu",
.keycfg = NULL,
.keystr = NULL,
.modmask = AnyModifier,
.init = dmenu_mode_init,
.get_data = dmenu_mode_get_data,
.result = NULL,
.destroy = dmenu_mode_free,
.token_match = token_match,
.mgrv = get_display_data,
.private_data = NULL,
.free = NULL
};
int dmenu_switcher_dialog ( void )
{
dmenu_mode.init ( &dmenu_mode );
DmenuModePrivateData *pd = (DmenuModePrivateData *) dmenu_mode.private_data;
char *input = NULL;
int retv = FALSE;
int restart = FALSE;
unsigned int cmd_list_length = 0;
char **cmd_list = dmenu_mode.get_data ( &( cmd_list_length ), &dmenu_mode );
int only_selected = FALSE;
if ( find_arg ( "-only-match" ) >= 0 || find_arg ( "-no-custom" ) >= 0 ) {
only_selected = TRUE;
if ( cmd_list_length == 0 ) {
return TRUE;
}
}
/* copy filter string */
input = g_strdup ( config.filter );
char *select = NULL;
find_arg_str ( "-select", &select );
if ( select != NULL ) {
char **tokens = tokenize ( select, config.case_sensitive );
unsigned int i = 0;
for ( i = 0; i < cmd_list_length; i++ ) {
if ( token_match ( tokens, cmd_list[i], config.case_sensitive, 0, NULL ) ) {
pd->selected_line = i;
break;
}
}
g_strfreev ( tokens );
}
do {
int next_pos = selected_line;
int mretv = menu ( list, length, &input, dmenu_prompt,
token_match, NULL, &selected_line, get_display_data, list, &next_pos, message );
unsigned int next_pos = pd->selected_line;
int mretv = menu ( &dmenu_mode, &input, pd->prompt,
&( pd->selected_line ), &next_pos, pd->message );
// Special behavior.
// TODO clean this up!
if ( only_selected ) {
@ -262,8 +329,8 @@ int dmenu_switcher_dialog ( void )
* Select item mode.
*/
restart = 1;
if ( ( mretv & ( MENU_OK | MENU_QUICK_SWITCH ) ) && list[selected_line] != NULL ) {
dmenu_output_formatted_line ( format, list[selected_line], selected_line, input );
if ( ( mretv & ( MENU_OK | MENU_QUICK_SWITCH ) ) && cmd_list[pd->selected_line] != NULL ) {
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
retv = TRUE;
if ( ( mretv & MENU_QUICK_SWITCH ) ) {
retv = 10 + ( mretv & MENU_LOWER_MASK );
@ -274,54 +341,51 @@ int dmenu_switcher_dialog ( void )
// In no custom mode we allow canceling.
restart = ( find_arg ( "-only-match" ) >= 0 );
}
selected_line = next_pos - 1;
pd->selected_line = next_pos - 1;
continue;
}
// We normally do not want to restart the loop.
restart = FALSE;
// Normal mode
if ( ( mretv & MENU_OK ) && list[selected_line] != NULL ) {
dmenu_output_formatted_line ( format, list[selected_line], selected_line, input );
if ( ( mretv & MENU_OK ) && cmd_list[pd->selected_line] != NULL ) {
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
if ( ( mretv & MENU_SHIFT ) ) {
restart = TRUE;
// Move to next line.
selected_line = MIN ( next_pos, length - 1 );
pd->selected_line = MIN ( next_pos, cmd_list_length - 1 );
}
retv = TRUE;
}
// Custom input
else if ( ( mretv & ( MENU_CUSTOM_INPUT ) ) ) {
dmenu_output_formatted_line ( format, input, -1, input );
dmenu_output_formatted_line ( pd->format, input, -1, input );
if ( ( mretv & MENU_SHIFT ) ) {
restart = TRUE;
// Move to next line.
selected_line = MIN ( next_pos, length - 1 );
pd->selected_line = MIN ( next_pos, cmd_list_length - 1 );
}
retv = TRUE;
}
// Quick switch with entry selected.
else if ( ( mretv & MENU_QUICK_SWITCH ) && selected_line >= 0 ) {
dmenu_output_formatted_line ( format, list[selected_line], selected_line, input );
else if ( ( mretv & MENU_QUICK_SWITCH ) && pd->selected_line >= 0 ) {
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
restart = FALSE;
retv = 10 + ( mretv & MENU_LOWER_MASK );
}
// Quick switch without entry selected.
else if ( ( mretv & MENU_QUICK_SWITCH ) && selected_line == -1 ) {
dmenu_output_formatted_line ( format, input, -1, input );
else if ( ( mretv & MENU_QUICK_SWITCH ) && pd->selected_line == -1 ) {
dmenu_output_formatted_line ( pd->format, input, -1, input );
restart = FALSE;
retv = 10 + ( mretv & MENU_LOWER_MASK );
}
} while ( restart );
g_strfreev ( list );
g_free ( urgent_list );
g_free ( active_list );
g_free ( input );
dmenu_mode.destroy ( &dmenu_mode );
return retv;
}

View File

@ -233,6 +233,7 @@ static Window create_window ( Display *display )
typedef struct MenuState
{
Switcher *sw;
unsigned int menu_lines;
unsigned int max_elements;
unsigned int max_rows;
@ -278,8 +279,6 @@ typedef struct MenuState
MenuReturn retv;
char **lines;
int line_height;
get_display_value mgrv;
void *mgrv_data;
}MenuState;
/**
@ -815,7 +814,7 @@ static void menu_draw ( MenuState *state )
{
TextBoxFontType type = ( ( ( i % state->max_rows ) & 1 ) == 0 ) ? NORMAL : ALT;
int fstate = 0;
const char *text = state->mgrv ( state->line_map[i + offset], state->mgrv_data, &fstate );
const char *text = state->sw->mgrv ( state->line_map[i + offset], state->sw, &fstate );
TextBoxFontType tbft = fstate | ( ( i + offset ) == state->selected ? HIGHLIGHT : type );
textbox_font ( state->boxes[i], tbft );
textbox_text ( state->boxes[i], text );
@ -830,7 +829,7 @@ static void menu_draw ( MenuState *state )
for ( i = 0; i < max_elements; i++ ) {
TextBoxFontType type = ( ( ( i % state->max_rows ) & 1 ) == 0 ) ? NORMAL : ALT;
int fstate = 0;
state->mgrv ( state->line_map[i + offset], state->mgrv_data, &fstate );
state->sw->mgrv ( state->line_map[i + offset], state->sw, &fstate );
TextBoxFontType tbft = fstate | ( ( i + offset ) == state->selected ? HIGHLIGHT : type );
textbox_font ( state->boxes[i], tbft );
textbox_draw ( state->boxes[i] );
@ -902,18 +901,18 @@ static void menu_paste ( MenuState *state, XSelectionEvent *xse )
}
}
MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prompt,
menu_match_cb mmc, void *mmc_data, int *selected_line,
get_display_value mgrv, void *mgrv_data, int *next_pos, const char *message )
MenuReturn menu ( Switcher *sw, char **input, char *prompt,
int *selected_line,
unsigned int *next_pos, const char *message )
{
int shift = FALSE;
MenuState state = {
.sw = sw,
.selected_line = selected_line,
.retv = MENU_CANCEL,
.prev_key = 0,
.last_button_press = 0,
.last_offset = 0,
.num_lines = num_lines,
.distance = NULL,
.quit = FALSE,
.skip_absorb = FALSE,
@ -924,11 +923,10 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
.update = FALSE,
.rchanged = TRUE,
.cur_page = -1,
.lines = lines,
.mgrv = mgrv,
.mgrv_data = mgrv_data,
.top_offset = 0
};
// Request the lines to show.
state.lines = sw->get_data ( &( state.num_lines ), sw );
unsigned int i;
if ( next_pos ) {
*next_pos = *selected_line;
@ -1086,7 +1084,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
state.selected = 0;
state.quit = FALSE;
menu_refilter ( &state, lines, mmc, mmc_data, config.levenshtein_sort, config.case_sensitive );
menu_refilter ( &state, state.lines, sw->token_match, sw, config.levenshtein_sort, config.case_sensitive );
for ( unsigned int i = 0; ( *( state.selected_line ) ) >= 0 && !state.selected && i < state.filtered_lines; i++ ) {
if ( state.line_map[i] == *( state.selected_line ) ) {
@ -1114,7 +1112,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
// If not in lazy mode, refilter.
if ( state.num_lines <= config.lazy_filter_limit ) {
if ( state.refilter ) {
menu_refilter ( &state, lines, mmc, mmc_data, config.levenshtein_sort, config.case_sensitive );
menu_refilter ( &state, state.lines, sw->token_match, sw, config.levenshtein_sort, config.case_sensitive );
menu_update ( &state );
}
}
@ -1122,7 +1120,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
// When timeout (and in lazy filter mode)
// We refilter then loop back and wait for Xevent.
if ( state.refilter ) {
menu_refilter ( &state, lines, mmc, mmc_data, config.levenshtein_sort, config.case_sensitive );
menu_refilter ( &state, state.lines, sw->token_match, sw, config.levenshtein_sort, config.case_sensitive );
menu_update ( &state );
}
}
@ -1301,6 +1299,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
void error_dialog ( const char *msg, int markup )
{
MenuState state = {
.sw = NULL,
.selected_line = NULL,
.retv = MENU_CANCEL,
.prev_key = 0,
@ -2065,19 +2064,9 @@ int main ( int argc, char *argv[] )
SwitcherMode switcher_run ( char **input, Switcher *sw )
{
char *prompt = g_strdup_printf ( "%s:", sw->name );
int selected_line = -1;
unsigned int cmd_list_length = 0;
char **cmd_list = NULL;
// get the list and get its length, before passing the length to menu
cmd_list = sw->get_data ( &cmd_list_length, sw );
int mretv = menu ( cmd_list, cmd_list_length, // List data.
input, prompt, // Input and prompt
sw->token_match, sw, // token match + arg.
&selected_line, // Selected line.
sw->mgrv, sw, NULL, NULL );
char *prompt = g_strdup_printf ( "%s:", sw->name );
int selected_line = -1;
int mretv = menu ( sw, input, prompt, &selected_line, NULL, NULL );
g_free ( prompt );
return sw->result ( mretv, input, selected_line, sw );