diff --git a/include/rofi.h b/include/rofi.h index 95fd06c6..69763325 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -93,5 +93,6 @@ const char * menu_state_get_user_input ( const MenuState *state ); void menu_state_free ( MenuState *state ); void menu_state_restart ( MenuState *state ); void menu_state_set_selected_line ( MenuState *state, unsigned int selected_line ); +void menu_state_queue_redraw ( void ); /*@}*/ #endif diff --git a/include/textbox.h b/include/textbox.h index ecc52784..c321eb47 100644 --- a/include/textbox.h +++ b/include/textbox.h @@ -36,6 +36,8 @@ typedef struct cairo_t *main_draw; int update; + int blink; + guint blink_timeout; } textbox; typedef enum diff --git a/source/rofi.c b/source/rofi.c index 3eb1f1b2..080dc3cf 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -64,7 +64,7 @@ #include "xrmoptions.h" #include "dialogs/dialogs.h" -ModeMode switcher_run ( char **input, Mode *sw ); +//ModeMode switcher_run ( char **input, Mode *sw ); typedef enum _MainLoopEvent { @@ -77,6 +77,7 @@ typedef struct _ModeHolder textbox *tb; } ModeHolder; +gboolean daemon_mode = FALSE; // Pidfile. extern Atom netatoms[NUM_NETATOMS]; char *pidfile = NULL; @@ -105,6 +106,8 @@ XIC xic; GThreadPool *tpool = NULL; GMainLoop *main_loop; +MenuState *current_active_menu = NULL; + static char * get_matching_state ( void ) { if ( config.case_sensitive ) { @@ -209,6 +212,14 @@ typedef struct MenuState void ( *x11_event_loop )( struct MenuState *state, XEvent *ev ); }MenuState; +void menu_state_queue_redraw ( void ) +{ + if ( current_active_menu ) { + current_active_menu->update = TRUE; + XClearArea ( display, main_window, 0, 0, 1, 1, True ); + XFlush ( display ); + } +} static MenuState *menu_state_create ( void ) { return g_malloc0 ( sizeof ( MenuState ) ); @@ -1643,6 +1654,7 @@ MenuState *menu ( Mode *sw, XMoveResizeWindow ( display, main_window, state->x, state->y, state->w, state->h ); cairo_xlib_surface_set_size ( surface, state->w, state->h ); XMapRaised ( display, main_window ); + XFlush ( display ); // if grabbing keyboard failed, fall through state->selected = 0; @@ -1806,14 +1818,14 @@ static int run_dmenu () return ret_state; } +static int pfd = -1; static void run_switcher ( ModeMode mode ) { - int pfd = setup (); + pfd = setup (); if ( pfd < 0 ) { return; } // Otherwise check if requested mode is enabled. - char *input = g_strdup ( config.filter ); for ( unsigned int i = 0; i < num_modi; i++ ) { if ( !mode_init ( modi[i].sw ) ) { error_dialog ( ERROR_MSG ( "Failed to initialize all the modi." ), ERROR_MSG_MARKUP ); @@ -1821,39 +1833,64 @@ static void run_switcher ( ModeMode mode ) return; } } - do { - ModeMode retv; + char *input = g_strdup ( config.filter ); + char *prompt = g_strdup_printf ( "%s:", mode_get_name ( modi[mode].sw ) ); + MenuState * state = menu ( modi[mode].sw, input, prompt, NULL, MENU_NORMAL ); + current_active_menu = state; + g_free ( prompt ); +} +static void process_result () +{ + MenuState * state = current_active_menu; + unsigned int selected_line = menu_state_get_selected_line ( state );; + MenuReturn mretv = menu_state_get_return_value ( state ); + char *input = g_strdup ( menu_state_get_user_input ( state ) ); + menu_state_free ( state ); + current_active_menu = NULL; + ModeMode retv = mode_result ( modi[curr_switcher].sw, mretv, &input, selected_line ); - curr_switcher = mode; - retv = switcher_run ( &input, modi[mode].sw ); - // Find next enabled - if ( retv == NEXT_DIALOG ) { - mode = ( mode + 1 ) % num_modi; - } - else if ( retv == PREVIOUS_DIALOG ) { - if ( mode == 0 ) { - mode = num_modi - 1; - } - else { - mode = ( mode - 1 ) % num_modi; - } - } - else if ( retv == RELOAD_DIALOG ) { - // do nothing. - } - else if ( retv < MODE_EXIT ) { - mode = ( retv ) % num_modi; + ModeMode mode = curr_switcher; + // Find next enabled + if ( retv == NEXT_DIALOG ) { + mode = ( mode + 1 ) % num_modi; + } + else if ( retv == PREVIOUS_DIALOG ) { + if ( mode == 0 ) { + mode = num_modi - 1; } else { - mode = retv; + mode = ( mode - 1 ) % num_modi; } - } while ( mode != MODE_EXIT ); + } + else if ( retv == RELOAD_DIALOG ) { + // do nothing. + } + else if ( retv < MODE_EXIT ) { + mode = ( retv ) % num_modi; + } + else { + mode = retv; + } + if ( mode != MODE_EXIT ) { + char *prompt = g_strdup_printf ( "%s:", mode_get_name ( modi[mode].sw ) ); + MenuState * state = menu ( modi[mode].sw, input, prompt, NULL, MENU_NORMAL ); + g_free ( prompt ); + // TODO FIX + //g_return_val_if_fail ( state != NULL, MODE_EXIT ); + current_active_menu = state; + g_free ( input ); + return; + } + // Cleanup g_free ( input ); for ( unsigned int i = 0; i < num_modi; i++ ) { mode_destroy ( modi[i].sw ); } // cleanup teardown ( pfd ); + if ( !daemon_mode ) { + g_main_loop_quit ( main_loop ); + } } int show_error_message ( const char *msg, int markup ) @@ -2123,6 +2160,19 @@ static void reload_configuration () */ static gboolean main_loop_x11_event_handler ( G_GNUC_UNUSED gpointer data ) { + if ( current_active_menu != NULL ) { + while ( XPending ( display ) ) { + XEvent ev; + // Read event, we know this won't block as we checked with XPending. + XNextEvent ( display, &ev ); + menu_state_itterrate ( current_active_menu, &ev ); + } + if ( menu_state_get_completed ( current_active_menu ) ) { + // This menu is done. + process_result (); + } + return G_SOURCE_CONTINUE; + } // X11 produced an event. Consume them. while ( XPending ( display ) ) { XEvent ev; @@ -2175,32 +2225,6 @@ static gboolean main_loop_signal_handler_usr1 ( G_GNUC_UNUSED gpointer data ) return G_SOURCE_CONTINUE; } -ModeMode switcher_run ( char **input, Mode *sw ) -{ - char *prompt = g_strdup_printf ( "%s:", mode_get_name ( sw ) ); - MenuState * state = menu ( sw, *input, prompt, NULL, MENU_NORMAL ); - g_free ( prompt ); - g_return_val_if_fail ( state != NULL, MODE_EXIT ); - - // Enter main loop. - while ( !menu_state_get_completed ( state ) ) { - // Wait for event. - XEvent ev; - // Get next event. (might block) - XNextEvent ( display, &ev ); - TICK_N ( "X Event" ); - menu_state_itterrate ( state, &ev ); - } - // Update input string. - g_free ( *input ); - *input = g_strdup ( menu_state_get_user_input ( state ) ); - - unsigned int selected_line = menu_state_get_selected_line ( state );; - MenuReturn mretv = menu_state_get_return_value ( state ); - menu_state_free ( state ); - return mode_result ( sw, mretv, input, selected_line ); -} - static int error_trap_depth = 0; static void error_trap_push ( G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED Display *xdisplay ) { @@ -2217,7 +2241,14 @@ static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, Display *xdispl XSync ( xdisplay, False ); /* get all errors out of the queue */ --error_trap_depth; } - +static gboolean delayed_start ( gpointer data ) +{ + if ( XPending ( display ) ) { + main_loop_x11_event_handler ( NULL ); + } + // menu_state_queue_redraw(); + return FALSE; +} int main ( int argc, char *argv[] ) { TIMINGS_START (); @@ -2400,7 +2431,27 @@ int main ( int argc, char *argv[] ) if ( find_arg_str ( "-show", &sname ) == TRUE ) { int index = switcher_get ( sname ); if ( index >= 0 ) { + main_loop = g_main_loop_new ( NULL, FALSE ); + GSource *source = x11_event_source_new ( display ); + x11_event_source_set_callback ( source, main_loop_x11_event_handler ); + + // Setup signal handling sources. + // SIGHup signal. + g_unix_signal_add ( SIGHUP, main_loop_signal_handler_hup, NULL ); + // SIGTERM + g_unix_signal_add ( SIGINT, main_loop_signal_handler_int, NULL ); + // SIGUSR1 + g_unix_signal_add ( SIGUSR1, main_loop_signal_handler_usr1, NULL ); + + // TODO delay this till mainloop is running or we might miss X events. run_switcher ( index ); + g_idle_add ( delayed_start, GINT_TO_POINTER ( index ) ); + // Start mainloop. + g_main_loop_run ( main_loop ); + + // Cleanup + g_source_unref ( (GSource *) source ); + g_main_loop_unref ( main_loop ); } else { fprintf ( stderr, "The %s switcher has not been enabled\n", sname ); @@ -2428,6 +2479,7 @@ int main ( int argc, char *argv[] ) if ( sncontext != NULL ) { sn_launchee_context_complete ( sncontext ); } + daemon_mode = TRUE; // Application Main loop. // This listens in the background for any events on the Xserver // catching global key presses. diff --git a/source/textbox.c b/source/textbox.c index 6a2ee40e..6b992c65 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -59,6 +59,17 @@ typedef struct _RowColor RowColor colors[num_states]; PangoContext *p_context = NULL; +static gboolean textbox_blink ( textbox *tb ) +{ + if ( tb->blink < 2) { + tb->blink = !tb->blink; + tb->update = TRUE; + menu_state_queue_redraw ( ); + } else { + tb->blink--; + } + return TRUE; +} textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h, TextBoxFontType tbft, const char *text ) @@ -88,6 +99,12 @@ textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h // auto height/width modes get handled here textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h ); + tb->blink_timeout = 0; + tb->blink = 1; + if ( ( flags & TB_EDITABLE ) == TB_EDITABLE ) { + tb->blink_timeout = g_timeout_add ( 1200, textbox_blink, tb ); + } + return tb; } @@ -218,6 +235,10 @@ void textbox_free ( textbox *tb ) if ( tb == NULL ) { return; } + if ( tb->blink_timeout > 0 ) { + g_source_remove ( tb->blink_timeout ); + tb->blink_timeout = 0; + } g_free ( tb->text ); @@ -304,7 +325,7 @@ static void texbox_update ( textbox *tb ) col = tb->color_fg; cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha * scale ); // draw the cursor - if ( tb->flags & TB_EDITABLE ) { + if ( tb->flags & TB_EDITABLE && tb->blink ) { cairo_rectangle ( tb->main_draw, x + cursor_x, y, cursor_width, font_height ); cairo_fill ( tb->main_draw ); } @@ -512,6 +533,8 @@ int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym k if ( !( tb->flags & TB_EDITABLE ) ) { return 0; } + int old_blink = tb->blink; + tb->blink = 2; if ( stat == XLookupKeySym || stat == XLookupBoth ) { // Left or Ctrl-b if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { @@ -586,7 +609,7 @@ int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym k return 1; } } - + tb->blink = old_blink; return 0; } diff --git a/source/x11-event-source.c b/source/x11-event-source.c index 7280a134..962070e5 100644 --- a/source/x11-event-source.c +++ b/source/x11-event-source.c @@ -18,7 +18,7 @@ static gboolean x11_event_source_prepare ( GSource * base, gint * timeout ) { X11EventSource *xs = (X11EventSource *) base; *timeout = -1; - return XPending ( xs->display ); + return XPending ( xs->display ) || g_source_query_unix_fd ( base, xs->fd_x11 ); } static gboolean x11_event_source_check ( GSource * base ) diff --git a/test/textbox-test.c b/test/textbox-test.c index e9d86c94..c7aa58e9 100644 --- a/test/textbox-test.c +++ b/test/textbox-test.c @@ -25,6 +25,9 @@ unsigned int normal_window_mode = 0; Display *display = NULL; Colormap map = None; XVisualInfo vinfo; +void menu_state_queue_redraw () +{ +} void error_dialog ( const char *msg, G_GNUC_UNUSED int markup ) {