mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
Test a first glib mainloop.
This commit is contained in:
parent
94cbe3a005
commit
80a6aa4549
2 changed files with 113 additions and 161 deletions
|
@ -40,15 +40,15 @@ typedef struct
|
|||
|
||||
typedef enum
|
||||
{
|
||||
TB_AUTOHEIGHT = 1 << 0,
|
||||
TB_AUTOWIDTH = 1 << 1,
|
||||
TB_LEFT = 1 << 16,
|
||||
TB_RIGHT = 1 << 17,
|
||||
TB_CENTER = 1 << 18,
|
||||
TB_EDITABLE = 1 << 19,
|
||||
TB_MARKUP = 1 << 20,
|
||||
TB_WRAP = 1 << 21,
|
||||
TB_PASSWORD = 1 << 22,
|
||||
TB_AUTOHEIGHT = 1 << 0,
|
||||
TB_AUTOWIDTH = 1 << 1,
|
||||
TB_LEFT = 1 << 16,
|
||||
TB_RIGHT = 1 << 17,
|
||||
TB_CENTER = 1 << 18,
|
||||
TB_EDITABLE = 1 << 19,
|
||||
TB_MARKUP = 1 << 20,
|
||||
TB_WRAP = 1 << 21,
|
||||
TB_PASSWORD = 1 << 22,
|
||||
} TextboxFlags;
|
||||
|
||||
typedef enum
|
||||
|
|
256
source/rofi.c
256
source/rofi.c
|
@ -45,6 +45,8 @@
|
|||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <cairo-xlib.h>
|
||||
|
||||
|
@ -100,6 +102,7 @@ XIM xim;
|
|||
XIC xic;
|
||||
|
||||
GThreadPool *tpool = NULL;
|
||||
GMainLoop *main_loop;
|
||||
|
||||
static char * get_matching_state ( void )
|
||||
{
|
||||
|
@ -2157,68 +2160,6 @@ static void reload_configuration ()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Separate thread that handles signals being send to rofi.
|
||||
* Currently it listens for three signals:
|
||||
* * HUP: reload the configuration.
|
||||
* * INT: Quit the program.
|
||||
* * USR1: Dump the current configuration to stdout.
|
||||
*
|
||||
* These messages are relayed to the main thread via a pipe, the write side of the pipe is passed
|
||||
* as argument to this thread.
|
||||
* When receiving a sig-int the thread quits.
|
||||
*/
|
||||
static gpointer rofi_signal_handler_process ( gpointer arg )
|
||||
{
|
||||
int pfd = *( (int *) arg );
|
||||
|
||||
// Create same mask again.
|
||||
sigset_t set;
|
||||
sigemptyset ( &set );
|
||||
sigaddset ( &set, SIGHUP );
|
||||
sigaddset ( &set, SIGINT );
|
||||
sigaddset ( &set, SIGUSR1 );
|
||||
// loop forever.
|
||||
while ( 1 ) {
|
||||
#ifdef __OpenBSD__
|
||||
int sig = 0;
|
||||
if ( sigwait ( &set, &sig ) < 0 ) {
|
||||
perror ( "sigwaitinfo failed, lets restart" );
|
||||
}
|
||||
#else
|
||||
siginfo_t info;
|
||||
int sig = sigwaitinfo ( &set, &info );
|
||||
if ( sig < 0 ) {
|
||||
perror ( "sigwaitinfo failed, lets restart" );
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// Send message to main thread.
|
||||
if ( sig == SIGHUP ) {
|
||||
ssize_t t = write ( pfd, "c", 1 );
|
||||
if ( t < 0 ) {
|
||||
fprintf ( stderr, "Failed to send signal to main thread.\n" );
|
||||
}
|
||||
}
|
||||
if ( sig == SIGUSR1 ) {
|
||||
ssize_t t = write ( pfd, "i", 1 );
|
||||
if ( t < 0 ) {
|
||||
fprintf ( stderr, "Failed to send signal to main thread.\n" );
|
||||
}
|
||||
}
|
||||
if ( sig == SIGINT ) {
|
||||
ssize_t t = write ( pfd, "q", 1 );
|
||||
if ( t < 0 ) {
|
||||
fprintf ( stderr, "Failed to send signal to main thread.\n" );
|
||||
}
|
||||
// Close my end and exit.
|
||||
g_thread_exit ( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process X11 events in the main-loop (gui-thread) of the application.
|
||||
*/
|
||||
|
@ -2249,34 +2190,30 @@ static void main_loop_x11_event_handler ( void )
|
|||
*
|
||||
* returns TRUE when mainloop should be stopped.
|
||||
*/
|
||||
static int main_loop_signal_handler ( char command, int quiet )
|
||||
static gboolean main_loop_signal_handler_hup ( G_GNUC_UNUSED gpointer data )
|
||||
{
|
||||
if ( command == 'c' ) {
|
||||
if ( !quiet ) {
|
||||
fprintf ( stdout, "Reload configuration\n" );
|
||||
}
|
||||
// Release the keybindings.
|
||||
release_global_keybindings ();
|
||||
// Reload config
|
||||
reload_configuration ();
|
||||
// Grab the possibly new keybindings.
|
||||
grab_global_keybindings ();
|
||||
if ( !quiet ) {
|
||||
print_global_keybindings ();
|
||||
}
|
||||
// We need to flush, otherwise the first key presses are not caught.
|
||||
XFlush ( display );
|
||||
}
|
||||
// Got message to quit.
|
||||
else if ( command == 'q' ) {
|
||||
// Break out of loop.
|
||||
return TRUE;
|
||||
}
|
||||
// Got message to print info
|
||||
else if ( command == 'i' ) {
|
||||
config_parse_xresource_dump ();
|
||||
}
|
||||
return FALSE;
|
||||
fprintf ( stdout, "Reload configuration\n" );
|
||||
// Release the keybindings.
|
||||
release_global_keybindings ();
|
||||
// Reload config
|
||||
reload_configuration ();
|
||||
// Grab the possibly new keybindings.
|
||||
grab_global_keybindings ();
|
||||
// We need to flush, otherwise the first key presses are not caught.
|
||||
XFlush ( display );
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
static gboolean main_loop_signal_handler_term ( G_GNUC_UNUSED gpointer data )
|
||||
{
|
||||
// Break out of loop.
|
||||
g_main_loop_quit ( main_loop );
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean main_loop_signal_handler_usr1 ( G_GNUC_UNUSED gpointer data )
|
||||
{
|
||||
config_parse_xresource_dump ();
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
ModeMode switcher_run ( char **input, Mode *sw )
|
||||
|
@ -2288,31 +2225,58 @@ ModeMode switcher_run ( char **input, Mode *sw )
|
|||
return mode_result ( sw, mretv, input, selected_line );
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup signal handling.
|
||||
* Block all the signals, start a signal processor thread to handle these events.
|
||||
*/
|
||||
static GThread *setup_signal_thread ( int *fd )
|
||||
{
|
||||
// Block all HUP,INT,USR1 signals.
|
||||
// In this and other child (they inherit mask)
|
||||
sigset_t set;
|
||||
sigemptyset ( &set );
|
||||
sigaddset ( &set, SIGHUP );
|
||||
sigaddset ( &set, SIGINT );
|
||||
sigaddset ( &set, SIGUSR1 );
|
||||
sigprocmask ( SIG_BLOCK, &set, NULL );
|
||||
// Create signal handler process.
|
||||
// This will use sigwaitinfo to read signals and forward them back to the main thread again.
|
||||
return g_thread_new ( "signal_process", rofi_signal_handler_process, (void *) fd );
|
||||
}
|
||||
|
||||
static int error_trap_depth = 0;
|
||||
static void error_trap_push ( G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED Display *xdisplay )
|
||||
{
|
||||
++error_trap_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom X11 Source implementation.
|
||||
*/
|
||||
typedef struct _X11EventSource
|
||||
{
|
||||
// Source
|
||||
GSource source;
|
||||
// Polling field
|
||||
GPollFD fd_x11;
|
||||
} X11EventSource;
|
||||
|
||||
static gboolean x11_event_source_prepare ( G_GNUC_UNUSED GSource * base, gint * timeout )
|
||||
{
|
||||
*timeout = -1;
|
||||
return XPending ( display );
|
||||
}
|
||||
|
||||
static gboolean x11_event_source_check ( GSource * base )
|
||||
{
|
||||
X11EventSource *xs = (X11EventSource *) base;
|
||||
if ( xs->fd_x11.revents ) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean x11_event_source_dispatch ( GSource * base, GSourceFunc callback, gpointer data )
|
||||
{
|
||||
X11EventSource *xs = (X11EventSource *) base;
|
||||
if ( xs->fd_x11.revents ) {
|
||||
printf ( "x11\n" );
|
||||
main_loop_x11_event_handler ();
|
||||
}
|
||||
if ( callback ) {
|
||||
callback ( data );
|
||||
}
|
||||
return G_SOURCE_CONTINUE;;
|
||||
}
|
||||
|
||||
static GSourceFuncs x11_event_source_funcs = {
|
||||
x11_event_source_prepare,
|
||||
x11_event_source_check,
|
||||
x11_event_source_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, Display *xdisplay )
|
||||
{
|
||||
if ( error_trap_depth == 0 ) {
|
||||
|
@ -2529,16 +2493,6 @@ int main ( int argc, char *argv[] )
|
|||
print_global_keybindings ();
|
||||
}
|
||||
|
||||
// Create a pipe to communicate between signal thread an main thread.
|
||||
int pfds[2];
|
||||
if ( pipe ( pfds ) != 0 ) {
|
||||
char * msg = g_strdup_printf ( "Failed to start rofi: '<i>%s</i>'", strerror ( errno ) );
|
||||
show_error_message ( msg, TRUE );
|
||||
g_free ( msg );
|
||||
exit ( EXIT_FAILURE );
|
||||
}
|
||||
GThread *pid_signal_proc = setup_signal_thread ( &( pfds[1] ) );
|
||||
|
||||
// done starting deamon.
|
||||
|
||||
if ( sncontext != NULL ) {
|
||||
|
@ -2550,43 +2504,41 @@ int main ( int argc, char *argv[] )
|
|||
// It also listens from messages from the signal process.
|
||||
XSelectInput ( display, DefaultRootWindow ( display ), KeyPressMask );
|
||||
XFlush ( display );
|
||||
int x11_fd = ConnectionNumber ( display );
|
||||
for (;; ) {
|
||||
fd_set in_fds;
|
||||
// Create a File Description Set containing x11_fd, and signal pipe
|
||||
FD_ZERO ( &in_fds );
|
||||
FD_SET ( x11_fd, &in_fds );
|
||||
FD_SET ( pfds[0], &in_fds );
|
||||
int x11_fd = ConnectionNumber ( display );
|
||||
|
||||
// Wait for X Event or a message on signal pipe
|
||||
if ( select ( MAX ( x11_fd, pfds[0] ) + 1, &in_fds, 0, 0, NULL ) >= 0 ) {
|
||||
// X11
|
||||
if ( FD_ISSET ( x11_fd, &in_fds ) ) {
|
||||
main_loop_x11_event_handler ();
|
||||
}
|
||||
// Signal Pipe
|
||||
if ( FD_ISSET ( pfds[0], &in_fds ) ) {
|
||||
// The signal thread send us a message. Process it.
|
||||
char c;
|
||||
ssize_t r = read ( pfds[0], &c, 1 );
|
||||
if ( r < 0 ) {
|
||||
fprintf ( stderr, "Failed to read data from signal thread: %s\n", strerror ( errno ) );
|
||||
}
|
||||
// Process the signal in the main_loop.
|
||||
else if ( main_loop_signal_handler ( c, quiet ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
X11EventSource *source = (X11EventSource *) g_source_new ( &x11_event_source_funcs, sizeof ( X11EventSource ) );
|
||||
source->fd_x11.fd = x11_fd;
|
||||
source->fd_x11.events = G_IO_IN | G_IO_ERR;
|
||||
g_source_add_poll ( (GSource *) source, &source->fd_x11 );
|
||||
main_loop = g_main_loop_new ( NULL, FALSE );
|
||||
g_source_attach ( (GSource *) source, NULL );
|
||||
|
||||
// Setup signal handling sources.
|
||||
GSource *sigs_hup = NULL, *sigs_term = NULL, *sigs_usr1 = NULL;
|
||||
// SIGHup signal.
|
||||
sigs_hup = g_unix_signal_source_new ( SIGHUP );
|
||||
g_source_set_callback ( sigs_hup, main_loop_signal_handler_hup, NULL, NULL );
|
||||
g_source_attach ( sigs_hup, NULL );
|
||||
// SIGTERM
|
||||
sigs_term = g_unix_signal_source_new ( SIGTERM );
|
||||
g_source_set_callback ( sigs_term, main_loop_signal_handler_term, NULL, NULL );
|
||||
g_source_attach ( sigs_term, NULL );
|
||||
// SIGUSR1
|
||||
sigs_usr1 = g_unix_signal_source_new ( SIGUSR1 );
|
||||
g_source_set_callback ( sigs_usr1, main_loop_signal_handler_usr1, NULL, NULL );
|
||||
g_source_attach ( sigs_usr1, NULL );
|
||||
|
||||
// Start mainloop.
|
||||
g_main_loop_run ( main_loop );
|
||||
|
||||
// Cleanup
|
||||
g_source_unref ( (GSource *) source );
|
||||
g_source_unref ( sigs_hup );
|
||||
g_source_unref ( sigs_term );
|
||||
g_source_unref ( sigs_usr1 );
|
||||
g_main_loop_unref ( main_loop );
|
||||
|
||||
release_global_keybindings ();
|
||||
// Join the signal process thread. (at this point it should have exited).
|
||||
// this also unrefs (de-allocs) the GThread object.
|
||||
g_thread_join ( pid_signal_proc );
|
||||
// Close pipe
|
||||
close ( pfds[0] );
|
||||
close ( pfds[1] );
|
||||
if ( !quiet ) {
|
||||
fprintf ( stdout, "Quit from daemon mode.\n" );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue