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:
parent
6191662ccf
commit
5ee5bb1e23
3 changed files with 86 additions and 46 deletions
|
@ -75,7 +75,7 @@ dnl ---------------------------------------------------------------------
|
|||
dnl Check for C functions.
|
||||
dnl ---------------------------------------------------------------------
|
||||
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([getenv],, AC_MSG_ERROR("Could not find getenv"))
|
||||
AC_CHECK_FUNC([strtok_r],, AC_MSG_ERROR("Could not find strtok_r"))
|
||||
|
@ -93,7 +93,7 @@ PKG_PROG_PKG_CONFIG
|
|||
dnl ---------------------------------------------------------------------
|
||||
dnl PKG_CONFIG based dependencies
|
||||
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])
|
||||
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
||||
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
#include <ctype.h>
|
||||
#include <stdint.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 "settings.h"
|
||||
#include "textbox.h"
|
||||
|
@ -41,8 +46,8 @@
|
|||
#include "helper.h"
|
||||
#include "xrmoptions.h"
|
||||
#include "view.h"
|
||||
// We limit at 1000000 rows for now.
|
||||
#define DMENU_MAX_ROWS 1000000
|
||||
|
||||
#define LOG_DOMAIN "Dialogs.DMenu"
|
||||
|
||||
struct range_pair
|
||||
{
|
||||
|
@ -84,6 +89,7 @@ typedef struct
|
|||
unsigned int do_markup;
|
||||
// List with entries.
|
||||
char **cmd_list;
|
||||
unsigned int cmd_list_real_length;
|
||||
unsigned int cmd_list_length;
|
||||
unsigned int only_selected;
|
||||
unsigned int selected_count;
|
||||
|
@ -91,47 +97,62 @@ typedef struct
|
|||
gchar **columns;
|
||||
gchar *column_separator;
|
||||
gboolean multi_select;
|
||||
|
||||
GCancellable *cancel;
|
||||
gulong cancel_source;
|
||||
GInputStream *input_stream;
|
||||
GDataInputStream *data_input_stream;
|
||||
} 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" );
|
||||
char **retv = NULL;
|
||||
unsigned int rvlength = 1;
|
||||
g_input_stream_close_finish ( G_INPUT_STREAM ( source_object ), res, NULL );
|
||||
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Closing data stream." );
|
||||
}
|
||||
|
||||
*length = 0;
|
||||
gchar *data = NULL;
|
||||
size_t data_l = 0;
|
||||
ssize_t l = 0;
|
||||
while ( ( l = getdelim ( &data, &data_l, pd->separator, fd ) ) > 0 ) {
|
||||
if ( rvlength < ( *length + 2 ) ) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
static void async_read_callback ( GObject *source_object, GAsyncResult *res, gpointer user_data )
|
||||
{
|
||||
GDataInputStream *stream = (GDataInputStream *) source_object;
|
||||
DmenuModePrivateData *pd = (DmenuModePrivateData *) user_data;
|
||||
gsize len;
|
||||
char *data = g_data_input_stream_read_upto_finish ( stream, res, &len, NULL );
|
||||
if ( data != NULL ) {
|
||||
free ( data );
|
||||
data = NULL;
|
||||
// Absorb separator, already in buffer so should not block.
|
||||
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 ) {
|
||||
retv = g_realloc ( retv, ( *length + 1 ) * sizeof ( char* ) );
|
||||
retv[( *length ) ] = NULL;
|
||||
if ( !g_cancellable_is_cancelled ( pd->cancel ) ) {
|
||||
// Hack, don't use get active.
|
||||
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 )
|
||||
|
@ -287,6 +308,21 @@ static void dmenu_mode_free ( Mode *sw )
|
|||
}
|
||||
DmenuModePrivateData *pd = (DmenuModePrivateData *) mode_get_private_data ( sw );
|
||||
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++ ) {
|
||||
if ( 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 ) {
|
||||
config.case_sensitive = FALSE;
|
||||
}
|
||||
FILE *fd = NULL;
|
||||
int fd = STDIN_FILENO;
|
||||
str = NULL;
|
||||
if ( find_arg_str ( "-input", &str ) ) {
|
||||
char *estr = rofi_expand_path ( str );
|
||||
fd = fopen ( str, "r" );
|
||||
if ( fd == NULL ) {
|
||||
fd = open ( str, O_RDONLY );
|
||||
if ( fd < 0 ) {
|
||||
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 );
|
||||
g_free ( msg );
|
||||
|
@ -369,10 +405,12 @@ static int dmenu_mode_init ( Mode *sw )
|
|||
}
|
||||
g_free ( estr );
|
||||
}
|
||||
pd->cmd_list = get_dmenu ( pd, fd == NULL ? stdin : fd, &( pd->cmd_list_length ) );
|
||||
if ( fd != NULL ) {
|
||||
fclose ( fd );
|
||||
}
|
||||
pd->cancel = g_cancellable_new ();
|
||||
pd->cancel_source = g_cancellable_connect ( pd->cancel, G_CALLBACK ( async_read_cancel ), pd, NULL );
|
||||
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;
|
||||
if ( find_arg_str ( "-display-columns", &columns ) ) {
|
||||
|
@ -597,8 +635,9 @@ int dmenu_switcher_dialog ( void )
|
|||
g_free ( input );
|
||||
return TRUE;
|
||||
}
|
||||
// TODO remove
|
||||
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_active ( state );
|
||||
|
||||
|
|
|
@ -250,6 +250,7 @@ static gboolean rofi_view_reload_idle ( G_GNUC_UNUSED gpointer data )
|
|||
|
||||
void rofi_view_reload ( void )
|
||||
{
|
||||
// @TODO add check if current view is equal to the callee
|
||||
if ( CacheState.idle_timeout == 0 ) {
|
||||
CacheState.idle_timeout = g_timeout_add ( 1000 / 10, rofi_view_reload_idle, NULL );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue