29#define G_LOG_DOMAIN "View"
43#include <xcb-imdkit/encoding.h>
45#include <xcb/xcb_ewmh.h>
46#include <xcb/xcb_icccm.h>
48#include <xkbcommon/xkbcommon-x11.h>
55#define SN_API_NOT_YET_FROZEN
84static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
85 G_GNUC_UNUSED uint32_t flag,
char *str,
86 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
87 G_GNUC_UNUSED
size_t nKeySym,
88 G_GNUC_UNUSED
void *user_data);
89static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
90 G_GNUC_UNUSED
void *user_data);
91xcb_xim_im_callback xim_callback = {.forward_event =
92 x11_event_handler_fowarding,
93 .commit_string = xim_commit_string,
94 .disconnected = xim_disconnected};
98extern GThreadPool *
tpool;
166}
BenchMark = {.time = NULL, .draws = 0, .last_ts = 0.0, .min = G_MAXDOUBLE};
169 if (!
config.benchmark_ui) {
178 double ts = g_timer_elapsed(
BenchMark.time, NULL);
179 double fps = 1024 / (ts -
BenchMark.last_ts);
184 printf(
"current: %.2f fps, avg: %.2f fps, min: %.2f fps, %lu draws\r\n",
201 g_debug(
"expose event");
205 xcb_flush(
xcb->connection);
209 return (
bench_update() == TRUE) ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
222 g_debug(
"Redraw view");
225 cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);
228 cairo_set_source_surface(d,
XcbState.fake_bg, 0.0, 0.0);
230 cairo_set_source_surface(d,
XcbState.fake_bg,
236 cairo_set_source_rgba(d, 0, 0, 0, 0.0);
241 cairo_set_operator(d, CAIRO_OPERATOR_OVER);
247 if (
config.enable_imdkit) {
257 cairo_surface_flush(
XcbState.edit_surf);
328 state->
x -= state->
width / 2;
341 state->
x -= state->
width / 2;
352 state->
x -= state->
width / 2;
359 "x-offset",
config.x_offset);
361 "y-offset",
config.y_offset);
370 uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
371 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
372 uint32_t vals[] = {state->
x, state->
y, state->
width, state->
height};
375 xcb_configure_window(
xcb->connection,
CacheState.main_window, mask, vals);
377 cairo_surface_destroy(
XcbState.edit_surf);
379 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
380 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
389 g_debug(
"Re-size window based internal request: %dx%d.", state->
width,
413 if (x11_type ==
XcbState.cursor_type) {
423 xcb_query_pointer_cookie_t pointer_cookie =
425 xcb_query_pointer_reply_t *pointer_reply =
426 xcb_query_pointer_reply(
xcb->connection, pointer_cookie, NULL);
428 if (pointer_reply == NULL) {
433 pointer_reply->win_y,
config.hover_select);
456 return G_SOURCE_REMOVE;
469 if (state &&
XcbState.repaint_source == 0) {
471 g_debug(
"redraw %llu",
XcbState.count);
472 XcbState.repaint_source = g_idle_add_full(
479 const char *
const fake_background) {
481 cairo_surface_t *s = NULL;
487 if (g_strcmp0(fake_background,
"real") == 0) {
489 }
else if (g_strcmp0(fake_background,
"screenshot") == 0) {
491 }
else if (g_strcmp0(fake_background,
"background") == 0) {
495 g_debug(
"Opening %s to use as background.", fpath);
496 s = cairo_image_surface_create_from_png(fpath);
502 if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {
503 g_debug(
"Failed to open surface fake background: %s",
504 cairo_status_to_string(cairo_surface_status(s)));
505 cairo_surface_destroy(s);
508 XcbState.fake_bg = cairo_image_surface_create(
512 cairo_t *dr = cairo_create(
XcbState.fake_bg);
514 cairo_set_source_surface(dr, s, 0, 0);
520 cairo_surface_destroy(s);
527 TICK_N(
"Fake transparency");
532static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
533 G_GNUC_UNUSED uint32_t flag,
char *str,
534 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
535 G_GNUC_UNUSED
size_t nKeySym,
536 G_GNUC_UNUSED
void *user_data) {
542#ifndef XCB_IMDKIT_1_0_3_LOWER
543 if (xcb_xim_get_encoding(im) == XCB_XIM_UTF8_STRING) {
545 }
else if (xcb_xim_get_encoding(im) == XCB_XIM_COMPOUND_TEXT) {
546 size_t newLength = 0;
547 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
553 size_t newLength = 0;
554 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
561static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
562 G_GNUC_UNUSED
void *user_data) {
566static void create_ic_callback(xcb_xim_t *im, xcb_xic_t new_ic,
567 G_GNUC_UNUSED
void *user_data) {
570 xcb_xim_set_ic_focus(im,
xcb->ic);
578 static xcb_point_t spot = {.x = 0, .y = 0};
579 if (spot.x != new_x || spot.y != new_y) {
582 xcb_xim_nested_list nested = xcb_xim_create_nested_list(
583 xcb->im, XCB_XIM_XNSpotLocation, &spot, NULL);
584 xcb_xim_set_ic_values(
xcb->im,
xcb->ic, NULL, NULL, XCB_XIM_XNClientWindow,
585 &
CacheState.main_window, XCB_XIM_XNFocusWindow,
586 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes,
592static void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED
void *user_data) {
594 uint32_t input_style = XCB_IM_PreeditPosition | XCB_IM_StatusArea;
600 xcb_xim_nested_list nested =
601 xcb_xim_create_nested_list(im, XCB_XIM_XNSpotLocation, &spot, NULL);
603 im, create_ic_callback, NULL, XCB_XIM_XNInputStyle, &input_style,
604 XCB_XIM_XNClientWindow, &
CacheState.main_window, XCB_XIM_XNFocusWindow,
605 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes, &nested, NULL);
613 uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
614 XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
615 XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
616 uint32_t xcb_event_masks =
617 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
618 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |
619 XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
620 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |
621 XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
623 uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,
624 XCB_GRAVITY_STATIC, XCB_BACKING_STORE_NOT_USEFUL,
625 xcb_event_masks,
map};
628 if (
config.enable_imdkit) {
629 xcb_xim_set_im_callback(
xcb->im, &xim_callback, NULL);
632 xcb_xim_open(
xcb->im, open_xim_callback,
true, NULL);
637 xcb_void_cookie_t cc = xcb_create_window_checked(
639 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
visual->visual_id, selmask,
641 xcb_generic_error_t *error;
642 error = xcb_request_check(
xcb->connection, cc);
644 g_error(
"xcb_create_window() failed error=0x%x\n", error->error_code);
650 TICK_N(
"xcb create window");
652 xcb_create_gc(
xcb->connection,
XcbState.gc, box_window, 0, 0);
656 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
660 XcbState.edit_surf = cairo_xcb_surface_create(
664 TICK_N(
"create cairo surface");
666 cairo_font_options_t *fo = cairo_font_options_create();
668 cairo_surface_get_font_options(
XcbState.edit_surf, fo);
670 PangoContext *p = pango_cairo_create_context(
XcbState.edit_draw);
672 pango_cairo_context_set_font_options(p, fo);
673 TICK_N(
"pango cairo font setup");
680 PangoFontMap *font_map = pango_cairo_font_map_get_default();
681 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
689 dpi = (
xcb->screen->height_in_pixels * 25.4) /
690 (
double)(
xcb->screen->height_in_millimeters);
693 g_debug(
"Auto-detected DPI: %.2lf", dpi);
694 PangoFontMap *font_map = pango_cairo_font_map_get_default();
695 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
699 PangoFontMap *font_map = pango_cairo_font_map_get_default();
701 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
709 PangoFontDescription *pfd = pango_font_description_from_string(font);
711 pango_context_set_font_description(p, pfd);
713 pango_font_description_free(pfd);
715 PangoLanguage *l = pango_language_get_default();
716 pango_context_set_language(p, l);
723 cairo_font_options_destroy(fo);
728 xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_MODAL};
731 sizeof(atoms) /
sizeof(xcb_atom_t));
733 &(
xcb->ewmh._NET_WM_WINDOW_TYPE_UTILITY), 1);
737 xcb_get_property_cookie_t awc;
738 awc = xcb_ewmh_get_active_window(&
xcb->ewmh,
xcb->screen_nbr);
740 if (xcb_ewmh_get_active_window_reply(&
xcb->ewmh, awc, &active_window,
742 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE, box_window,
743 XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1,
748 &(
xcb->ewmh._NET_WM_STATE_ABOVE), 1);
749 uint32_t values[] = {1};
750 xcb_change_window_attributes(
xcb->connection, box_window,
751 XCB_CW_OVERRIDE_REDIRECT, values);
754 &(
xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);
758 TICK_N(
"setup window attributes");
762 xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_FULLSCREEN,
763 xcb->ewmh._NET_WM_STATE_ABOVE};
765 sizeof(atoms) /
sizeof(xcb_atom_t));
768 xcb_atom_t protocols[] = {
netatoms[WM_TAKE_FOCUS]};
769 xcb_icccm_set_wm_protocols(
xcb->connection, box_window,
770 xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),
773 TICK_N(
"setup window fullscreen");
776 const char wm_class_name[] =
"rofi\0Rofi";
777 xcb_icccm_set_wm_class(
xcb->connection, box_window,
sizeof(wm_class_name),
780 TICK_N(
"setup window name and class");
781 const char *transparency =
786 if (
xcb->sncontext != NULL) {
787 sn_launchee_context_setup_window(
xcb->sncontext,
CacheState.main_window);
789 TICK_N(
"setup startup notification");
794 pid_t pid = getpid();
795 xcb_ewmh_set_wm_pid(&(
xcb->ewmh),
CacheState.main_window, pid);
798 const char *hostname = g_get_host_name();
799 char *ahost = g_hostname_to_ascii(hostname);
801 xcb_icccm_set_wm_client_machine(
xcb->connection,
CacheState.main_window,
802 XCB_ATOM_STRING, 8, strlen(ahost), ahost);
821 "width", state->
width);
833 if (state->
x != xce->x || state->
y != xce->y) {
838 if (state->
width != xce->width || state->
height != xce->height) {
839 state->
width = xce->width;
840 state->
height = xce->height;
843 cairo_surface_destroy(
XcbState.edit_surf);
845 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
846 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
851 cairo_xcb_surface_create(
xcb->connection,
XcbState.edit_pixmap,
854 g_debug(
"Re-size window based external request: %d %d", state->
width,
877 g_debug(
"redraw %llu",
XcbState.count);
878 XcbState.repaint_source = g_idle_add_full(
913 g_source_remove(
XcbState.idle_timeout);
929 g_source_remove(
XcbState.repaint_source);
933 cairo_surface_destroy(
XcbState.fake_bg);
941 cairo_surface_destroy(
XcbState.edit_surf);
945 g_debug(
"Unmapping and free'ing window");
948 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
952 if (
map != XCB_COLORMAP_NONE) {
953 xcb_free_colormap(
xcb->connection,
map);
954 map = XCB_COLORMAP_NONE;
956 xcb_flush(
xcb->connection);
957 g_assert(g_queue_is_empty(&(
CacheState.views)));
967 ssize_t len = strlen(title);
968 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
970 xcb->ewmh.UTF8_STRING, 8, len, title);
971 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
972 CacheState.main_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING,
int monitor_active(workarea *mon)
void display_early_cleanup(void)
void display_revert_input_focus(void)
struct _workarea workarea
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
char * rofi_expand_path(const char *input)
unsigned int mode_get_num_entries(const Mode *mode)
void textbox_set_pango_context(const char *font, PangoContext *p)
void textbox_text(textbox *tb, const char *text)
int textbox_get_cursor_x_pos(const textbox *tb)
void rofi_view_queue_redraw(void)
RofiViewState * rofi_view_get_active(void)
void rofi_view_handle_text(RofiViewState *state, const char *text)
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
gboolean rofi_set_im_window_pos(int new_x, int new_y)
const view_proxy * xcb_view_proxy
void input_history_save(void)
void input_history_initialize(void)
box * box_create(widget *parent, const char *name, RofiOrientation type)
@ ROFI_ORIENTATION_HORIZONTAL
@ ROFI_ORIENTATION_VERTICAL
#define DEFAULT_MENU_WIDTH
int rofi_theme_get_integer(const widget *wid, const char *property, int def)
int rofi_theme_get_position(const widget *wid, const char *property, int def)
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
int rofi_theme_get_boolean(const widget *wid, const char *property, int def)
RofiDistance rofi_theme_get_distance(const widget *wid, const char *property, int def)
const char * rofi_theme_get_string(const widget *wid, const char *property, const char *def)
struct _view_proxy view_proxy
void rofi_view_update(RofiViewState *state, gboolean qr)
struct _rofi_view_cache_state CacheState
static const int loc_transtable[9]
int xcb_configure_notify_event_t
cairo_surface_t * x11_helper_get_screenshot_surface(void)
cairo_surface_t * x11_helper_get_bg_surface(void)
void x11_set_cursor(xcb_window_t window, X11CursorType type)
void cairo_image_surface_blur(cairo_surface_t *surface, int radius, double deviation)
xcb_window_t xcb_stuff_get_root_window(void)
void window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count)
void xcb_stuff_set_clipboard(char *data)
void x11_disable_decoration(xcb_window_t window)
xcb_atom_t netatoms[NUM_NETATOMS]
xcb_visualtype_t * visual
cairo_surface_t * fake_bg
static struct @155221133275114015303222275063026125104100003333 BenchMark
static void xcb_rofi_view_get_current_monitor(int *width, int *height)
static gboolean bench_update(void)
static void xcb_rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
static void xcb_rofi_view_calculate_window_width(RofiViewState *state)
static void xcb___create_window(MenuFlags menu_flags)
static void xcb_rofi_view_window_update_size(RofiViewState *state)
static void xcb_rofi_view_set_window_title(const char *title)
static struct @245150067040235115245101050276046267042376347112 XcbState
cairo_surface_t * edit_surf
static void xcb_rofi_view_update(RofiViewState *state, gboolean qr)
static void xcb_rofi_view_setup_fake_transparency(widget *win, const char *const fake_background)
static void xcb_rofi_view_cleanup(void)
static void xcb_rofi_view_set_cursor(RofiCursorType type)
static gboolean xcb_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data)
static gboolean xcb_rofi_view_repaint(G_GNUC_UNUSED void *data)
static void xcb_rofi_view_calculate_window_position(RofiViewState *state)
static int xcb_rofi_view_calculate_window_height(RofiViewState *state)
static void xcb_rofi_view_reload(void)
static void xcb_rofi_view_frame_callback(void)
X11CursorType cursor_type
static xcb_window_t xcb_rofi_view_get_window(void)
static void xcb_rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
static void xcb_rofi_view_ping_mouse(RofiViewState *state)
static void xcb_rofi_view_queue_redraw(void)
static X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type)
static void xcb_rofi_view_hide(void)