diff --git a/event.c b/event.c index f5272333..ee121362 100644 --- a/event.c +++ b/event.c @@ -827,6 +827,9 @@ event_handle_randr_output_change_notify(xcb_randr_notify_event_t *ev) p_delete(&output_name); p_delete(&info); + + /* The docs for RRSetOutputPrimary say we get this signal */ + screen_update_primary(); } } diff --git a/globalconf.h b/globalconf.h index f936369e..8d5791cc 100644 --- a/globalconf.h +++ b/globalconf.h @@ -80,6 +80,10 @@ typedef struct xcb_key_symbols_t *keysyms; /** Logical screens */ screen_array_t screens; + /** The primary screen, access through screen_get_primary() */ + screen_t *primary_screen; + /** Do we have RandR 1.3 or newer? */ + bool have_randr_13; /** Root window key bindings */ key_array_t keys; /** Root window mouse bindings */ diff --git a/mouse.c b/mouse.c index af080b28..cf7bf498 100644 --- a/mouse.c +++ b/mouse.c @@ -135,7 +135,7 @@ luaA_mouse_index(lua_State *L) if (globalconf.focus.client) luaA_pushscreen(L, globalconf.focus.client->screen); else - luaA_pushscreen(L, globalconf.screens.tab[0]); + luaA_pushscreen(L, screen_get_primary()); return 1; } diff --git a/objects/screen.c b/objects/screen.c index 3026c827..924b3059 100644 --- a/objects/screen.c +++ b/objects/screen.c @@ -44,6 +44,7 @@ /** Screen is a table where indexes are screen numbers. You can use `screen[1]` * to get access to the first screen, etc. Alternatively, if RANDR information * is available, you can use output names for finding screen objects. + * The primary screen can be accessed as `screen.primary`. * Each screen has a set of properties. * * @tfield table geometry The screen coordinates. Immutable. @@ -60,6 +61,8 @@ struct screen_output_t char *name; /** The size in millimeters */ uint32_t mm_width, mm_height; + /** The XID */ + xcb_randr_output_t output; }; static void @@ -150,11 +153,20 @@ screen_scan_randr(void) { xcb_randr_query_version_reply_t *version_reply = xcb_randr_query_version_reply(globalconf.connection, - xcb_randr_query_version(globalconf.connection, 1, 1), 0); + xcb_randr_query_version(globalconf.connection, 1, 3), 0); if(version_reply) { + uint32_t major_version = version_reply->major_version; + uint32_t minor_version = version_reply->minor_version; + p_delete(&version_reply); + /* Do we agree on a supported version? */ + if (major_version != 1 || minor_version < 2) + return false; + + globalconf.have_randr_13 = minor_version >= 3; + /* A quick XRandR recall: * You have CRTC that manages a part of a SCREEN. * Each CRTC can draw stuff on one or more OUTPUT. */ @@ -206,7 +218,8 @@ screen_scan_randr(void) screen_output_array_append(&new_screen->outputs, (screen_output_t) { .name = name, .mm_width = output_info_r->mm_width, - .mm_height = output_info_r->mm_height }); + .mm_height = output_info_r->mm_height, + .output = randr_outputs[j] }); p_delete(&output_info_r); } @@ -217,6 +230,7 @@ screen_scan_randr(void) } p_delete(&screen_res_r); + screen_update_primary(); return screens_exist(); } @@ -536,6 +550,55 @@ screen_get_index(screen_t *s) return 0; } +void +screen_update_primary(void) +{ + if (!globalconf.have_randr_13) + return; + + screen_t *primary_screen = NULL; + xcb_randr_get_output_primary_reply_t *primary = + xcb_randr_get_output_primary_reply(globalconf.connection, + xcb_randr_get_output_primary(globalconf.connection, globalconf.screen->root), + NULL); + + if (!primary) + return; + + foreach(screen, globalconf.screens) + { + foreach(output, (*screen)->outputs) + if (output->output == primary->output) + primary_screen = *screen; + } + p_delete(&primary); + + if (!primary_screen || primary_screen == globalconf.primary_screen) + return; + + lua_State *L = globalconf_get_lua_State(); + screen_t *old = globalconf.primary_screen; + globalconf.primary_screen = primary_screen; + + if (old) + { + luaA_object_push(L, old); + luaA_object_emit_signal(L, -1, "primary_changed", 0); + lua_pop(L, 1); + } + luaA_object_push(L, primary_screen); + luaA_object_emit_signal(L, -1, "primary_changed", 0); + lua_pop(L, 1); +} + +screen_t * +screen_get_primary(void) +{ + if (!globalconf.primary_screen && globalconf.screens.len > 0) + globalconf.primary_screen = globalconf.screens.tab[0]; + return globalconf.primary_screen; +} + /** Screen module. * \param L The Lua VM state. * \return The number of elements pushed on stack. @@ -548,10 +611,15 @@ luaA_screen_module_index(lua_State *L) const char *name; if(lua_type(L, 2) == LUA_TSTRING && (name = lua_tostring(L, 2))) + { + if(A_STREQ(name, "primary")) + return luaA_object_push(L, screen_get_primary()); + foreach(screen, globalconf.screens) foreach(output, (*screen)->outputs) if(A_STREQ(output->name, name)) - return luaA_object_push(L, screen); + return luaA_object_push(L, *screen); + } return luaA_object_push(L, luaA_checkscreen(L, 2)); } @@ -648,6 +716,10 @@ screen_class_setup(lua_State *L) * @signal property::workarea */ signal_add(&screen_class.signals, "property::workarea"); + /** + * @signal primary_changed + */ + signal_add(&screen_class.signals, "primary_changed"); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/objects/screen.h b/objects/screen.h index 95cf5d82..28ecf6b2 100644 --- a/objects/screen.h +++ b/objects/screen.h @@ -47,6 +47,8 @@ bool screen_coord_in_screen(screen_t *, int, int); int screen_get_index(screen_t *); area_t display_area_get(void); void screen_client_moveto(client_t *, screen_t *, bool); +void screen_update_primary(void); +screen_t *screen_get_primary(void); void luaA_pushscreen(lua_State *, screen_t *); screen_t *luaA_checkscreen(lua_State *, int);