diff options
Diffstat (limited to 'source/view.c')
-rw-r--r-- | source/view.c | 686 |
1 files changed, 124 insertions, 562 deletions
diff --git a/source/view.c b/source/view.c index 5ea660e3..23a4c0ca 100644 --- a/source/view.c +++ b/source/view.c @@ -34,26 +34,18 @@ #include <errno.h> #include <time.h> #include <locale.h> -#include <xkbcommon/xkbcommon-x11.h> -#include <xcb/xkb.h> -#include <xcb/xcb_ewmh.h> -#include <xcb/xcb_icccm.h> #include <cairo.h> -#include <cairo-xcb.h> - -#define SN_API_NOT_YET_FROZEN -#include <libsn/sn.h> #include "timings.h" #include "settings.h" #include "rofi.h" #include "mode.h" -#include "xcb-internal.h" #include "xkb-internal.h" #include "helper.h" #include "helper-theme.h" +#include "display.h" #include "x11-helper.h" #include "xrmoptions.h" #include "dialogs/dialogs.h" @@ -66,7 +58,6 @@ /** The Rofi View log domain */ #define LOG_DOMAIN "View" -#include "xcb.h" /** * @param state The handle to the view * @param qr Indicate if queue_redraw should be called on changes. @@ -88,26 +79,10 @@ RofiViewState *current_active_menu = NULL; */ struct { - /** main x11 windows */ - xcb_window_t main_window; - /** surface containing the fake background. */ - cairo_surface_t *fake_bg; - /** Draw context for main window */ - xcb_gcontext_t gc; - /** Main X11 side pixmap to draw on. */ - xcb_pixmap_t edit_pixmap; - /** Cairo Surface for edit_pixmap */ - cairo_surface_t *edit_surf; - /** Drawable context for edit_surf */ - cairo_t *edit_draw; - /** Indicate that fake background should be drawn relative to the window */ - int fake_bgrel; /** Main flags */ MenuFlags flags; /** List of stacked views */ GQueue views; - /** Current work area */ - workarea mon; /** timeout for reloading */ guint idle_timeout; /** debug counter for redraws */ @@ -117,11 +92,6 @@ struct /** Window fullscreen */ gboolean fullscreen; } CacheState = { - .main_window = XCB_WINDOW_NONE, - .fake_bg = NULL, - .edit_surf = NULL, - .edit_draw = NULL, - .fake_bgrel = FALSE, .flags = MENU_NORMAL, .views = G_QUEUE_INIT, .idle_timeout = 0, @@ -130,15 +100,6 @@ struct .fullscreen = FALSE, }; -void rofi_view_get_current_monitor ( int *width, int *height ) -{ - if ( width ) { - *width = CacheState.mon.w; - } - if ( height ) { - *height = CacheState.mon.h; - } -} static char * get_matching_state ( void ) { if ( config.case_sensitive ) { @@ -175,11 +136,6 @@ static int lev_sort ( const void *p1, const void *p2, void *arg ) static void menu_capture_screenshot ( void ) { const char *outp = g_getenv ( "ROFI_PNG_OUTPUT" ); - if ( CacheState.edit_surf == NULL ) { - // Nothing to store. - fprintf ( stderr, "There is no rofi surface to store\n" ); - return; - } const char *xdg_pict_dir = g_get_user_special_dir ( G_USER_DIRECTORY_PICTURES ); if ( outp == NULL && xdg_pict_dir == NULL ) { fprintf ( stderr, "XDG user picture directory or ROFI_PNG_OUTPUT is not set. Cannot store screenshot.\n" ); @@ -210,7 +166,7 @@ static void menu_capture_screenshot ( void ) fpath = g_strdup ( outp ); } fprintf ( stderr, color_green "Storing screenshot %s\n"color_reset, fpath ); - cairo_status_t status = cairo_surface_write_to_png ( CacheState.edit_surf, fpath ); + cairo_status_t status = CAIRO_STATUS_SUCCESS;//cairo_surface_write_to_png ( CacheState.edit_surf, fpath ); if ( status != CAIRO_STATUS_SUCCESS ) { fprintf ( stderr, "Failed to produce screenshot '%s', got error: '%s'\n", fpath, cairo_status_to_string ( status ) ); @@ -228,11 +184,6 @@ static gboolean rofi_view_repaint ( G_GNUC_UNUSED void * data ) // After a resize the edit_pixmap surface might not contain anything anymore. // If we already re-painted, this does nothing. rofi_view_update ( current_active_menu, FALSE ); - g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "expose event" ); - TICK_N ( "Expose" ); - xcb_copy_area ( xcb->connection, CacheState.edit_pixmap, CacheState.main_window, CacheState.gc, - 0, 0, 0, 0, current_active_menu->width, current_active_menu->height ); - xcb_flush ( xcb->connection ); TICK_N ( "flush" ); CacheState.repaint_source = 0; } @@ -254,126 +205,26 @@ static void rofi_view_update_prompt ( RofiViewState *state ) } } -/** - * Calculates the window position - */ -static void rofi_view_calculate_window_position ( RofiViewState *state ) -{ - int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location ); - int anchor = location; - if ( !listview_get_fixed_num_lines ( state->list_view ) ) { - anchor = location; - if ( location == WL_CENTER ) { - anchor = WL_NORTH; - } - else if ( location == WL_EAST ) { - anchor = WL_NORTH_EAST; - } - else if ( location == WL_WEST ) { - anchor = WL_NORTH_WEST; - } - } - anchor = rofi_theme_get_position ( WIDGET ( state->main_window ), "anchor", anchor ); - - if ( CacheState.fullscreen ) { - state->x = CacheState.mon.x; - state->y = CacheState.mon.y; - return; - } - state->y = CacheState.mon.y + ( CacheState.mon.h ) / 2; - state->x = CacheState.mon.x + ( CacheState.mon.w ) / 2; - // Determine window location - switch ( location ) - { - case WL_NORTH_WEST: - state->x = CacheState.mon.x; - case WL_NORTH: - state->y = CacheState.mon.y; - break; - case WL_NORTH_EAST: - state->y = CacheState.mon.y; - case WL_EAST: - state->x = CacheState.mon.x + CacheState.mon.w; - break; - case WL_SOUTH_EAST: - state->x = CacheState.mon.x + CacheState.mon.w; - case WL_SOUTH: - state->y = CacheState.mon.y + CacheState.mon.h; - break; - case WL_SOUTH_WEST: - state->y = CacheState.mon.y + CacheState.mon.h; - case WL_WEST: - state->x = CacheState.mon.x; - break; - case WL_CENTER: - default: - break; - } - switch ( anchor ) - { - case WL_SOUTH_WEST: - state->y -= state->height; - break; - case WL_SOUTH: - state->x -= state->width / 2; - state->y -= state->height; - break; - case WL_SOUTH_EAST: - state->x -= state->width; - state->y -= state->height; - break; - case WL_NORTH_EAST: - state->x -= state->width; - break; - case WL_NORTH_WEST: - break; - case WL_NORTH: - state->x -= state->width / 2; - break; - case WL_EAST: - state->x -= state->width; - state->y -= state->height / 2; - break; - case WL_WEST: - state->y -= state->height / 2; - break; - case WL_CENTER: - state->y -= state->height / 2; - state->x -= state->width / 2; - break; - default: - break; - } - // Apply offset. - Distance x = rofi_theme_get_distance ( WIDGET ( state->main_window ), "x-offset", config.x_offset ); - Distance y = rofi_theme_get_distance ( WIDGET ( state->main_window ), "y-offset", config.y_offset ); - state->x += distance_get_pixel ( x, ORIENTATION_HORIZONTAL ); - state->y += distance_get_pixel ( y, ORIENTATION_VERTICAL ); -} - static void rofi_view_window_update_size ( RofiViewState * state ) { - uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - uint32_t vals[] = { state->x, state->y, state->width, state->height }; - - // Display it. - xcb_configure_window ( xcb->connection, CacheState.main_window, mask, vals ); - 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 ); + if ( state->pool != NULL ) + display_buffer_pool_free(state->pool); + state->pool = NULL; g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Re-size window based internal request: %dx%d.", state->width, state->height ); // Should wrap main window in a widget. widget_resize ( WIDGET ( state->main_window ), state->width, state->height ); } +void rofi_view_set_size ( RofiViewState * state, gint width, gint height ) +{ + if ( width > -1 ) + state->width = width; + if ( height > -1 ) + state->height = height; + rofi_view_window_update_size(state); +} + static void rofi_view_reload_message_bar ( RofiViewState *state ) { if ( state->mesg_box == NULL ) { @@ -408,6 +259,19 @@ void rofi_view_reload ( void ) CacheState.idle_timeout = g_timeout_add ( 1000 / 10, rofi_view_reload_idle, NULL ); } } + +void rofi_view_frame_callback( void ) +{ + RofiViewState *state = rofi_view_get_active(); + if ( state == NULL ) + return; + + state->frame_callback = TRUE; + if ( widget_need_redraw ( WIDGET ( state->main_window ) ) ) { + rofi_view_queue_redraw(); + } +} + void rofi_view_queue_redraw ( void ) { if ( current_active_menu && CacheState.repaint_source == 0 ) { @@ -423,6 +287,12 @@ void rofi_view_restart ( RofiViewState *state ) state->retv = MENU_CANCEL; } +void rofi_view_quit ( RofiViewState *state ) +{ + state->quit = TRUE; + state->retv = MENU_CANCEL; +} + RofiViewState * rofi_view_get_active ( void ) { return current_active_menu; @@ -463,8 +333,7 @@ void rofi_view_set_selected_line ( RofiViewState *state, unsigned int selected_l } } listview_set_selected ( state->list_view, selected ); - xcb_clear_area ( xcb->connection, CacheState.main_window, 1, 0, 0, 1, 1 ); - xcb_flush ( xcb->connection ); + // FIXME: draw new state } void rofi_view_free ( RofiViewState *state ) @@ -587,125 +456,20 @@ static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data } } } -static void rofi_view_setup_fake_transparency ( const char* const fake_background ) -{ - if ( CacheState.fake_bg == NULL ) { - cairo_surface_t *s = NULL; - /** - * Select Background to use for fake transparency. - * Current options: 'real', 'screenshot','background' - */ - TICK_N ( "Fake start" ); - if ( g_strcmp0 ( fake_background, "real" ) == 0 ) { - return; - } - else if ( g_strcmp0 ( fake_background, "screenshot" ) == 0 ) { - s = x11_helper_get_screenshot_surface (); - } - else if ( g_strcmp0 ( fake_background, "background" ) == 0 ) { - s = x11_helper_get_bg_surface (); - } - else { - char *fpath = rofi_expand_path ( fake_background ); - g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Opening %s to use as background.", fpath ); - s = cairo_image_surface_create_from_png ( fpath ); - CacheState.fake_bgrel = TRUE; - g_free ( fpath ); - } - TICK_N ( "Get surface." ); - if ( s != NULL ) { - if ( cairo_surface_status ( s ) != CAIRO_STATUS_SUCCESS ) { - g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Failed to open surface fake background: %s", - cairo_status_to_string ( cairo_surface_status ( s ) ) ); - cairo_surface_destroy ( s ); - s = NULL; - } - else { - CacheState.fake_bg = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, CacheState.mon.w, CacheState.mon.h ); - cairo_t *dr = cairo_create ( CacheState.fake_bg ); - if ( CacheState.fake_bgrel ) { - cairo_set_source_surface ( dr, s, 0, 0 ); - } - else { - cairo_set_source_surface ( dr, s, -CacheState.mon.x, -CacheState.mon.y ); - } - cairo_paint ( dr ); - cairo_destroy ( dr ); - cairo_surface_destroy ( s ); - } - } - TICK_N ( "Fake transparency" ); - } -} void __create_window ( MenuFlags menu_flags ) { - uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; - uint32_t selval[] = { - XCB_BACK_PIXMAP_NONE, 0, - XCB_GRAVITY_STATIC, - XCB_BACKING_STORE_NOT_USEFUL, - XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | - XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE | - XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION, - map - }; - - xcb_window_t box = xcb_generate_id ( xcb->connection ); - xcb_void_cookie_t cc = xcb_create_window_checked ( xcb->connection, depth->depth, box, xcb_stuff_get_root_window ( xcb ), - 0, 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, - visual->visual_id, selmask, selval ); - xcb_generic_error_t *error; - error = xcb_request_check ( xcb->connection, cc ); - if ( error ) { - printf ( "xcb_create_window() failed error=0x%x\n", error->error_code ); - exit ( EXIT_FAILURE ); - } - TICK_N ( "xcb create window" ); - CacheState.gc = xcb_generate_id ( xcb->connection ); - xcb_create_gc ( xcb->connection, CacheState.gc, box, 0, 0 ); - - TICK_N ( "xcb create gc" ); - // Create a drawable. - CacheState.edit_pixmap = xcb_generate_id ( xcb->connection ); - xcb_create_pixmap ( xcb->connection, depth->depth, - CacheState.edit_pixmap, CacheState.main_window, 200, 100 ); - - CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, 200, 100 ); - CacheState.edit_draw = cairo_create ( CacheState.edit_surf ); + // FIXME: create surface + // FIXME: roll next buffer TICK_N ( "create cairo surface" ); - // Set up pango context. - cairo_font_options_t *fo = cairo_font_options_create (); - // Take font description from xlib surface - cairo_surface_get_font_options ( CacheState.edit_surf, fo ); // TODO should we update the drawable each time? - PangoContext *p = pango_cairo_create_context ( CacheState.edit_draw ); - // Set the font options from the xlib surface - pango_cairo_context_set_font_options ( p, fo ); + PangoContext *p = pango_context_new ( ); + pango_context_set_font_map(p, pango_cairo_font_map_get_default()); TICK_N ( "pango cairo font setup" ); - CacheState.main_window = box; CacheState.flags = menu_flags; - monitor_active ( &( CacheState.mon ) ); // Setup dpi - if ( config.dpi > 1 ) { - PangoFontMap *font_map = pango_cairo_font_map_get_default (); - pango_cairo_font_map_set_resolution ( (PangoCairoFontMap *) font_map, (double) config.dpi ); - } - else if ( config.dpi == 0 || config.dpi == 1 ) { - // Auto-detect mode. - double dpi = 96; - if ( CacheState.mon.mh > 0 && config.dpi == 1 ) { - dpi = ( CacheState.mon.h * 25.4 ) / (double) ( CacheState.mon.mh ); - } - else { - dpi = ( xcb->screen->height_in_pixels * 25.4 ) / (double) ( xcb->screen->height_in_millimeters ); - } - - g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Auto-detected DPI: %.2lf", dpi ); - PangoFontMap *font_map = pango_cairo_font_map_get_default (); - pango_cairo_font_map_set_resolution ( (PangoCairoFontMap *) font_map, dpi ); - } + // FIXME: use scale, cairo_surface_set_device_scale // Setup font. // Dummy widget. container *win = container_create ( "window.box" ); @@ -725,50 +489,7 @@ void __create_window ( MenuFlags menu_flags ) textbox_set_pango_context ( font, p ); // cleanup g_object_unref ( p ); - cairo_font_options_destroy ( fo ); - - TICK_N ( "textbox setup" ); - // // make it an unmanaged window - if ( ( ( menu_flags & MENU_NORMAL_WINDOW ) == 0 ) ) { - window_set_atom_prop ( box, xcb->ewmh._NET_WM_STATE, &( xcb->ewmh._NET_WM_STATE_ABOVE ), 1 ); - uint32_t values[] = { 1 }; - xcb_change_window_attributes ( xcb->connection, box, XCB_CW_OVERRIDE_REDIRECT, values ); - } - else{ - window_set_atom_prop ( box, xcb->ewmh._NET_WM_WINDOW_TYPE, &( xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL ), 1 ); - x11_disable_decoration ( box ); - } - - TICK_N ( "setup window attributes" ); - CacheState.fullscreen = rofi_theme_get_boolean ( WIDGET ( win ), "fullscreen", config.fullscreen ); - if ( CacheState.fullscreen ) { - xcb_atom_t atoms[] = { - xcb->ewmh._NET_WM_STATE_FULLSCREEN, - xcb->ewmh._NET_WM_STATE_ABOVE - }; - window_set_atom_prop ( box, xcb->ewmh._NET_WM_STATE, atoms, sizeof ( atoms ) / sizeof ( xcb_atom_t ) ); - } - - TICK_N ( "setup window fullscreen" ); - // Set the WM_NAME - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box, xcb->ewmh._NET_WM_NAME, xcb->ewmh.UTF8_STRING, 8, 4, "rofi" ); - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 4, "rofi" ); - - const char wm_class_name[] = "rofi\0Rofi"; - xcb_icccm_set_wm_class ( xcb->connection, box, sizeof ( wm_class_name ), wm_class_name ); - TICK_N ( "setup window name and class" ); - char *transparency = rofi_theme_get_string ( WIDGET ( win ), "transparency", NULL ); - if ( transparency == NULL && config.fake_transparency ) { - transparency = config.fake_background; - } - if ( transparency ) { - rofi_view_setup_fake_transparency ( transparency ); - } - if ( xcb->sncontext != NULL ) { - sn_launchee_context_setup_window ( xcb->sncontext, CacheState.main_window ); - } - TICK_N ( "setup startup notification" ); widget_free ( WIDGET ( win ) ); TICK_N ( "done" ); } @@ -780,10 +501,6 @@ void __create_window ( MenuFlags menu_flags ) */ static void rofi_view_calculate_window_width ( RofiViewState *state ) { - if ( CacheState.fullscreen ) { - state->width = CacheState.mon.w; - return; - } if ( config.menu_width < 0 ) { double fw = textbox_get_estimated_char_width ( ); state->width = -( fw * config.menu_width ); @@ -791,7 +508,7 @@ static void rofi_view_calculate_window_width ( RofiViewState *state ) } else{ // Calculate as float to stop silly, big rounding down errors. - state->width = config.menu_width < 101 ? ( CacheState.mon.w / 100.0f ) * ( float ) config.menu_width : config.menu_width; + state->width = config.menu_width < 101 ? ( /* FIXME: ??? what to use instead of monitor size here? */ 1000. / 100.0f ) * ( float ) config.menu_width : config.menu_width; } // Use theme configured width, if set. Distance width = rofi_theme_get_distance ( WIDGET ( state->main_window ), "width", state->width ); @@ -920,26 +637,16 @@ void rofi_view_update ( RofiViewState *state, gboolean qr ) return; } g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Redraw view" ); + if ( state->pool == NULL ) { + state->pool = display_buffer_pool_new(state->width, state->height); + } TICK (); - cairo_t *d = CacheState.edit_draw; + cairo_surface_t *surface = display_buffer_pool_get_next_buffer(state->pool); + cairo_t *d = cairo_create(surface); cairo_set_operator ( d, CAIRO_OPERATOR_SOURCE ); - if ( CacheState.fake_bg != NULL ) { - if ( CacheState.fake_bgrel ) { - cairo_set_source_surface ( d, CacheState.fake_bg, 0.0, 0.0 ); - } - else { - cairo_set_source_surface ( d, CacheState.fake_bg, - -(double) ( state->x - CacheState.mon.x ), - -(double) ( state->y - CacheState.mon.y ) ); - } - cairo_paint ( d ); - cairo_set_operator ( d, CAIRO_OPERATOR_OVER ); - } - else { - // Paint the background transparent. - cairo_set_source_rgba ( d, 0, 0, 0, 0.0 ); - cairo_paint ( d ); - } + // Paint the background transparent. + cairo_set_source_rgba ( d, 0, 0, 0, 0.0 ); + cairo_paint ( d ); TICK_N ( "Background" ); // Always paint as overlay over the background. @@ -950,71 +657,35 @@ void rofi_view_update ( RofiViewState *state, gboolean qr ) widget_draw ( WIDGET ( state->overlay ), d ); } TICK_N ( "widgets" ); - cairo_surface_flush ( CacheState.edit_surf ); + cairo_destroy(d); + display_surface_commit ( surface ); + if ( qr ) { rofi_view_queue_redraw (); } } -/** - * @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 ) +void rofi_view_mouse_navigation ( rofi_mouse_wheel_direction direction ) { - if ( xse->property == XCB_ATOM_NONE ) { - fprintf ( stderr, "Failed to convert selection\n" ); - } - 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 { - fprintf ( stderr, "Failed\n" ); - } -} + RofiViewState *state = rofi_view_get_active(); -static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_event_t *xbe ) -{ - // Scroll event - if ( xbe->detail > 3 ) { - if ( xbe->detail == 4 ) { + switch ( direction ) + { + case ROFI_MOUSE_WHEEL_UP: listview_nav_up ( state->list_view ); - } - else if ( xbe->detail == 5 ) { + break; + case ROFI_MOUSE_WHEEL_DOWN: listview_nav_down ( state->list_view ); - } - else if ( xbe->detail == 6 ) { + break; + case ROFI_MOUSE_WHEEL_LEFT: listview_nav_left ( state->list_view ); - } - else if ( xbe->detail == 7 ) { + break; + case ROFI_MOUSE_WHEEL_RIGHT: listview_nav_right ( state->list_view ); - } - return; - } - else { - xcb_button_press_event_t rel = *xbe; - if ( widget_clicked ( WIDGET ( state->main_window ), &rel ) ) { - return; - } + break; } } + static void _rofi_view_reload_row ( RofiViewState *state ) { g_free ( state->line_map ); @@ -1114,7 +785,6 @@ static void rofi_view_refilter ( RofiViewState *state ) int height = rofi_view_calculate_height ( state ); if ( height != state->height ) { state->height = height; - rofi_view_calculate_window_position ( state ); rofi_view_window_update_size ( state ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Resize based on re-filter" ); } @@ -1141,14 +811,8 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, KeyBindingAction actio { // Handling of paste case PASTE_PRIMARY: - xcb_convert_selection ( xcb->connection, CacheState.main_window, XCB_ATOM_PRIMARY, - xcb->ewmh.UTF8_STRING, xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME ); - xcb_flush ( xcb->connection ); - break; case PASTE_SECONDARY: - xcb_convert_selection ( xcb->connection, CacheState.main_window, netatoms[CLIPBOARD], - xcb->ewmh.UTF8_STRING, xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME ); - xcb_flush ( xcb->connection ); + // FIXME: implement clipboard break; case SCREENSHOT: menu_capture_screenshot ( ); @@ -1346,92 +1010,49 @@ gboolean rofi_view_trigger_action ( RofiViewState *state, KeyBindingAction actio return ret; } -static void rofi_view_handle_keypress ( RofiViewState *state, xkb_stuff *xkb, xcb_key_press_event_t *xkpe ) +void rofi_view_handle_keypress ( widget_modifier_mask modmask, xkb_keysym_t key, char *text, int len ) { - xcb_keysym_t key; - char pad[32]; - int len = 0; - - key = xkb_state_key_get_one_sym ( xkb->state, xkpe->detail ); - - if ( xkb->compose.state != NULL ) { - if ( ( key != XKB_KEY_NoSymbol ) && ( xkb_compose_state_feed ( xkb->compose.state, key ) == XKB_COMPOSE_FEED_ACCEPTED ) ) { - switch ( xkb_compose_state_get_status ( xkb->compose.state ) ) - { - case XKB_COMPOSE_CANCELLED: - /* Eat the keysym that cancelled the compose sequence. - * This is default behaviour with Xlib */ - case XKB_COMPOSE_COMPOSING: - key = XKB_KEY_NoSymbol; - break; - case XKB_COMPOSE_COMPOSED: - key = xkb_compose_state_get_one_sym ( xkb->compose.state ); - len = xkb_compose_state_get_utf8 ( xkb->compose.state, pad, sizeof ( pad ) ); - break; - case XKB_COMPOSE_NOTHING: - break; - } - if ( ( key == XKB_KEY_NoSymbol ) && ( len == 0 ) ) { - return; - } - } - } - - if ( len == 0 ) { - len = xkb_state_key_get_utf8 ( xkb->state, xkpe->detail, pad, sizeof ( pad ) ); - } - - xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods ( xkb->state, xkpe->detail ); - - unsigned int modstate = x11_canonalize_mask ( xkpe->state & ( ~consumed ) ); + RofiViewState *state = rofi_view_get_active(); if ( key != XKB_KEY_NoSymbol ) { KeyBindingAction action; - action = abe_find_action ( modstate, key ); + action = abe_find_action ( modmask, key ); if ( rofi_view_trigger_action ( state, action ) ) { return; } } - if ( ( len > 0 ) && ( textbox_append_char ( state->text, pad, len ) ) ) { + if ( ( len > 0 ) && ( textbox_append_char ( state->text, text, len ) ) ) { state->refilter = TRUE; - return; } } +void rofi_view_maybe_update ( void ) +{ + RofiViewState *state = rofi_view_get_active(); + + if ( rofi_view_get_completed ( state ) ) { + // This menu is done. + rofi_view_finalize ( state ); + // cleanup + state = rofi_view_get_active(); + if ( state == NULL ) { + rofi_quit_main_loop(); + return; + } + } + + if ( state->refilter ) { + rofi_view_refilter ( state ); + } + rofi_view_update ( state, TRUE ); +} + +/* FIXME: dispatch from Wayland callbacks void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_stuff *xkb ) { switch ( ev->response_type & ~0x80 ) { - case XCB_CONFIGURE_NOTIFY: - { - xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *) ev; - 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_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Re-size window based external request: %d %d\n", 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 ) { @@ -1477,37 +1098,35 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st } break; } - case XCB_KEY_PRESS: - rofi_view_handle_keypress ( state, xkb, (xcb_key_press_event_t *) ev ); - break; - case XCB_KEY_RELEASE: - { - xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) ev; - unsigned int modstate = x11_canonalize_mask ( xkre->state ); - if ( modstate == 0 ) { - abe_trigger_release ( ); - } - break; - } default: break; } - // Update if requested. - if ( state->refilter ) { - rofi_view_refilter ( state ); +} +*/ +void rofi_view_handle_mouse_button( widget_button_event *be ) +{ + RofiViewState *state = rofi_view_get_active(); + + if ( be->pressed ) { + widget_clicked ( WIDGET ( state->main_window ), be ); } - rofi_view_update ( state, TRUE ); +} - if ( ( ev->response_type & ~0x80 ) == XCB_EXPOSE && CacheState.repaint_source == 0 ) { - CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL ); +void rofi_view_handle_mouse_motion(widget_motion_event *me) +{ + RofiViewState *state = rofi_view_get_active(); + + if ( config.click_to_exit == TRUE ) { + state->mouse_seen = TRUE; } + widget_motion_notify ( WIDGET ( state->main_window ), me ); } static int rofi_view_calculate_height ( RofiViewState *state ) { unsigned int height = 0; if ( listview_get_num_lines ( state->list_view ) == 0 || CacheState.fullscreen == TRUE ) { - height = CacheState.mon.h; + height = 300; // FIXME: whatever fits return height; } @@ -1516,7 +1135,7 @@ static int rofi_view_calculate_height ( RofiViewState *state ) return height; } -static gboolean rofi_view_modi_clicked_cb ( widget *textbox, G_GNUC_UNUSED xcb_button_press_event_t *xbe, void *udata ) +static gboolean rofi_view_modi_clicked_cb ( widget *textbox, G_GNUC_UNUSED widget_button_event *be, void *udata ) { RofiViewState *state = ( RofiViewState *) udata; for ( unsigned int i = 0; i < state->num_modi; i++ ) { @@ -1530,12 +1149,11 @@ static gboolean rofi_view_modi_clicked_cb ( widget *textbox, G_GNUC_UNUSED xcb_b return FALSE; } // @TODO don't like this construction. -static void rofi_view_listview_mouse_activated_cb ( listview *lv, xcb_button_press_event_t *xce, void *udata ) +static void rofi_view_listview_mouse_activated_cb ( listview *lv, widget_button_event *be, void *udata ) { RofiViewState *state = (RofiViewState *) udata; - int control = x11_modifier_active ( xce->state, X11MOD_CONTROL ); state->retv = MENU_OK; - if ( control ) { + if ( be->modifiers == WIDGET_MODMASK_CONTROL ) { state->retv |= MENU_CUSTOM_ACTION; } ( state->selected_line ) = state->line_map[listview_get_selected ( lv )]; @@ -1562,14 +1180,11 @@ RofiViewState *rofi_view_create ( Mode *sw, state->refilter = TRUE; state->finalize = finalize; state->mouse_seen = FALSE; + state->frame_callback = TRUE; // Request the lines to show. state->num_lines = mode_get_num_entries ( sw ); - TICK_N ( "Startup notification" ); - - // Get active monitor size. - TICK_N ( "Get active monitor" ); state->main_window = container_create ( "window.box" ); state->main_box = box_create ( "window.mainbox.box", BOX_VERTICAL ); @@ -1592,9 +1207,8 @@ RofiViewState *rofi_view_create ( Mode *sw, } } - int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location ); - int end = ( location == WL_SOUTH_EAST || location == WL_SOUTH || location == WL_SOUTH_WEST ); - box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end ? 9 : 0 ); + // FIXME: re-add input box at the bottom? + box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, 0 ); state->case_indicator = textbox_create ( "window.mainbox.inputbar.case-indicator", TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*" ); // Add small separator between case indicator and text box. @@ -1617,13 +1231,14 @@ RofiViewState *rofi_view_create ( Mode *sw, state->mesg_tb = textbox_create ( "window.mainbox.message.textbox", TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL ); container_add ( state->mesg_box, WIDGET ( state->mesg_tb ) ); rofi_view_reload_message_bar ( state ); - box_add ( state->main_box, WIDGET ( state->mesg_box ), FALSE, end ? 8 : 2 ); + // FIXME: re-add input box at the bottom? + box_add ( state->main_box, WIDGET ( state->mesg_box ), FALSE, 2 ); state->overlay = textbox_create ( "window.overlay", TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat" ); state->overlay->widget.parent = WIDGET ( state->main_window ); widget_disable ( WIDGET ( state->overlay ) ); - state->list_view = listview_create ( "window.mainbox.listview", update_callback, state, config.element_height, end ); + state->list_view = listview_create ( "window.mainbox.listview", update_callback, state, config.element_height, FALSE /* FIXME: entry-at-bottom */ ); // Set configuration listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR ); listview_set_scroll_type ( state->list_view, config.scroll_method ); @@ -1642,23 +1257,14 @@ RofiViewState *rofi_view_create ( Mode *sw, rofi_view_calculate_window_width ( state ); // Need to resize otherwise calculated desired height is wrong. widget_resize ( WIDGET ( state->main_window ), state->width, 100 ); - // Only needed when window is fixed size. - if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == MENU_NORMAL_WINDOW ) { - listview_set_fixed_num_lines ( state->list_view ); - rofi_view_window_update_size ( state ); - } - // Move the window to the correct x,y position. - rofi_view_calculate_window_position ( state ); state->quit = FALSE; rofi_view_refilter ( state ); rofi_view_update ( state, TRUE ); - xcb_map_window ( xcb->connection, CacheState.main_window ); + + // FIXME: push the surface + // maybe rofi_view_queue_redraw() ? |