From ac8868f3b14853e977d2aaad09da8638ad1e09ed Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Wed, 31 May 2017 20:21:58 +0200 Subject: Indent icon code rework Signed-off-by: Quentin Glidic --- source/dialogs/drun.c | 83 ++++++++++++++++++++++++----------------------- source/view.c | 2 +- source/widgets/listview.c | 2 +- source/widgets/textbox.c | 27 ++++++++------- 4 files changed, 58 insertions(+), 56 deletions(-) (limited to 'source') diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c index a10057e6..ae7eaea3 100644 --- a/source/dialogs/drun.c +++ b/source/dialogs/drun.c @@ -89,9 +89,9 @@ typedef struct unsigned int cmd_list_length_actual; unsigned int history_length; // List of disabled entries. - GHashTable *disabled_entries; - unsigned int disabled_entries_length; - GThread *thread; + GHashTable *disabled_entries; + unsigned int disabled_entries_length; + GThread *thread; } DRunModePrivateData; struct RegexEvalArg @@ -423,41 +423,44 @@ static void drun_icon_fetch ( gpointer data ) { // as long as dr->icon is updated atomicly.. (is a pointer write atomic?) // this should be fine running in another thread. - GTimer *t = g_timer_new (); - DRunModePrivateData *pd = (DRunModePrivateData*)data; - for ( size_t i = 0; i < pd->cmd_list_length; i++ ) { - DRunModeEntry *dr = &( pd->entry_list[i] ); - if ( dr->icon_name == NULL ) - continue; - gchar *icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, NULL, "Applications", dr->icon_name, 32, 1, TRUE ); - if ( icon_path == NULL ) { - g_free(dr->icon_name); - dr->icon_name = NULL; - continue; - } - else - g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Found Icon %s(%d): %s", dr->icon_name, 32, icon_path ); - - if ( g_str_has_suffix ( icon_path, ".png" ) ) - dr->icon = cairo_image_surface_create_from_png(icon_path); - else if ( g_str_has_suffix ( icon_path, ".svg" ) ) - dr->icon = cairo_image_surface_create_from_svg(icon_path, 32); - else { - g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Icon type not yet supported: %s", icon_path ); - char *r = dr->icon_name; - dr->icon_name = NULL; - g_free(r); - } - g_free(icon_path); - // if ( (i%100) == 99 ) - { - - rofi_view_reload(); - } - } - rofi_view_reload(); - g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "elapsed: %f\n" , g_timer_elapsed ( t, NULL)); - g_timer_destroy ( t ); + GTimer *t = g_timer_new (); + DRunModePrivateData *pd = (DRunModePrivateData *) data; + for ( size_t i = 0; i < pd->cmd_list_length; i++ ) { + DRunModeEntry *dr = &( pd->entry_list[i] ); + if ( dr->icon_name == NULL ) { + continue; + } + gchar *icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, NULL, "Applications", dr->icon_name, 32, 1, TRUE ); + if ( icon_path == NULL ) { + g_free ( dr->icon_name ); + dr->icon_name = NULL; + continue; + } + else{ + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Found Icon %s(%d): %s", dr->icon_name, 32, icon_path ); + } + + if ( g_str_has_suffix ( icon_path, ".png" ) ) { + dr->icon = cairo_image_surface_create_from_png ( icon_path ); + } + else if ( g_str_has_suffix ( icon_path, ".svg" ) ) { + dr->icon = cairo_image_surface_create_from_svg ( icon_path, 32 ); + } + else { + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Icon type not yet supported: %s", icon_path ); + char *r = dr->icon_name; + dr->icon_name = NULL; + g_free ( r ); + } + g_free ( icon_path ); + // if ( (i%100) == 99 ) + { + rofi_view_reload (); + } + } + rofi_view_reload (); + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "elapsed: %f\n", g_timer_elapsed ( t, NULL ) ); + g_timer_destroy ( t ); } static int drun_mode_init ( Mode *sw ) @@ -531,7 +534,7 @@ static void drun_mode_destroy ( Mode *sw ) { DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( sw ); if ( rmpd != NULL ) { - if ( rmpd->thread ){ + if ( rmpd->thread ) { g_thread_join ( rmpd->thread ); rmpd->thread = NULL; } @@ -572,7 +575,7 @@ static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line, { DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw ); g_return_val_if_fail ( pd->entry_list != NULL, NULL ); - DRunModeEntry *dr = &( pd->entry_list[selected_line] ); + DRunModeEntry *dr = &( pd->entry_list[selected_line] ); return dr->icon; } diff --git a/source/view.c b/source/view.c index 6d2b7aea..921c0d5f 100644 --- a/source/view.c +++ b/source/view.c @@ -906,7 +906,7 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB else{ list = pango_attr_list_new (); } - int icon_height = textbox_get_font_height ( t ); + int icon_height = textbox_get_font_height ( t ); cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height ); textbox_icon ( t, icon ); diff --git a/source/widgets/listview.c b/source/widgets/listview.c index 2cab442d..427a53c2 100644 --- a/source/widgets/listview.c +++ b/source/widgets/listview.c @@ -243,7 +243,7 @@ static void listview_recompute_elements ( listview *lv ) char *name = g_strjoin ( ".", lv->listview_name, "element", NULL ); for ( unsigned int i = lv->cur_elements; i < newne; i++ ) { TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0; - flags |= ((config.show_icons)? TB_ICON:0); + flags |= ( ( config.show_icons ) ? TB_ICON : 0 ); lv->boxes[i] = textbox_create_full ( WIDGET_TYPE_LISTVIEW_ELEMENT, name, flags, NORMAL, "" ); widget_set_trigger_action_handler ( WIDGET ( lv->boxes[i] ), listview_element_trigger_action, lv ); } diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c index 27bc5246..a5a8cfac 100644 --- a/source/widgets/textbox.c +++ b/source/widgets/textbox.c @@ -143,8 +143,8 @@ textbox* textbox_create_full ( WidgetType type, const char *name, TextboxFlags f tb->changed = FALSE; tb->layout = pango_layout_new ( p_context ); - if ( (tb->flags&TB_ICON) == TB_ICON) { - tb->left_offset = 1.2*textbox_get_estimated_char_height(); + if ( ( tb->flags & TB_ICON ) == TB_ICON ) { + tb->left_offset = 1.2 * textbox_get_estimated_char_height (); } textbox_font ( tb, tbft ); @@ -189,7 +189,6 @@ textbox* textbox_create_full ( WidgetType type, const char *name, TextboxFlags f tb->widget.trigger_action = textbox_editable_trigger_action; } - // Enabled by default tb->widget.enabled = rofi_theme_get_boolean ( WIDGET ( tb ), "enabled", TRUE ); return tb; @@ -366,7 +365,7 @@ static void textbox_free ( widget *wid ) static void textbox_draw ( widget *wid, cairo_t *draw ) { textbox *tb = (textbox *) wid; - unsigned int offset = tb->left_offset + (( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0); + unsigned int offset = tb->left_offset + ( ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0 ); if ( tb->changed ) { __textbox_update_pango_text ( tb ); @@ -378,21 +377,21 @@ static void textbox_draw ( widget *wid, cairo_t *draw ) int y = top + ( pango_font_metrics_get_ascent ( tb->metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE; // draw Icon - if ( (tb->flags&TB_ICON) == TB_ICON && tb->icon != NULL ) { + if ( ( tb->flags & TB_ICON ) == TB_ICON && tb->icon != NULL ) { int iconheight = textbox_get_font_height ( tb ); - cairo_save(draw); + cairo_save ( draw ); /*int iconw = cairo_image_surface_get_width (tb->icon);*/ - int iconh = cairo_image_surface_get_height (tb->icon); - double scale = (double)iconheight / iconh; + int iconh = cairo_image_surface_get_height ( tb->icon ); + double scale = (double) iconheight / iconh; - cairo_translate(draw, x, y); - cairo_scale(draw, scale, scale); - cairo_set_source_surface(draw, tb->icon, 0,0); - cairo_paint(draw); - cairo_restore(draw); + cairo_translate ( draw, x, y ); + cairo_scale ( draw, scale, scale ); + cairo_set_source_surface ( draw, tb->icon, 0, 0 ); + cairo_paint ( draw ); + cairo_restore ( draw ); } - x+=offset; + x += offset; if ( tb->flags & TB_RIGHT ) { int line_width = 0; -- cgit v1.2.3 From 52aac6d3b68024ff8f44973202715f9e0a6fe818 Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Wed, 31 May 2017 20:26:12 +0200 Subject: gitmodules: Update libnkutils Signed-off-by: Quentin Glidic --- source/keyb.c | 2 +- source/rofi.c | 22 ++++++++++++---------- source/view.c | 10 +++++----- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'source') diff --git a/source/keyb.c b/source/keyb.c index 26837c05..394be6eb 100644 --- a/source/keyb.c +++ b/source/keyb.c @@ -140,7 +140,7 @@ void setup_abe ( void ) } } -static gboolean binding_trigger_action ( guint scope, gpointer user_data ) +static gboolean binding_trigger_action ( guint64 scope, gpointer user_data ) { return rofi_view_trigger_action ( rofi_view_get_active (), scope, GPOINTER_TO_UINT ( user_data ) ); } diff --git a/source/rofi.c b/source/rofi.c index 441edebf..92c1da86 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -91,6 +91,7 @@ void rofi_add_error_message ( GString *str ) struct xkb_stuff xkb = { .xcb_connection = NULL, .bindings = NULL, + .bindings_seat = NULL, }; /** Path to the configuration file */ @@ -667,9 +668,9 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN { case XCB_XKB_MAP_NOTIFY: { - struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_get_context ( xkb.bindings ), xcb->connection, xkb.device_id, 0 ); + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xkb.bindings_seat ), xcb->connection, xkb.device_id, 0 ); struct xkb_state *state = xkb_x11_state_new_from_device ( keymap, xcb->connection, xkb.device_id ); - nk_bindings_update_keymap ( xkb.bindings, keymap, state ); + nk_bindings_seat_update_keymap ( xkb.bindings_seat, keymap, state ); xkb_keymap_unref ( keymap ); xkb_state_unref ( state ); break; @@ -677,13 +678,13 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN case XCB_XKB_STATE_NOTIFY: { xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev; - nk_bindings_update_mask ( xkb.bindings, - ksne->baseMods, - ksne->latchedMods, - ksne->lockedMods, - ksne->baseGroup, - ksne->latchedGroup, - ksne->lockedGroup ); + nk_bindings_seat_update_mask ( xkb.bindings_seat, + ksne->baseMods, + ksne->latchedMods, + ksne->lockedMods, + ksne->baseGroup, + ksne->latchedGroup, + ksne->lockedGroup ); xcb_generic_event_t dev; dev.response_type = 0; main_loop_x11_event_handler_view ( &dev ); @@ -1063,7 +1064,8 @@ int main ( int argc, char *argv[] ) return EXIT_FAILURE; } - xkb.bindings = nk_bindings_new ( xkb_context, keymap, state ); + xkb.bindings = nk_bindings_new (); + xkb.bindings_seat = nk_bindings_seat_new ( xkb.bindings, xkb_context, keymap, state ); if ( xcb_connection_has_error ( xcb->connection ) ) { g_warning ( "Connection has error" ); diff --git a/source/view.c b/source/view.c index 921c0d5f..3e5e0a8f 100644 --- a/source/view.c +++ b/source/view.c @@ -1438,13 +1438,13 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb xcb_button_press_event_t *bpe = (xcb_button_press_event_t *) event; state->mouse.x = bpe->event_x; state->mouse.y = bpe->event_y; - nk_bindings_handle_button ( xkb->bindings, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time ); + nk_bindings_seat_handle_button ( xkb->bindings_seat, bpe->detail, NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time ); break; } case XCB_BUTTON_RELEASE: { xcb_button_release_event_t *bre = (xcb_button_release_event_t *) event; - nk_bindings_handle_button ( xkb->bindings, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time ); + nk_bindings_seat_handle_button ( xkb->bindings_seat, bre->detail, NK_BINDINGS_BUTTON_STATE_RELEASE, bre->time ); if ( config.click_to_exit == TRUE ) { if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) { if ( ( state->mouse_seen == FALSE ) && ( bre->event != CacheState.main_window ) ) { @@ -1467,7 +1467,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb for ( gint8 bi = 0; bi < 7; ++bi ) { if ( kne->keys[by] & ( 1 << bi ) ) { // X11 keycodes starts at 8 - nk_bindings_handle_key ( xkb->bindings, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED ); + nk_bindings_seat_handle_key ( xkb->bindings_seat, ( 8 * by + bi ) + 8, NK_BINDINGS_KEY_STATE_PRESSED ); } } } @@ -1478,7 +1478,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *) event; gchar *text; - text = nk_bindings_handle_key ( xkb->bindings, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS ); + text = nk_bindings_seat_handle_key ( xkb->bindings_seat, xkpe->detail, NK_BINDINGS_KEY_STATE_PRESS ); if ( ( text != NULL ) && ( textbox_append_char ( state->text, text, strlen ( text ) ) ) ) { state->refilter = TRUE; } @@ -1487,7 +1487,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *event, xkb case XCB_KEY_RELEASE: { xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) event; - nk_bindings_handle_key ( xkb->bindings, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE ); + nk_bindings_seat_handle_key ( xkb->bindings_seat, xkre->detail, NK_BINDINGS_KEY_STATE_RELEASE ); break; } default: -- cgit v1.2.3 From 087acb10281123c0282fb4febd1c1b9fe168a2ab Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Wed, 31 May 2017 22:42:33 +0200 Subject: gitmodules: Update libnkutils Signed-off-by: Quentin Glidic --- source/rofi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/rofi.c b/source/rofi.c index 92c1da86..b97e741e 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -1000,12 +1000,6 @@ int main ( int argc, char *argv[] ) return EXIT_FAILURE; } - struct xkb_context *xkb_context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ); - if ( xkb_context == NULL ) { - g_warning ( "cannot create XKB context!" ); - cleanup (); - return EXIT_FAILURE; - } xkb.xcb_connection = xcb->connection; xkb.device_id = xkb_x11_get_core_keyboard_device_id ( xcb->connection ); @@ -1051,7 +1045,8 @@ int main ( int argc, char *argv[] ) required_map_parts, /* map */ &details ); - struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( xkb_context, xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); + xkb.bindings_seat = nk_bindings_seat_new ( xkb.bindings, XKB_CONTEXT_NO_FLAGS ); + struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xkb.bindings_seat ), xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); if ( keymap == NULL ) { g_warning ( "Failed to get Keymap for current keyboard device." ); cleanup (); @@ -1065,7 +1060,7 @@ int main ( int argc, char *argv[] ) } xkb.bindings = nk_bindings_new (); - xkb.bindings_seat = nk_bindings_seat_new ( xkb.bindings, xkb_context, keymap, state ); + nk_bindings_seat_update_keymap ( xkb.bindings_seat, keymap, state ); if ( xcb_connection_has_error ( xcb->connection ) ) { g_warning ( "Connection has error" ); -- cgit v1.2.3 From 4c8e9247ad8842496f43fec420376db3938b697b Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Thu, 1 Jun 2017 00:00:09 +0200 Subject: rofi: Fix NkBindings calls order Signed-off-by: Quentin Glidic --- source/rofi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/rofi.c b/source/rofi.c index b97e741e..f18c880b 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -1045,6 +1045,7 @@ int main ( int argc, char *argv[] ) required_map_parts, /* map */ &details ); + xkb.bindings = nk_bindings_new (); xkb.bindings_seat = nk_bindings_seat_new ( xkb.bindings, XKB_CONTEXT_NO_FLAGS ); struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device ( nk_bindings_seat_get_context ( xkb.bindings_seat ), xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS ); if ( keymap == NULL ) { @@ -1059,7 +1060,6 @@ int main ( int argc, char *argv[] ) return EXIT_FAILURE; } - xkb.bindings = nk_bindings_new (); nk_bindings_seat_update_keymap ( xkb.bindings_seat, keymap, state ); if ( xcb_connection_has_error ( xcb->connection ) ) { -- cgit v1.2.3 From 46dee2671dfa23635d885e855d36d46df63586b1 Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Thu, 1 Jun 2017 00:12:03 +0200 Subject: x11-helper: Rename xcb.c Signed-off-by: Quentin Glidic --- source/dialogs/drun.c | 1 + source/dialogs/window.c | 1 - source/helper.c | 2 +- source/mode.c | 1 - source/rofi.c | 1 - source/view.c | 1 - source/widgets/scrollbar.c | 1 - source/widgets/textbox.c | 1 - source/x11-helper.c | 758 --------------------------------------------- source/xcb.c | 757 ++++++++++++++++++++++++++++++++++++++++++++ source/xrmoptions.c | 1 - 11 files changed, 759 insertions(+), 766 deletions(-) delete mode 100644 source/x11-helper.c create mode 100644 source/xcb.c (limited to 'source') diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c index ae7eaea3..83aabef4 100644 --- a/source/dialogs/drun.c +++ b/source/dialogs/drun.c @@ -50,6 +50,7 @@ #include "history.h" #include "dialogs/drun.h" #include "nkutils-xdg-theme.h" +#include "xcb.h" #define DRUN_CACHE_FILE "rofi2.druncache" diff --git a/source/dialogs/window.c b/source/dialogs/window.c index d19e1c61..f3276ba2 100644 --- a/source/dialogs/window.c +++ b/source/dialogs/window.c @@ -52,7 +52,6 @@ #include "settings.h" #include "helper.h" #include "widgets/textbox.h" -#include "x11-helper.h" #include "dialogs/window.h" #define WINLIST 32 diff --git a/source/helper.c b/source/helper.c index 5299ced3..a75e8413 100644 --- a/source/helper.c +++ b/source/helper.c @@ -47,10 +47,10 @@ #include #include #include +#include "xcb.h" #include "helper.h" #include "helper-theme.h" #include "settings.h" -#include "x11-helper.h" #include "rofi.h" #include "view.h" diff --git a/source/mode.c b/source/mode.c index 5e070e3c..c8ccfa68 100644 --- a/source/mode.c +++ b/source/mode.c @@ -30,7 +30,6 @@ #include #include "rofi.h" #include "xrmoptions.h" -#include "x11-helper.h" #include "mode.h" // This one should only be in mode implementations. diff --git a/source/rofi.c b/source/rofi.c index f18c880b..38c5cd12 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -58,7 +58,6 @@ #include "rofi.h" #include "helper.h" #include "widgets/textbox.h" -#include "x11-helper.h" #include "xrmoptions.h" #include "dialogs/dialogs.h" diff --git a/source/view.c b/source/view.c index 3e5e0a8f..f3569532 100644 --- a/source/view.c +++ b/source/view.c @@ -58,7 +58,6 @@ #include "xkb-internal.h" #include "helper.h" #include "helper-theme.h" -#include "x11-helper.h" #include "xrmoptions.h" #include "dialogs/dialogs.h" diff --git a/source/widgets/scrollbar.c b/source/widgets/scrollbar.c index bd5f7716..b6c70b18 100644 --- a/source/widgets/scrollbar.c +++ b/source/widgets/scrollbar.c @@ -31,7 +31,6 @@ #include "widgets/textbox.h" #include "widgets/listview.h" #include "widgets/scrollbar.h" -#include "x11-helper.h" #include "theme.h" diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c index a5a8cfac..7bac65f5 100644 --- a/source/widgets/textbox.c +++ b/source/widgets/textbox.c @@ -36,7 +36,6 @@ #include "keyb.h" #include "helper.h" #include "helper-theme.h" -#include "x11-helper.h" #include "mode.h" #include "view.h" diff --git a/source/x11-helper.c b/source/x11-helper.c deleted file mode 100644 index 94b5b53d..00000000 --- a/source/x11-helper.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * rofi - * - * MIT/X11 License - * Copyright © 2012 Sean Pringle - * Copyright © 2013-2017 Qball Cow - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -/** Log domain for this module */ -#define G_LOG_DOMAIN "X11Helper" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "xcb-internal.h" -#include "xcb.h" -#include "settings.h" -#include "helper.h" -#include "x11-helper.h" - -#include -/** Checks if the if x and y is inside rectangle. */ -#define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) ) -#include "x11-helper.h" -#include "xkb-internal.h" -WindowManager current_window_manager = WM_EWHM; - -/** - * Structure holding xcb objects needed to function. - */ -struct _xcb_stuff xcb_int = { - .connection = NULL, - .screen = NULL, - .screen_nbr = -1, - .sndisplay = NULL, - .sncontext = NULL, - .monitors = NULL -}; -xcb_stuff *xcb = &xcb_int; - -/** - * Depth of root window. - */ -xcb_depth_t *depth = NULL; -xcb_visualtype_t *visual = NULL; -xcb_colormap_t map = XCB_COLORMAP_NONE; -/** - * Visual of the root window. - */ -static xcb_visualtype_t *root_visual = NULL; -xcb_atom_t netatoms[NUM_NETATOMS]; -const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) }; - -/** - * Holds for each supported modifier the possible modifier mask. - * Check x11_mod_masks[MODIFIER]&mask != 0 to see if MODIFIER is activated. - */ -cairo_surface_t *x11_helper_get_screenshot_surface ( void ) -{ - return cairo_xcb_surface_create ( xcb->connection, - xcb_stuff_get_root_window ( xcb ), root_visual, - xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); -} - -static xcb_pixmap_t get_root_pixmap ( xcb_connection_t *c, - xcb_screen_t *screen, - xcb_atom_t atom ) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - xcb_pixmap_t rootpixmap = XCB_NONE; - - cookie = xcb_get_property ( c, - 0, - screen->root, - atom, - XCB_ATOM_PIXMAP, - 0, - 1 ); - - reply = xcb_get_property_reply ( c, cookie, NULL ); - - if ( reply ) { - if ( xcb_get_property_value_length ( reply ) == sizeof ( xcb_pixmap_t ) ) { - memcpy ( &rootpixmap, xcb_get_property_value ( reply ), sizeof ( xcb_pixmap_t ) ); - } - free ( reply ); - } - - return rootpixmap; -} - -cairo_surface_t * x11_helper_get_bg_surface ( void ) -{ - xcb_pixmap_t pm = get_root_pixmap ( xcb->connection, xcb->screen, netatoms[ESETROOT_PMAP_ID] ); - if ( pm == XCB_NONE ) { - return NULL; - } - return cairo_xcb_surface_create ( xcb->connection, pm, root_visual, - xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); -} - -cairo_surface_t* cairo_image_surface_create_from_svg ( const gchar* file, int height ) -{ - cairo_surface_t *surface; - cairo_t *cr; - RsvgHandle * handle; - RsvgDimensionData dimensions; - - handle = rsvg_handle_new_from_file ( file, NULL ); - rsvg_handle_get_dimensions ( handle, &dimensions ); - double scale = (double) height / dimensions.height; - surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, - (double) dimensions.width * scale, - (double) dimensions.height * scale ); - cr = cairo_create ( surface ); - cairo_scale ( cr, scale, scale ); - rsvg_handle_render_cairo ( handle, cr ); - cairo_destroy ( cr ); - - rsvg_handle_close ( handle, NULL ); - g_object_unref ( handle ); - - return surface; -} - -// retrieve a text property from a window -// technically we could use window_get_prop(), but this is better for character set support -char* window_get_text_prop ( xcb_window_t w, xcb_atom_t atom ) -{ - xcb_get_property_cookie_t c = xcb_get_property ( xcb->connection, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX ); - xcb_get_property_reply_t *r = xcb_get_property_reply ( xcb->connection, c, NULL ); - if ( r ) { - if ( xcb_get_property_value_length ( r ) > 0 ) { - char *str = NULL; - if ( r->type == netatoms[UTF8_STRING] ) { - str = g_strndup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) ); - } - else if ( r->type == netatoms[STRING] ) { - str = rofi_latin_to_utf8_strdup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) ); - } - else { - str = g_strdup ( "Invalid encoding." ); - } - - free ( r ); - return str; - } - free ( r ); - } - return NULL; -} - -void window_set_atom_prop ( xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count ) -{ - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, w, prop, XCB_ATOM_ATOM, 32, count, atoms ); -} - -/**** - * Code used to get monitor layout. - */ - -/** - * Free monitor structure. - */ -static void x11_monitor_free ( workarea *m ) -{ - g_free ( m->name ); - g_free ( m ); -} - -static void x11_monitors_free ( void ) -{ - while ( xcb->monitors != NULL ) { - workarea *m = xcb->monitors; - xcb->monitors = m->next; - x11_monitor_free ( m ); - } -} - -/** - * Create monitor based on output id - */ -static workarea * x11_get_monitor_from_output ( xcb_randr_output_t out ) -{ - xcb_randr_get_output_info_reply_t *op_reply; - xcb_randr_get_crtc_info_reply_t *crtc_reply; - xcb_randr_get_output_info_cookie_t it = xcb_randr_get_output_info ( xcb->connection, out, XCB_CURRENT_TIME ); - op_reply = xcb_randr_get_output_info_reply ( xcb->connection, it, NULL ); - if ( op_reply->crtc == XCB_NONE ) { - free ( op_reply ); - return NULL; - } - xcb_randr_get_crtc_info_cookie_t ct = xcb_randr_get_crtc_info ( xcb->connection, op_reply->crtc, XCB_CURRENT_TIME ); - crtc_reply = xcb_randr_get_crtc_info_reply ( xcb->connection, ct, NULL ); - if ( !crtc_reply ) { - free ( op_reply ); - return NULL; - } - workarea *retv = g_malloc0 ( sizeof ( workarea ) ); - retv->x = crtc_reply->x; - retv->y = crtc_reply->y; - retv->w = crtc_reply->width; - retv->h = crtc_reply->height; - - retv->mw = op_reply->mm_width; - retv->mh = op_reply->mm_height; - - char *tname = (char *) xcb_randr_get_output_info_name ( op_reply ); - int tname_len = xcb_randr_get_output_info_name_length ( op_reply ); - - retv->name = g_malloc0 ( ( tname_len + 1 ) * sizeof ( char ) ); - memcpy ( retv->name, tname, tname_len ); - - free ( crtc_reply ); - free ( op_reply ); - return retv; -} - -static int x11_is_extension_present ( const char *extension ) -{ - xcb_query_extension_cookie_t randr_cookie = xcb_query_extension ( xcb->connection, strlen ( extension ), extension ); - - xcb_query_extension_reply_t *randr_reply = xcb_query_extension_reply ( xcb->connection, randr_cookie, NULL ); - - int present = randr_reply->present; - - free ( randr_reply ); - - return present; -} - -static void x11_build_monitor_layout_xinerama () -{ - xcb_xinerama_query_screens_cookie_t screens_cookie = xcb_xinerama_query_screens_unchecked ( - xcb->connection - ); - - xcb_xinerama_query_screens_reply_t *screens_reply = xcb_xinerama_query_screens_reply ( - xcb->connection, - screens_cookie, - NULL - ); - - xcb_xinerama_screen_info_iterator_t screens_iterator = xcb_xinerama_query_screens_screen_info_iterator ( - screens_reply - ); - - for (; screens_iterator.rem > 0; xcb_xinerama_screen_info_next ( &screens_iterator ) ) { - workarea *w = g_malloc0 ( sizeof ( workarea ) ); - - w->x = screens_iterator.data->x_org; - w->y = screens_iterator.data->y_org; - w->w = screens_iterator.data->width; - w->h = screens_iterator.data->height; - - w->next = xcb->monitors; - xcb->monitors = w; - } - - int index = 0; - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - iter->monitor_id = index++; - } - - free ( screens_reply ); -} - -void x11_build_monitor_layout () -{ - if ( xcb->monitors ) { - return; - } - // If RANDR is not available, try Xinerama - if ( !x11_is_extension_present ( "RANDR" ) ) { - // Check if xinerama is available. - if ( x11_is_extension_present ( "XINERAMA" ) ) { - g_debug ( "Query XINERAMA for monitor layout." ); - x11_build_monitor_layout_xinerama (); - return; - } - g_debug ( "No RANDR or Xinerama available for getting monitor layout." ); - return; - } - g_debug ( "Query RANDR for monitor layout." ); - - xcb_randr_get_screen_resources_current_reply_t *res_reply; - xcb_randr_get_screen_resources_current_cookie_t src; - src = xcb_randr_get_screen_resources_current ( xcb->connection, xcb->screen->root ); - res_reply = xcb_randr_get_screen_resources_current_reply ( xcb->connection, src, NULL ); - if ( !res_reply ) { - return; //just report error - } - int mon_num = xcb_randr_get_screen_resources_current_outputs_length ( res_reply ); - xcb_randr_output_t *ops = xcb_randr_get_screen_resources_current_outputs ( res_reply ); - - // Get primary. - xcb_randr_get_output_primary_cookie_t pc = xcb_randr_get_output_primary ( xcb->connection, xcb->screen->root ); - xcb_randr_get_output_primary_reply_t *pc_rep = xcb_randr_get_output_primary_reply ( xcb->connection, pc, NULL ); - - for ( int i = mon_num - 1; i >= 0; i-- ) { - workarea *w = x11_get_monitor_from_output ( ops[i] ); - if ( w ) { - w->next = xcb->monitors; - xcb->monitors = w; - if ( pc_rep && pc_rep->output == ops[i] ) { - w->primary = TRUE; - } - } - } - // Number monitor - int index = 0; - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - iter->monitor_id = index++; - } - // If exists, free primary output reply. - if ( pc_rep ) { - free ( pc_rep ); - } - free ( res_reply ); -} - -void x11_dump_monitor_layout ( void ) -{ - int is_term = isatty ( fileno ( stdout ) ); - printf ( "Monitor layout:\n" ); - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - printf ( "%s ID%s: %d", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->monitor_id ); - if ( iter->primary ) { - printf ( " (primary)" ); - } - printf ( "\n" ); - printf ( "%s name%s: %s\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->name ); - printf ( "%s position%s: %d,%d\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->x, iter->y ); - printf ( "%s size%s: %d,%d\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->w, iter->h ); - if ( iter->mw > 0 && iter->mh > 0 ) { - printf ( "%s size%s: %dmm,%dmm dpi: %.0f,%.0f\n", - ( is_term ) ? color_bold : "", - is_term ? color_reset : "", - iter->mw, - iter->mh, - iter->w * 25.4 / (double) iter->mw, - iter->h * 25.4 / (double) iter->mh - ); - } - printf ( "\n" ); - } -} - -static int monitor_get_dimension ( int monitor_id, workarea *mon ) -{ - memset ( mon, 0, sizeof ( workarea ) ); - mon->w = xcb->screen->width_in_pixels; - mon->h = xcb->screen->height_in_pixels; - - workarea *iter = NULL; - for ( iter = xcb->monitors; iter; iter = iter->next ) { - if ( iter->monitor_id == monitor_id ) { - *mon = *iter; - return TRUE; - } - } - return FALSE; -} -// find the dimensions of the monitor displaying point x,y -static void monitor_dimensions ( int x, int y, workarea *mon ) -{ - memset ( mon, 0, sizeof ( workarea ) ); - mon->w = xcb->screen->width_in_pixels; - mon->h = xcb->screen->height_in_pixels; - - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - if ( INTERSECT ( x, y, iter->x, iter->y, iter->w, iter->h ) ) { - *mon = *iter; - break; - } - } -} - -/** - * @param root The X11 window used to find the pointer position. Usually the root window. - * @param x The x position of the mouse [out] - * @param y The y position of the mouse [out] - * - * find mouse pointer location - * - * @returns TRUE when found, FALSE otherwise - */ -static int pointer_get ( xcb_window_t root, int *x, int *y ) -{ - *x = 0; - *y = 0; - xcb_query_pointer_cookie_t c = xcb_query_pointer ( xcb->connection, root ); - xcb_query_pointer_reply_t *r = xcb_query_pointer_reply ( xcb->connection, c, NULL ); - if ( r ) { - *x = r->root_x; - *y = r->root_y; - free ( r ); - return TRUE; - } - - return FALSE; -} - -static int monitor_active_from_id ( int mon_id, workarea *mon ) -{ - xcb_window_t root = xcb->screen->root; - int x, y; - // At mouse position. - if ( mon_id == -3 ) { - if ( pointer_get ( root, &x, &y ) ) { - monitor_dimensions ( x, y, mon ); - mon->x = x; - mon->y = y; - return TRUE; - } - } - // Focused monitor - else if ( mon_id == -1 ) { - // Get the current desktop. - unsigned int current_desktop = 0; - xcb_get_property_cookie_t gcdc; - gcdc = xcb_ewmh_get_current_desktop ( &xcb->ewmh, xcb->screen_nbr ); - if ( xcb_ewmh_get_current_desktop_reply ( &xcb->ewmh, gcdc, ¤t_desktop, NULL ) ) { - xcb_get_property_cookie_t c = xcb_ewmh_get_desktop_viewport ( &xcb->ewmh, xcb->screen_nbr ); - xcb_ewmh_get_desktop_viewport_reply_t vp; - if ( xcb_ewmh_get_desktop_viewport_reply ( &xcb->ewmh, c, &vp, NULL ) ) { - if ( current_desktop < vp.desktop_viewport_len ) { - monitor_dimensions ( vp.desktop_viewport[current_desktop].x, - vp.desktop_viewport[current_desktop].y, mon ); - xcb_ewmh_get_desktop_viewport_reply_wipe ( &vp ); - return TRUE; - } - xcb_ewmh_get_desktop_viewport_reply_wipe ( &vp ); - } - } - } - else if ( mon_id == -2 || mon_id == -4 ) { - xcb_window_t active_window; - xcb_get_property_cookie_t awc; - awc = xcb_ewmh_get_active_window ( &xcb->ewmh, xcb->screen_nbr ); - if ( xcb_ewmh_get_active_window_reply ( &xcb->ewmh, awc, &active_window, NULL ) ) { - // get geometry. - xcb_get_geometry_cookie_t c = xcb_get_geometry ( xcb->connection, active_window ); - xcb_get_geometry_reply_t *r = xcb_get_geometry_reply ( xcb->connection, c, NULL ); - if ( r ) { - xcb_translate_coordinates_cookie_t ct = xcb_translate_coordinates ( xcb->connection, active_window, root, r->x, r->y ); - xcb_translate_coordinates_reply_t *t = xcb_translate_coordinates_reply ( xcb->connection, ct, NULL ); - if ( t ) { - if ( mon_id == -2 ) { - // place the menu above the window - // if some window is focused, place menu above window, else fall - // back to selected monitor. - mon->x = t->dst_x - r->x; - mon->y = t->dst_y - r->y; - mon->w = r->width; - mon->h = r->height; - free ( r ); - free ( t ); - return TRUE; - } - else if ( mon_id == -4 ) { - monitor_dimensions ( t->dst_x, t->dst_y, mon ); - free ( r ); - free ( t ); - return TRUE; - } - } - free ( r ); - } - } - } - // Monitor that has mouse pointer. - else if ( mon_id == -5 ) { - if ( pointer_get ( root, &x, &y ) ) { - monitor_dimensions ( x, y, mon ); - return TRUE; - } - // This is our give up point. - return FALSE; - } - g_debug ( "Failed to find monitor, fall back to monitor showing mouse." ); - return monitor_active_from_id ( -5, mon ); -} - -// determine which monitor holds the active window, or failing that the mouse pointer -int monitor_active ( workarea *mon ) -{ - if ( config.monitor != NULL ) { - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - if ( g_strcmp0 ( config.monitor, iter->name ) == 0 ) { - *mon = *iter; - return TRUE; - } - } - } - // Grab primary. - if ( g_strcmp0 ( config.monitor, "primary" ) == 0 ) { - for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { - if ( iter->primary ) { - *mon = *iter; - return TRUE; - } - } - } - // IF fail, fall back to classic mode. - char *end = NULL; - gint64 mon_id = g_ascii_strtoll ( config.monitor, &end, 0 ); - if ( end != config.monitor ) { - if ( mon_id >= 0 ) { - if ( monitor_get_dimension ( mon_id, mon ) ) { - return TRUE; - } - g_warning ( "Failed to find selected monitor." ); - } - else { - return monitor_active_from_id ( mon_id, mon ); - } - } - // Fallback. - monitor_dimensions ( 0, 0, mon ); - return FALSE; -} -int take_pointer ( xcb_window_t w, int iters ) -{ - int i = 0; - while ( TRUE ) { - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Connection has error" ); - exit ( EXIT_FAILURE ); - } - xcb_grab_pointer_cookie_t cc = xcb_grab_pointer ( xcb->connection, 1, w, XCB_EVENT_MASK_BUTTON_RELEASE, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, w, XCB_NONE, XCB_CURRENT_TIME ); - xcb_grab_pointer_reply_t *r = xcb_grab_pointer_reply ( xcb->connection, cc, NULL ); - if ( r ) { - if ( r->status == XCB_GRAB_STATUS_SUCCESS ) { - free ( r ); - return 1; - } - free ( r ); - } - if ( ( ++i ) > iters ) { - break; - } - usleep ( 1000 ); - } - return 0; -} -int take_keyboard ( xcb_window_t w, int iters ) -{ - int i = 0; - while ( TRUE ) { - if ( xcb_connection_has_error ( xcb->connection ) ) { - g_warning ( "Connection has error" ); - exit ( EXIT_FAILURE ); - } - xcb_grab_keyboard_cookie_t cc = xcb_grab_keyboard ( xcb->connection, - 1, w, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC ); - xcb_grab_keyboard_reply_t *r = xcb_grab_keyboard_reply ( xcb->connection, cc, NULL ); - if ( r ) { - if ( r->status == XCB_GRAB_STATUS_SUCCESS ) { - free ( r ); - return 1; - } - free ( r ); - } - if ( ( ++i ) > iters ) { - break; - } - usleep ( 1000 ); - } - return 0; -} - -void release_keyboard ( void ) -{ - xcb_ungrab_keyboard ( xcb->connection, XCB_CURRENT_TIME ); -} -void release_pointer ( void ) -{ - xcb_ungrab_pointer ( xcb->connection, XCB_CURRENT_TIME ); -} - -/** - * Fill in the list of frequently used X11 Atoms. - */ -static void x11_create_frequently_used_atoms ( void ) -{ - // X atom values - for ( int i = 0; i < NUM_NETATOMS; i++ ) { - xcb_intern_atom_cookie_t cc = xcb_intern_atom ( xcb->connection, 0, strlen ( netatom_names[i] ), netatom_names[i] ); - xcb_intern_atom_reply_t *r = xcb_intern_atom_reply ( xcb->connection, cc, NULL ); - if ( r ) { - netatoms[i] = r->atom; - free ( r ); - } - } -} - -void x11_setup ( void ) -{ - // determine numlock mask so we can bind on keys with and without it - x11_create_frequently_used_atoms ( ); -} - -void x11_create_visual_and_colormap ( void ) -{ - xcb_depth_t *root_depth = NULL; - xcb_depth_iterator_t depth_iter; - for ( depth_iter = xcb_screen_allowed_depths_iterator ( xcb->screen ); depth_iter.rem; xcb_depth_next ( &depth_iter ) ) { - xcb_depth_t *d = depth_iter.data; - - xcb_visualtype_iterator_t visual_iter; - for ( visual_iter = xcb_depth_visuals_iterator ( d ); visual_iter.rem; xcb_visualtype_next ( &visual_iter ) ) { - xcb_visualtype_t *v = visual_iter.data; - if ( ( v->bits_per_rgb_value == 8 ) && ( d->depth == 32 ) && ( v->_class == XCB_VISUAL_CLASS_TRUE_COLOR ) ) { - depth = d; - visual = v; - } - if ( xcb->screen->root_visual == v->visual_id ) { - root_depth = d; - root_visual = v; - } - } - } - if ( visual != NULL ) { - xcb_void_cookie_t c; - xcb_generic_error_t *e; - map = xcb_generate_id ( xcb->connection ); - c = xcb_create_colormap_checked ( xcb->connection, XCB_COLORMAP_ALLOC_NONE, map, xcb->screen->root, visual->visual_id ); - e = xcb_request_check ( xcb->connection, c ); - if ( e ) { - depth = NULL; - visual = NULL; - free ( e ); - } - } - - if ( visual == NULL ) { - depth = root_depth; - visual = root_visual; - map = xcb->screen->default_colormap; - } -} - -xcb_window_t xcb_stuff_get_root_window ( xcb_stuff *xcb ) -{ - return xcb->screen->root; -} - -void xcb_stuff_wipe ( xcb_stuff *xcb ) -{ - if ( xcb->connection != NULL ) { - g_debug ( "Cleaning up XCB and XKB" ); - if ( xcb->sncontext != NULL ) { - sn_launchee_context_unref ( xcb->sncontext ); - xcb->sncontext = NULL; - } - if ( xcb->sndisplay != NULL ) { - sn_display_unref ( xcb->sndisplay ); - xcb->sndisplay = NULL; - } - x11_monitors_free (); - xcb_ewmh_connection_wipe ( &( xcb->ewmh ) ); - xcb_flush ( xcb->connection ); - xcb_aux_sync ( xcb->connection ); - xcb_disconnect ( xcb->connection ); - xcb->connection = NULL; - xcb->screen = NULL; - xcb->screen_nbr = 0; - } -} - -void x11_disable_decoration ( xcb_window_t window ) -{ - // Flag used to indicate we are setting the decoration type. - const uint32_t MWM_HINTS_DECORATIONS = ( 1 << 1 ); - // Motif property data structure - struct MotifWMHints - { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t inputMode; - uint32_t state; - }; - - struct MotifWMHints hints; - hints.flags = MWM_HINTS_DECORATIONS; - hints.decorations = 0; - hints.functions = 0; - hints.inputMode = 0; - hints.state = 0; - - xcb_atom_t ha = netatoms[_MOTIF_WM_HINTS]; - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, window, ha, ha, 32, 5, &hints ); -} - -void x11_helper_discover_window_manager ( void ) -{ - xcb_window_t wm_win = 0; - xcb_get_property_cookie_t cc = xcb_ewmh_get_supporting_wm_check_unchecked ( &xcb->ewmh, - xcb_stuff_get_root_window ( xcb ) ); - - if ( xcb_ewmh_get_supporting_wm_check_reply ( &xcb->ewmh, cc, &wm_win, NULL ) ) { - xcb_ewmh_get_utf8_strings_reply_t wtitle; - xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name_unchecked ( &( xcb->ewmh ), wm_win ); - if ( xcb_ewmh_get_wm_name_reply ( &( xcb->ewmh ), cookie, &wtitle, (void *) 0 ) ) { - if ( wtitle.strings_len > 0 ) { - g_debug ( "Found window manager: %s", wtitle.strings ); - if ( g_strcmp0 ( wtitle.strings, "i3" ) == 0 ) { - current_window_manager = WM_I3; - } - else if ( g_strcmp0 ( wtitle.strings, "awesome" ) == 0 ) { - current_window_manager = WM_AWESOME; - } - else if ( g_strcmp0 ( wtitle.strings, "Openbox" ) == 0 ) { - current_window_manager = WM_OPENBOX; - } - } - xcb_ewmh_get_utf8_strings_reply_wipe ( &wtitle ); - } - } -} diff --git a/source/xcb.c b/source/xcb.c new file mode 100644 index 00000000..e9a300a2 --- /dev/null +++ b/source/xcb.c @@ -0,0 +1,757 @@ +/* + * rofi + * + * MIT/X11 License + * Copyright © 2012 Sean Pringle + * Copyright © 2013-2017 Qball Cow + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/** Log domain for this module */ +#define G_LOG_DOMAIN "X11Helper" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "xcb-internal.h" +#include "xcb.h" +#include "settings.h" +#include "helper.h" + +#include +/** Checks if the if x and y is inside rectangle. */ +#define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) ) +#include "xkb-internal.h" +WindowManager current_window_manager = WM_EWHM; + +/** + * Structure holding xcb objects needed to function. + */ +struct _xcb_stuff xcb_int = { + .connection = NULL, + .screen = NULL, + .screen_nbr = -1, + .sndisplay = NULL, + .sncontext = NULL, + .monitors = NULL +}; +xcb_stuff *xcb = &xcb_int; + +/** + * Depth of root window. + */ +xcb_depth_t *depth = NULL; +xcb_visualtype_t *visual = NULL; +xcb_colormap_t map = XCB_COLORMAP_NONE; +/** + * Visual of the root window. + */ +static xcb_visualtype_t *root_visual = NULL; +xcb_atom_t netatoms[NUM_NETATOMS]; +const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) }; + +/** + * Holds for each supported modifier the possible modifier mask. + * Check x11_mod_masks[MODIFIER]&mask != 0 to see if MODIFIER is activated. + */ +cairo_surface_t *x11_helper_get_screenshot_surface ( void ) +{ + return cairo_xcb_surface_create ( xcb->connection, + xcb_stuff_get_root_window ( xcb ), root_visual, + xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); +} + +static xcb_pixmap_t get_root_pixmap ( xcb_connection_t *c, + xcb_screen_t *screen, + xcb_atom_t atom ) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + xcb_pixmap_t rootpixmap = XCB_NONE; + + cookie = xcb_get_property ( c, + 0, + screen->root, + atom, + XCB_ATOM_PIXMAP, + 0, + 1 ); + + reply = xcb_get_property_reply ( c, cookie, NULL ); + + if ( reply ) { + if ( xcb_get_property_value_length ( reply ) == sizeof ( xcb_pixmap_t ) ) { + memcpy ( &rootpixmap, xcb_get_property_value ( reply ), sizeof ( xcb_pixmap_t ) ); + } + free ( reply ); + } + + return rootpixmap; +} + +cairo_surface_t * x11_helper_get_bg_surface ( void ) +{ + xcb_pixmap_t pm = get_root_pixmap ( xcb->connection, xcb->screen, netatoms[ESETROOT_PMAP_ID] ); + if ( pm == XCB_NONE ) { + return NULL; + } + return cairo_xcb_surface_create ( xcb->connection, pm, root_visual, + xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); +} + +cairo_surface_t* cairo_image_surface_create_from_svg ( const gchar* file, int height ) +{ + cairo_surface_t *surface; + cairo_t *cr; + RsvgHandle * handle; + RsvgDimensionData dimensions; + + handle = rsvg_handle_new_from_file ( file, NULL ); + rsvg_handle_get_dimensions ( handle, &dimensions ); + double scale = (double) height / dimensions.height; + surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, + (double) dimensions.width * scale, + (double) dimensions.height * scale ); + cr = cairo_create ( surface ); + cairo_scale ( cr, scale, scale ); + rsvg_handle_render_cairo ( handle, cr ); + cairo_destroy ( cr ); + + rsvg_handle_close ( handle, NULL ); + g_object_unref ( handle ); + + return surface; +} + +// retrieve a text property from a window +// technically we could use window_get_prop(), but this is better for character set support +char* window_get_text_prop ( xcb_window_t w, xcb_atom_t atom ) +{ + xcb_get_property_cookie_t c = xcb_get_property ( xcb->connection, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX ); + xcb_get_property_reply_t *r = xcb_get_property_reply ( xcb->connection, c, NULL ); + if ( r ) { + if ( xcb_get_property_value_length ( r ) > 0 ) { + char *str = NULL; + if ( r->type == netatoms[UTF8_STRING] ) { + str = g_strndup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) ); + } + else if ( r->type == netatoms[STRING] ) { + str = rofi_latin_to_utf8_strdup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) ); + } + else { + str = g_strdup ( "Invalid encoding." ); + } + + free ( r ); + return str; + } + free ( r ); + } + return NULL; +} + +void window_set_atom_prop ( xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count ) +{ + xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, w, prop, XCB_ATOM_ATOM, 32, count, atoms ); +} + +/**** + * Code used to get monitor layout. + */ + +/** + * Free monitor structure. + */ +static void x11_monitor_free ( workarea *m ) +{ + g_free ( m->name ); + g_free ( m ); +} + +static void x11_monitors_free ( void ) +{ + while ( xcb->monitors != NULL ) { + workarea *m = xcb->monitors; + xcb->monitors = m->next; + x11_monitor_free ( m ); + } +} + +/** + * Create monitor based on output id + */ +static workarea * x11_get_monitor_from_output ( xcb_randr_output_t out ) +{ + xcb_randr_get_output_info_reply_t *op_reply; + xcb_randr_get_crtc_info_reply_t *crtc_reply; + xcb_randr_get_output_info_cookie_t it = xcb_randr_get_output_info ( xcb->connection, out, XCB_CURRENT_TIME ); + op_reply = xcb_randr_get_output_info_reply ( xcb->connection, it, NULL ); + if ( op_reply->crtc == XCB_NONE ) { + free ( op_reply ); + return NULL; + } + xcb_randr_get_crtc_info_cookie_t ct = xcb_randr_get_crtc_info ( xcb->connection, op_reply->crtc, XCB_CURRENT_TIME ); + crtc_reply = xcb_randr_get_crtc_info_reply ( xcb->connection, ct, NULL ); + if ( !crtc_reply ) { + free ( op_reply ); + return NULL; + } + workarea *retv = g_malloc0 ( sizeof ( workarea ) ); + retv->x = crtc_reply->x; + retv->y = crtc_reply->y; + retv->w = crtc_reply->width; + retv->h = crtc_reply->height; + + retv->mw = op_reply->mm_width; + retv->mh = op_reply->mm_height; + + char *tname = (char *) xcb_randr_get_output_info_name ( op_reply ); + int tname_len = xcb_randr_get_output_info_name_length ( op_reply ); + + retv->name = g_malloc0 ( ( tname_len + 1 ) * sizeof ( char ) ); + memcpy ( retv->name, tname, tname_len ); + + free ( crtc_reply ); + free ( op_reply ); + return retv; +} + +static int x11_is_extension_present ( const char *extension ) +{ + xcb_query_extension_cookie_t randr_cookie = xcb_query_extension ( xcb->connection, strlen ( extension ), extension ); + + xcb_query_extension_reply_t *randr_reply = xcb_query_extension_reply ( xcb->connection, randr_cookie, NULL ); + + int present = randr_reply->present; + + free ( randr_reply ); + + return present; +} + +static void x11_build_monitor_layout_xinerama () +{ + xcb_xinerama_query_screens_cookie_t screens_cookie = xcb_xinerama_query_screens_unchecked ( + xcb->connection + ); + + xcb_xinerama_query_screens_reply_t *screens_reply = xcb_xinerama_query_screens_reply ( + xcb->connection, + screens_cookie, + NULL + ); + + xcb_xinerama_screen_info_iterator_t screens_iterator = xcb_xinerama_query_screens_screen_info_iterator ( + screens_reply + ); + + for (; screens_iterator.rem > 0; xcb_xinerama_screen_info_next ( &screens_iterator ) ) { + workarea *w = g_malloc0 ( sizeof ( workarea ) ); + + w->x = screens_iterator.data->x_org; + w->y = screens_iterator.data->y_org; + w->w = screens_iterator.data->width; + w->h = screens_iterator.data->height; + + w->next = xcb->monitors; + xcb->monitors = w; + } + + int index = 0; + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + iter->monitor_id = index++; + } + + free ( screens_reply ); +} + +void x11_build_monitor_layout () +{ + if ( xcb->monitors ) { + return; + } + // If RANDR is not available, try Xinerama + if ( !x11_is_extension_present ( "RANDR" ) ) { + // Check if xinerama is available. + if ( x11_is_extension_present ( "XINERAMA" ) ) { + g_debug ( "Query XINERAMA for monitor layout." ); + x11_build_monitor_layout_xinerama (); + return; + } + g_debug ( "No RANDR or Xinerama available for getting monitor layout." ); + return; + } + g_debug ( "Query RANDR for monitor layout." ); + + xcb_randr_get_screen_resources_current_reply_t *res_reply; + xcb_randr_get_screen_resources_current_cookie_t src; + src = xcb_randr_get_screen_resources_current ( xcb->connection, xcb->screen->root ); + res_reply = xcb_randr_get_screen_resources_current_reply ( xcb->connection, src, NULL ); + if ( !res_reply ) { + return; //just report error + } + int mon_num = xcb_randr_get_screen_resources_current_outputs_length ( res_reply ); + xcb_randr_output_t *ops = xcb_randr_get_screen_resources_current_outputs ( res_reply ); + + // Get primary. + xcb_randr_get_output_primary_cookie_t pc = xcb_randr_get_output_primary ( xcb->connection, xcb->screen->root ); + xcb_randr_get_output_primary_reply_t *pc_rep = xcb_randr_get_output_primary_reply ( xcb->connection, pc, NULL ); + + for ( int i = mon_num - 1; i >= 0; i-- ) { + workarea *w = x11_get_monitor_from_output ( ops[i] ); + if ( w ) { + w->next = xcb->monitors; + xcb->monitors = w; + if ( pc_rep && pc_rep->output == ops[i] ) { + w->primary = TRUE; + } + } + } + // Number monitor + int index = 0; + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + iter->monitor_id = index++; + } + // If exists, free primary output reply. + if ( pc_rep ) { + free ( pc_rep ); + } + free ( res_reply ); +} + +void x11_dump_monitor_layout ( void ) +{ + int is_term = isatty ( fileno ( stdout ) ); + printf ( "Monitor layout:\n" ); + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + printf ( "%s ID%s: %d", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->monitor_id ); + if ( iter->primary ) { + printf ( " (primary)" ); + } + printf ( "\n" ); + printf ( "%s name%s: %s\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->name ); + printf ( "%s position%s: %d,%d\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->x, iter->y ); + printf ( "%s size%s: %d,%d\n", ( is_term ) ? color_bold : "", is_term ? color_reset : "", iter->w, iter->h ); + if ( iter->mw > 0 && iter->mh > 0 ) { + printf ( "%s size%s: %dmm,%dmm dpi: %.0f,%.0f\n", + ( is_term ) ? color_bold : "", + is_term ? color_reset : "", + iter->mw, + iter->mh, + iter->w * 25.4 / (double) iter->mw, + iter->h * 25.4 / (double) iter->mh + ); + } + printf ( "\n" ); + } +} + +static int monitor_get_dimension ( int monitor_id, workarea *mon ) +{ + memset ( mon, 0, sizeof ( workarea ) ); + mon->w = xcb->screen->width_in_pixels; + mon->h = xcb->screen->height_in_pixels; + + workarea *iter = NULL; + for ( iter = xcb->monitors; iter; iter = iter->next ) { + if ( iter->monitor_id == monitor_id ) { + *mon = *iter; + return TRUE; + } + } + return FALSE; +} +// find the dimensions of the monitor displaying point x,y +static void monitor_dimensions ( int x, int y, workarea *mon ) +{ + memset ( mon, 0, sizeof ( workarea ) ); + mon->w = xcb->screen->width_in_pixels; + mon->h = xcb->screen->height_in_pixels; + + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + if ( INTERSECT ( x, y, iter->x, iter->y, iter->w, iter->h ) ) { + *mon = *iter; + break; + } + } +} + +/** + * @param root The X11 window used to find the pointer position. Usually the root window. + * @param x The x position of the mouse [out] + * @param y The y position of the mouse [out] + * + * find mouse pointer location + * + * @returns TRUE when found, FALSE otherwise + */ +static int pointer_get ( xcb_window_t root, int *x, int *y ) +{ + *x = 0; + *y = 0; + xcb_query_pointer_cookie_t c = xcb_query_pointer ( xcb->connection, root ); + xcb_query_pointer_reply_t *r = xcb_query_pointer_reply ( xcb->connection, c, NULL ); + if ( r ) { + *x = r->root_x; + *y = r->root_y; + free ( r ); + return TRUE; + } + + return FALSE; +} + +static int monitor_active_from_id ( int mon_id, workarea *mon ) +{ + xcb_window_t root = xcb->screen->root; + int x, y; + // At mouse position. + if ( mon_id == -3 ) { + if ( pointer_get ( root, &x, &y ) ) { + monitor_dimensions ( x, y, mon ); + mon->x = x; + mon->y = y; + return TRUE; + } + } + // Focused monitor + else if ( mon_id == -1 ) { + // Get the current desktop. + unsigned int current_desktop = 0; + xcb_get_property_cookie_t gcdc; + gcdc = xcb_ewmh_get_current_desktop ( &xcb->ewmh, xcb->screen_nbr ); + if ( xcb_ewmh_get_cur