screen: Split the `outputs` code away from the screen logic.

It moves the actual place where when screen array is stored into the
area object. This allows to store the outputs when screens are not
automatically created.
This commit is contained in:
Emmanuel Lepage Vallee 2019-06-16 23:54:02 -04:00
parent 68488f6218
commit 1304f46c0c
3 changed files with 189 additions and 102 deletions

View File

@ -131,6 +131,8 @@ awesome_atexit(bool restart)
/* Close Lua */
lua_close(L);
screen_cleanup();
/* 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
* is saved, the focus will move to its parent with revert-to none.

View File

@ -277,6 +277,8 @@ static void
screen_output_wipe(screen_output_t *output)
{
p_delete(&output->name);
randr_output_array_wipe(&output->outputs);
}
ARRAY_FUNCS(screen_output_t, screen_output, screen_output_wipe)
@ -284,13 +286,6 @@ ARRAY_FUNCS(screen_output_t, screen_output, screen_output_wipe)
static lua_class_t screen_class;
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 */
static bool
screen_checker(screen_t *s)
@ -385,11 +380,42 @@ typedef struct viewport_t
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)
{
@ -427,6 +453,11 @@ luaA_viewports(lua_State *L)
/* 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));
@ -472,12 +503,14 @@ viewport_add(lua_State *L, int x, int y, int w, int h)
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;
last_screen_viewport = node;
}
assert(first_screen_viewport && last_screen_viewport);
@ -509,6 +542,13 @@ viewport_purge(void)
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);
}
@ -528,6 +568,12 @@ viewport_purge(void)
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;
@ -547,6 +593,43 @@ screen_add(lua_State *L, screen_array_t *screens)
/* Monitors were introduced in RandR 1.5 */
#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
screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
{
@ -563,14 +646,12 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
monitor_iter.rem; xcb_randr_monitor_info_next(&monitor_iter))
{
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))
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,
@ -578,42 +659,19 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
monitor_iter.data->height
);
screen_output_array_append(&viewport->outputs, output);
if (globalconf.ignore_screens)
continue;
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.y = monitor_iter.data->y;
new_screen->geometry.width = monitor_iter.data->width;
new_screen->geometry.height = monitor_iter.data->height;
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);
@ -625,6 +683,39 @@ screen_scan_randr_monitors(lua_State *L, screen_array_t *screens)
}
#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
screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
{
@ -664,6 +755,8 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
crtc_info_r->height
);
screen_get_randr_crtcs_outputs(L, crtc_info_r, &viewport->outputs);
if (globalconf.ignore_screens)
{
p_delete(&crtc_info_r);
@ -673,43 +766,16 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
/* Prepare the new screen */
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.y = crtc_info_r->y;
new_screen->geometry.width= crtc_info_r->width;
new_screen->geometry.height= crtc_info_r->height;
new_screen->xid = randr_crtcs[i];
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(&new_screen->outputs, output);
p_delete(&output_info_r);
if (A_STREQ(name, "default"))
{
/* Detect the older NVIDIA blobs */
foreach(output, new_screen->viewport->outputs) {
if (A_STREQ(output->name, "default")) {
/* non RandR 1.2+ X driver don't return any usable multihead
* data. I'm looking at you, nvidia binary blob!
*/
@ -718,9 +784,12 @@ screen_scan_randr_crtcs(lua_State *L, screen_array_t *screens)
/* Get rid of the screens that we already created */
foreach(screen, *screens)
luaA_object_unref(L, *screen);
screen_array_wipe(screens);
screen_array_init(screens);
p_delete(&screen_res_r);
return;
}
}
@ -834,6 +903,7 @@ screen_scan_xinerama(lua_State *L, screen_array_t *screens)
screen_t *s = screen_add(L, screens);
viewport->screen = s;
s->viewport = viewport;
s->geometry.x = xsi[screen].x_org;
s->geometry.y = xsi[screen].y_org;
s->geometry.width = xsi[screen].width;
@ -859,6 +929,7 @@ static void screen_scan_x11(lua_State *L, screen_array_t *screens)
screen_t *s = screen_add(L, screens);
viewport->screen = s;
s->viewport = viewport;
s->geometry.x = 0;
s->geometry.y = 0;
s->geometry.width = xcb_screen->width_in_pixels;
@ -954,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
screen_modified(screen_t *existing_screen, screen_t *other_screen)
{
@ -969,25 +1049,36 @@ screen_modified(screen_t *existing_screen, screen_t *other_screen)
screen_update_workarea(existing_screen);
}
bool outputs_changed = existing_screen->outputs.len != other_screen->outputs.len;
if(!outputs_changed)
for(int i = 0; i < existing_screen->outputs.len; i++) {
screen_output_t *existing_output = &existing_screen->outputs.tab[i];
screen_output_t *other_output = &other_screen->outputs.tab[i];
const int other_len = other_screen->viewport ?
other_screen->viewport->outputs.len : 0;
const int existing_len = existing_screen->viewport ?
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_height != other_output->mm_height;
outputs_changed |= A_STRNEQ(existing_output->name, other_output->name);
}
/* Brute-force update the outputs by swapping */
screen_output_array_t tmp = other_screen->outputs;
other_screen->outputs = existing_screen->outputs;
existing_screen->outputs = tmp;
if(existing_screen->viewport || other_screen->viewport) {
viewport_t *tmp = other_screen->viewport;
other_screen->viewport = existing_screen->viewport;
if(outputs_changed) {
luaA_object_push(L, existing_screen);
luaA_object_emit_signal(L, -1, "property::outputs", 0);
lua_pop(L, 1);
existing_screen->viewport = tmp;
if(outputs_changed) {
luaA_object_push(L, existing_screen);
luaA_object_emit_signal(L, -1, "property::outputs", 0);
lua_pop(L, 1);
}
}
}
@ -1353,10 +1444,11 @@ screen_update_primary(void)
foreach(screen, globalconf.screens)
{
foreach(output, (*screen)->outputs)
foreach (randr_output, output->outputs)
if (*randr_output == primary->output)
primary_screen = *screen;
if ((*screen)->viewport)
foreach(output, (*screen)->viewport->outputs)
foreach (randr_output, output->outputs)
if (*randr_output == primary->output)
primary_screen = *screen;
}
p_delete(&primary);
@ -1415,9 +1507,11 @@ luaA_screen_module_index(lua_State *L)
}
foreach(screen, globalconf.screens)
foreach(output, (*screen)->outputs)
if(A_STREQ(output->name, name))
return luaA_object_push(L, *screen);
if ((*screen)->viewport)
foreach(output, (*screen)->viewport->outputs)
if(A_STREQ(output->name, name))
return luaA_object_push(L, *screen);
luaA_warn(L, "Unknown screen output name: %s", name);
lua_pushnil(L);
return 1;
@ -1484,18 +1578,8 @@ luaA_screen_get_index(lua_State *L, screen_t *s)
static int
luaA_screen_get_outputs(lua_State *L, screen_t *s)
{
lua_createtable(L, 0, s->outputs.len);
foreach(output, s->outputs)
{
lua_createtable(L, 2, 0);
luaA_viewport_get_outputs(L, s->viewport);
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. */
return 1;
}
@ -1691,7 +1775,7 @@ screen_class_setup(lua_State *L)
luaA_class_setup(L, &screen_class, "screen", NULL,
(lua_class_allocator_t) screen_new,
(lua_class_collector_t) screen_wipe,
(lua_class_collector_t) NULL,
(lua_class_checker_t) screen_checker,
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
screen_methods, screen_meta);

View File

@ -39,8 +39,8 @@ struct a_screen
area_t geometry;
/** Screen workarea */
area_t workarea;
/** The screen outputs informations */
screen_output_array_t outputs;
/** Opaque pointer to the psysical geometry */
struct viewport_t *viewport;
/** Some XID identifying this screen */
uint32_t xid;
};
@ -59,6 +59,7 @@ screen_t *screen_get_primary(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);