Merge pull request #2886 from Elv13/screen_init_merge_part1
(ignore this) Part 1 of the Lua managed screen PR
This commit is contained in:
commit
14c78ef19c
|
@ -50,14 +50,14 @@ addons:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- env: LUA=5.2 LUANAME=lua5.2 DO_COVERAGE=coveralls
|
- env: LUA=5.2 LUANAME=lua5.2 DO_COVERAGE=coveralls MANUAL_SCREENS=1
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- *BASE_PACKAGES
|
- *BASE_PACKAGES
|
||||||
- liblua5.2-dev
|
- liblua5.2-dev
|
||||||
- lua5.2
|
- lua5.2
|
||||||
- env: LUA=5.3 LUANAME=lua5.3 DO_COVERAGE=codecov
|
- env: LUA=5.3 LUANAME=lua5.3 DO_COVERAGE=codecov MANUAL_SCREENS=1
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
|
@ -229,7 +229,8 @@ install:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
script:
|
script:
|
||||||
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -DLUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION -DSTRICT_TESTS=true -D DO_COVERAGE=$DO_COVERAGE -D CMAKE_C_FLAGS=-Werror"
|
- if [ "$MANUAL_SCREENS" != "1" ]; then export MANUAL_SCREENS=0; fi
|
||||||
|
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -D LUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION -D STRICT_TESTS=true -D DO_COVERAGE=$DO_COVERAGE -D TEST_MANUAL_SCREENS=$MANUAL_SCREENS -D CMAKE_C_FLAGS=-Werror"
|
||||||
- |
|
- |
|
||||||
if [ "$EMPTY_THEME_WHILE_LOADING" = 1 ]; then
|
if [ "$EMPTY_THEME_WHILE_LOADING" = 1 ]; then
|
||||||
# Break beautiful so that trying to access the theme before beautiful.init() causes an error
|
# Break beautiful so that trying to access the theme before beautiful.init() causes an error
|
||||||
|
|
|
@ -404,6 +404,12 @@ target_link_libraries(test-gravity
|
||||||
if(DO_COVERAGE)
|
if(DO_COVERAGE)
|
||||||
set(TESTS_RUN_ENV DO_COVERAGE=1)
|
set(TESTS_RUN_ENV DO_COVERAGE=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Start AwesomeWM tests with `--screen off`
|
||||||
|
if ("${TEST_MANUAL_SCREENS}" MATCHES "1")
|
||||||
|
set(TEST_RUN_ARGS "--W --m")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_target(check-integration
|
add_custom_target(check-integration
|
||||||
${CMAKE_COMMAND} -E env CMAKE_BINARY_DIR='${CMAKE_BINARY_DIR}' ${TESTS_RUN_ENV} ./tests/run.sh \$\${TEST_RUN_ARGS:--W}
|
${CMAKE_COMMAND} -E env CMAKE_BINARY_DIR='${CMAKE_BINARY_DIR}' ${TESTS_RUN_ENV} ./tests/run.sh \$\${TEST_RUN_ARGS:--W}
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
|
40
awesome.c
40
awesome.c
|
@ -131,6 +131,8 @@ awesome_atexit(bool restart)
|
||||||
/* Close Lua */
|
/* Close Lua */
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
|
|
||||||
|
screen_cleanup();
|
||||||
|
|
||||||
/* X11 is a great protocol. There is a save-set so that reparenting WMs
|
/* X11 is a great protocol. There is a save-set so that reparenting WMs
|
||||||
* don't kill clients when they shut down. However, when a focused windows
|
* don't kill clients when they shut down. However, when a focused windows
|
||||||
* is saved, the focus will move to its parent with revert-to none.
|
* is saved, the focus will move to its parent with revert-to none.
|
||||||
|
@ -565,6 +567,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 +597,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 +638,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 +913,44 @@ 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)
|
||||||
|
{
|
||||||
|
/* Disable automatic screen creation, awful.screen has a fallback */
|
||||||
|
globalconf.ignore_screens = true;
|
||||||
|
|
||||||
|
if(!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 */
|
||||||
|
|
|
@ -137,6 +137,7 @@ file = {
|
||||||
'../lib/awful/dbus.lua',
|
'../lib/awful/dbus.lua',
|
||||||
'../lib/awful/init.lua',
|
'../lib/awful/init.lua',
|
||||||
'../lib/awful/remote.lua',
|
'../lib/awful/remote.lua',
|
||||||
|
'../lib/awful/screen/dpi.lua',
|
||||||
'../lib/awful/startup_notification.lua',
|
'../lib/awful/startup_notification.lua',
|
||||||
'../lib/awful/mouse/drag_to_tag.lua',
|
'../lib/awful/mouse/drag_to_tag.lua',
|
||||||
'../lib/gears/init.lua',
|
'../lib/gears/init.lua',
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -21,7 +21,7 @@ end
|
||||||
--
|
--
|
||||||
-- @param obj An object that should have a .screen property.
|
-- @param obj An object that should have a .screen property.
|
||||||
local function check_focus(obj)
|
local function check_focus(obj)
|
||||||
if not obj.screen.valid then return end
|
if (not obj.screen) or not obj.screen.valid then return end
|
||||||
-- When no visible client has the focus...
|
-- When no visible client has the focus...
|
||||||
if not client.focus or not client.focus:isvisible() then
|
if not client.focus or not client.focus:isvisible() then
|
||||||
local c = aclient.focus.history.get(screen[obj.screen], 0, filter_sticky)
|
local c = aclient.focus.history.get(screen[obj.screen], 0, filter_sticky)
|
||||||
|
|
|
@ -99,6 +99,9 @@ local delayed_arrange = {}
|
||||||
-- @staticfct awful.layout.get
|
-- @staticfct awful.layout.get
|
||||||
function layout.get(screen)
|
function layout.get(screen)
|
||||||
screen = screen or capi.mouse.screen
|
screen = screen or capi.mouse.screen
|
||||||
|
|
||||||
|
if not screen then return nil end
|
||||||
|
|
||||||
local t = get_screen(screen).selected_tag
|
local t = get_screen(screen).selected_tag
|
||||||
return tag.getproperty(t, "layout") or layout.suit.floating
|
return tag.getproperty(t, "layout") or layout.suit.floating
|
||||||
end
|
end
|
||||||
|
@ -308,7 +311,7 @@ capi.screen.connect_signal("padding", layout.arrange)
|
||||||
|
|
||||||
capi.client.connect_signal("focus", function(c)
|
capi.client.connect_signal("focus", function(c)
|
||||||
local screen = c.screen
|
local screen = c.screen
|
||||||
if layout.get(screen).need_focus_update then
|
if screen and layout.get(screen).need_focus_update then
|
||||||
layout.arrange(screen)
|
layout.arrange(screen)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -679,6 +679,30 @@ capi.screen.connect_signal("request::wallpaper::connected", function(new_handler
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Create some screens when none exist. This can happen when AwesomeWM is
|
||||||
|
-- started with `--screen off` and no handler is used.
|
||||||
|
capi.screen.connect_signal("scanned", function()
|
||||||
|
if capi.screen.count() == 0 then
|
||||||
|
-- Private API to scan for screens now.
|
||||||
|
if #capi.screen._viewports() == 0 then
|
||||||
|
capi.screen._scan_quiet()
|
||||||
|
end
|
||||||
|
|
||||||
|
local viewports = capi.screen._viewports()
|
||||||
|
|
||||||
|
if #viewports > 0 then
|
||||||
|
for _, area in ipairs(viewports) do
|
||||||
|
local geo = area.geometry
|
||||||
|
capi.screen.fake_add(geo.x, geo.y, geo.width, geo.height)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
capi.screen.fake_add(0, 0, 640, 480)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(capi.screen.count() > 0, "Creating screens failed")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- When the tag history changed.
|
--- When the tag history changed.
|
||||||
-- @signal tag::history::update
|
-- @signal tag::history::update
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,88 @@ function gtable.merge(t, set)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update the `target` table with entries from the `new` table.
|
||||||
|
--
|
||||||
|
-- Compared to `gears.table.merge`, this version is intended to work using both
|
||||||
|
-- an `identifier` function and a `merger` function. This works only for
|
||||||
|
-- indexed tables.
|
||||||
|
--
|
||||||
|
-- The main use case is when changing the table reference is not possible or
|
||||||
|
-- when the `target` contains additional content that must be kept.
|
||||||
|
--
|
||||||
|
-- Note that calling this function involve a lot of looping and should not be
|
||||||
|
-- done often.
|
||||||
|
--
|
||||||
|
-- @tparam table target The table to modify.
|
||||||
|
-- @tparam table new The table which contains the new content.
|
||||||
|
-- @tparam function identifier A function which take the table entry (either
|
||||||
|
-- from the `target` or `new` table) and return an unique identifier. The
|
||||||
|
-- identifier type isn't important as long as `==` works to compare them.
|
||||||
|
-- @tparam[opt] function merger A function takes the entry to modify as first
|
||||||
|
-- parameter and the new entry as second. The function must return the merged
|
||||||
|
-- value. If none is provided, there is no attempt to merge the content.
|
||||||
|
-- @treturn table The target table (for daisy chaining).
|
||||||
|
-- @treturn table The new entries.
|
||||||
|
-- @treturn table The removed entries.
|
||||||
|
-- @treturn table The updated entries.
|
||||||
|
-- @staticfct gears.table.diff_merge
|
||||||
|
-- @usage local output, added, removed, updated = gears.table.diff_merge(
|
||||||
|
-- output, input, function(v) return v.id end, gears.table.crush,
|
||||||
|
-- )
|
||||||
|
function gtable.diff_merge(target, new, identifier, merger)
|
||||||
|
local n_id, o_id, up = {}, {}, {}
|
||||||
|
local add, rem = gtable.clone(new, false), gtable.clone(target, false)
|
||||||
|
|
||||||
|
for _, v in ipairs(target) do
|
||||||
|
o_id[identifier(v)] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, v in ipairs(new) do
|
||||||
|
n_id[identifier(v)] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in ipairs(rem) do
|
||||||
|
if n_id[identifier(v)] then
|
||||||
|
rem[k] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in ipairs(add) do
|
||||||
|
local id = identifier(v)
|
||||||
|
local old = o_id[id]
|
||||||
|
if old then
|
||||||
|
add[k] = nil
|
||||||
|
if merger then
|
||||||
|
o_id[id] = merger(old, v)
|
||||||
|
table.insert(up, old)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(target, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in ipairs(target) do
|
||||||
|
local id = identifier(v)
|
||||||
|
if o_id[id] then
|
||||||
|
target[k] = o_id[id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compact.
|
||||||
|
rem, add = gtable.from_sparse(rem), gtable.from_sparse(add)
|
||||||
|
|
||||||
|
for _, v in ipairs(rem) do
|
||||||
|
for k, v2 in ipairs(target) do
|
||||||
|
if v == v2 then
|
||||||
|
table.remove(target, k)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return target, add, rem, up
|
||||||
|
end
|
||||||
|
|
||||||
--- Map a function to a table.
|
--- Map a function to a table.
|
||||||
--
|
--
|
||||||
-- The function is applied to each value on the table, returning a modified
|
-- The function is applied to each value on the table, returning a modified
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -44,7 +44,7 @@ local function get_widget_context(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local context = self._widget_context
|
local context = self._widget_context
|
||||||
local dpi = s.dpi
|
local dpi = s and s.dpi or 96
|
||||||
if (not context) or context.screen ~= s or context.dpi ~= dpi then
|
if (not context) or context.screen ~= s or context.dpi ~= dpi then
|
||||||
context = {
|
context = {
|
||||||
screen = s,
|
screen = s,
|
||||||
|
|
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
|
||||||
|
|
|
@ -47,6 +47,8 @@ OPTIONS
|
||||||
Ajouter un répertoire au chemin de recherche de bibliothèque.
|
Ajouter un répertoire au chemin de recherche de bibliothèque.
|
||||||
*-a*, *--no-argb*::
|
*-a*, *--no-argb*::
|
||||||
N'utilise pas le codage ARGB.
|
N'utilise pas le codage ARGB.
|
||||||
|
*-m*, *--screen*:: 'off' ou 'on'::
|
||||||
|
Utiliser "manual" pour exécuter rc.lua avant de créer les écrans.
|
||||||
*-r*, *--replace*::
|
*-r*, *--replace*::
|
||||||
Remplace le gestionnaire de fenêtres existant.
|
Remplace le gestionnaire de fenêtres existant.
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ OPTIONS
|
||||||
Add a directory to the library search path.
|
Add a directory to the library search path.
|
||||||
*-a*, *--no-argb*::
|
*-a*, *--no-argb*::
|
||||||
Don't use ARGB visuals.
|
Don't use ARGB visuals.
|
||||||
|
*-m*, *--screen*:: 'off' or 'on'::
|
||||||
|
Use "off" to execute rc.lua before creating the screens.
|
||||||
*-r*, *--replace*::
|
*-r*, *--replace*::
|
||||||
Replace an existing window manager.
|
Replace an existing window manager.
|
||||||
|
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
||||||
|
|
632
objects/screen.c
632
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.
|
||||||
*
|
*
|
||||||
|
@ -225,6 +277,8 @@ static void
|
||||||
screen_output_wipe(screen_output_t *output)
|
screen_output_wipe(screen_output_t *output)
|
||||||
{
|
{
|
||||||
p_delete(&output->name);
|
p_delete(&output->name);
|
||||||
|
|
||||||
|
randr_output_array_wipe(&output->outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARRAY_FUNCS(screen_output_t, screen_output, screen_output_wipe)
|
ARRAY_FUNCS(screen_output_t, screen_output, screen_output_wipe)
|
||||||
|
@ -232,13 +286,6 @@ ARRAY_FUNCS(screen_output_t, screen_output, screen_output_wipe)
|
||||||
static lua_class_t screen_class;
|
static lua_class_t screen_class;
|
||||||
LUA_OBJECT_FUNCS(screen_class, screen_t, screen)
|
LUA_OBJECT_FUNCS(screen_class, screen_t, screen)
|
||||||
|
|
||||||
/** Collect a screen. */
|
|
||||||
static void
|
|
||||||
screen_wipe(screen_t *s)
|
|
||||||
{
|
|
||||||
screen_output_array_wipe(&s->outputs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if a screen is valid */
|
/** Check if a screen is valid */
|
||||||
static bool
|
static bool
|
||||||
screen_checker(screen_t *s)
|
screen_checker(screen_t *s)
|
||||||
|
@ -297,6 +344,243 @@ 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;
|
||||||
|
screen_output_array_t outputs;
|
||||||
|
} viewport_t;
|
||||||
|
|
||||||
|
static viewport_t *first_screen_viewport = NULL;
|
||||||
|
static viewport_t *last_screen_viewport = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
luaA_viewport_get_outputs(lua_State *L, viewport_t *a)
|
||||||
|
{
|
||||||
|
lua_createtable(L, 0, a ? a->outputs.len : 0);
|
||||||
|
|
||||||
|
if (!a)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
foreach(output, a->outputs) {
|
||||||
|
lua_createtable(L, 3, 0);
|
||||||
|
|
||||||
|
lua_pushstring(L, "mm_width");
|
||||||
|
lua_pushinteger(L, output->mm_width);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "mm_height");
|
||||||
|
lua_pushinteger(L, output->mm_height);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "name");
|
||||||
|
lua_pushstring(L, output->name);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
/* Add to the outputs */
|
||||||
|
lua_rawseti(L, -2, count++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Add the outputs table to the arguments */
|
||||||
|
lua_pushstring(L, "outputs");
|
||||||
|
luaA_viewport_get_outputs(L, a);
|
||||||
|
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;
|
||||||
|
|
||||||
|
screen_output_array_init(&node->outputs);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
foreach(existing_screen, globalconf.screens)
|
||||||
|
if ((*existing_screen)->viewport == cur)
|
||||||
|
(*existing_screen)->viewport = NULL;
|
||||||
|
|
||||||
|
screen_output_array_wipe(&cur->outputs);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
foreach(existing_screen, globalconf.screens)
|
||||||
|
if ((*existing_screen)->viewport == tmp)
|
||||||
|
(*existing_screen)->viewport = NULL;
|
||||||
|
|
||||||
|
screen_output_array_wipe(&tmp->outputs);
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
@ -309,6 +593,43 @@ screen_add(lua_State *L, screen_array_t *screens)
|
||||||
|
|
||||||
/* Monitors were introduced in RandR 1.5 */
|
/* Monitors were introduced in RandR 1.5 */
|
||||||
#ifdef XCB_RANDR_GET_MONITORS
|
#ifdef XCB_RANDR_GET_MONITORS
|
||||||
|
|
||||||
|
static screen_output_t
|
||||||
|
screen_get_randr_output(lua_State *L, xcb_randr_monitor_info_iterator_t *it)
|
||||||
|
{
|
||||||
|
screen_output_t output;
|
||||||
|
xcb_randr_output_t *randr_outputs;
|
||||||
|
xcb_get_atom_name_cookie_t name_c;
|
||||||
|
xcb_get_atom_name_reply_t *name_r;
|
||||||
|
|
||||||
|
output.mm_width = it->data->width_in_millimeters;
|
||||||
|
output.mm_height = it->data->height_in_millimeters;
|
||||||
|
|
||||||
|
name_c = xcb_get_atom_name_unchecked(globalconf.connection, it->data->name);
|
||||||
|
name_r = xcb_get_atom_name_reply(globalconf.connection, name_c, NULL);
|
||||||
|
|
||||||
|
if (name_r) {
|
||||||
|
const char *name = xcb_get_atom_name_name(name_r);
|
||||||
|
size_t len = xcb_get_atom_name_name_length(name_r);
|
||||||
|
|
||||||
|
output.name = memcpy(p_new(char *, len + 1), name, len);
|
||||||
|
output.name[len] = '\0';
|
||||||
|
p_delete(&name_r);
|
||||||
|
} else {
|
||||||
|
output.name = a_strdup("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
randr_output_array_init(&output.outputs);
|
||||||
|
|
||||||
|
randr_outputs = xcb_randr_monitor_info_outputs(it->data);
|
||||||
|
|
||||||
|
for(int i = 0; i < xcb_randr_monitor_info_outputs_length(it->data); i++) {
|
||||||
|
randr_output_array_append(&output.outputs, randr_outputs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
||||||
{
|
{
|
||||||
|
@ -325,44 +646,32 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
||||||
monitor_iter.rem; xcb_randr_monitor_info_next(&monitor_iter))
|
monitor_iter.rem; xcb_randr_monitor_info_next(&monitor_iter))
|
||||||
{
|
{
|
||||||
screen_t *new_screen;
|
screen_t *new_screen;
|
||||||
screen_output_t output;
|
|
||||||
xcb_randr_output_t *randr_outputs;
|
|
||||||
xcb_get_atom_name_cookie_t name_c;
|
|
||||||
xcb_get_atom_name_reply_t *name_r;
|
|
||||||
|
|
||||||
if(!xcb_randr_monitor_info_outputs_length(monitor_iter.data))
|
if(!xcb_randr_monitor_info_outputs_length(monitor_iter.data))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
screen_output_t output = screen_get_randr_output(L, &monitor_iter);
|
||||||
|
|
||||||
|
viewport_t *viewport = viewport_add(L,
|
||||||
|
monitor_iter.data->x,
|
||||||
|
monitor_iter.data->y,
|
||||||
|
monitor_iter.data->width,
|
||||||
|
monitor_iter.data->height
|
||||||
|
);
|
||||||
|
|
||||||
|
screen_output_array_append(&viewport->outputs, output);
|
||||||
|
|
||||||
|
if (globalconf.ignore_screens)
|
||||||
|
continue;
|
||||||
|
|
||||||
new_screen = screen_add(L, screens);
|
new_screen = screen_add(L, screens);
|
||||||
|
viewport->screen = new_screen;
|
||||||
|
new_screen->viewport = viewport;
|
||||||
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;
|
||||||
new_screen->geometry.height = monitor_iter.data->height;
|
new_screen->geometry.height = monitor_iter.data->height;
|
||||||
new_screen->xid = monitor_iter.data->name;
|
new_screen->xid = monitor_iter.data->name;
|
||||||
|
|
||||||
output.mm_width = monitor_iter.data->width_in_millimeters;
|
|
||||||
output.mm_height = monitor_iter.data->height_in_millimeters;
|
|
||||||
|
|
||||||
name_c = xcb_get_atom_name_unchecked(globalconf.connection, monitor_iter.data->name);
|
|
||||||
name_r = xcb_get_atom_name_reply(globalconf.connection, name_c, NULL);
|
|
||||||
if (name_r) {
|
|
||||||
const char *name = xcb_get_atom_name_name(name_r);
|
|
||||||
size_t len = xcb_get_atom_name_name_length(name_r);
|
|
||||||
|
|
||||||
output.name = memcpy(p_new(char *, len + 1), name, len);
|
|
||||||
output.name[len] = '\0';
|
|
||||||
p_delete(&name_r);
|
|
||||||
} else {
|
|
||||||
output.name = a_strdup("unknown");
|
|
||||||
}
|
|
||||||
randr_output_array_init(&output.outputs);
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
randr_output_array_append(&output.outputs, randr_outputs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
screen_output_array_append(&new_screen->outputs, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p_delete(&monitors_r);
|
p_delete(&monitors_r);
|
||||||
|
@ -374,6 +683,39 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
screen_get_randr_crtcs_outputs(lua_State *L, xcb_randr_get_crtc_info_reply_t *crtc_info_r, screen_output_array_t *outputs)
|
||||||
|
{
|
||||||
|
xcb_randr_output_t *randr_outputs = xcb_randr_get_crtc_info_outputs(crtc_info_r);
|
||||||
|
|
||||||
|
for(int j = 0; j < xcb_randr_get_crtc_info_outputs_length(crtc_info_r); j++)
|
||||||
|
{
|
||||||
|
xcb_randr_get_output_info_cookie_t output_info_c = xcb_randr_get_output_info(globalconf.connection, randr_outputs[j], XCB_CURRENT_TIME);
|
||||||
|
xcb_randr_get_output_info_reply_t *output_info_r = xcb_randr_get_output_info_reply(globalconf.connection, output_info_c, NULL);
|
||||||
|
screen_output_t output;
|
||||||
|
|
||||||
|
if (!output_info_r) {
|
||||||
|
warn("RANDR GetOutputInfo failed; this should not be possible");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = xcb_randr_get_output_info_name_length(output_info_r);
|
||||||
|
/* name is not NULL terminated */
|
||||||
|
char *name = memcpy(p_new(char *, len + 1), xcb_randr_get_output_info_name(output_info_r), len);
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
output.name = name;
|
||||||
|
output.mm_width = output_info_r->mm_width;
|
||||||
|
output.mm_height = output_info_r->mm_height;
|
||||||
|
randr_output_array_init(&output.outputs);
|
||||||
|
randr_output_array_append(&output.outputs, randr_outputs[j]);
|
||||||
|
|
||||||
|
screen_output_array_append(outputs, output);
|
||||||
|
|
||||||
|
p_delete(&output_info_r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
|
screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
|
||||||
{
|
{
|
||||||
|
@ -406,45 +748,34 @@ 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
|
||||||
|
);
|
||||||
|
|
||||||
|
screen_get_randr_crtcs_outputs(L, crtc_info_r, &viewport->outputs);
|
||||||
|
|
||||||
|
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->viewport = viewport;
|
||||||
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;
|
||||||
new_screen->geometry.height= crtc_info_r->height;
|
new_screen->geometry.height= crtc_info_r->height;
|
||||||
new_screen->xid = randr_crtcs[i];
|
new_screen->xid = randr_crtcs[i];
|
||||||
|
|
||||||
xcb_randr_output_t *randr_outputs = xcb_randr_get_crtc_info_outputs(crtc_info_r);
|
/* Detect the older NVIDIA blobs */
|
||||||
|
foreach(output, new_screen->viewport->outputs) {
|
||||||
for(int j = 0; j < xcb_randr_get_crtc_info_outputs_length(crtc_info_r); j++)
|
if (A_STREQ(output->name, "default")) {
|
||||||
{
|
|
||||||
xcb_randr_get_output_info_cookie_t output_info_c = xcb_randr_get_output_info(globalconf.connection, randr_outputs[j], XCB_CURRENT_TIME);
|
|
||||||
xcb_randr_get_output_info_reply_t *output_info_r = xcb_randr_get_output_info_reply(globalconf.connection, output_info_c, NULL);
|
|
||||||
screen_output_t output;
|
|
||||||
|
|
||||||
if (!output_info_r) {
|
|
||||||
warn("RANDR GetOutputInfo failed; this should not be possible");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len = xcb_randr_get_output_info_name_length(output_info_r);
|
|
||||||
/* name is not NULL terminated */
|
|
||||||
char *name = memcpy(p_new(char *, len + 1), xcb_randr_get_output_info_name(output_info_r), len);
|
|
||||||
name[len] = '\0';
|
|
||||||
|
|
||||||
output.name = name;
|
|
||||||
output.mm_width = output_info_r->mm_width;
|
|
||||||
output.mm_height = output_info_r->mm_height;
|
|
||||||
randr_output_array_init(&output.outputs);
|
|
||||||
randr_output_array_append(&output.outputs, randr_outputs[j]);
|
|
||||||
|
|
||||||
screen_output_array_append(&new_screen->outputs, output);
|
|
||||||
|
|
||||||
|
|
||||||
p_delete(&output_info_r);
|
|
||||||
|
|
||||||
if (A_STREQ(name, "default"))
|
|
||||||
{
|
|
||||||
/* non RandR 1.2+ X driver don't return any usable multihead
|
/* non RandR 1.2+ X driver don't return any usable multihead
|
||||||
* data. I'm looking at you, nvidia binary blob!
|
* data. I'm looking at you, nvidia binary blob!
|
||||||
*/
|
*/
|
||||||
|
@ -453,9 +784,12 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
|
||||||
/* Get rid of the screens that we already created */
|
/* Get rid of the screens that we already created */
|
||||||
foreach(screen, *screens)
|
foreach(screen, *screens)
|
||||||
luaA_object_unref(L, *screen);
|
luaA_object_unref(L, *screen);
|
||||||
|
|
||||||
screen_array_wipe(screens);
|
screen_array_wipe(screens);
|
||||||
screen_array_init(screens);
|
screen_array_init(screens);
|
||||||
|
|
||||||
|
p_delete(&screen_res_r);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,6 +819,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 +845,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 +891,19 @@ 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->viewport = viewport;
|
||||||
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 +916,20 @@ 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->viewport = viewport;
|
||||||
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 +946,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 +983,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)
|
||||||
|
@ -629,6 +1025,15 @@ screen_removed(lua_State *L, int sidx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void screen_cleanup(void)
|
||||||
|
{
|
||||||
|
while(globalconf.screens.len)
|
||||||
|
screen_array_take(&globalconf.screens, 0);
|
||||||
|
|
||||||
|
monitor_unmark();
|
||||||
|
viewport_purge();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_modified(screen_t *existing_screen, screen_t *other_screen)
|
screen_modified(screen_t *existing_screen, screen_t *other_screen)
|
||||||
{
|
{
|
||||||
|
@ -644,20 +1049,30 @@ screen_modified(screen_t *existing_screen, screen_t *other_screen)
|
||||||
screen_update_workarea(existing_screen);
|
screen_update_workarea(existing_screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool outputs_changed = existing_screen->outputs.len != other_screen->outputs.len;
|
const int other_len = other_screen->viewport ?
|
||||||
if(!outputs_changed)
|
other_screen->viewport->outputs.len : 0;
|
||||||
for(int i = 0; i < existing_screen->outputs.len; i++) {
|
|
||||||
screen_output_t *existing_output = &existing_screen->outputs.tab[i];
|
const int existing_len = existing_screen->viewport ?
|
||||||
screen_output_t *other_output = &other_screen->outputs.tab[i];
|
existing_screen->viewport->outputs.len : 0;
|
||||||
|
|
||||||
|
bool outputs_changed = (!(existing_screen->viewport && other_screen->viewport))
|
||||||
|
|| existing_len != other_len;
|
||||||
|
|
||||||
|
if(existing_screen->viewport && other_screen->viewport && !outputs_changed)
|
||||||
|
for(int i = 0; i < existing_screen->viewport->outputs.len; i++) {
|
||||||
|
screen_output_t *existing_output = &existing_screen->viewport->outputs.tab[i];
|
||||||
|
screen_output_t *other_output = &other_screen->viewport->outputs.tab[i];
|
||||||
outputs_changed |= existing_output->mm_width != other_output->mm_width;
|
outputs_changed |= existing_output->mm_width != other_output->mm_width;
|
||||||
outputs_changed |= existing_output->mm_height != other_output->mm_height;
|
outputs_changed |= existing_output->mm_height != other_output->mm_height;
|
||||||
outputs_changed |= A_STRNEQ(existing_output->name, other_output->name);
|
outputs_changed |= A_STRNEQ(existing_output->name, other_output->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Brute-force update the outputs by swapping */
|
/* Brute-force update the outputs by swapping */
|
||||||
screen_output_array_t tmp = other_screen->outputs;
|
if(existing_screen->viewport || other_screen->viewport) {
|
||||||
other_screen->outputs = existing_screen->outputs;
|
viewport_t *tmp = other_screen->viewport;
|
||||||
existing_screen->outputs = tmp;
|
other_screen->viewport = existing_screen->viewport;
|
||||||
|
|
||||||
|
existing_screen->viewport = tmp;
|
||||||
|
|
||||||
if(outputs_changed) {
|
if(outputs_changed) {
|
||||||
luaA_object_push(L, existing_screen);
|
luaA_object_push(L, existing_screen);
|
||||||
|
@ -665,12 +1080,15 @@ screen_modified(screen_t *existing_screen, screen_t *other_screen)
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
screen_refresh(gpointer unused)
|
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 +1100,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. */
|
||||||
|
@ -1022,7 +1444,8 @@ screen_update_primary(void)
|
||||||
|
|
||||||
foreach(screen, globalconf.screens)
|
foreach(screen, globalconf.screens)
|
||||||
{
|
{
|
||||||
foreach(output, (*screen)->outputs)
|
if ((*screen)->viewport)
|
||||||
|
foreach(output, (*screen)->viewport->outputs)
|
||||||
foreach (randr_output, output->outputs)
|
foreach (randr_output, output->outputs)
|
||||||
if (*randr_output == primary->output)
|
if (*randr_output == primary->output)
|
||||||
primary_screen = *screen;
|
primary_screen = *screen;
|
||||||
|
@ -1077,11 +1500,18 @@ 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)
|
if ((*screen)->viewport)
|
||||||
|
foreach(output, (*screen)->viewport->outputs)
|
||||||
if(A_STREQ(output->name, name))
|
if(A_STREQ(output->name, name))
|
||||||
return luaA_object_push(L, *screen);
|
return luaA_object_push(L, *screen);
|
||||||
|
|
||||||
luaA_warn(L, "Unknown screen output name: %s", name);
|
luaA_warn(L, "Unknown screen output name: %s", name);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1090,6 +1520,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
|
||||||
|
@ -1126,18 +1578,8 @@ luaA_screen_get_index(lua_State *L, screen_t *s)
|
||||||
static int
|
static int
|
||||||
luaA_screen_get_outputs(lua_State *L, screen_t *s)
|
luaA_screen_get_outputs(lua_State *L, screen_t *s)
|
||||||
{
|
{
|
||||||
lua_createtable(L, 0, s->outputs.len);
|
luaA_viewport_get_outputs(L, s->viewport);
|
||||||
foreach(output, s->outputs)
|
|
||||||
{
|
|
||||||
lua_createtable(L, 2, 0);
|
|
||||||
|
|
||||||
lua_pushinteger(L, output->mm_width);
|
|
||||||
lua_setfield(L, -2, "mm_width");
|
|
||||||
lua_pushinteger(L, output->mm_height);
|
|
||||||
lua_setfield(L, -2, "mm_height");
|
|
||||||
|
|
||||||
lua_setfield(L, -2, output->name);
|
|
||||||
}
|
|
||||||
/* The table of tables we created. */
|
/* The table of tables we created. */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1312,8 +1754,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 }
|
||||||
|
@ -1331,7 +1775,7 @@ screen_class_setup(lua_State *L)
|
||||||
|
|
||||||
luaA_class_setup(L, &screen_class, "screen", NULL,
|
luaA_class_setup(L, &screen_class, "screen", NULL,
|
||||||
(lua_class_allocator_t) screen_new,
|
(lua_class_allocator_t) screen_new,
|
||||||
(lua_class_collector_t) screen_wipe,
|
(lua_class_collector_t) NULL,
|
||||||
(lua_class_checker_t) screen_checker,
|
(lua_class_checker_t) screen_checker,
|
||||||
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
|
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
|
||||||
screen_methods, screen_meta);
|
screen_methods, screen_meta);
|
||||||
|
|
|
@ -39,8 +39,8 @@ struct a_screen
|
||||||
area_t geometry;
|
area_t geometry;
|
||||||
/** Screen workarea */
|
/** Screen workarea */
|
||||||
area_t workarea;
|
area_t workarea;
|
||||||
/** The screen outputs informations */
|
/** Opaque pointer to the psysical geometry */
|
||||||
screen_output_array_t outputs;
|
struct viewport_t *viewport;
|
||||||
/** Some XID identifying this screen */
|
/** Some XID identifying this screen */
|
||||||
uint32_t xid;
|
uint32_t xid;
|
||||||
};
|
};
|
||||||
|
@ -57,6 +57,9 @@ 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);
|
||||||
|
void screen_cleanup(void);
|
||||||
|
|
||||||
screen_t *luaA_checkscreen(lua_State *, int);
|
screen_t *luaA_checkscreen(lua_State *, int);
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ local function iter_scr(_, _, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function screen._areas()
|
function screen._viewports()
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
10
tests/run.sh
10
tests/run.sh
|
@ -23,16 +23,19 @@ Usage: $0 [OPTION]... [FILE]...
|
||||||
Options:
|
Options:
|
||||||
-v: verbose mode
|
-v: verbose mode
|
||||||
-W: warnings become errors
|
-W: warnings become errors
|
||||||
|
-m: Use --screen off
|
||||||
-h: show this help
|
-h: show this help
|
||||||
EOF
|
EOF
|
||||||
exit "$1"
|
exit "$1"
|
||||||
}
|
}
|
||||||
fail_on_warning=
|
fail_on_warning=
|
||||||
|
manual_screens=
|
||||||
verbose=${VERBOSE:-0}
|
verbose=${VERBOSE:-0}
|
||||||
while getopts vWh opt; do
|
while getopts vWmh opt; do
|
||||||
case $opt in
|
case $opt in
|
||||||
v) verbose=1 ;;
|
v) verbose=1 ;;
|
||||||
W) fail_on_warning=1 ;;
|
W) fail_on_warning=1 ;;
|
||||||
|
m) manual_screens=" --screen off" ;;
|
||||||
h) usage 0 ;;
|
h) usage 0 ;;
|
||||||
*) usage 64 ;;
|
*) usage 64 ;;
|
||||||
esac
|
esac
|
||||||
|
@ -105,7 +108,9 @@ fi
|
||||||
|
|
||||||
# Add test dir (for _runner.lua).
|
# Add test dir (for _runner.lua).
|
||||||
# shellcheck disable=SC2206
|
# shellcheck disable=SC2206
|
||||||
awesome_options=($AWESOME_OPTIONS --search lib --search "$this_dir")
|
awesome_options=($AWESOME_OPTIONS $manual_screens --search lib --search "$this_dir")
|
||||||
|
|
||||||
|
awesome_options+=(--screen off)
|
||||||
|
|
||||||
# Cleanup on errors / aborting.
|
# Cleanup on errors / aborting.
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
@ -172,6 +177,7 @@ fi
|
||||||
# Start awesome.
|
# Start awesome.
|
||||||
start_awesome() {
|
start_awesome() {
|
||||||
cd "$build_dir"
|
cd "$build_dir"
|
||||||
|
|
||||||
# Kill awesome after $TEST_TIMEOUT seconds (e.g. for errors during test setup).
|
# Kill awesome after $TEST_TIMEOUT seconds (e.g. for errors during test setup).
|
||||||
# SOURCE_DIRECTORY is used by .luacov.
|
# SOURCE_DIRECTORY is used by .luacov.
|
||||||
DISPLAY="$D" SOURCE_DIRECTORY="$source_dir" \
|
DISPLAY="$D" SOURCE_DIRECTORY="$source_dir" \
|
||||||
|
|
|
@ -64,6 +64,34 @@ local steps = {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
end,
|
||||||
|
-- Make sure the error code still works when all screens are gone.
|
||||||
|
function()
|
||||||
|
while screen.count() > 0 do
|
||||||
|
screen[1]:fake_remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Don't make the test fail.
|
||||||
|
local called = false
|
||||||
|
require("gears.debug").print_warning = function() called = true end
|
||||||
|
|
||||||
|
-- Cause an error in a protected call!
|
||||||
|
awesome.emit_signal("debug::error", "err")
|
||||||
|
|
||||||
|
assert(called)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
-- Test the `automatic_factory` getter and setter.
|
||||||
|
function()
|
||||||
|
assert(type(screen.automatic_factory) == "boolean")
|
||||||
|
local orig = screen.automatic_factory
|
||||||
|
screen.automatic_factory = not orig
|
||||||
|
assert(screen.automatic_factory ~= orig)
|
||||||
|
assert(type(screen.automatic_factory) == "boolean")
|
||||||
|
screen.automatic_factory = not screen.automatic_factory
|
||||||
|
assert(screen.automatic_factory == orig)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,22 @@ local runner = require("_runner")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
|
|
||||||
-- Make sure we have at least two screens to test this on
|
-- Make sure we have at least two screens to test this on.
|
||||||
screen.fake_add(-100, -100, 50, 50)
|
local origin_width = screen[1].geometry.width
|
||||||
|
screen[1]:fake_resize(
|
||||||
|
screen[1].geometry.x,
|
||||||
|
screen[1].geometry.y,
|
||||||
|
origin_width/2,
|
||||||
|
screen[1].geometry.height
|
||||||
|
)
|
||||||
|
|
||||||
|
screen.fake_add(
|
||||||
|
screen[1].geometry.x+origin_width/2,
|
||||||
|
screen[1].geometry.y,
|
||||||
|
origin_width/2,
|
||||||
|
screen[1].geometry.height
|
||||||
|
)
|
||||||
|
|
||||||
assert(screen.count() == 2)
|
assert(screen.count() == 2)
|
||||||
|
|
||||||
-- Each screen gets a wibox displaying our only_on_screen widget
|
-- Each screen gets a wibox displaying our only_on_screen widget
|
||||||
|
@ -116,7 +130,12 @@ table.insert(steps, function()
|
||||||
for s in screen do
|
for s in screen do
|
||||||
assert(not widget_visible_on(s))
|
assert(not widget_visible_on(s))
|
||||||
end
|
end
|
||||||
screen.fake_add(-100, -100, 50, 50)
|
screen.fake_add(
|
||||||
|
screen[1].geometry.x+origin_width/2,
|
||||||
|
screen[1].geometry.y,
|
||||||
|
origin_width/2,
|
||||||
|
screen[1].geometry.height
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
end)
|
end)
|
||||||
table.insert(steps, function()
|
table.insert(steps, function()
|
||||||
|
|
Loading…
Reference in New Issue