xcb: Move (most) event handling to xcb.c

Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
This commit is contained in:
Quentin Glidic 2017-06-01 13:30:29 +02:00
parent 4792a16593
commit 93cb04e30f
No known key found for this signature in database
GPG Key ID: AC203F96E2C34BB7
6 changed files with 210 additions and 156 deletions

View File

@ -77,6 +77,8 @@ void rofi_add_error_message ( GString *str );
*/
void rofi_set_return_code ( int code );
void rofi_quit_main_loop ( void );
/**
* @param name Search for mode with this name.
*

View File

@ -93,12 +93,33 @@ MenuReturn rofi_view_get_return_value ( const RofiViewState *state );
unsigned int rofi_view_get_next_position ( const RofiViewState *state );
/**
* @param state the Menu handle
* @param event the event to handle
* @param xkb the keyboard handle
* @param text The text to add to the input box
*
* Process an Xevent.
* Update the state if needed.
*/
void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, NkBindingsSeat *seat );
void rofi_view_handle_text ( RofiViewState *state, char *text );
/**
* @param state the Menu handle
* @param x The X coordinates of the motion
* @param x The Y coordinates of the motion
*
* Update the state if needed.
*/
void rofi_view_handle_mouse_motion( RofiViewState *state, gint x, gint y );
/**
* @param state the Menu handle
*
* Update the state if needed.
*/
void rofi_view_maybe_update ( RofiViewState *state );
void rofi_view_temp_configure_notify ( RofiViewState *state, xcb_configure_notify_event_t *xce );
void rofi_view_temp_click_to_exit ( RofiViewState *state, xcb_window_t target );
/**
* @param state the Menu handle
*
* Update the state if needed.
*/
void rofi_view_frame_callback ( void );
/**
* @param state the Menu handle
*

View File

@ -60,6 +60,7 @@ struct _xcb_stuff
} xkb;
NkBindings *bindings;
NkBindingsSeat *bindings_seat;
gboolean mouse_seen;
};
#endif

View File

@ -591,6 +591,11 @@ static gboolean setup_modi ( void )
return FALSE;
}
void rofi_quit_main_loop ( void )
{
g_main_loop_quit ( main_loop );
}
static gboolean main_loop_signal_handler_int ( G_GNUC_UNUSED gpointer data )
{
// Break out of loop.

View File

@ -972,40 +972,6 @@ void rofi_view_update ( RofiViewState *state, gboolean qr )
}
}
/**
* @param state Internal state of the menu.
* @param xse X selection event.
*
* Handle paste event.
*/
static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t *xse )
{
if ( xse->property == XCB_ATOM_NONE ) {
g_warning ( "Failed to convert selection" );
}
else if ( xse->property == xcb->ewmh.UTF8_STRING ) {
gchar *text = window_get_text_prop ( CacheState.main_window, xcb->ewmh.UTF8_STRING );
if ( text != NULL && text[0] != '\0' ) {
unsigned int dl = strlen ( text );
// Strip new line
for ( unsigned int i = 0; i < dl; i++ ) {
if ( text[i] == '\n' ) {
dl = i;
}
}
// Insert string move cursor.
textbox_insert ( state->text, state->text->cursor, text, dl );
textbox_cursor ( state->text, state->text->cursor + g_utf8_strlen ( text, -1 ) );
// Force a redraw and refiltering of the text.
state->refilter = TRUE;
}
g_free ( text );
}
else {
g_warning ( "Failed" );
}
}
static void _rofi_view_reload_row ( RofiViewState *state )
{
g_free ( state->line_map );
@ -1382,122 +1348,83 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, BindingsScope scope, g
return FALSE;
}
void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, NkBindingsSeat *seat )
void rofi_view_handle_text ( RofiViewState *state, char *text )
{
switch ( event->response_type & ~0x80 )
{
case XCB_CONFIGURE_NOTIFY:
{
xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *) event;
if ( xce->window == CacheState.main_window ) {
if ( state->x != xce->x || state->y != xce->y ) {
state->x = xce->x;
state->y = xce->y;
widget_queue_redraw ( WIDGET ( state->main_window ) );
}
if ( state->width != xce->width || state->height != xce->height ) {
state->width = xce->width;
state->height = xce->height;
if ( textbox_append_text ( state->text, text, strlen ( text ) ) ) {
state->refilter = TRUE;
}
}
cairo_destroy ( CacheState.edit_draw );
cairo_surface_destroy ( CacheState.edit_surf );
void rofi_view_handle_mouse_motion( RofiViewState *state, gint x, gint y )
{
state->mouse.x = x;
state->mouse.y = y;
if ( state->mouse.motion_target != NULL ) {
widget_xy_to_relative ( state->mouse.motion_target, &x, &y );
widget_motion_notify ( state->mouse.motion_target, x, y );
}
}
xcb_free_pixmap ( xcb->connection, CacheState.edit_pixmap );
CacheState.edit_pixmap = xcb_generate_id ( xcb->connection );
xcb_create_pixmap ( xcb->connection, depth->depth, CacheState.edit_pixmap, CacheState.main_window,
state->width, state->height );
void rofi_view_maybe_update ( RofiViewState *state )
{
if ( rofi_view_get_completed ( state ) ) {
// This menu is done.
rofi_view_finalize ( state );
// cleanup
if ( rofi_view_get_active () == NULL ) {
rofi_quit_main_loop();
return;
}
}
CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height );
CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
g_debug ( "Re-size window based external request: %d %d", state->width, state->height );
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
}
}
break;
}
case XCB_MOTION_NOTIFY:
{
if ( config.click_to_exit == TRUE ) {
state->mouse_seen = TRUE;
}
xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) event );
state->mouse.x = xme.event_x;
state->mouse.y = xme.event_y;
if ( state->mouse.motion_target != NULL ) {
gint x = state->mouse.x;
gint y = state->mouse.y;
widget_xy_to_relative ( state->mouse.motion_target, &x, &y );
widget_motion_notify ( state->mouse.motion_target, x, y );
}
break;
}
case XCB_BUTTON_PRESS:
{
xcb_button_press_event_t *bpe = (xcb_button_press_event_t *) event;
state->mouse.x = bpe->event_x;
state->mouse.y = bpe->event_y;
nk_bindings_seat_handle_button ( seat, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time );
break;
}
case XCB_BUTTON_RELEASE:
{
xcb_button_release_event_t *bre = (xcb_button_release_event_t *) event;
nk_bindings_seat_handle_button ( seat, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time );
if ( config.click_to_exit == TRUE ) {
if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) {
if ( ( state->mouse_seen == FALSE ) && ( bre->event != CacheState.main_window ) ) {
state->quit = TRUE;
state->retv = MENU_CANCEL;
}
}
state->mouse_seen = FALSE;
}
break;
}
// Paste event.
case XCB_SELECTION_NOTIFY:
rofi_view_paste ( state, (xcb_selection_notify_event_t *) event );
break;
case XCB_KEYMAP_NOTIFY:
{
xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *) event;
for ( gint32 by = 0; by < 31; ++by ) {
for ( gint8 bi = 0; bi < 7; ++bi ) {
if ( kne->keys[by] & ( 1 << bi ) ) {
// X11 keycodes starts at 8
nk_bindings_seat_handle_key ( seat, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED );
}
}
}
break;
}
case XCB_KEY_PRESS:
{
xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) event;
gchar *text;
text = nk_bindings_seat_handle_key ( seat, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS );
if ( ( text != NULL ) && ( textbox_append_text ( state->text, text, strlen ( text ) ) ) ) {
state->refilter = TRUE;
}
break;
}
case XCB_KEY_RELEASE:
{
xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event;
nk_bindings_seat_handle_key ( seat, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE );
break;
}
default:
break;
}
// Update if requested.
if ( state->refilter ) {
rofi_view_refilter ( state );
}
rofi_view_update ( state, TRUE );
}
if ( ( event->response_type & ~0x80 ) == XCB_EXPOSE && CacheState.repaint_source == 0 ) {
void rofi_view_temp_configure_notify ( RofiViewState *state, xcb_configure_notify_event_t *xce )
{
if ( xce->window == CacheState.main_window ) {
if ( state->x != xce->x || state->y != xce->y ) {
state->x = xce->x;
state->y = xce->y;
widget_queue_redraw ( WIDGET ( state->main_window ) );
}
if ( state->width != xce->width || state->height != xce->height ) {
state->width = xce->width;
state->height = xce->height;
cairo_destroy ( CacheState.edit_draw );
cairo_surface_destroy ( CacheState.edit_surf );
xcb_free_pixmap ( xcb->connection, CacheState.edit_pixmap );
CacheState.edit_pixmap = xcb_generate_id ( xcb->connection );
xcb_create_pixmap ( xcb->connection, depth->depth, CacheState.edit_pixmap, CacheState.main_window,
state->width, state->height );
CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height );
CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
g_debug ( "Re-size window based external request: %d %d", state->width, state->height );
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
}
}
}
void rofi_view_temp_click_to_exit ( RofiViewState *state, xcb_window_t target )
{
if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) {
if ( target != CacheState.main_window ) {
state->quit = TRUE;
state->retv = MENU_CANCEL;
}
}
}
void rofi_view_frame_callback ( void )
{
if ( CacheState.repaint_source == 0 ) {
CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL );
}
}

View File

@ -557,23 +557,123 @@ int monitor_active ( workarea *mon )
return FALSE;
}
/**
* @param state Internal state of the menu.
* @param xse X selection event.
*
* Handle paste event.
*/
static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t *xse )
{
if ( xse->property == XCB_ATOM_NONE ) {
g_warning ( "Failed to convert selection" );
}
else if ( xse->property == xcb->ewmh.UTF8_STRING ) {
gchar *text = window_get_text_prop ( xse->requestor, xcb->ewmh.UTF8_STRING );
if ( text != NULL && text[0] != '\0' ) {
unsigned int dl = strlen ( text );
// Strip new line
for ( unsigned int i = 0; i < dl; i++ ) {
if ( text[i] == '\n' ) {
text[i] = '\0';
}
}
rofi_view_handle_text ( state, text );
}
g_free ( text );
}
else {
g_warning ( "Failed" );
}
}
/**
* Process X11 events in the main-loop (gui-thread) of the application.
*/
static void main_loop_x11_event_handler_view ( xcb_generic_event_t *ev )
static void main_loop_x11_event_handler_view ( xcb_generic_event_t *event )
{
RofiViewState *state = rofi_view_get_active ();
if ( state != NULL ) {
rofi_view_itterrate ( state, ev, xcb->bindings_seat );
if ( rofi_view_get_completed ( state ) ) {
// This menu is done.
rofi_view_finalize ( state );
// cleanup
if ( rofi_view_get_active () == NULL ) {
g_main_loop_quit ( xcb->main_loop );
if ( state == NULL ) {
return;
}
switch ( event->response_type & ~0x80 )
{
case XCB_EXPOSE:
rofi_view_frame_callback ();
break;
case XCB_CONFIGURE_NOTIFY:
{
xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *) event;
rofi_view_temp_configure_notify ( state, xce );
break;
}
case XCB_MOTION_NOTIFY:
{
if ( config.click_to_exit == TRUE ) {
xcb->mouse_seen = TRUE;
}
xcb_motion_notify_event_t *xme = (xcb_motion_notify_event_t *) event;
rofi_view_handle_mouse_motion ( state, xme->event_x, xme->event_y );
break;
}
case XCB_BUTTON_PRESS:
{
xcb_button_press_event_t *bpe = (xcb_button_press_event_t *) event;
rofi_view_handle_mouse_motion ( state, bpe->event_x, bpe->event_y );
nk_bindings_seat_handle_button ( xcb->bindings_seat, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time );
break;
}
case XCB_BUTTON_RELEASE:
{
xcb_button_release_event_t *bre = (xcb_button_release_event_t *) event;
nk_bindings_seat_handle_button ( xcb->bindings_seat, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time );
if ( config.click_to_exit == TRUE ) {
if ( ! xcb->mouse_seen ) {
rofi_view_temp_click_to_exit ( state, bre->event );
}
xcb->mouse_seen = FALSE;
}
break;
}
// Paste event.
case XCB_SELECTION_NOTIFY:
rofi_view_paste ( state, (xcb_selection_notify_event_t *) event );
break;
case XCB_KEYMAP_NOTIFY:
{
xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *) event;
for ( gint32 by = 0; by < 31; ++by ) {
for ( gint8 bi = 0; bi < 7; ++bi ) {
if ( kne->keys[by] & ( 1 << bi ) ) {
// X11 keycodes starts at 8
nk_bindings_seat_handle_key ( xcb->bindings_seat, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED );
}
}
}
break;
}
case XCB_KEY_PRESS:
{
xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) event;
gchar *text;
text = nk_bindings_seat_handle_key ( xcb->bindings_seat, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS );
if ( text != NULL ) {
rofi_view_handle_text ( state, text );
}
break;
}
case XCB_KEY_RELEASE:
{
xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event;
nk_bindings_seat_handle_key ( xcb->bindings_seat, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE );
break;
}
default:
break;
}
rofi_view_maybe_update ( state );
}
static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer user_data )
@ -613,9 +713,7 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
ksne->baseGroup,
ksne->latchedGroup,
ksne->lockedGroup );
xcb_generic_event_t dev;
dev.response_type = 0;
main_loop_x11_event_handler_view ( &dev );
rofi_view_maybe_update ( rofi_view_get_active () );
break;
}
}