diff --git a/doc/rofi-manpage.markdown b/doc/rofi-manpage.markdown index 49a9578e..c0c3fd2a 100644 --- a/doc/rofi-manpage.markdown +++ b/doc/rofi-manpage.markdown @@ -11,7 +11,7 @@ rofi - A window switcher, run dialog and dmenu replacement [ -terminal *terminal* ] [ -location *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 ] [ -show *mode* ] [ -switcher *mode1,mode2* ] +[ -disable-history ] [ -levenshtein-sort ] [ -show *mode* ] [ -switcher *mode1,mode2* ] [ -e *message*] ## DESCRIPTION @@ -256,6 +256,9 @@ The default key combinations are: rofi -switchers "window,run,ssh,Workspaces:i3_switch_workspaces.sh" -show Workspaces +`-e` *message* + + Popup a message dialog (used internally for showing errors) with *message*. ## Keybindings diff --git a/include/rofi.h b/include/rofi.h index 9d45c70f..dd8cd9cc 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -132,4 +132,6 @@ int token_match ( char **tokens, const char *input, __attribute__( ( unused ) ) int index, __attribute__( ( unused ) ) void *data ); + +void error_dialog ( char *msg ); #endif diff --git a/source/rofi.c b/source/rofi.c index 2b8e01fb..117259c3 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -1070,12 +1070,14 @@ static void menu_calculate_window_and_element_width ( MenuState *state, workarea state->w -= config.menu_bw * 2; } - state->element_width = state->w - ( 2 * ( config.padding ) ); - // Divide by the # columns - state->element_width = ( state->element_width - ( state->columns - 1 ) * LINE_MARGIN ) / state->columns; - if ( config.hmode == TRUE ) { - state->element_width = ( state->w - ( 2 * ( config.padding ) ) - state->max_elements * LINE_MARGIN ) / ( - state->max_elements + 1 ); + if(state->columns > 0 ) { + state->element_width = state->w - ( 2 * ( config.padding ) ); + // Divide by the # columns + state->element_width = ( state->element_width - ( state->columns - 1 ) * LINE_MARGIN ) / state->columns; + if ( config.hmode == TRUE ) { + state->element_width = ( state->w - ( 2 * ( config.padding ) ) - state->max_elements * LINE_MARGIN ) / ( + state->max_elements + 1 ); + } } } @@ -1410,6 +1412,7 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom .init = TRUE, .quit = FALSE, .filtered_lines = 0, + .max_elements = 0, // We want to filter on the first run. .refilter = TRUE, .update = FALSE @@ -1661,6 +1664,91 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom return state.retv; } +void error_dialog ( char *msg ) +{ + MenuState state = { + .selected_line = NULL, + .retv = MENU_CANCEL, + .prev_key = 0, + .last_button_press = 0, + .last_offset = 0, + .num_lines = 0, + .distance = NULL, + .init = FALSE, + .quit = FALSE, + .filtered_lines = 0, + .columns = 0, + .update =TRUE, + }; + workarea mon; + // Get active monitor size. + monitor_active ( &mon ); + // main window isn't explicitly destroyed in case we switch modes. Reusing it prevents flicker + XWindowAttributes attr; + if ( main_window == None || XGetWindowAttributes ( display, main_window, &attr ) == 0 ) { + main_window = create_window ( display ); + } + + + menu_calculate_window_and_element_width ( &state, &mon ); + state.max_elements = 0; + + state.text = textbox_create ( main_window, TB_AUTOHEIGHT, + ( config.padding ), + ( config.padding ), + ( state.w - ( 2 * ( config.padding ) ) ), + 1, + NORMAL, + ( msg != NULL ) ? msg : "" ); + textbox_show ( state.text ); + int line_height = textbox_get_height ( state.text ); + + // resize window vertically to suit + // Subtract the margin of the last row. + state.h = line_height * ( state.max_rows + 1 ) + ( config.padding ) * 2 + LINE_MARGIN; + if ( config.hmode == TRUE ) { + state.h = line_height + ( config.padding ) * 2; + } + + // Move the window to the correct x,y position. + calculate_window_position ( &state, &mon ); + XMoveResizeWindow ( display, main_window, state.x, state.y, state.w, state.h ); + + // Display it. + XMapRaised ( display, main_window ); + + if ( take_keyboard ( main_window ) ) { + + while(!state.quit) { + // Update if requested. + if ( state.update ) { + textbox_draw ( state.text ); + state.update = FALSE; + } + // Wait for event. + XEvent ev; + XNextEvent ( display, &ev ); + + + // Handle event. + if ( ev.type == Expose ) { + while ( XCheckTypedEvent ( display, Expose, &ev ) ) { + ; + } + state.update = TRUE; + } + // Key press event. + else if ( ev.type == KeyPress ) { + while ( XCheckTypedEvent ( display, KeyPress, &ev ) ) { + ; + } + state.quit = TRUE; + } + } + release_keyboard (); + } + +} SwitcherMode run_switcher_window ( char **input, G_GNUC_UNUSED void *data ) { Screen *screen = DefaultScreenOfDisplay ( display ); @@ -2276,6 +2364,17 @@ int main ( int argc, char *argv[] ) display_get_i3_path ( display ); #endif + char *msg = NULL; + if ( find_arg_str ( argc, argv, "-e", &(msg) ) ) { + textbox_setup ( + config.menu_bg, config.menu_fg, + config.menu_hlbg, + config.menu_hlfg ); + error_dialog(msg); + textbox_cleanup (); + exit (EXIT_SUCCESS); + } + // flags to run immediately and exit char *sname = NULL; diff --git a/source/run-dialog.c b/source/run-dialog.c index c3dace60..d7e57f4f 100644 --- a/source/run-dialog.c +++ b/source/run-dialog.c @@ -60,9 +60,19 @@ static inline void execsh ( const char *cmd, int run_in_term ) args[i++] = g_strdup ( cmd ); args[i++] = NULL; + GError *error = NULL; g_spawn_async ( NULL, args, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, NULL ); + NULL, NULL, 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); + } // Free the args list. g_strfreev ( args ); diff --git a/source/script-dialog.c b/source/script-dialog.c index 8654c4f4..32172cdf 100644 --- a/source/script-dialog.c +++ b/source/script-dialog.c @@ -48,6 +48,7 @@ pid_t execute_generator ( char * cmd ) args[3] = NULL; int fd = -1; + GError *error = NULL; g_spawn_async_with_pipes ( NULL, args, NULL, @@ -56,7 +57,17 @@ pid_t execute_generator ( char * cmd ) NULL, NULL, NULL, &fd, NULL, - 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; } diff --git a/source/ssh-dialog.c b/source/ssh-dialog.c index 33ef03af..133e62ae 100644 --- a/source/ssh-dialog.c +++ b/source/ssh-dialog.c @@ -65,10 +65,20 @@ static inline int execshssh ( const char *host ) args[i++] = g_strdup ( host ); args[i++] = NULL; + GError *error = NULL; g_spawn_async ( NULL, args, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, NULL ); + NULL, NULL, NULL, &error ); + if( error != NULL ) + { + char *msg = g_strdup_printf("Failed to execute: 'ssh %s'\nError: '%s'", host, + error->message); + error_dialog(msg); + g_free(msg); + // print error. + g_error_free(error); + } // Free the args list. g_strfreev ( args );