From df7468b4910ebb6dfefb5da7e2e46def6f0d4d8c Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Fri, 19 Aug 2016 10:46:38 +0200 Subject: [PATCH] Use XRandr to get monitor layout instead of xinerama. * You can now specify monitor by name, or primary status. --- config/config.c | 2 +- configure.ac | 2 +- doc/rofi-manpage.markdown | 10 +- doc/rofi.1 | 18 +- include/settings.h | 2 +- include/x11-helper.h | 24 ++- include/xcb-internal.h | 3 +- source/helper.c | 20 +- source/rofi.c | 15 +- source/view.c | 2 +- source/x11-helper.c | 379 +++++++++++++++++++++++--------------- source/xrmoptions.c | 104 +++++------ 12 files changed, 345 insertions(+), 236 deletions(-) diff --git a/config/config.c b/config/config.c index f5b6b989..e3b8f83f 100644 --- a/config/config.c +++ b/config/config.c @@ -112,7 +112,7 @@ Settings config = { .tokenize = TRUE, .regex = FALSE, /** Monitor */ - .monitor = -1, + .monitor = "-1", /** set line margin */ .line_margin = 2, /** Set filter */ diff --git a/configure.ac b/configure.ac index e25a0f5d..e3ccdf34 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ dnl --------------------------------------------------------------------- dnl PKG_CONFIG based dependencies dnl --------------------------------------------------------------------- PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40]) -GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon >= 0.5.0 xkbcommon-x11 xcb-ewmh xcb-xinerama xcb-icccm xcb-xrm]) +GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon >= 0.5.0 xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-randr]) PKG_CHECK_MODULES([pango], [pango pangocairo]) PKG_CHECK_MODULES([cairo], [cairo cairo-xcb]) PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0]) diff --git a/doc/rofi-manpage.markdown b/doc/rofi-manpage.markdown index 501872f6..2b9b0b2c 100644 --- a/doc/rofi-manpage.markdown +++ b/doc/rofi-manpage.markdown @@ -370,10 +370,16 @@ Default: *5000* When one entry is left, automatically select it. `-m` *num* + +`-m` *name* + `-monitor` *num* +`-monitor` *name* + Select (Xinerama) monitor to display **rofi** on. -Negative numbers are handled differently: +As input it accepts: *primary* (if primary output is set), the *xrandr* output name or integer number (in order of +detection). Negative numbers are handled differently: * **-1**: the currently focused monitor. * **-2**: the currently focused window (i.e. rofi will be displayed on top of the focused window). @@ -384,6 +390,8 @@ Negative numbers are handled differently: Default: *-1* +See `rofi -h` output for the detected monitors, their position and size. + ### PATTERN setting `-terminal` diff --git a/doc/rofi.1 b/doc/rofi.1 index 9cb424c1..fa06458e 100644 --- a/doc/rofi.1 +++ b/doc/rofi.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "ROFI\-MANPAGE" "" "July 2016" "" "" +.TH "ROFI\-MANPAGE" "" "2016-08-18" "" "" . .SH "NAME" \fBrofi\fR \- A window switcher, run launcher, ssh dialog and dmenu replacement @@ -621,10 +621,19 @@ Default: \fI5000\fR When one entry is left, automatically select it\. . .P -\fB\-m\fR \fInum\fR \fB\-monitor\fR \fInum\fR +\fB\-m\fR \fInum\fR . .P -Select (Xinerama) monitor to display \fBrofi\fR on\. Negative numbers are handled differently: +\fB\-m\fR \fIname\fR +. +.P +\fB\-monitor\fR \fInum\fR +. +.P +\fB\-monitor\fR \fIname\fR +. +.P +Select (Xinerama) monitor to display \fBrofi\fR on\. As input it accepts: \fIprimary\fR (if primary output is set), the \fIxrandr\fR output name or integer number (in order of detection)\. Negative numbers are handled differently: . .IP "\(bu" 4 \fB\-1\fR: the currently focused monitor\. @@ -646,6 +655,9 @@ Default: \fI\-1\fR . .IP "" 0 . +.P +See \fBrofi \-h\fR output for the detected monitors, their position and size\. +. .SS "PATTERN setting" \fB\-terminal\fR . diff --git a/include/settings.h b/include/settings.h index b4c915ee..39b60868 100644 --- a/include/settings.h +++ b/include/settings.h @@ -109,7 +109,7 @@ typedef struct unsigned int tokenize; unsigned int regex; /** Monitors */ - int monitor; + char *monitor; /** Line margin */ unsigned int line_margin; /** filter */ diff --git a/include/x11-helper.h b/include/x11-helper.h index f1b5fb30..0058fbdf 100644 --- a/include/x11-helper.h +++ b/include/x11-helper.h @@ -45,18 +45,21 @@ enum { EWMH_ATOMS ( ATOM_ENUM ), NUM_NETATOMS }; extern const char *netatom_names[]; extern xcb_atom_t netatoms[NUM_NETATOMS]; -typedef struct -{ - int x, y, w, h; - int l, r, t, b; -} workarea; -void monitor_active ( workarea *mon ); +typedef struct _workarea +{ + int monitor_id; + int primary; + int x, y, w, h; + char *name; + struct _workarea *next; +} workarea; +int monitor_active ( workarea *mon ); // find the dimensions of the monitor displaying point x,y void monitor_dimensions ( int x, int y, workarea *mon ); // Find the dimensions of the monitor specified by user. -int monitor_get_dimension ( int monitor, workarea *mon ); +int monitor_get_dimension ( int monitor_id, workarea *mon ); int monitor_get_smallest_size ( void ); /** @@ -145,5 +148,12 @@ void x11_helper_set_cairo_rgba ( cairo_t *d, Color col ); * @returns a cairo surface with the background image of the desktop. */ cairo_surface_t * x11_helper_get_bg_surface ( void ); + +/** + * Creates an internal represenation of the available monitors. + * Used for positioning rofi. + */ +void x11_build_monitor_layout ( void ); +void x11_dump_monitor_layout ( void ); /*@}*/ #endif diff --git a/include/xcb-internal.h b/include/xcb-internal.h index 2f437d20..dc4d5db2 100644 --- a/include/xcb-internal.h +++ b/include/xcb-internal.h @@ -6,6 +6,7 @@ #include #include + /** * Structure to keep xcb stuff around. */ @@ -18,7 +19,7 @@ struct _xcb_stuff int screen_nbr; SnDisplay *sndisplay; SnLauncheeContext *sncontext; - gboolean has_xinerama; + struct _workarea *monitors; }; #endif diff --git a/source/helper.c b/source/helper.c index 684256f8..905babfd 100644 --- a/source/helper.c +++ b/source/helper.c @@ -476,16 +476,14 @@ int config_sanity_check ( void ) // Check size { - int ssize = monitor_get_smallest_size ( ); - if ( config.monitor >= 0 ) { - workarea mon; - if ( monitor_get_dimension ( config.monitor, &mon ) ) { - ssize = MIN ( mon.w, mon.h ); - } - else{ - g_string_append_printf ( msg, "\tconfig.monitor=%d Could not find monitor.\n", config.monitor ); - ssize = 0; - } + int ssize = monitor_get_smallest_size ( ); + workarea mon; + if ( monitor_active ( &mon ) ) { + ssize = MIN ( mon.w, mon.h ); + } + else{ + g_string_append_printf ( msg, "\tconfig.monitor=%s Could not find monitor.\n", config.monitor ); + ssize = 0; } // Have todo an estimate here. if ( ( 2 * ( config.padding + config.menu_bw ) ) > ( 0.9 * ssize ) ) { @@ -511,7 +509,7 @@ int config_sanity_check ( void ) pango_font_description_free ( pfd ); } - if ( config.monitor == -3 ) { + if ( g_strcmp0 ( config.monitor, "-3" ) == 0 ) { // On -3, set to location 1. config.location = 1; config.fullscreen = 0; diff --git a/source/rofi.c b/source/rofi.c index 74b2f5f6..0215fdc9 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -261,6 +260,7 @@ static void help ( G_GNUC_UNUSED int argc, char **argv ) printf ( "Global options:\n" ); print_options (); printf ( "\n" ); + x11_dump_monitor_layout (); printf ( "For more information see: man rofi\n" ); #ifdef GIT_VERSION printf ( "Version: "GIT_VERSION "\n" ); @@ -268,6 +268,7 @@ static void help ( G_GNUC_UNUSED int argc, char **argv ) printf ( "Version: "VERSION "\n" ); #endif printf ( "Bugreports: "PACKAGE_BUGREPORT "\n" ); + printf ( "Support: #rofi @ freenode.net\n" ); } /** @@ -663,6 +664,8 @@ int main ( int argc, char *argv[] ) xcb->screen = xcb_aux_get_screen ( xcb->connection, xcb->screen_nbr ); + x11_build_monitor_layout (); + xcb_intern_atom_cookie_t *ac = xcb_ewmh_init_atoms ( xcb->connection, &xcb->ewmh ); xcb_generic_error_t *errors = NULL; xcb_ewmh_init_atoms_replies ( &xcb->ewmh, ac, &errors ); @@ -755,16 +758,6 @@ int main ( int argc, char *argv[] ) fprintf ( stderr, "Connection has error\n" ); exit ( EXIT_FAILURE ); } - - const xcb_query_extension_reply_t *er = xcb_get_extension_data ( xcb->connection, &xcb_xinerama_id ); - if ( er ) { - if ( er->present ) { - xcb_xinerama_is_active_cookie_t is_active_req = xcb_xinerama_is_active ( xcb->connection ); - xcb_xinerama_is_active_reply_t *is_active = xcb_xinerama_is_active_reply ( xcb->connection, is_active_req, NULL ); - xcb->has_xinerama = is_active->state; - free ( is_active ); - } - } main_loop = g_main_loop_new ( NULL, FALSE ); TICK_N ( "Setup mainloop" ); diff --git a/source/view.c b/source/view.c index 21c0123a..b2e325ff 100644 --- a/source/view.c +++ b/source/view.c @@ -1152,7 +1152,7 @@ static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t } // 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) ); + textbox_cursor ( state->text, state->text->cursor + g_utf8_strlen ( text, -1 ) ); // Force a redraw and refiltering of the text. state->update = TRUE; state->refilter = TRUE; diff --git a/source/x11-helper.c b/source/x11-helper.c index 2bb46cdd..bebfea8a 100644 --- a/source/x11-helper.c +++ b/source/x11-helper.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include "xcb-internal.h" #include "xcb.h" #include "settings.h" @@ -54,12 +54,12 @@ #include "xkb-internal.h" struct _xcb_stuff xcb_int = { - .connection = NULL, - .screen = NULL, - .screen_nbr = -1, - .sndisplay = NULL, - .sncontext = NULL, - .has_xinerama = FALSE, + .connection = NULL, + .screen = NULL, + .screen_nbr = -1, + .sndisplay = NULL, + .sncontext = NULL, + .monitors = NULL }; xcb_stuff *xcb = &xcb_int; @@ -154,102 +154,160 @@ void window_set_atom_prop ( xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, 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; + + 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; +} + +void x11_build_monitor_layout () +{ + if ( xcb->monitors ) { + return; + } + 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 ); + printf ( "\n" ); + } +} + int monitor_get_smallest_size ( void ) { - xcb_generic_error_t *error; - int size = MIN ( xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); - - if ( !xcb->has_xinerama ) { - return size; + int size = MIN ( xcb->screen->width_in_pixels, xcb->screen->height_in_pixels ); + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + size = MIN ( iter->w, size ); + size = MIN ( iter->h, size ); } - xcb_xinerama_query_screens_cookie_t cookie_screen; - - cookie_screen = xcb_xinerama_query_screens ( xcb->connection ); - xcb_xinerama_query_screens_reply_t *query_screens; - query_screens = xcb_xinerama_query_screens_reply ( xcb->connection, cookie_screen, &error ); - if ( error ) { - fprintf ( stderr, "Error getting screen info\n" ); - return size; - } - xcb_xinerama_screen_info_t *screens = xcb_xinerama_query_screens_screen_info ( query_screens ); - int len = xcb_xinerama_query_screens_screen_info_length ( query_screens ); - for ( int i = 0; i < len; i++ ) { - xcb_xinerama_screen_info_t *info = &screens[i]; - size = MIN ( info->width, size ); - size = MIN ( info->height, size ); - } - free ( query_screens ); - return size; } -int monitor_get_dimension ( int monitor, workarea *mon ) +int monitor_get_dimension ( int monitor_id, workarea *mon ) { - xcb_generic_error_t *error = NULL; memset ( mon, 0, sizeof ( workarea ) ); mon->w = xcb->screen->width_in_pixels; mon->h = xcb->screen->height_in_pixels; - if ( !xcb->has_xinerama ) { - return FALSE; + workarea *iter = NULL; + for ( iter = xcb->monitors; iter; iter = iter->next ) { + if ( iter->monitor_id == monitor_id ) { + *mon = *iter; + return TRUE; + } } - - xcb_xinerama_query_screens_cookie_t cookie_screen; - cookie_screen = xcb_xinerama_query_screens ( xcb->connection ); - xcb_xinerama_query_screens_reply_t *query_screens; - query_screens = xcb_xinerama_query_screens_reply ( xcb->connection, cookie_screen, &error ); - if ( error ) { - fprintf ( stderr, "Error getting screen info\n" ); - return FALSE; - } - xcb_xinerama_screen_info_t *screens = xcb_xinerama_query_screens_screen_info ( query_screens ); - int len = xcb_xinerama_query_screens_screen_info_length ( query_screens ); - if ( monitor < len ) { - xcb_xinerama_screen_info_t *info = &screens[monitor]; - mon->w = info->width; - mon->h = info->height; - mon->x = info->x_org; - mon->y = info->y_org; - free ( query_screens ); - return TRUE; - } - free ( query_screens ); - return FALSE; } // find the dimensions of the monitor displaying point x,y void monitor_dimensions ( int x, int y, workarea *mon ) { - xcb_generic_error_t *error = NULL; memset ( mon, 0, sizeof ( workarea ) ); mon->w = xcb->screen->width_in_pixels; mon->h = xcb->screen->height_in_pixels; - if ( !xcb->has_xinerama ) { - return; - } - - xcb_xinerama_query_screens_cookie_t cookie_screen; - cookie_screen = xcb_xinerama_query_screens ( xcb->connection ); - xcb_xinerama_query_screens_reply_t *query_screens; - query_screens = xcb_xinerama_query_screens_reply ( xcb->connection, cookie_screen, &error ); - if ( error ) { - fprintf ( stderr, "Error getting screen info\n" ); - return; - } - xcb_xinerama_screen_info_t *screens = xcb_xinerama_query_screens_screen_info ( query_screens ); - int len = xcb_xinerama_query_screens_screen_info_length ( query_screens ); - for ( int i = 0; i < len; i++ ) { - xcb_xinerama_screen_info_t *info = &screens[i]; - if ( INTERSECT ( x, y, 1, 1, info->x_org, info->y_org, info->width, info->height ) ) { - mon->w = info->width; - mon->h = info->height; - mon->x = info->x_org; - mon->y = info->y_org; + for ( workarea *iter = xcb->monitors; iter; iter = iter->next ) { + if ( INTERSECT ( x, y, 1, 1, iter->x, iter->y, iter->w, iter->h ) ) { + *mon = *iter; break; } } - free ( query_screens ); } /** @@ -278,85 +336,113 @@ static int pointer_get ( xcb_window_t root, int *x, int *y ) } // determine which monitor holds the active window, or failing that the mouse pointer -void monitor_active ( workarea *mon ) +int monitor_active ( workarea *mon ) { xcb_window_t root = xcb->screen->root; int x, y; - if ( config.monitor >= 0 ) { - if ( monitor_get_dimension ( config.monitor, mon ) ) { - return; - } - fprintf ( stderr, "Failed to find selected monitor.\n" ); - } - if ( config.monitor == -3 ) { - if ( pointer_get ( root, &x, &y ) ) { - monitor_dimensions ( x, y, mon ); - mon->x = x; - mon->y = y; - return; - } - } - // Get the current desktop. - unsigned int current_desktop = 0; - if ( config.monitor == -1 && xcb_ewmh_get_current_desktop_reply ( &xcb->ewmh, - xcb_ewmh_get_current_desktop ( &xcb->ewmh, xcb->screen_nbr ), - ¤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; + 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; } - xcb_ewmh_get_desktop_viewport_reply_wipe ( &vp ); } } - - xcb_window_t active_window; - if ( xcb_ewmh_get_active_window_reply ( &xcb->ewmh, - xcb_ewmh_get_active_window ( &xcb->ewmh, xcb->screen_nbr ), &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 ( config.monitor == -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; - mon->t = r->border_width; - mon->b = r->border_width; - mon->l = r->border_width; - mon->r = r->border_width; - free ( r ); - free ( t ); - return; - } - else if ( config.monitor == -4 ) { - monitor_dimensions ( t->dst_x, t->dst_y, mon ); - free ( r ); - free ( t ); - return; + // 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; + } + fprintf ( stderr, "Failed to find selected monitor.\n" ); + } + // At mouse position. + else 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 ); } } - free ( r ); + } + 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; + } } } - if ( pointer_get ( root, &x, &y ) ) { - monitor_dimensions ( x, y, mon ); - return; - } - + // Fallback. monitor_dimensions ( 0, 0, mon ); + return FALSE; } int take_pointer ( xcb_window_t w ) { @@ -794,6 +880,7 @@ void xcb_stuff_wipe ( xcb_stuff *xcb ) sn_display_unref ( xcb->sndisplay ); xcb->sndisplay = NULL; } + x11_monitors_free (); xcb_disconnect ( xcb->connection ); xcb->connection = NULL; xcb->screen = NULL; diff --git a/source/xrmoptions.c b/source/xrmoptions.c index 288ad324..b6681a79 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -79,116 +79,116 @@ typedef struct * Currently supports string, boolean and number (signed and unsigned). */ static XrmOption xrmOptions[] = { - { xrm_String, "switchers", { .str = &config.modi }, NULL, + { xrm_String, "switchers", { .str = &config.modi }, NULL, "", CONFIG_DEFAULT }, - { xrm_String, "modi", { .str = &config.modi }, NULL, + { xrm_String, "modi", { .str = &config.modi }, NULL, "Enabled modi", CONFIG_DEFAULT }, - { xrm_Number, "opacity", { .num = &config.window_opacity }, NULL, + { xrm_Number, "opacity", { .num = &config.window_opacity }, NULL, "Window opacity", CONFIG_DEFAULT }, - { xrm_SNumber, "width", { .snum = &config.menu_width }, NULL, + { xrm_SNumber, "width", { .snum = &config.menu_width }, NULL, "Window width", CONFIG_DEFAULT }, - { xrm_Number, "lines", { .num = &config.menu_lines }, NULL, + { xrm_Number, "lines", { .num = &config.menu_lines }, NULL, "Number of lines", CONFIG_DEFAULT }, - { xrm_Number, "columns", { .num = &config.menu_columns }, NULL, + { xrm_Number, "columns", { .num = &config.menu_columns }, NULL, "Number of columns", CONFIG_DEFAULT }, - { xrm_String, "font", { .str = &config.menu_font }, NULL, + { xrm_String, "font", { .str = &config.menu_font }, NULL, "Font to use", CONFIG_DEFAULT }, - { xrm_String, "color-normal", { .str = &config.color_normal }, NULL, + { xrm_String, "color-normal", { .str = &config.color_normal }, NULL, "Color scheme for normal row", CONFIG_DEFAULT }, - { xrm_String, "color-urgent", { .str = &config.color_urgent }, NULL, + { xrm_String, "color-urgent", { .str = &config.color_urgent }, NULL, "Color scheme for urgent row", CONFIG_DEFAULT }, - { xrm_String, "color-active", { .str = &config.color_active }, NULL, + { xrm_String, "color-active", { .str = &config.color_active }, NULL, "Color scheme for active row", CONFIG_DEFAULT }, - { xrm_String, "color-window", { .str = &config.color_window }, NULL, + { xrm_String, "color-window", { .str = &config.color_window }, NULL, "Color scheme window", CONFIG_DEFAULT }, - { xrm_Number, "borderwidth", { .num = &config.menu_bw }, NULL, + { xrm_Number, "borderwidth", { .num = &config.menu_bw }, NULL, "", CONFIG_DEFAULT }, - { xrm_Number, "bw", { .num = &config.menu_bw }, NULL, + { xrm_Number, "bw", { .num = &config.menu_bw }, NULL, "Border width", CONFIG_DEFAULT }, - { xrm_Number, "location", { .num = &config.location }, NULL, + { xrm_Number, "location", { .num = &config.location }, NULL, "Location on screen", CONFIG_DEFAULT }, - { xrm_Number, "padding", { .num = &config.padding }, NULL, + { xrm_Number, "padding", { .num = &config.padding }, NULL, "Padding", CONFIG_DEFAULT }, - { xrm_SNumber, "yoffset", { .snum = &config.y_offset }, NULL, + { xrm_SNumber, "yoffset", { .snum = &config.y_offset }, NULL, "Y-offset relative to location", CONFIG_DEFAULT }, - { xrm_SNumber, "xoffset", { .snum = &config.x_offset }, NULL, + { xrm_SNumber, "xoffset", { .snum = &config.x_offset }, NULL, "X-offset relative to location", CONFIG_DEFAULT }, - { xrm_Boolean, "fixed-num-lines", { .num = &config.fixed_num_lines }, NULL, + { xrm_Boolean, "fixed-num-lines", { .num = &config.fixed_num_lines }, NULL, "Always show number of lines", CONFIG_DEFAULT }, - { xrm_String, "terminal", { .str = &config.terminal_emulator }, NULL, + { xrm_String, "terminal", { .str = &config.terminal_emulator }, NULL, "Terminal to use", CONFIG_DEFAULT }, - { xrm_String, "ssh-client", { .str = &config.ssh_client }, NULL, + { xrm_String, "ssh-client", { .str = &config.ssh_client }, NULL, "Ssh client to use", CONFIG_DEFAULT }, - { xrm_String, "ssh-command", { .str = &config.ssh_command }, NULL, + { xrm_String, "ssh-command", { .str = &config.ssh_command }, NULL, "Ssh command to execute", CONFIG_DEFAULT }, - { xrm_String, "run-command", { .str = &config.run_command }, NULL, + { xrm_String, "run-command", { .str = &config.run_command }, NULL, "Run command to execute", CONFIG_DEFAULT }, - { xrm_String, "run-list-command", { .str = &config.run_list_command }, NULL, + { xrm_String, "run-list-command", { .str = &config.run_list_command }, NULL, "Command to get extra run targets", CONFIG_DEFAULT }, - { xrm_String, "run-shell-command", { .str = &config.run_shell_command }, NULL, + { xrm_String, "run-shell-command", { .str = &config.run_shell_command }, NULL, "Run command to execute that runs in shell", CONFIG_DEFAULT }, - { xrm_String, "window-command", { .str = &config.window_command }, NULL, + { xrm_String, "window-command", { .str = &config.window_command }, NULL, "Command executed on accep-entry-custom for window modus", CONFIG_DEFAULT }, - { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL, + { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL, "Disable history in run/ssh", CONFIG_DEFAULT }, - { xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort }, NULL, + { xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort }, NULL, "Use levenshtein sorting", CONFIG_DEFAULT }, - { xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive }, NULL, + { xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive }, NULL, "Set case-sensitivity", CONFIG_DEFAULT }, - { xrm_Boolean, "cycle", { .num = &config.cycle }, NULL, + { xrm_Boolean, "cycle", { .num = &config.cycle }, NULL, "Cycle through the results list", CONFIG_DEFAULT }, - { xrm_Boolean, "sidebar-mode", { .num = &config.sidebar_mode }, NULL, + { xrm_Boolean, "sidebar-mode", { .num = &config.sidebar_mode }, NULL, "Enable sidebar-mode", CONFIG_DEFAULT }, - { xrm_SNumber, "eh", { .snum = &config.element_height }, NULL, + { xrm_SNumber, "eh", { .snum = &config.element_height }, NULL, "Row height (in chars)", CONFIG_DEFAULT }, - { xrm_Boolean, "auto-select", { .num = &config.auto_select }, NULL, + { xrm_Boolean, "auto-select", { .num = &config.auto_select }, NULL, "Enable auto select mode", CONFIG_DEFAULT }, - { xrm_Boolean, "parse-hosts", { .num = &config.parse_hosts }, NULL, + { xrm_Boolean, "parse-hosts", { .num = &config.parse_hosts }, NULL, "Parse hosts file for ssh mode", CONFIG_DEFAULT }, - { xrm_Boolean, "parse-known-hosts", { .num = &config.parse_known_hosts }, NULL, + { xrm_Boolean, "parse-known-hosts", { .num = &config.parse_known_hosts }, NULL, "Parse known_hosts file for ssh mode", CONFIG_DEFAULT }, - { xrm_String, "combi-modi", { .str = &config.combi_modi }, NULL, + { xrm_String, "combi-modi", { .str = &config.combi_modi }, NULL, "Set the modi to combine in combi mode", CONFIG_DEFAULT }, - { xrm_Boolean, "glob", { .num = &config.glob }, NULL, + { xrm_Boolean, "glob", { .num = &config.glob }, NULL, "Use glob matching", CONFIG_DEFAULT }, - { xrm_Boolean, "regex", { .num = &config.regex }, NULL, + { xrm_Boolean, "regex", { .num = &config.regex }, NULL, "Use regex matching", CONFIG_DEFAULT }, - { xrm_Boolean, "tokenize", { .num = &config.tokenize }, NULL, + { xrm_Boolean, "tokenize", { .num = &config.tokenize }, NULL, "Tokenize input string", CONFIG_DEFAULT }, - { xrm_Number, "monitor", { .snum = &config.monitor }, NULL, + { xrm_String, "monitor", { .str = &config.monitor }, NULL, "", CONFIG_DEFAULT }, /* Alias for dmenu compatibility. */ - { xrm_SNumber, "m", { .snum = &config.monitor }, NULL, + { xrm_String, "m", { .str = &config.monitor }, NULL, "Monitor id to show on", CONFIG_DEFAULT }, - { xrm_Number, "line-margin", { .num = &config.line_margin }, NULL, + { xrm_Number, "line-margin", { .num = &config.line_margin }, NULL, "Margin between rows", CONFIG_DEFAULT }, - { xrm_String, "filter", { .str = &config.filter }, NULL, + { xrm_String, "filter", { .str = &config.filter }, NULL, "Pre-set filter", CONFIG_DEFAULT }, - { xrm_String, "separator-style", { .str = &config.separator_style }, NULL, + { xrm_String, "separator-style", { .str = &config.separator_style }, NULL, "Separator style (none, dash, solid)", CONFIG_DEFAULT }, - { xrm_Boolean, "hide-scrollbar", { .num = &config.hide_scrollbar }, NULL, + { xrm_Boolean, "hide-scrollbar", { .num = &config.hide_scrollbar }, NULL, "Hide scroll-bar", CONFIG_DEFAULT }, - { xrm_Boolean, "fullscreen", { .num = &config.fullscreen }, NULL, + { xrm_Boolean, "fullscreen", { .num = &config.fullscreen }, NULL, "Fullscreen", CONFIG_DEFAULT }, - { xrm_Boolean, "fake-transparency", { .num = &config.fake_transparency }, NULL, + { xrm_Boolean, "fake-transparency", { .num = &config.fake_transparency }, NULL, "Fake transparency", CONFIG_DEFAULT }, - { xrm_SNumber, "dpi", { .snum = &config.dpi }, NULL, + { xrm_SNumber, "dpi", { .snum = &config.dpi }, NULL, "DPI", CONFIG_DEFAULT }, - { xrm_Number, "threads", { .num = &config.threads }, NULL, + { xrm_Number, "threads", { .num = &config.threads }, NULL, "Threads to use for string matching", CONFIG_DEFAULT }, - { xrm_Number, "scrollbar-width", { .num = &config.scrollbar_width }, NULL, + { xrm_Number, "scrollbar-width", { .num = &config.scrollbar_width }, NULL, "Scrollbar width", CONFIG_DEFAULT }, - { xrm_Number, "scroll-method", { .num = &config.scroll_method }, NULL, + { xrm_Number, "scroll-method", { .num = &config.scroll_method }, NULL, "Scrolling method. (0: Page, 1: Centered)", CONFIG_DEFAULT }, - { xrm_String, "fake-background", { .str = &config.fake_background }, NULL, + { xrm_String, "fake-background", { .str = &config.fake_background }, NULL, "Background to use for fake transparency. (background or screenshot)", CONFIG_DEFAULT }, - { xrm_String, "window-format", { .str = &config.window_format }, NULL, + { xrm_String, "window-format", { .str = &config.window_format }, NULL, "Window Format. w (desktop name), t (title), n (name), r (role), c (class)", CONFIG_DEFAULT }, };