mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
rofi: Convert to XCB events
Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
This commit is contained in:
parent
2eb63456db
commit
fe7ca2079d
12 changed files with 337 additions and 324 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "libgwater"]
|
||||
path = libgwater
|
||||
url = git://github.com/sardemff7/libgwater
|
|
@ -1,6 +1,11 @@
|
|||
# Specify automake version.
|
||||
AUTOMAKE_OPTIONS = 1.11.3
|
||||
|
||||
ACLOCAL_AMFLAGS = -I libgwater ${ACLOCAL_FLAGS}
|
||||
|
||||
noinst_LIBRARIES =
|
||||
include $(top_srcdir)/libgwater-xcb-nolibtool.mk
|
||||
|
||||
##
|
||||
# Rofi the program
|
||||
##
|
||||
|
@ -60,6 +65,7 @@ rofi_SOURCES=\
|
|||
rofi_CFLAGS=\
|
||||
$(AM_CFLAGS)\
|
||||
$(glib_CFLAGS)\
|
||||
$(GW_XCB_CFLAGS)\
|
||||
$(x11_CFLAGS)\
|
||||
$(xinerama_CFLAGS)\
|
||||
$(pango_CFLAGS)\
|
||||
|
@ -73,6 +79,7 @@ rofi_CFLAGS=\
|
|||
|
||||
rofi_LDADD=\
|
||||
$(glib_LIBS)\
|
||||
$(GW_XCB_LIBS)\
|
||||
$(x11_LIBS)\
|
||||
$(xinerama_LIBS)\
|
||||
$(libsn_LIBS)\
|
||||
|
|
|
@ -30,6 +30,12 @@ dnl System extensions
|
|||
dnl ---------------------------------------------------------------------
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Static libraries programs
|
||||
dnl ---------------------------------------------------------------------
|
||||
AC_PROG_RANLIB
|
||||
AM_PROG_AR
|
||||
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Base CFLAGS
|
||||
dnl ---------------------------------------------------------------------
|
||||
|
@ -77,7 +83,8 @@ dnl ---------------------------------------------------------------------
|
|||
dnl X11, Glib, Xinerama, Pango, Cairo, libstartup notification
|
||||
dnl ---------------------------------------------------------------------
|
||||
PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40])
|
||||
PKG_CHECK_MODULES([x11], [x11])
|
||||
GW_CHECK_XCB([xcb-aux xkbcommon xkbcommon-x11])
|
||||
PKG_CHECK_MODULES([x11], [x11 x11-xcb])
|
||||
PKG_CHECK_MODULES([xinerama], [xinerama])
|
||||
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
||||
PKG_CHECK_MODULES([cairo], [cairo cairo-xlib])
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef ROFI_MAIN_H
|
||||
#define ROFI_MAIN_H
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
|
|
|
@ -113,7 +113,7 @@ void textbox_draw ( textbox *tb, cairo_t *draw );
|
|||
*
|
||||
* @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1)
|
||||
*/
|
||||
int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym key, Status stat );
|
||||
int textbox_keypress ( textbox *tb, xcb_key_press_event_t *ev, char *pad, int pad_len, KeySym key, Status stat );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
|
|
|
@ -69,7 +69,7 @@ struct RofiViewState
|
|||
|
||||
MenuFlags menu_flags;
|
||||
// Handlers.
|
||||
void ( *x11_event_loop )( struct RofiViewState *state, XEvent *ev );
|
||||
void ( *x11_event_loop )( struct RofiViewState *state, xcb_generic_event_t *ev );
|
||||
void ( *finalize )( struct RofiViewState *state );
|
||||
};
|
||||
/** @} */
|
||||
|
|
|
@ -47,7 +47,7 @@ void rofi_view_finalize ( RofiViewState *state );
|
|||
|
||||
MenuReturn rofi_view_get_return_value ( const RofiViewState *state );
|
||||
unsigned int rofi_view_get_next_position ( const RofiViewState *state );
|
||||
void rofi_view_itterrate ( RofiViewState *state, XEvent *event );
|
||||
void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event );
|
||||
unsigned int rofi_view_get_completed ( const RofiViewState *state );
|
||||
const char * rofi_view_get_user_input ( const RofiViewState *state );
|
||||
|
||||
|
|
1
libgwater
Submodule
1
libgwater
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 50a0f8a4bc2d762c412b6dd1823a14949de583aa
|
20
libgwater-xcb-nolibtool.mk
Normal file
20
libgwater-xcb-nolibtool.mk
Normal file
|
@ -0,0 +1,20 @@
|
|||
noinst_LIBRARIES += \
|
||||
libgwater/libgwater-xcb.a
|
||||
|
||||
libgwater_libgwater_xcb_a_SOURCES = \
|
||||
libgwater/xcb/libgwater-xcb.c \
|
||||
libgwater/xcb/libgwater-xcb.h
|
||||
|
||||
libgwater_libgwater_xcb_a_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(GW_XCB_INTERNAL_CFLAGS)
|
||||
|
||||
|
||||
GW_XCB_CFLAGS = \
|
||||
-I$(srcdir)/libgwater/xcb \
|
||||
$(GW_XCB_INTERNAL_CFLAGS)
|
||||
|
||||
GW_XCB_LIBS = \
|
||||
libgwater/libgwater-xcb.a \
|
||||
$(GW_XCB_INTERNAL_LIBS)
|
||||
|
|
@ -34,9 +34,13 @@
|
|||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/keysym.h>
|
||||
|
@ -45,6 +49,8 @@
|
|||
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include <libgwater-xcb.h>
|
||||
|
||||
#define SN_API_NOT_YET_FROZEN
|
||||
#include <libsn/sn.h>
|
||||
|
||||
|
@ -67,6 +73,8 @@ char *pidfile = NULL;
|
|||
const char *cache_dir = NULL;
|
||||
SnDisplay *sndisplay = NULL;
|
||||
SnLauncheeContext *sncontext = NULL;
|
||||
xcb_connection_t *xcb_connection = NULL;
|
||||
xcb_screen_t *xcb_screen = NULL;
|
||||
Display *display = NULL;
|
||||
char *display_str = NULL;
|
||||
char *config_path = NULL;
|
||||
|
@ -77,7 +85,7 @@ unsigned int num_modi = 0;
|
|||
unsigned int curr_switcher = 0;
|
||||
|
||||
GMainLoop *main_loop = NULL;
|
||||
GSource *main_loop_source = NULL;
|
||||
GWaterXcbSource *main_loop_source = NULL;
|
||||
gboolean quiet = FALSE;
|
||||
|
||||
static int dmenu_mode = FALSE;
|
||||
|
@ -277,19 +285,19 @@ int show_error_message ( const char *msg, int markup )
|
|||
* Function that listens for global key-presses.
|
||||
* This is only used when in daemon mode.
|
||||
*/
|
||||
static void handle_keypress ( XEvent *ev )
|
||||
static void handle_keypress ( xcb_key_press_event_t *ev )
|
||||
{
|
||||
int index;
|
||||
KeySym key = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 );
|
||||
index = locate_switcher ( key, ev->xkey.state );
|
||||
KeySym key = XkbKeycodeToKeysym ( display, ev->detail, 0, 0 );
|
||||
index = locate_switcher ( key, ev->state );
|
||||
if ( index >= 0 ) {
|
||||
run_switcher ( index );
|
||||
}
|
||||
else {
|
||||
fprintf ( stderr,
|
||||
"Warning: Unhandled keypress in global keyhandler, keycode = %u mask = %u\n",
|
||||
ev->xkey.keycode,
|
||||
ev->xkey.state );
|
||||
ev->detail,
|
||||
ev->state );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,7 +362,7 @@ static void cleanup ()
|
|||
rofi_view_workers_finalize ();
|
||||
if ( main_loop != NULL ) {
|
||||
if ( main_loop_source ) {
|
||||
g_source_destroy ( main_loop_source );
|
||||
g_water_xcb_source_unref ( main_loop_source );
|
||||
}
|
||||
g_main_loop_unref ( main_loop );
|
||||
main_loop = NULL;
|
||||
|
@ -542,19 +550,14 @@ static void reload_configuration ()
|
|||
/**
|
||||
* Process X11 events in the main-loop (gui-thread) of the application.
|
||||
*/
|
||||
static gboolean main_loop_x11_event_handler ( G_GNUC_UNUSED gpointer data )
|
||||
static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data )
|
||||
{
|
||||
RofiViewState *state = rofi_view_get_active ();
|
||||
if ( state != NULL ) {
|
||||
while ( XPending ( display ) ) {
|
||||
XEvent ev;
|
||||
// Read event, we know this won't block as we checked with XPending.
|
||||
XNextEvent ( display, &ev );
|
||||
if ( sndisplay != NULL ) {
|
||||
sn_display_process_event ( sndisplay, &ev );
|
||||
}
|
||||
rofi_view_itterrate ( state, &ev );
|
||||
sn_xcb_display_process_event ( sndisplay, ev );
|
||||
}
|
||||
if ( state != NULL ) {
|
||||
rofi_view_itterrate ( state, ev );
|
||||
if ( rofi_view_get_completed ( state ) ) {
|
||||
// This menu is done.
|
||||
rofi_view_finalize ( state );
|
||||
|
@ -566,24 +569,14 @@ static gboolean main_loop_x11_event_handler ( G_GNUC_UNUSED gpointer data )
|
|||
}
|
||||
}
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
else {
|
||||
// X11 produced an event. Consume them.
|
||||
while ( XPending ( display ) ) {
|
||||
XEvent ev;
|
||||
// Read event, we know this won't block as we checked with XPending.
|
||||
XNextEvent ( display, &ev );
|
||||
if ( sndisplay != NULL ) {
|
||||
sn_display_process_event ( sndisplay, &ev );
|
||||
}
|
||||
// If we get an event that does not belong to a window:
|
||||
// Ignore it.
|
||||
if ( ev.xany.window == None ) {
|
||||
continue;
|
||||
}
|
||||
// If keypress, handle it.
|
||||
if ( ev.type == KeyPress ) {
|
||||
handle_keypress ( &ev );
|
||||
if ( ( ev->response_type & ~0x80 ) == XCB_KEY_PRESS ) {
|
||||
handle_keypress ( (xcb_key_press_event_t *) ev );
|
||||
}
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
@ -606,7 +599,7 @@ static gboolean main_loop_signal_handler_hup ( G_GNUC_UNUSED gpointer data )
|
|||
// Grab the possibly new keybindings.
|
||||
grab_global_keybindings ();
|
||||
// We need to flush, otherwise the first key presses are not caught.
|
||||
XFlush ( display );
|
||||
xcb_flush ( xcb_connection );
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -722,8 +715,9 @@ static gboolean startup ( G_GNUC_UNUSED gpointer data )
|
|||
sn_launchee_context_complete ( sncontext );
|
||||
}
|
||||
daemon_mode = TRUE;
|
||||
XSelectInput ( display, DefaultRootWindow ( display ), KeyPressMask );
|
||||
XFlush ( display );
|
||||
uint32_t mask[] = { XCB_EVENT_MASK_KEY_PRESS };
|
||||
xcb_change_window_attributes ( xcb_connection, xcb_screen->root, XCB_CW_EVENT_MASK, mask );
|
||||
xcb_flush ( xcb_connection );
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
|
@ -807,6 +801,9 @@ int main ( int argc, char *argv[] )
|
|||
}
|
||||
TICK_N ( "Open Display" );
|
||||
|
||||
xcb_connection = XGetXCBConnection ( display );
|
||||
xcb_screen = xcb_aux_get_screen ( xcb_connection, DefaultScreen ( display ) );
|
||||
|
||||
main_loop = g_main_loop_new ( NULL, FALSE );
|
||||
|
||||
TICK_N ( "Setup mainloop" );
|
||||
|
@ -856,8 +853,7 @@ int main ( int argc, char *argv[] )
|
|||
}
|
||||
|
||||
x11_setup ( display );
|
||||
main_loop_source = x11_event_source_new ( display );
|
||||
x11_event_source_set_callback ( main_loop_source, main_loop_x11_event_handler );
|
||||
main_loop_source = g_water_xcb_source_new_for_connection ( NULL, xcb_connection, main_loop_x11_event_handler, NULL, NULL );
|
||||
|
||||
TICK_N ( "X11 Setup " );
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
@ -532,7 +533,7 @@ static void textbox_cursor_del_word ( textbox *tb )
|
|||
// 0 = unhandled
|
||||
// 1 = handled
|
||||
// -1 = handled and return pressed (finished)
|
||||
int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym key, Status stat )
|
||||
int textbox_keypress ( textbox *tb, xcb_key_press_event_t *ev, char *pad, int pad_len, KeySym key, Status stat )
|
||||
{
|
||||
if ( !( tb->flags & TB_EDITABLE ) ) {
|
||||
return 0;
|
||||
|
@ -541,67 +542,67 @@ int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, int pad_len, KeySym k
|
|||
tb->blink = 2;
|
||||
if ( stat == XLookupKeySym || stat == XLookupBoth ) {
|
||||
// Left or Ctrl-b
|
||||
if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) {
|
||||
if ( abe_test_action ( MOVE_CHAR_BACK, ev->state, key ) ) {
|
||||
textbox_cursor_dec ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Right or Ctrl-F
|
||||
else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->state, key ) ) {
|
||||
textbox_cursor_inc ( tb );
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Ctrl-U: Kill from the beginning to the end of the line.
|
||||
else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( CLEAR_LINE, ev->state, key ) ) {
|
||||
textbox_text ( tb, "" );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-A
|
||||
else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MOVE_FRONT, ev->state, key ) ) {
|
||||
textbox_cursor ( tb, 0 );
|
||||
return 2;
|
||||
}
|
||||
// Ctrl-E
|
||||
else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MOVE_END, ev->state, key ) ) {
|
||||
textbox_cursor_end ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Ctrl-Alt-h
|
||||
else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( REMOVE_WORD_BACK, ev->state, key ) ) {
|
||||
textbox_cursor_bkspc_word ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-Alt-d
|
||||
else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->state, key ) ) {
|
||||
textbox_cursor_del_word ( tb );
|
||||
return 1;
|
||||
} // Delete or Ctrl-D
|
||||
else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->state, key ) ) {
|
||||
textbox_cursor_del ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Alt-B
|
||||
else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MOVE_WORD_BACK, ev->state, key ) ) {
|
||||
textbox_cursor_dec_word ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Alt-F
|
||||
else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->state, key ) ) {
|
||||
textbox_cursor_inc_word ( tb );
|
||||
return 2;
|
||||
}
|
||||
// BackSpace, Ctrl-h
|
||||
else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->state, key ) ) {
|
||||
textbox_cursor_bkspc ( tb );
|
||||
return 1;
|
||||
}
|
||||
else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( ACCEPT_CUSTOM, ev->state, key ) ) {
|
||||
return -2;
|
||||
}
|
||||
else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->state, key ) ) {
|
||||
return -3;
|
||||
}
|
||||
else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( ACCEPT_ENTRY, ev->state, key ) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
319
source/view.c
319
source/view.c
|
@ -308,9 +308,95 @@ unsigned int rofi_view_get_completed ( const RofiViewState *state )
|
|||
return state->quit;
|
||||
}
|
||||
|
||||
void rofi_view_itterrate ( RofiViewState *state, XEvent *event )
|
||||
static void rofi_view_resize ( RofiViewState *state )
|
||||
{
|
||||
state->x11_event_loop ( state, event );
|
||||
unsigned int sbw = config.line_margin + 8;
|
||||
widget_move ( WIDGET ( state->scrollbar ), state->w - state->border - sbw, state->top_offset );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
int width = ( state->w - ( 2 * ( state->border ) + ( state->num_modi - 1 ) * config.line_margin ) ) / state->num_modi;
|
||||
for ( unsigned int j = 0; j < state->num_modi; j++ ) {
|
||||
textbox_moveresize ( state->modi[j],
|
||||
state->border + j * ( width + config.line_margin ), state->h - state->line_height - state->border,
|
||||
width, state->line_height );
|
||||
textbox_draw ( state->modi[j], draw );
|
||||
}
|
||||
}
|
||||
int entrybox_width = state->w - ( 2 * ( state->border ) ) - textbox_get_width ( state->prompt_tb )
|
||||
- textbox_get_width ( state->case_indicator );
|
||||
textbox_moveresize ( state->text, state->text->widget.x, state->text->widget.y, entrybox_width, state->line_height );
|
||||
widget_move ( WIDGET ( state->case_indicator ), state->w - state->border - textbox_get_width ( state->case_indicator ), state->border );
|
||||
/**
|
||||
* Resize in Height
|
||||
*/
|
||||
{
|
||||
unsigned int last_length = state->max_elements;
|
||||
int element_height = state->line_height * config.element_height + config.line_margin;
|
||||
// Calculated new number of boxes.
|
||||
int h = ( state->h - state->top_offset - config.padding );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
h -= state->line_height + config.line_margin;
|
||||
}
|
||||
if ( h < 0 ) {
|
||||
fprintf ( stderr, "Current padding %u (on each side) does not fit within visible window %u.\n", config.padding, state->h );
|
||||
h = ( state->h - state->top_offset - state->h / 3 );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
h -= state->line_height + config.line_margin;
|
||||
}
|
||||
}
|
||||
state->max_rows = MAX ( 1, ( h / element_height ) );
|
||||
state->menu_lines = state->max_rows;
|
||||
state->max_elements = state->max_rows * config.menu_columns;
|
||||
// Free boxes no longer needed.
|
||||
for ( unsigned int i = state->max_elements; i < last_length; i++ ) {
|
||||
textbox_free ( state->boxes[i] );
|
||||
}
|
||||
// resize array.
|
||||
state->boxes = g_realloc ( state->boxes, state->max_elements * sizeof ( textbox* ) );
|
||||
|
||||
int y_offset = state->top_offset;
|
||||
int x_offset = state->border;
|
||||
// Add newly added boxes.
|
||||
for ( unsigned int i = last_length; i < state->max_elements; i++ ) {
|
||||
state->boxes[i] = textbox_create ( 0, x_offset, y_offset,
|
||||
state->element_width, element_height, NORMAL, "" );
|
||||
}
|
||||
scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin );
|
||||
}
|
||||
|
||||
state->rchanged = TRUE;
|
||||
state->update = TRUE;
|
||||
}
|
||||
|
||||
void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event )
|
||||
{
|
||||
uint8_t type = event->response_type & ~0x80;
|
||||
switch ( type )
|
||||
{
|
||||
case XCB_EXPOSE:
|
||||
state->update = TRUE;
|
||||
break;
|
||||
case XCB_CONFIGURE_NOTIFY:
|
||||
{
|
||||
xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *) event;
|
||||
if ( xce->window == main_window ) {
|
||||
if ( state->x != xce->x || state->y != xce->y ) {
|
||||
state->x = xce->x;
|
||||
state->y = xce->y;
|
||||
state->update = TRUE;
|
||||
}
|
||||
if ( state->w != xce->width || state->h != xce->height ) {
|
||||
state->w = xce->width;
|
||||
state->h = xce->height;
|
||||
cairo_xlib_surface_set_size ( surface, state->w, state->h );
|
||||
rofi_view_resize ( state );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
state->x11_event_loop ( state, event, xkb );
|
||||
}
|
||||
rofi_view_update ( state );
|
||||
}
|
||||
|
||||
const char * rofi_view_get_user_input ( const RofiViewState *state )
|
||||
|
@ -881,7 +967,7 @@ void rofi_view_update ( RofiViewState *state )
|
|||
*
|
||||
* Handle paste event.
|
||||
*/
|
||||
static void rofi_view_paste ( RofiViewState *state, XSelectionEvent *xse )
|
||||
static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t *xse )
|
||||
{
|
||||
if ( xse->property == netatoms[UTF8_STRING] ) {
|
||||
gchar *text = window_get_text_prop ( display, main_window, netatoms[UTF8_STRING] );
|
||||
|
@ -903,65 +989,6 @@ static void rofi_view_paste ( RofiViewState *state, XSelectionEvent *xse )
|
|||
}
|
||||
}
|
||||
|
||||
static void rofi_view_resize ( RofiViewState *state )
|
||||
{
|
||||
unsigned int sbw = config.line_margin + 8;
|
||||
widget_move ( WIDGET ( state->scrollbar ), state->w - state->border - sbw, state->top_offset );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
int width = ( state->w - ( 2 * ( state->border ) + ( state->num_modi - 1 ) * config.line_margin ) ) / state->num_modi;
|
||||
for ( unsigned int j = 0; j < state->num_modi; j++ ) {
|
||||
textbox_moveresize ( state->modi[j],
|
||||
state->border + j * ( width + config.line_margin ), state->h - state->line_height - state->border,
|
||||
width, state->line_height );
|
||||
textbox_draw ( state->modi[j], draw );
|
||||
}
|
||||
}
|
||||
int entrybox_width = state->w - ( 2 * ( state->border ) ) - textbox_get_width ( state->prompt_tb )
|
||||
- textbox_get_width ( state->case_indicator );
|
||||
textbox_moveresize ( state->text, state->text->widget.x, state->text->widget.y, entrybox_width, state->line_height );
|
||||
widget_move ( WIDGET ( state->case_indicator ), state->w - state->border - textbox_get_width ( state->case_indicator ), state->border );
|
||||
/**
|
||||
* Resize in Height
|
||||
*/
|
||||
{
|
||||
unsigned int last_length = state->max_elements;
|
||||
int element_height = state->line_height * config.element_height + config.line_margin;
|
||||
// Calculated new number of boxes.
|
||||
int h = ( state->h - state->top_offset - config.padding );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
h -= state->line_height + config.line_margin;
|
||||
}
|
||||
if ( h < 0 ) {
|
||||
fprintf ( stderr, "Current padding %u (on each side) does not fit within visible window %u.\n", config.padding, state->h );
|
||||
h = ( state->h - state->top_offset - state->h / 3 );
|
||||
if ( config.sidebar_mode == TRUE ) {
|
||||
h -= state->line_height + config.line_margin;
|
||||
}
|
||||
}
|
||||
state->max_rows = MAX ( 1, ( h / element_height ) );
|
||||
state->menu_lines = state->max_rows;
|
||||
state->max_elements = state->max_rows * config.menu_columns;
|
||||
// Free boxes no longer needed.
|
||||
for ( unsigned int i = state->max_elements; i < last_length; i++ ) {
|
||||
textbox_free ( state->boxes[i] );
|
||||
}
|
||||
// resize array.
|
||||
state->boxes = g_realloc ( state->boxes, state->max_elements * sizeof ( textbox* ) );
|
||||
|
||||
int y_offset = state->top_offset;
|
||||
int x_offset = state->border;
|
||||
// Add newly added boxes.
|
||||
for ( unsigned int i = last_length; i < state->max_elements; i++ ) {
|
||||
state->boxes[i] = textbox_create ( 0, x_offset, y_offset,
|
||||
state->element_width, element_height, NORMAL, "" );
|
||||
}
|
||||
scrollbar_resize ( state->scrollbar, -1, ( state->max_rows ) * ( element_height ) - config.line_margin );
|
||||
}
|
||||
|
||||
state->rchanged = TRUE;
|
||||
state->update = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param state Internal state of the menu.
|
||||
* @param key the Key being pressed.
|
||||
|
@ -1047,32 +1074,32 @@ static int rofi_view_keyboard_navigation ( RofiViewState *state, KeySym key, uns
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rofi_view_mouse_navigation ( RofiViewState *state, XButtonEvent *xbe )
|
||||
static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_event_t *xbe )
|
||||
{
|
||||
// Scroll event
|
||||
if ( xbe->button > 3 ) {
|
||||
if ( xbe->button == 4 ) {
|
||||
if ( xbe->detail > 3 ) {
|
||||
if ( xbe->detail == 4 ) {
|
||||
rofi_view_nav_up ( state );
|
||||
}
|
||||
else if ( xbe->button == 5 ) {
|
||||
else if ( xbe->detail == 5 ) {
|
||||
rofi_view_nav_down ( state );
|
||||
}
|
||||
else if ( xbe->button == 6 ) {
|
||||
else if ( xbe->detail == 6 ) {
|
||||
rofi_view_nav_left ( state );
|
||||
}
|
||||
else if ( xbe->button == 7 ) {
|
||||
else if ( xbe->detail == 7 ) {
|
||||
rofi_view_nav_right ( state );
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if ( state->scrollbar && widget_intersect ( &( state->scrollbar->widget ), xbe->x, xbe->y ) ) {
|
||||
state->selected = scrollbar_clicked ( state->scrollbar, xbe->y );
|
||||
if ( state->scrollbar && widget_intersect ( &( state->scrollbar->widget ), xbe->event_x, xbe->event_y ) ) {
|
||||
state->selected = scrollbar_clicked ( state->scrollbar, xbe->event_y );
|
||||
state->update = TRUE;
|
||||
return;
|
||||
}
|
||||
for ( unsigned int i = 0; config.sidebar_mode == TRUE && i < state->num_modi; i++ ) {
|
||||
if ( widget_intersect ( &( state->modi[i]->widget ), xbe->x, xbe->y ) ) {
|
||||
if ( widget_intersect ( &( state->modi[i]->widget ), xbe->event_x, xbe->event_y ) ) {
|
||||
( state->selected_line ) = 0;
|
||||
state->retv = MENU_QUICK_SWITCH | ( i & MENU_LOWER_MASK );
|
||||
state->quit = TRUE;
|
||||
|
@ -1081,7 +1108,7 @@ static void rofi_view_mouse_navigation ( RofiViewState *state, XButtonEvent *xbe
|
|||
}
|
||||
}
|
||||
for ( unsigned int i = 0; i < state->max_elements; i++ ) {
|
||||
if ( widget_intersect ( &( state->boxes[i]->widget ), xbe->x, xbe->y ) ) {
|
||||
if ( widget_intersect ( &( state->boxes[i]->widget ), xbe->event_x, xbe->event_y ) ) {
|
||||
// Only allow items that are visible to be selected.
|
||||
if ( ( state->last_offset + i ) >= state->filtered_lines ) {
|
||||
break;
|
||||
|
@ -1219,115 +1246,87 @@ void rofi_view_setup_fake_transparency ( Display *display, RofiViewState *state
|
|||
}
|
||||
}
|
||||
|
||||
static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev )
|
||||
static void rofi_view_mainloop_iter ( RofiViewState *state, xcb_generic_event_t *ev )
|
||||
{
|
||||
if ( ev->type == KeymapNotify ) {
|
||||
XRefreshKeyboardMapping ( &( ev->xmapping ) );
|
||||
}
|
||||
else if ( ev->type == ConfigureNotify ) {
|
||||
XConfigureEvent xce = ev->xconfigure;
|
||||
if ( xce.window == main_window ) {
|
||||
if ( state->x != (int ) xce.x || state->y != (int) xce.y ) {
|
||||
state->x = xce.x;
|
||||
state->y = xce.y;
|
||||
state->update = TRUE;
|
||||
}
|
||||
if ( state->w != (unsigned int) xce.width || state->h != (unsigned int ) xce.height ) {
|
||||
state->w = xce.width;
|
||||
state->h = xce.height;
|
||||
cairo_xlib_surface_set_size ( surface, state->w, state->h );
|
||||
rofi_view_resize ( state );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ev->type == FocusIn ) {
|
||||
switch ( ev->response_type & ~0x80 )
|
||||
{
|
||||
case XCB_FOCUS_IN:
|
||||
if ( ( state->menu_flags & MENU_NORMAL_WINDOW ) == 0 ) {
|
||||
take_keyboard ( display, main_window );
|
||||
}
|
||||
}
|
||||
else if ( ev->type == FocusOut ) {
|
||||
break;
|
||||
case XCB_FOCUS_OUT:
|
||||
if ( ( state->menu_flags & MENU_NORMAL_WINDOW ) == 0 ) {
|
||||
release_keyboard ( display );
|
||||
}
|
||||
}
|
||||
// Handle event.
|
||||
else if ( ev->type == Expose ) {
|
||||
while ( XCheckTypedEvent ( display, Expose, ev ) ) {
|
||||
;
|
||||
}
|
||||
break;
|
||||
case XCB_MOTION_NOTIFY:
|
||||
{
|
||||
xcb_motion_notify_event_t *xme = (xcb_motion_notify_event_t *) ev;
|
||||
if ( xme->event_x >= state->scrollbar->widget.x && xme->event_x < ( state->scrollbar->widget.x + state->scrollbar->widget.w ) ) {
|
||||
state->selected = scrollbar_clicked ( state->scrollbar, xme->event_y );
|
||||
state->update = TRUE;
|
||||
}
|
||||
else if ( ev->type == MotionNotify ) {
|
||||
while ( XCheckTypedEvent ( display, MotionNotify, ev ) ) {
|
||||
;
|
||||
}
|
||||
XMotionEvent xme = ev->xmotion;
|
||||
if ( xme.x >= state->scrollbar->widget.x && xme.x < ( state->scrollbar->widget.x + state->scrollbar->widget.w ) ) {
|
||||
state->selected = scrollbar_clicked ( state->scrollbar, xme.y );
|
||||
state->update = TRUE;
|
||||
}
|
||||
}
|
||||
// Button press event.
|
||||
else if ( ev->type == ButtonPress ) {
|
||||
while ( XCheckTypedEvent ( display, ButtonPress, ev ) ) {
|
||||
;
|
||||
}
|
||||
rofi_view_mouse_navigation ( state, &( ev->xbutton ) );
|
||||
break;
|
||||
}
|
||||
case XCB_BUTTON_PRESS:
|
||||
rofi_view_mouse_navigation ( state, (xcb_button_press_event_t *) ev );
|
||||
break;
|
||||
// Paste event.
|
||||
else if ( ev->type == SelectionNotify ) {
|
||||
do {
|
||||
rofi_view_paste ( state, &( ev->xselection ) );
|
||||
} while ( XCheckTypedEvent ( display, SelectionNotify, ev ) );
|
||||
}
|
||||
// Key press event.
|
||||
else if ( ev->type == KeyPress ) {
|
||||
do {
|
||||
case XCB_SELECTION_NOTIFY:
|
||||
rofi_view_paste ( state, (xcb_selection_notify_event_t *) ev );
|
||||
break;
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) ev;
|
||||
XEvent fake_event;
|
||||
fake_event.type = KeyPress;
|
||||
fake_event.xany.display = display;
|
||||
fake_event.xany.window = xkpe->event;
|
||||
fake_event.xkey.state = xkpe->state;
|
||||
fake_event.xkey.keycode = xkpe->detail;
|
||||
// This is needed for letting the Input Method handle combined keys.
|
||||
// E.g. `e into è
|
||||
if ( XFilterEvent ( ev, main_window ) ) {
|
||||
continue;
|
||||
}
|
||||
Status stat;
|
||||
char pad[32];
|
||||
KeySym key; // = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 );
|
||||
int len = Xutf8LookupString ( xic, &( ev->xkey ), pad, sizeof ( pad ), &key, &stat );
|
||||
int len = Xutf8LookupString ( xic, &( fake_event.xkey ), pad, sizeof ( pad ), &key, &stat );
|
||||
pad[len] = 0;
|
||||
if ( stat == XLookupKeySym || stat == XLookupBoth ) {
|
||||
// Handling of paste
|
||||
if ( abe_test_action ( PASTE_PRIMARY, ev->xkey.state, key ) ) {
|
||||
if ( abe_test_action ( PASTE_PRIMARY, xkpe->state, key ) ) {
|
||||
XConvertSelection ( display, XA_PRIMARY, netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, CurrentTime );
|
||||
}
|
||||
else if ( abe_test_action ( PASTE_SECONDARY, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( PASTE_SECONDARY, xkpe->state, key ) ) {
|
||||
XConvertSelection ( display, netatoms[CLIPBOARD], netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window,
|
||||
CurrentTime );
|
||||
}
|
||||
if ( abe_test_action ( SCREENSHOT, ev->xkey.state, key ) ) {
|
||||
if ( abe_test_action ( SCREENSHOT, xkpe->state, key ) ) {
|
||||
menu_capture_screenshot ( );
|
||||
break;
|
||||
}
|
||||
if ( abe_test_action ( TOGGLE_SORT, ev->xkey.state, key ) ) {
|
||||
if ( abe_test_action ( TOGGLE_SORT, xkpe->state, key ) ) {
|
||||
config.levenshtein_sort = !config.levenshtein_sort;
|
||||
state->refilter = TRUE;
|
||||
state->update = TRUE;
|
||||
textbox_text ( state->case_indicator, get_matching_state () );
|
||||
break;
|
||||
}
|
||||
else if ( abe_test_action ( MODE_PREVIOUS, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MODE_PREVIOUS, xkpe->state, key ) ) {
|
||||
state->retv = MENU_PREVIOUS;
|
||||
( state->selected_line ) = 0;
|
||||
state->quit = TRUE;
|
||||
break;
|
||||
}
|
||||
// Menu navigation.
|
||||
else if ( abe_test_action ( MODE_NEXT, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( MODE_NEXT, xkpe->state, key ) ) {
|
||||
state->retv = MENU_NEXT;
|
||||
( state->selected_line ) = 0;
|
||||
state->quit = TRUE;
|
||||
break;
|
||||
}
|
||||
// Toggle case sensitivity.
|
||||
else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, xkpe->state, key ) ) {
|
||||
config.case_sensitive = !config.case_sensitive;
|
||||
( state->selected_line ) = 0;
|
||||
state->refilter = TRUE;
|
||||
|
@ -1336,7 +1335,7 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev )
|
|||
break;
|
||||
}
|
||||
// Special delete entry command.
|
||||
else if ( abe_test_action ( DELETE_ENTRY, ev->xkey.state, key ) ) {
|
||||
else if ( abe_test_action ( DELETE_ENTRY, xkpe->state, key ) ) {
|
||||
if ( state->selected < state->filtered_lines ) {
|
||||
( state->selected_line ) = state->line_map[state->selected];
|
||||
state->retv = MENU_ENTRY_DELETE;
|
||||
|
@ -1345,7 +1344,7 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev )
|
|||
}
|
||||
}
|
||||
for ( unsigned int a = CUSTOM_1; a <= CUSTOM_19; a++ ) {
|
||||
if ( abe_test_action ( a, ev->xkey.state, key ) ) {
|
||||
if ( abe_test_action ( a, xkpe->state, key ) ) {
|
||||
state->selected_line = UINT32_MAX;
|
||||
if ( state->selected < state->filtered_lines ) {
|
||||
( state->selected_line ) = state->line_map[state->selected];
|
||||
|
@ -1355,20 +1354,20 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev )
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ( rofi_view_keyboard_navigation ( state, key, ev->xkey.state ) ) {
|
||||
continue;
|
||||
if ( rofi_view_keyboard_navigation ( state, key, xkpe->state ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
// Skip if we detected key before.
|
||||
if ( state->quit ) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
int rc = textbox_keypress ( state->text, ev, pad, len, key, stat );
|
||||
int rc = textbox_keypress ( state->text, xkpe, pad, len, key, stat );
|
||||
// Row is accepted.
|
||||
if ( rc < 0 ) {
|
||||
int shift = ( ( ev->xkey.state & ShiftMask ) == ShiftMask );
|
||||
int shift = ( ( xkpe->state & ShiftMask ) == ShiftMask );
|
||||
|
||||
// If a valid item is selected, return that..
|
||||
state->selected_line = UINT32_MAX;
|
||||
|
@ -1404,7 +1403,8 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, XEvent *ev )
|
|||
state->update = TRUE;
|
||||
}
|
||||
}
|
||||
} while ( XCheckTypedEvent ( display, KeyPress, ev ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update if requested.
|
||||
if ( state->refilter ) {
|
||||
|
@ -1625,38 +1625,15 @@ RofiViewState *rofi_view_create ( Mode *sw,
|
|||
}
|
||||
return state;
|
||||
}
|
||||
static void __error_dialog_event_loop ( RofiViewState *state, XEvent *ev )
|
||||
static void __error_dialog_event_loop ( RofiViewState *state, xcb_generic_event_t *ev )
|
||||
{
|
||||
// Handle event.
|
||||
if ( ev->type == Expose ) {
|
||||
while ( XCheckTypedEvent ( display, Expose, ev ) ) {
|
||||
;
|
||||
}
|
||||
state->update = TRUE;
|
||||
}
|
||||
else if ( ev->type == ConfigureNotify ) {
|
||||
XConfigureEvent xce = ev->xconfigure;
|
||||
if ( xce.window == main_window ) {
|
||||
if ( state->x != (int ) xce.x || state->y != (int) xce.y ) {
|
||||
state->x = xce.x;
|
||||
state->y = xce.y;
|
||||
state->update = TRUE;
|
||||
}
|
||||
if ( state->w != (unsigned int) xce.width || state->h != (unsigned int ) xce.height ) {
|
||||
state->w = xce.width;
|
||||
state->h = xce.height;
|
||||
cairo_xlib_surface_set_size ( surface, state->w, state->h );
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ( ev->response_type & ~0x80 )
|
||||
{
|
||||
// Key press event.
|
||||
else if ( ev->type == KeyPress ) {
|
||||
while ( XCheckTypedEvent ( display, KeyPress, ev ) ) {
|
||||
;
|
||||
}
|
||||
case XCB_KEY_PRESS:
|
||||
state->quit = TRUE;
|
||||
}
|
||||
rofi_view_update ( state );
|
||||
}
|
||||
void process_result_error ( RofiViewState *state );
|
||||
void rofi_view_error_dialog ( const char *msg, int markup )
|
||||
|
|
Loading…
Reference in a new issue