1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-18 13:54:36 -05:00

First rough version of async loading for dmenu.

This commit is contained in:
Dave Davenport 2016-09-17 18:57:44 +02:00
parent 6191662ccf
commit 5ee5bb1e23
3 changed files with 86 additions and 46 deletions

View file

@ -75,7 +75,7 @@ dnl ---------------------------------------------------------------------
dnl Check for C functions. dnl Check for C functions.
dnl --------------------------------------------------------------------- dnl ---------------------------------------------------------------------
AC_CHECK_FUNC([getline],, AC_MSG_ERROR("Could not find getline in c library")) AC_CHECK_FUNC([getline],, AC_MSG_ERROR("Could not find getline in c library"))
AC_CHECK_FUNC([getdelim],, AC_MSG_ERROR("Could not find getdelim in c library")) AC_CHECK_FUNC([open],, AC_MSG_ERROR("Could not find open in c library"))
AC_CHECK_FUNC([sysconf],, AC_MSG_ERROR("Could not find sysconf")) AC_CHECK_FUNC([sysconf],, AC_MSG_ERROR("Could not find sysconf"))
AC_CHECK_FUNC([getenv],, AC_MSG_ERROR("Could not find getenv")) AC_CHECK_FUNC([getenv],, AC_MSG_ERROR("Could not find getenv"))
AC_CHECK_FUNC([strtok_r],, AC_MSG_ERROR("Could not find strtok_r")) AC_CHECK_FUNC([strtok_r],, AC_MSG_ERROR("Could not find strtok_r"))
@ -93,7 +93,7 @@ PKG_PROG_PKG_CONFIG
dnl --------------------------------------------------------------------- dnl ---------------------------------------------------------------------
dnl PKG_CONFIG based dependencies dnl PKG_CONFIG based dependencies
dnl --------------------------------------------------------------------- dnl ---------------------------------------------------------------------
PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40]) PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40 gio-unix-2.0])
GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon >= 0.5.0 xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-randr xcb-xinerama]) GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon >= 0.5.0 xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-randr xcb-xinerama])
PKG_CHECK_MODULES([pango], [pango pangocairo]) PKG_CHECK_MODULES([pango], [pango pangocairo])
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb]) PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])

View file

@ -34,6 +34,11 @@
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "rofi.h" #include "rofi.h"
#include "settings.h" #include "settings.h"
#include "textbox.h" #include "textbox.h"
@ -41,8 +46,8 @@
#include "helper.h" #include "helper.h"
#include "xrmoptions.h" #include "xrmoptions.h"
#include "view.h" #include "view.h"
// We limit at 1000000 rows for now.
#define DMENU_MAX_ROWS 1000000 #define LOG_DOMAIN "Dialogs.DMenu"
struct range_pair struct range_pair
{ {
@ -84,6 +89,7 @@ typedef struct
unsigned int do_markup; unsigned int do_markup;
// List with entries. // List with entries.
char **cmd_list; char **cmd_list;
unsigned int cmd_list_real_length;
unsigned int cmd_list_length; unsigned int cmd_list_length;
unsigned int only_selected; unsigned int only_selected;
unsigned int selected_count; unsigned int selected_count;
@ -91,47 +97,62 @@ typedef struct
gchar **columns; gchar **columns;
gchar *column_separator; gchar *column_separator;
gboolean multi_select; gboolean multi_select;
GCancellable *cancel;
gulong cancel_source;
GInputStream *input_stream;
GDataInputStream *data_input_stream;
} DmenuModePrivateData; } DmenuModePrivateData;
static char **get_dmenu ( DmenuModePrivateData *pd, FILE *fd, unsigned int *length ) static void async_close_callback ( GObject *source_object, GAsyncResult *res, G_GNUC_UNUSED gpointer user_data )
{ {
TICK_N ( "Read stdin START" ); g_input_stream_close_finish ( G_INPUT_STREAM ( source_object ), res, NULL );
char **retv = NULL; g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Closing data stream." );
unsigned int rvlength = 1; }
*length = 0; static void async_read_callback ( GObject *source_object, GAsyncResult *res, gpointer user_data )
gchar *data = NULL; {
size_t data_l = 0; GDataInputStream *stream = (GDataInputStream *) source_object;
ssize_t l = 0; DmenuModePrivateData *pd = (DmenuModePrivateData *) user_data;
while ( ( l = getdelim ( &data, &data_l, pd->separator, fd ) ) > 0 ) { gsize len;
if ( rvlength < ( *length + 2 ) ) { char *data = g_data_input_stream_read_upto_finish ( stream, res, &len, NULL );
rvlength *= 2;
retv = g_realloc ( retv, ( rvlength ) * sizeof ( char* ) );
}
if ( data[l - 1] == pd->separator ) {
data[l - 1] = '\0';
l--;
}
char *utfstr = rofi_force_utf8 ( data, l );
retv[( *length )] = utfstr;
( *length )++;
// Stop when we hit 2³¹ entries.
if ( ( *length ) >= DMENU_MAX_ROWS ) {
break;
}
}
if ( data != NULL ) { if ( data != NULL ) {
free ( data ); // Absorb separator, already in buffer so should not block.
data = NULL; g_data_input_stream_read_byte ( stream, NULL, NULL );
if ( ( pd->cmd_list_length + 2 ) > pd->cmd_list_real_length ) {
pd->cmd_list_real_length = MAX ( pd->cmd_list_real_length * 2, 512 );
pd->cmd_list = g_realloc ( pd->cmd_list, ( pd->cmd_list_real_length ) * sizeof ( char* ) );
}
char *utfstr = rofi_force_utf8 ( data, len );
pd->cmd_list[pd->cmd_list_length] = utfstr;
pd->cmd_list[pd->cmd_list_length + 1] = NULL;
g_free ( data );
pd->cmd_list_length++;
rofi_view_reload ();
g_data_input_stream_read_upto_async ( pd->data_input_stream, &( pd->separator ), 1, G_PRIORITY_DEFAULT, pd->cancel,
async_read_callback, pd );
return;
} }
if ( retv != NULL ) { if ( !g_cancellable_is_cancelled ( pd->cancel ) ) {
retv = g_realloc ( retv, ( *length + 1 ) * sizeof ( char* ) ); // Hack, don't use get active.
retv[( *length ) ] = NULL; rofi_view_set_overlay ( rofi_view_get_active (), NULL );
g_input_stream_close_async ( G_INPUT_STREAM ( stream ), G_PRIORITY_DEFAULT, pd->cancel, async_close_callback, pd );
} }
TICK_N ( "Read stdin STOP" ); }
return retv;
static void async_read_cancel ( G_GNUC_UNUSED GCancellable *cancel, G_GNUC_UNUSED gpointer data )
{
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Cancelled the async read." );
}
static void get_dmenu ( DmenuModePrivateData *pd )
{
g_data_input_stream_read_upto_async ( pd->data_input_stream, &( pd->separator ), 1, G_PRIORITY_DEFAULT, pd->cancel,
async_read_callback, pd );
} }
static unsigned int dmenu_mode_get_num_entries ( const Mode *sw ) static unsigned int dmenu_mode_get_num_entries ( const Mode *sw )
@ -287,6 +308,21 @@ static void dmenu_mode_free ( Mode *sw )
} }
DmenuModePrivateData *pd = (DmenuModePrivateData *) mode_get_private_data ( sw ); DmenuModePrivateData *pd = (DmenuModePrivateData *) mode_get_private_data ( sw );
if ( pd != NULL ) { if ( pd != NULL ) {
if ( pd->cancel ) {
// If open, cancel reads.
if ( pd->input_stream && !g_input_stream_is_closed ( pd->input_stream ) ) {
g_cancellable_cancel ( pd->cancel );
}
// This blocks until cancel is done.
g_cancellable_disconnect ( pd->cancel, pd->cancel_source );
if ( pd->input_stream ) {
// Should close the stream if not yet done.
g_object_unref ( pd->data_input_stream );
g_object_unref ( pd->input_stream );
}
g_object_unref ( pd->cancel );
}
for ( size_t i = 0; i < pd->cmd_list_length; i++ ) { for ( size_t i = 0; i < pd->cmd_list_length; i++ ) {
if ( pd->cmd_list[i] ) { if ( pd->cmd_list[i] ) {
free ( pd->cmd_list[i] ); free ( pd->cmd_list[i] );
@ -355,12 +391,12 @@ static int dmenu_mode_init ( Mode *sw )
if ( find_arg ( "-i" ) >= 0 ) { if ( find_arg ( "-i" ) >= 0 ) {
config.case_sensitive = FALSE; config.case_sensitive = FALSE;
} }
FILE *fd = NULL; int fd = STDIN_FILENO;
str = NULL; str = NULL;
if ( find_arg_str ( "-input", &str ) ) { if ( find_arg_str ( "-input", &str ) ) {
char *estr = rofi_expand_path ( str ); char *estr = rofi_expand_path ( str );
fd = fopen ( str, "r" ); fd = open ( str, O_RDONLY );
if ( fd == NULL ) { if ( fd < 0 ) {
char *msg = g_markup_printf_escaped ( "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr, strerror ( errno ) ); char *msg = g_markup_printf_escaped ( "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr, strerror ( errno ) );
rofi_view_error_dialog ( msg, TRUE ); rofi_view_error_dialog ( msg, TRUE );
g_free ( msg ); g_free ( msg );
@ -369,10 +405,12 @@ static int dmenu_mode_init ( Mode *sw )
} }
g_free ( estr ); g_free ( estr );
} }
pd->cmd_list = get_dmenu ( pd, fd == NULL ? stdin : fd, &( pd->cmd_list_length ) ); pd->cancel = g_cancellable_new ();
if ( fd != NULL ) { pd->cancel_source = g_cancellable_connect ( pd->cancel, G_CALLBACK ( async_read_cancel ), pd, NULL );
fclose ( fd ); pd->input_stream = g_unix_input_stream_new ( fd, fd != STDIN_FILENO );
} pd->data_input_stream = g_data_input_stream_new ( pd->input_stream );
get_dmenu ( pd );
gchar *columns = NULL; gchar *columns = NULL;
if ( find_arg_str ( "-display-columns", &columns ) ) { if ( find_arg_str ( "-display-columns", &columns ) ) {
@ -597,8 +635,9 @@ int dmenu_switcher_dialog ( void )
g_free ( input ); g_free ( input );
return TRUE; return TRUE;
} }
// TODO remove
RofiViewState *state = rofi_view_create ( &dmenu_mode, input, pd->prompt, pd->message, menu_flags, dmenu_finalize ); RofiViewState *state = rofi_view_create ( &dmenu_mode, input, pd->prompt, pd->message, menu_flags, dmenu_finalize );
// @TODO we should do this better.
rofi_view_set_overlay ( state, "Loading.. " );
rofi_view_set_selected_line ( state, pd->selected_line ); rofi_view_set_selected_line ( state, pd->selected_line );
rofi_view_set_active ( state ); rofi_view_set_active ( state );

View file

@ -250,6 +250,7 @@ static gboolean rofi_view_reload_idle ( G_GNUC_UNUSED gpointer data )
void rofi_view_reload ( void ) void rofi_view_reload ( void )
{ {
// @TODO add check if current view is equal to the callee
if ( CacheState.idle_timeout == 0 ) { if ( CacheState.idle_timeout == 0 ) {
CacheState.idle_timeout = g_timeout_add ( 1000 / 10, rofi_view_reload_idle, NULL ); CacheState.idle_timeout = g_timeout_add ( 1000 / 10, rofi_view_reload_idle, NULL );
} }