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);
329 state->
x -= state->
width / 2;
342 state->
x -= state->
width / 2;
353 state->
x -= state->
width / 2;
360 "x-offset",
config.x_offset);
362 "y-offset",
config.y_offset);
371 uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
372 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
373 uint32_t vals[] = {state->
x, state->
y, state->
width, state->
height};
376 xcb_configure_window(
xcb->connection,
CacheState.main_window, mask, vals);
378 cairo_surface_destroy(
XcbState.edit_surf);
380 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
381 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
390 g_debug(
"Re-size window based internal request: %dx%d.", state->
width,
414 if (x11_type ==
XcbState.cursor_type) {
424 xcb_query_pointer_cookie_t pointer_cookie =
426 xcb_query_pointer_reply_t *pointer_reply =
427 xcb_query_pointer_reply(
xcb->connection, pointer_cookie, NULL);
429 if (pointer_reply == NULL) {
434 pointer_reply->win_y,
config.hover_select);
454 return G_SOURCE_REMOVE;
467 if (state &&
XcbState.repaint_source == 0) {
469 g_debug(
"redraw %llu",
XcbState.count);
470 XcbState.repaint_source = g_idle_add_full(
477 const char *
const fake_background) {
479 cairo_surface_t *s = NULL;
485 if (g_strcmp0(fake_background,
"real") == 0) {
487 }
else if (g_strcmp0(fake_background,
"screenshot") == 0) {
489 }
else if (g_strcmp0(fake_background,
"background") == 0) {
493 g_debug(
"Opening %s to use as background.", fpath);
494 s = cairo_image_surface_create_from_png(fpath);
500 if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {
501 g_debug(
"Failed to open surface fake background: %s",
502 cairo_status_to_string(cairo_surface_status(s)));
503 cairo_surface_destroy(s);
506 XcbState.fake_bg = cairo_image_surface_create(
510 cairo_t *dr = cairo_create(
XcbState.fake_bg);
512 cairo_set_source_surface(dr, s, 0, 0);
518 cairo_surface_destroy(s);
525 TICK_N(
"Fake transparency");
530static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
531 G_GNUC_UNUSED uint32_t flag,
char *str,
532 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
533 G_GNUC_UNUSED
size_t nKeySym,
534 G_GNUC_UNUSED
void *user_data) {
540#ifndef XCB_IMDKIT_1_0_3_LOWER
541 if (xcb_xim_get_encoding(im) == XCB_XIM_UTF8_STRING) {
543 }
else if (xcb_xim_get_encoding(im) == XCB_XIM_COMPOUND_TEXT) {
544 size_t newLength = 0;
545 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
551 size_t newLength = 0;
552 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
559static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
560 G_GNUC_UNUSED
void *user_data) {
564static void create_ic_callback(xcb_xim_t *im, xcb_xic_t new_ic,
565 G_GNUC_UNUSED
void *user_data) {
568 xcb_xim_set_ic_focus(im,
xcb->ic);
576 static xcb_point_t spot = {.x = 0, .y = 0};
577 if (spot.x != new_x || spot.y != new_y) {
580 xcb_xim_nested_list nested = xcb_xim_create_nested_list(
581 xcb->im, XCB_XIM_XNSpotLocation, &spot, NULL);
582 xcb_xim_set_ic_values(
xcb->im,
xcb->ic, NULL, NULL, XCB_XIM_XNClientWindow,
583 &
CacheState.main_window, XCB_XIM_XNFocusWindow,
584 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes,
590static void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED
void *user_data) {
592 uint32_t input_style = XCB_IM_PreeditPosition | XCB_IM_StatusArea;
598 xcb_xim_nested_list nested =
599 xcb_xim_create_nested_list(im, XCB_XIM_XNSpotLocation, &spot, NULL);
601 im, create_ic_callback, NULL, XCB_XIM_XNInputStyle, &input_style,
602 XCB_XIM_XNClientWindow, &
CacheState.main_window, XCB_XIM_XNFocusWindow,
603 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes, &nested, NULL);
611 uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
612 XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
613 XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
614 uint32_t xcb_event_masks =
615 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
616 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |
617 XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
618 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |
619 XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
621 uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,
622 XCB_GRAVITY_STATIC, XCB_BACKING_STORE_NOT_USEFUL,
623 xcb_event_masks,
map};
626 if (
config.enable_imdkit) {
627 xcb_xim_set_im_callback(
xcb->im, &xim_callback, NULL);
630 xcb_xim_open(
xcb->im, open_xim_callback,
true, NULL);
635 xcb_void_cookie_t cc = xcb_create_window_checked(
637 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
visual->visual_id, selmask,
639 xcb_generic_error_t *error;
640 error = xcb_request_check(
xcb->connection, cc);
642 g_error(
"xcb_create_window() failed error=0x%x\n", error->error_code);
646 TICK_N(
"xcb create window");
648 xcb_create_gc(
xcb->connection,
XcbState.gc, box_window, 0, 0);
652 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
656 XcbState.edit_surf = cairo_xcb_surface_create(
660 TICK_N(
"create cairo surface");
662 cairo_font_options_t *fo = cairo_font_options_create();
664 cairo_surface_get_font_options(
XcbState.edit_surf, fo);
666 PangoContext *p = pango_cairo_create_context(
XcbState.edit_draw);
668 pango_cairo_context_set_font_options(p, fo);
669 TICK_N(
"pango cairo font setup");
676 PangoFontMap *font_map = pango_cairo_font_map_get_default();
677 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
685 dpi = (
xcb->screen->height_in_pixels * 25.4) /
686 (
double)(
xcb->screen->height_in_millimeters);
689 g_debug(
"Auto-detected DPI: %.2lf", dpi);
690 PangoFontMap *font_map = pango_cairo_font_map_get_default();
691 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
695 PangoFontMap *font_map = pango_cairo_font_map_get_default();
697 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
705 PangoFontDescription *pfd = pango_font_description_from_string(font);
707 pango_context_set_font_description(p, pfd);
709 pango_font_description_free(pfd);
711 PangoLanguage *l = pango_language_get_default();
712 pango_context_set_language(p, l);
719 cairo_font_options_destroy(fo);
725 &(
xcb->ewmh._NET_WM_STATE_ABOVE), 1);
726 uint32_t values[] = {1};
727 xcb_change_window_attributes(
xcb->connection, box_window,
728 XCB_CW_OVERRIDE_REDIRECT, values);
731 &(
xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);
735 TICK_N(
"setup window attributes");
739 xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_FULLSCREEN,
740 xcb->ewmh._NET_WM_STATE_ABOVE};
742 sizeof(atoms) /
sizeof(xcb_atom_t));
745 xcb_atom_t protocols[] = {
netatoms[WM_TAKE_FOCUS]};
746 xcb_icccm_set_wm_protocols(
xcb->connection, box_window,
747 xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),
750 TICK_N(
"setup window fullscreen");
753 const char wm_class_name[] =
"rofi\0Rofi";
754 xcb_icccm_set_wm_class(
xcb->connection, box_window,
sizeof(wm_class_name),
757 TICK_N(
"setup window name and class");
758 const char *transparency =
763 if (
xcb->sncontext != NULL) {
764 sn_launchee_context_setup_window(
xcb->sncontext,
CacheState.main_window);
766 TICK_N(
"setup startup notification");
771 pid_t pid = getpid();
772 xcb_ewmh_set_wm_pid(&(
xcb->ewmh),
CacheState.main_window, pid);
775 const char *hostname = g_get_host_name();
776 char *ahost = g_hostname_to_ascii(hostname);
778 xcb_icccm_set_wm_client_machine(
xcb->connection,
CacheState.main_window,
779 XCB_ATOM_STRING, 8, strlen(ahost), ahost);
798 "width", state->
width);
810 if (state->
x != xce->x || state->
y != xce->y) {
815 if (state->
width != xce->width || state->
height != xce->height) {
816 state->
width = xce->width;
817 state->
height = xce->height;
820 cairo_surface_destroy(
XcbState.edit_surf);
822 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
823 XcbState.edit_pixmap = xcb_generate_id(
xcb->connection);
828 cairo_xcb_surface_create(
xcb->connection,
XcbState.edit_pixmap,
831 g_debug(
"Re-size window based external request: %d %d", state->
width,
854 g_debug(
"redraw %llu",
XcbState.count);
855 XcbState.repaint_source = g_idle_add_full(
890 g_source_remove(
XcbState.idle_timeout);
906 g_source_remove(
XcbState.repaint_source);
910 cairo_surface_destroy(
XcbState.fake_bg);
918 cairo_surface_destroy(
XcbState.edit_surf);
922 g_debug(
"Unmapping and free'ing window");
925 xcb_free_pixmap(
xcb->connection,
XcbState.edit_pixmap);
929 if (
map != XCB_COLORMAP_NONE) {
930 xcb_free_colormap(
xcb->connection,
map);
931 map = XCB_COLORMAP_NONE;
933 xcb_flush(
xcb->connection);
934 g_assert(g_queue_is_empty(&(
CacheState.views)));
944 ssize_t len = strlen(title);
945 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
947 xcb->ewmh.UTF8_STRING, 8, len, title);
948 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
949 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, 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 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)
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 struct @377203263163211155301074074321032144320117357172 XcbState
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)
static struct @360144012110351074273012021035172042147021313275 BenchMark
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)