init: Add a command line option to start AwesomeWM without screens.
This commit add an optional `--screen off` command to initialize Lua without first adding the screens. This is inconvinient for most users since it restrict the APIs that are usable out of the box. However, this allows AwesomeWM to work independently from the hardware. This means that when a screen is unplugged, it is the Lua code that will remove the screen instead of CAPI pulling the carpet from under. It also allows to ignore some screen areas before the screen is ever created. Combined, it makes it possible to work with screens even when they are physically disconnected. Finally, it will allow for an awful.rules like API to control how screens are created. All in all, some people need this for their setup and some people might want to do it anyway for fine grained and/or dynamaic multi-screen setups. This commit also adds 4 new signals to `capi` to be able to execute code at specific points during the initialization. The commit improves naughty error notifications to work even if problems occurs before the screens are added. Note that AwesomeWM will exit if no screens are created. While it would be easy to just call `refresh_screen();` after unsetting the magic variable, doing so would have corner cases. Better be harsher and prevent the user from shooting themselves in the foot from not reading the f****** manual. Code introduced in future commits will take care of automatically calling fake_screen in the event nothing is created. Fixes #1382
This commit is contained in:
parent
9920fdd3f1
commit
433898599d
32
awesome.c
32
awesome.c
|
@ -565,6 +565,7 @@ exit_help(int exit_code)
|
||||||
--search DIR add a directory to the library search path\n\
|
--search DIR add a directory to the library search path\n\
|
||||||
-k, --check check configuration file syntax\n\
|
-k, --check check configuration file syntax\n\
|
||||||
-a, --no-argb disable client transparency support\n\
|
-a, --no-argb disable client transparency support\n\
|
||||||
|
-m, --screen on|off enable or disable automatic screen creation (default: on)\n\
|
||||||
-r, --replace replace an existing window manager\n");
|
-r, --replace replace an existing window manager\n");
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
@ -594,6 +595,7 @@ main(int argc, char **argv)
|
||||||
{ "search", 1, NULL, 's' },
|
{ "search", 1, NULL, 's' },
|
||||||
{ "no-argb", 0, NULL, 'a' },
|
{ "no-argb", 0, NULL, 'a' },
|
||||||
{ "replace", 0, NULL, 'r' },
|
{ "replace", 0, NULL, 'r' },
|
||||||
|
{ "screen" , 1, NULL, 'm' },
|
||||||
{ "reap", 1, NULL, '\1' },
|
{ "reap", 1, NULL, '\1' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
@ -634,6 +636,14 @@ main(int argc, char **argv)
|
||||||
if (confpath != NULL)
|
if (confpath != NULL)
|
||||||
fatal("--config may only be specified once");
|
fatal("--config may only be specified once");
|
||||||
confpath = a_strdup(optarg);
|
confpath = a_strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
/* Validation */
|
||||||
|
if ((!optarg) || !(A_STREQ(optarg, "off") || A_STREQ(optarg, "on")))
|
||||||
|
fatal("The possible values of -m/--screen are \"on\" or \"off\"");
|
||||||
|
|
||||||
|
globalconf.no_auto_screen = A_STREQ(optarg, "off");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
string_array_append(&searchpath, a_strdup(optarg));
|
string_array_append(&searchpath, a_strdup(optarg));
|
||||||
|
@ -901,20 +911,38 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
ewmh_init_lua();
|
ewmh_init_lua();
|
||||||
|
|
||||||
|
/* Parse and run configuration file before adding the screens */
|
||||||
|
if (globalconf.no_auto_screen && !luaA_parserc(&xdg, confpath))
|
||||||
|
fatal("couldn't find any rc file");
|
||||||
|
|
||||||
/* init screens information */
|
/* init screens information */
|
||||||
screen_scan();
|
screen_scan();
|
||||||
|
|
||||||
/* Parse and run configuration file */
|
/* Parse and run configuration file after adding the screens */
|
||||||
if (!luaA_parserc(&xdg, confpath))
|
if (((!globalconf.no_auto_screen) && !luaA_parserc(&xdg, confpath)))
|
||||||
fatal("couldn't find any rc file");
|
fatal("couldn't find any rc file");
|
||||||
|
|
||||||
p_delete(&confpath);
|
p_delete(&confpath);
|
||||||
|
|
||||||
xdgWipeHandle(&xdg);
|
xdgWipeHandle(&xdg);
|
||||||
|
|
||||||
|
/* Both screen scanning mode have this signal, it cannot be in screen_scan
|
||||||
|
since the automatic screen generation don't have executed rc.lua yet. */
|
||||||
|
screen_emit_scanned();
|
||||||
|
|
||||||
|
/* Exit if the user doesn't read the instructions properly */
|
||||||
|
if (globalconf.no_auto_screen && !globalconf.screens.len)
|
||||||
|
fatal("When -m/--screen is set to \"off\", you **must** create a "
|
||||||
|
"screen object before or inside the screen \"scanned\" "
|
||||||
|
" signal. Using AwesomeWM with no screen is **not supported**.");
|
||||||
|
|
||||||
|
client_emit_scanning();
|
||||||
|
|
||||||
/* scan existing windows */
|
/* scan existing windows */
|
||||||
scan(tree_c);
|
scan(tree_c);
|
||||||
|
|
||||||
|
client_emit_scanned();
|
||||||
|
|
||||||
luaA_emit_startup();
|
luaA_emit_startup();
|
||||||
|
|
||||||
/* Setup the main context */
|
/* Setup the main context */
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct drawable_t drawable_t;
|
typedef struct drawable_t drawable_t;
|
||||||
|
typedef struct a_screen_area screen_area_t;
|
||||||
typedef struct drawin_t drawin_t;
|
typedef struct drawin_t drawin_t;
|
||||||
typedef struct a_screen screen_t;
|
typedef struct a_screen screen_t;
|
||||||
typedef struct button_t button_t;
|
typedef struct button_t button_t;
|
||||||
|
@ -111,6 +112,10 @@ typedef struct
|
||||||
bool have_randr_15;
|
bool have_randr_15;
|
||||||
/** Do we have a RandR screen update pending? */
|
/** Do we have a RandR screen update pending? */
|
||||||
bool screen_refresh_pending;
|
bool screen_refresh_pending;
|
||||||
|
/** Should screens be created before rc.lua is loaded? */
|
||||||
|
bool no_auto_screen;
|
||||||
|
/** Should the screen be created automatically? */
|
||||||
|
bool ignore_screens;
|
||||||
/** Check for XTest extension */
|
/** Check for XTest extension */
|
||||||
bool have_xtest;
|
bool have_xtest;
|
||||||
/** Check for SHAPE extension */
|
/** Check for SHAPE extension */
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local naughty = require("naughty.core")
|
local naughty = require("naughty.core")
|
||||||
|
local gdebug = require("gears.debug")
|
||||||
local capi = {awesome = awesome}
|
local capi = {awesome = awesome}
|
||||||
if dbus then
|
if dbus then
|
||||||
naughty.dbus = require("naughty.dbus")
|
naughty.dbus = require("naughty.dbus")
|
||||||
|
@ -18,11 +19,48 @@ naughty.container = require("naughty.container")
|
||||||
naughty.action = require("naughty.action")
|
naughty.action = require("naughty.action")
|
||||||
naughty.notification = require("naughty.notification")
|
naughty.notification = require("naughty.notification")
|
||||||
|
|
||||||
|
-- Attempt to handle early errors when using the manual screen mode.
|
||||||
|
--
|
||||||
|
-- Creating a notification popup before the screens are added won't work. To
|
||||||
|
-- work around this, the code below initializes some screens. One potential
|
||||||
|
-- problem is that it could emit enough signal to cause even more errors and
|
||||||
|
-- lose the original error.
|
||||||
|
--
|
||||||
|
-- For example, the following error can be displayed using this fallback:
|
||||||
|
--
|
||||||
|
-- screen.connect_signal("scanned", function() foobar() end)
|
||||||
|
--
|
||||||
|
local function screen_fallback()
|
||||||
|
if screen.count() == 0 then
|
||||||
|
gdebug.print_warning("An error occurred before a scrren was added")
|
||||||
|
|
||||||
|
-- Private API to scan for screens now.
|
||||||
|
if #screen._viewports() == 0 then
|
||||||
|
screen._scan_quiet()
|
||||||
|
end
|
||||||
|
|
||||||
|
local viewports = screen._viewports()
|
||||||
|
|
||||||
|
if #viewports > 0 then
|
||||||
|
for _, viewport in ipairs(viewports) do
|
||||||
|
local geo = viewport.geometry
|
||||||
|
screen.fake_add(geo.x, geo.y, geo.width, geo.height)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
screen.fake_add(0, 0, 640, 480)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Handle runtime errors during startup
|
-- Handle runtime errors during startup
|
||||||
if capi.awesome.startup_errors then
|
if capi.awesome.startup_errors then
|
||||||
|
|
||||||
-- Wait until `rc.lua` is executed before creating the notifications.
|
-- Wait until `rc.lua` is executed before creating the notifications.
|
||||||
-- Otherwise nothing is handling them (yet).
|
-- Otherwise nothing is handling them (yet).
|
||||||
awesome.connect_signal("startup", function()
|
client.connect_signal("scanning", function()
|
||||||
|
-- A lot of things have to go wrong for this to happen, but it can.
|
||||||
|
screen_fallback()
|
||||||
|
|
||||||
naughty.emit_signal(
|
naughty.emit_signal(
|
||||||
"request::display_error", capi.awesome.startup_errors, true
|
"request::display_error", capi.awesome.startup_errors, true
|
||||||
)
|
)
|
||||||
|
@ -32,15 +70,20 @@ end
|
||||||
-- Handle runtime errors after startup
|
-- Handle runtime errors after startup
|
||||||
do
|
do
|
||||||
local in_error = false
|
local in_error = false
|
||||||
|
|
||||||
capi.awesome.connect_signal("debug::error", function (err)
|
capi.awesome.connect_signal("debug::error", function (err)
|
||||||
-- Make sure we don't go into an endless error loop
|
-- Make sure we don't go into an endless error loop
|
||||||
if in_error then return end
|
if in_error then return end
|
||||||
|
|
||||||
in_error = true
|
in_error = true
|
||||||
|
|
||||||
|
screen_fallback()
|
||||||
|
|
||||||
naughty.emit_signal("request::display_error", tostring(err), false)
|
naughty.emit_signal("request::display_error", tostring(err), false)
|
||||||
|
|
||||||
in_error = false
|
in_error = false
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return naughty
|
return naughty
|
||||||
|
|
19
luaa.c
19
luaa.c
|
@ -19,14 +19,17 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** awesome core API
|
/** AwesomeWM lifecycle API.
|
||||||
*
|
*
|
||||||
* Additionally to the classes described here, one can also use X properties as
|
* This module contains the functions and signal to manage the lifecycle of the
|
||||||
* described in @{xproperties}.
|
* AwesomeWM process. It allows to execute code at specific point from the early
|
||||||
|
* initialization all the way to the last events before exiting or restarting.
|
||||||
|
*
|
||||||
|
* Additionally it handles signals for spawn and keyboard related events.
|
||||||
*
|
*
|
||||||
* @author Julien Danjou <julien@danjou.info>
|
* @author Julien Danjou <julien@danjou.info>
|
||||||
* @copyright 2008-2009 Julien Danjou
|
* @copyright 2008-2009 Julien Danjou
|
||||||
* @module awesome
|
* @coreclassmod awesome
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Register a new xproperty.
|
/** Register a new xproperty.
|
||||||
|
@ -150,13 +153,13 @@ extern const struct luaL_Reg awesome_mouse_meta[];
|
||||||
* @signal refresh
|
* @signal refresh
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Awesome is about to enter the event loop.
|
/** AwesomeWM is about to enter the event loop.
|
||||||
*
|
*
|
||||||
* This means all initialization has been done.
|
* This means all initialization has been done.
|
||||||
* @signal startup
|
* @signal startup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Awesome is exiting / about to restart.
|
/** AwesomeWM is exiting / about to restart.
|
||||||
*
|
*
|
||||||
* This signal is emitted in the `atexit` handler as well when awesome
|
* This signal is emitted in the `atexit` handler as well when awesome
|
||||||
* restarts.
|
* restarts.
|
||||||
|
@ -167,8 +170,8 @@ extern const struct luaL_Reg awesome_mouse_meta[];
|
||||||
|
|
||||||
/** The output status of a screen has changed.
|
/** The output status of a screen has changed.
|
||||||
*
|
*
|
||||||
* @param output String containing which output has changed.
|
* @tparam string output String containing which output has changed.
|
||||||
* @param connection_state String containing the connection status of
|
* @tparam string connection_state String containing the connection status of
|
||||||
* the output: It will be either "Connected", "Disconnected" or
|
* the output: It will be either "Connected", "Disconnected" or
|
||||||
* "Unknown".
|
* "Unknown".
|
||||||
* @signal screen::change
|
* @signal screen::change
|
||||||
|
|
|
@ -132,6 +132,21 @@
|
||||||
* @table awful.object
|
* @table awful.object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** AwesomeWM is about to scan for existing clients.
|
||||||
|
*
|
||||||
|
* Connect to this signal when code needs to be executed after screens are
|
||||||
|
* initialized, but before clients are added.
|
||||||
|
*
|
||||||
|
* @signal scanning
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** AwesomeWM is done scanning for clients.
|
||||||
|
*
|
||||||
|
* This is emitted before the `startup` signal and after the `scanning` signal.
|
||||||
|
*
|
||||||
|
* @signal scanned
|
||||||
|
*/
|
||||||
|
|
||||||
/** When a client gains focus.
|
/** When a client gains focus.
|
||||||
* @signal focus
|
* @signal focus
|
||||||
*/
|
*/
|
||||||
|
@ -1038,6 +1053,20 @@ DO_CLIENT_SET_STRING_PROPERTY(role)
|
||||||
DO_CLIENT_SET_STRING_PROPERTY(machine)
|
DO_CLIENT_SET_STRING_PROPERTY(machine)
|
||||||
#undef DO_CLIENT_SET_STRING_PROPERTY
|
#undef DO_CLIENT_SET_STRING_PROPERTY
|
||||||
|
|
||||||
|
void
|
||||||
|
client_emit_scanned(void)
|
||||||
|
{
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
luaA_class_emit_signal(L, &client_class, "scanned", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
client_emit_scanning(void)
|
||||||
|
{
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
luaA_class_emit_signal(L, &client_class, "scanning", 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
client_set_motif_wm_hints(lua_State *L, int cidx, motif_wm_hints_t hints)
|
client_set_motif_wm_hints(lua_State *L, int cidx, motif_wm_hints_t hints)
|
||||||
{
|
{
|
||||||
|
|
|
@ -244,6 +244,8 @@ void client_refresh_partial(client_t *, int16_t, int16_t, uint16_t, uint16_t);
|
||||||
void client_class_setup(lua_State *);
|
void client_class_setup(lua_State *);
|
||||||
void client_send_configure(client_t *);
|
void client_send_configure(client_t *);
|
||||||
void client_find_transient_for(client_t *);
|
void client_find_transient_for(client_t *);
|
||||||
|
void client_emit_scanned(void);
|
||||||
|
void client_emit_scanning(void);
|
||||||
drawable_t *client_get_drawable(client_t *, int, int);
|
drawable_t *client_get_drawable(client_t *, int, int);
|
||||||
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
|
drawable_t *client_get_drawable_offset(client_t *, int *, int *);
|
||||||
|
|
||||||
|
|
372
objects/screen.c
372
objects/screen.c
|
@ -62,6 +62,37 @@
|
||||||
*/
|
*/
|
||||||
#define FAKE_SCREEN_XID ((uint32_t) 0xffffffff)
|
#define FAKE_SCREEN_XID ((uint32_t) 0xffffffff)
|
||||||
|
|
||||||
|
/** AwesomeWM is about to scan for existing screens.
|
||||||
|
*
|
||||||
|
* Connect to this signal when code needs to be executed after the Lua context
|
||||||
|
* is initialized and modules are loaded, but before screens are added.
|
||||||
|
*
|
||||||
|
* To manage screens manually, set `screen.automatic_factory = false` and
|
||||||
|
* connect to the `property::viewports` signal. It is then possible to use
|
||||||
|
* `screen.fake_add` to create virtual screens. Be careful when using this,
|
||||||
|
* when done incorrectly, no screens will be created. Using Awesome with zero
|
||||||
|
* screens is **not** supported.
|
||||||
|
*
|
||||||
|
* @signal scanning
|
||||||
|
* @see property::viewports
|
||||||
|
* @see screen.fake_add
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** AwesomeWM is done scanning for screens.
|
||||||
|
*
|
||||||
|
* Connect to this signal to execute code after the screens have been created,
|
||||||
|
* but before the clients are added. This signal can also be used to split
|
||||||
|
* physical screens into multiple virtual screens before the clients (and their
|
||||||
|
* rules) are executed.
|
||||||
|
*
|
||||||
|
* Note that if no screens exist at this point, the fallback code will be
|
||||||
|
* triggered and the default (detected) screens will be added.
|
||||||
|
*
|
||||||
|
* @signal scanned
|
||||||
|
* @see screen.fake_resize
|
||||||
|
* @see screen.fake_add
|
||||||
|
*/
|
||||||
|
|
||||||
/** Screen is a table where indexes are screen numbers. You can use `screen[1]`
|
/** 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
|
* to get access to the first screen, etc. Alternatively, if RANDR information
|
||||||
* is available, you can use output names for finding screen objects.
|
* is available, you can use output names for finding screen objects.
|
||||||
|
@ -94,12 +125,33 @@
|
||||||
* @signal swapped
|
* @signal swapped
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** This signal is emitted when the list of physical screen viewport changes.
|
||||||
|
*
|
||||||
|
* Each viewport in the list corresponds to a **physical** screen rectangle, which
|
||||||
|
* is **not** the `viewports` property of the `screen` objects.
|
||||||
|
*
|
||||||
|
* @signal property::viewports
|
||||||
|
* @tparam table viewports
|
||||||
|
* @see automatic_factory
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The primary screen.
|
* The primary screen.
|
||||||
*
|
*
|
||||||
* @tfield screen primary
|
* @tfield screen primary
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `screen` objects are created automatically when new viewports are detected.
|
||||||
|
*
|
||||||
|
* Be very, very careful when setting this to false. You might end up with
|
||||||
|
* no screens. This is **not** supported. Always connect to the `scanned`
|
||||||
|
* signal to make sure to create a fallback screen if none were created.
|
||||||
|
*
|
||||||
|
* @tfield[opt=true] boolean screen.automatic_factory
|
||||||
|
* @see property::viewports
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The screen coordinates.
|
* The screen coordinates.
|
||||||
*
|
*
|
||||||
|
@ -297,6 +349,192 @@ screen_deduplicate(lua_State *L, screen_array_t *screens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Keep track of the screen viewport(s) independently from the screen objects.
|
||||||
|
*
|
||||||
|
* A viewport is a collection of `outputs` objects and their associated
|
||||||
|
* metadata. This structure is copied into Lua and then further extended from
|
||||||
|
* there. The `id` field allows to differentiate between viewports that share
|
||||||
|
* the same position and dimensions without having to rely on userdata pointer
|
||||||
|
* comparison.
|
||||||
|
*
|
||||||
|
* Screen objects are widely used by the public API and imply a very "visible"
|
||||||
|
* concept. A viewport is a subset of what the concerns the "screen" class
|
||||||
|
* previously handled. It is meant to be used by some low level Lua logic to
|
||||||
|
* create screens from Lua rather than from C. This is required to increase the
|
||||||
|
* flexibility of multi-screen setup or when screens are connected and
|
||||||
|
* disconnected often.
|
||||||
|
*
|
||||||
|
* Design rationals:
|
||||||
|
*
|
||||||
|
* * The structure is not directly shared with Lua to avoid having to use the
|
||||||
|
* slow "miss_handler" and unsafe "valid" systems used by other CAPI objects.
|
||||||
|
* * The `viewport_t` implements a linked-list because its main purpose is to
|
||||||
|
* offers a deduplication algorithm. Random access is never required.
|
||||||
|
* * Everything that can be done in Lua is done in Lua.
|
||||||
|
* * Since the legacy and "new" way to initialize screens share a lot of steps,
|
||||||
|
* the C code is bent to share as much code as possible. This will reduce the
|
||||||
|
* "dead code" and improve code coverage by the tests.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct viewport_t
|
||||||
|
{
|
||||||
|
bool marked;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
struct viewport_t *next;
|
||||||
|
screen_t *screen;
|
||||||
|
} viewport_t;
|
||||||
|
|
||||||
|
static viewport_t *first_screen_viewport = NULL;
|
||||||
|
static viewport_t *last_screen_viewport = NULL;
|
||||||
|
|
||||||
|
static int
|
||||||
|
luaA_viewports(lua_State *L)
|
||||||
|
{
|
||||||
|
/* All viewports */
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
viewport_t *a = first_screen_viewport;
|
||||||
|
|
||||||
|
if (!a)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
/* The geometry */
|
||||||
|
lua_pushstring(L, "geometry");
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
lua_pushstring(L, "x");
|
||||||
|
lua_pushinteger(L, a->x);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "y");
|
||||||
|
lua_pushinteger(L, a->y);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "width");
|
||||||
|
lua_pushinteger(L, a->width);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "height");
|
||||||
|
lua_pushinteger(L, a->height);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
/* Add the geometry table to the arguments */
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_rawseti(L, -2, count++);
|
||||||
|
} while ((a = a->next));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give Lua a chance to handle or blacklist a viewport before creating the
|
||||||
|
* screen object.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
viewports_notify(lua_State *L)
|
||||||
|
{
|
||||||
|
if (!first_screen_viewport)
|
||||||
|
return;
|
||||||
|
|
||||||
|
luaA_viewports(L);
|
||||||
|
|
||||||
|
luaA_class_emit_signal(L, &screen_class, "property::viewports", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static viewport_t *
|
||||||
|
viewport_add(lua_State *L, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
/* Search existing to avoid having to deduplicate later */
|
||||||
|
viewport_t *a = first_screen_viewport;
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (a && a->x == x && a->y == y && a->width == w && a->height == h)
|
||||||
|
{
|
||||||
|
a->marked = true;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
} while (a && (a = a->next));
|
||||||
|
|
||||||
|
viewport_t *node = malloc(sizeof(viewport_t));
|
||||||
|
node->x = x;
|
||||||
|
node->y = y;
|
||||||
|
node->width = w;
|
||||||
|
node->height = h;
|
||||||
|
node->next = NULL;
|
||||||
|
node->screen = NULL;
|
||||||
|
node->marked = true;
|
||||||
|
|
||||||
|
if (!first_screen_viewport) {
|
||||||
|
first_screen_viewport = node;
|
||||||
|
last_screen_viewport = node;
|
||||||
|
} else {
|
||||||
|
last_screen_viewport->next = node;
|
||||||
|
last_screen_viewport = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(first_screen_viewport && last_screen_viewport);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
monitor_unmark(void)
|
||||||
|
{
|
||||||
|
viewport_t *a = first_screen_viewport;
|
||||||
|
|
||||||
|
if (!a)
|
||||||
|
return;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
a->marked = false;
|
||||||
|
} while((a = a->next));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
viewport_purge(void)
|
||||||
|
{
|
||||||
|
viewport_t *cur = first_screen_viewport;
|
||||||
|
|
||||||
|
/* Move the head of the list */
|
||||||
|
while (first_screen_viewport && !first_screen_viewport->marked) {
|
||||||
|
cur = first_screen_viewport;
|
||||||
|
first_screen_viewport = cur->next;
|
||||||
|
free(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first_screen_viewport) {
|
||||||
|
last_screen_viewport = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = first_screen_viewport;
|
||||||
|
|
||||||
|
/* Drop unmarked entries */
|
||||||
|
do {
|
||||||
|
if (cur->next && !cur->next->marked) {
|
||||||
|
viewport_t *tmp = cur->next;
|
||||||
|
cur->next = cur->next->next;
|
||||||
|
|
||||||
|
if (tmp == last_screen_viewport)
|
||||||
|
last_screen_viewport = cur;
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
} else
|
||||||
|
cur = cur->next;
|
||||||
|
|
||||||
|
} while(cur);
|
||||||
|
}
|
||||||
|
|
||||||
static screen_t *
|
static screen_t *
|
||||||
screen_add(lua_State *L, screen_array_t *screens)
|
screen_add(lua_State *L, screen_array_t *screens)
|
||||||
{
|
{
|
||||||
|
@ -333,7 +571,18 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
||||||
if(!xcb_randr_monitor_info_outputs_length(monitor_iter.data))
|
if(!xcb_randr_monitor_info_outputs_length(monitor_iter.data))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
viewport_t *viewport = viewport_add(L,
|
||||||
|
monitor_iter.data->x,
|
||||||
|
monitor_iter.data->y,
|
||||||
|
monitor_iter.data->width,
|
||||||
|
monitor_iter.data->height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (globalconf.ignore_screens)
|
||||||
|
continue;
|
||||||
|
|
||||||
new_screen = screen_add(L, screens);
|
new_screen = screen_add(L, screens);
|
||||||
|
viewport->screen = new_screen;
|
||||||
new_screen->geometry.x = monitor_iter.data->x;
|
new_screen->geometry.x = monitor_iter.data->x;
|
||||||
new_screen->geometry.y = monitor_iter.data->y;
|
new_screen->geometry.y = monitor_iter.data->y;
|
||||||
new_screen->geometry.width = monitor_iter.data->width;
|
new_screen->geometry.width = monitor_iter.data->width;
|
||||||
|
@ -355,9 +604,11 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
||||||
} else {
|
} else {
|
||||||
output.name = a_strdup("unknown");
|
output.name = a_strdup("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
randr_output_array_init(&output.outputs);
|
randr_output_array_init(&output.outputs);
|
||||||
|
|
||||||
randr_outputs = xcb_randr_monitor_info_outputs(monitor_iter.data);
|
randr_outputs = xcb_randr_monitor_info_outputs(monitor_iter.data);
|
||||||
|
|
||||||
for(int i = 0; i < xcb_randr_monitor_info_outputs_length(monitor_iter.data); i++) {
|
for(int i = 0; i < xcb_randr_monitor_info_outputs_length(monitor_iter.data); i++) {
|
||||||
randr_output_array_append(&output.outputs, randr_outputs[i]);
|
randr_output_array_append(&output.outputs, randr_outputs[i]);
|
||||||
}
|
}
|
||||||
|
@ -406,8 +657,22 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
|
||||||
if(!xcb_randr_get_crtc_info_outputs_length(crtc_info_r))
|
if(!xcb_randr_get_crtc_info_outputs_length(crtc_info_r))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
viewport_t *viewport = viewport_add(L,
|
||||||
|
crtc_info_r->x,
|
||||||
|
crtc_info_r->y,
|
||||||
|
crtc_info_r->width,
|
||||||
|
crtc_info_r->height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (globalconf.ignore_screens)
|
||||||
|
{
|
||||||
|
p_delete(&crtc_info_r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prepare the new screen */
|
/* Prepare the new screen */
|
||||||
screen_t *new_screen = screen_add(L, screens);
|
screen_t *new_screen = screen_add(L, screens);
|
||||||
|
viewport->screen = new_screen;
|
||||||
new_screen->geometry.x = crtc_info_r->x;
|
new_screen->geometry.x = crtc_info_r->x;
|
||||||
new_screen->geometry.y = crtc_info_r->y;
|
new_screen->geometry.y = crtc_info_r->y;
|
||||||
new_screen->geometry.width= crtc_info_r->width;
|
new_screen->geometry.width= crtc_info_r->width;
|
||||||
|
@ -485,6 +750,7 @@ screen_scan_randr(lua_State *L, screen_array_t *screens)
|
||||||
if(!version_reply)
|
if(!version_reply)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
major_version = version_reply->major_version;
|
major_version = version_reply->major_version;
|
||||||
minor_version = version_reply->minor_version;
|
minor_version = version_reply->minor_version;
|
||||||
p_delete(&version_reply);
|
p_delete(&version_reply);
|
||||||
|
@ -510,7 +776,7 @@ screen_scan_randr(lua_State *L, screen_array_t *screens)
|
||||||
else
|
else
|
||||||
screen_scan_randr_crtcs(L, screens);
|
screen_scan_randr_crtcs(L, screens);
|
||||||
|
|
||||||
if (screens->len == 0)
|
if (screens->len == 0 && !globalconf.ignore_screens)
|
||||||
{
|
{
|
||||||
/* Scanning failed, disable randr again */
|
/* Scanning failed, disable randr again */
|
||||||
xcb_randr_select_input(globalconf.connection,
|
xcb_randr_select_input(globalconf.connection,
|
||||||
|
@ -556,7 +822,18 @@ screen_scan_xinerama(lua_State *L, screen_array_t *screens)
|
||||||
|
|
||||||
for(int screen = 0; screen < xinerama_screen_number; screen++)
|
for(int screen = 0; screen < xinerama_screen_number; screen++)
|
||||||
{
|
{
|
||||||
|
viewport_t *viewport = viewport_add(L,
|
||||||
|
xsi[screen].x_org,
|
||||||
|
xsi[screen].y_org,
|
||||||
|
xsi[screen].width,
|
||||||
|
xsi[screen].height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (globalconf.ignore_screens)
|
||||||
|
continue;
|
||||||
|
|
||||||
screen_t *s = screen_add(L, screens);
|
screen_t *s = screen_add(L, screens);
|
||||||
|
viewport->screen = s;
|
||||||
s->geometry.x = xsi[screen].x_org;
|
s->geometry.x = xsi[screen].x_org;
|
||||||
s->geometry.y = xsi[screen].y_org;
|
s->geometry.y = xsi[screen].y_org;
|
||||||
s->geometry.width = xsi[screen].width;
|
s->geometry.width = xsi[screen].width;
|
||||||
|
@ -569,7 +846,19 @@ screen_scan_xinerama(lua_State *L, screen_array_t *screens)
|
||||||
static void screen_scan_x11(lua_State *L, screen_array_t *screens)
|
static void screen_scan_x11(lua_State *L, screen_array_t *screens)
|
||||||
{
|
{
|
||||||
xcb_screen_t *xcb_screen = globalconf.screen;
|
xcb_screen_t *xcb_screen = globalconf.screen;
|
||||||
|
|
||||||
|
viewport_t *viewport = viewport_add(L,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
xcb_screen->width_in_pixels,
|
||||||
|
xcb_screen->height_in_pixels
|
||||||
|
);
|
||||||
|
|
||||||
|
if (globalconf.ignore_screens)
|
||||||
|
return;
|
||||||
|
|
||||||
screen_t *s = screen_add(L, screens);
|
screen_t *s = screen_add(L, screens);
|
||||||
|
viewport->screen = s;
|
||||||
s->geometry.x = 0;
|
s->geometry.x = 0;
|
||||||
s->geometry.y = 0;
|
s->geometry.y = 0;
|
||||||
s->geometry.width = xcb_screen->width_in_pixels;
|
s->geometry.width = xcb_screen->width_in_pixels;
|
||||||
|
@ -586,21 +875,36 @@ screen_added(lua_State *L, screen_t *screen)
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get screens informations and fill global configuration.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
screen_scan(void)
|
screen_emit_scanned(void)
|
||||||
|
{
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
luaA_class_emit_signal(L, &screen_class, "scanned", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
screen_emit_scanning(void)
|
||||||
|
{
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
luaA_class_emit_signal(L, &screen_class, "scanning", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screen_scan_common(bool quiet)
|
||||||
{
|
{
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
|
|
||||||
L = globalconf_get_lua_State();
|
L = globalconf_get_lua_State();
|
||||||
|
|
||||||
|
monitor_unmark();
|
||||||
|
|
||||||
screen_scan_randr(L, &globalconf.screens);
|
screen_scan_randr(L, &globalconf.screens);
|
||||||
if (globalconf.screens.len == 0)
|
if (globalconf.screens.len == 0)
|
||||||
screen_scan_xinerama(L, &globalconf.screens);
|
screen_scan_xinerama(L, &globalconf.screens);
|
||||||
if (globalconf.screens.len == 0)
|
if (globalconf.screens.len == 0)
|
||||||
screen_scan_x11(L, &globalconf.screens);
|
screen_scan_x11(L, &globalconf.screens);
|
||||||
check(globalconf.screens.len > 0);
|
|
||||||
|
check(globalconf.screens.len > 0 || globalconf.ignore_screens);
|
||||||
|
|
||||||
screen_deduplicate(L, &globalconf.screens);
|
screen_deduplicate(L, &globalconf.screens);
|
||||||
|
|
||||||
|
@ -608,9 +912,30 @@ screen_scan(void)
|
||||||
screen_added(L, *screen);
|
screen_added(L, *screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewport_purge();
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
viewports_notify(L);
|
||||||
|
|
||||||
screen_update_primary();
|
screen_update_primary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get screens informations and fill global configuration.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
screen_scan(void)
|
||||||
|
{
|
||||||
|
screen_emit_scanning();
|
||||||
|
screen_scan_common(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
luaA_scan_quiet(lua_State *L)
|
||||||
|
{
|
||||||
|
screen_scan_common(true);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called when a screen is removed, removes references to the old screen */
|
/* Called when a screen is removed, removes references to the old screen */
|
||||||
static void
|
static void
|
||||||
screen_removed(lua_State *L, int sidx)
|
screen_removed(lua_State *L, int sidx)
|
||||||
|
@ -671,6 +996,8 @@ screen_refresh(gpointer unused)
|
||||||
{
|
{
|
||||||
globalconf.screen_refresh_pending = false;
|
globalconf.screen_refresh_pending = false;
|
||||||
|
|
||||||
|
monitor_unmark();
|
||||||
|
|
||||||
screen_array_t new_screens;
|
screen_array_t new_screens;
|
||||||
screen_array_t removed_screens;
|
screen_array_t removed_screens;
|
||||||
lua_State *L = globalconf_get_lua_State();
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
@ -682,6 +1009,10 @@ screen_refresh(gpointer unused)
|
||||||
else
|
else
|
||||||
screen_scan_randr_crtcs(L, &new_screens);
|
screen_scan_randr_crtcs(L, &new_screens);
|
||||||
|
|
||||||
|
viewport_purge();
|
||||||
|
|
||||||
|
viewports_notify(L);
|
||||||
|
|
||||||
screen_deduplicate(L, &new_screens);
|
screen_deduplicate(L, &new_screens);
|
||||||
|
|
||||||
/* Running without any screens at all is no fun. */
|
/* Running without any screens at all is no fun. */
|
||||||
|
@ -1077,6 +1408,11 @@ luaA_screen_module_index(lua_State *L)
|
||||||
{
|
{
|
||||||
if(A_STREQ(name, "primary"))
|
if(A_STREQ(name, "primary"))
|
||||||
return luaA_object_push(L, screen_get_primary());
|
return luaA_object_push(L, screen_get_primary());
|
||||||
|
else if (A_STREQ(name, "automatic_factory"))
|
||||||
|
{
|
||||||
|
lua_pushboolean(L, !globalconf.ignore_screens);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
foreach(screen, globalconf.screens)
|
foreach(screen, globalconf.screens)
|
||||||
foreach(output, (*screen)->outputs)
|
foreach(output, (*screen)->outputs)
|
||||||
|
@ -1090,6 +1426,28 @@ luaA_screen_module_index(lua_State *L)
|
||||||
return luaA_object_push(L, luaA_checkscreen(L, 2));
|
return luaA_object_push(L, luaA_checkscreen(L, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
luaA_screen_module_newindex(lua_State *L)
|
||||||
|
{
|
||||||
|
const char *buf = luaL_checkstring(L, 2);
|
||||||
|
|
||||||
|
if (A_STREQ(buf, "automatic_factory"))
|
||||||
|
{
|
||||||
|
globalconf.ignore_screens = !luaA_checkboolean(L, 3);
|
||||||
|
|
||||||
|
/* It *can* be useful if screens are added/removed later, but generally,
|
||||||
|
* setting this should be done before screens are added
|
||||||
|
*/
|
||||||
|
if (globalconf.ignore_screens && !globalconf.no_auto_screen)
|
||||||
|
luaA_warn(L,
|
||||||
|
"Setting automatic_factory only makes sense when AwesomeWM is"
|
||||||
|
" started with `--screen off`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return luaA_default_newindex(L);
|
||||||
|
}
|
||||||
|
|
||||||
/** Iterate over screens.
|
/** Iterate over screens.
|
||||||
* @usage
|
* @usage
|
||||||
* for s in screen do
|
* for s in screen do
|
||||||
|
@ -1312,8 +1670,10 @@ screen_class_setup(lua_State *L)
|
||||||
{
|
{
|
||||||
LUA_CLASS_METHODS(screen)
|
LUA_CLASS_METHODS(screen)
|
||||||
{ "count", luaA_screen_count },
|
{ "count", luaA_screen_count },
|
||||||
|
{ "_viewports", luaA_viewports },
|
||||||
|
{ "_scan_quiet", luaA_scan_quiet },
|
||||||
{ "__index", luaA_screen_module_index },
|
{ "__index", luaA_screen_module_index },
|
||||||
{ "__newindex", luaA_default_newindex },
|
{ "__newindex", luaA_screen_module_newindex },
|
||||||
{ "__call", luaA_screen_module_call },
|
{ "__call", luaA_screen_module_call },
|
||||||
{ "fake_add", luaA_screen_fake_add },
|
{ "fake_add", luaA_screen_fake_add },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
|
|
@ -57,6 +57,8 @@ void screen_update_primary(void);
|
||||||
void screen_update_workarea(screen_t *);
|
void screen_update_workarea(screen_t *);
|
||||||
screen_t *screen_get_primary(void);
|
screen_t *screen_get_primary(void);
|
||||||
void screen_schedule_refresh(void);
|
void screen_schedule_refresh(void);
|
||||||
|
void screen_emit_scanned(void);
|
||||||
|
void screen_emit_scanning(void);
|
||||||
|
|
||||||
screen_t *luaA_checkscreen(lua_State *, int);
|
screen_t *luaA_checkscreen(lua_State *, int);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue