screen: Turn into proper lua object

This makes the screen objects use our existing infrastructure for implementing
classes and objects with lua instead of hand-rolling an own version.

This results in some small API change: Screen objects no longer have an
add_signal() function and instead this function exists on the parent screen
class.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2014-03-30 16:37:19 +02:00
parent d8b73de739
commit 271f084735
11 changed files with 165 additions and 249 deletions

View file

@ -59,7 +59,7 @@ typedef struct xproperty xproperty_t;
ARRAY_TYPE(button_t *, button)
ARRAY_TYPE(tag_t *, tag)
ARRAY_TYPE(screen_t, screen)
ARRAY_TYPE(screen_t *, screen)
ARRAY_TYPE(client_t *, client)
ARRAY_TYPE(drawin_t *, drawin)
ARRAY_TYPE(xproperty_t, xproperty)

View file

@ -152,9 +152,8 @@ local function arrange_tag(t)
layout.arrange(tag.getscreen(t))
end
capi.screen.add_signal("arrange")
for s = 1, capi.screen.count() do
capi.screen[s]:add_signal("arrange")
tag.attached_connect_signal(s, "property::mwfact", arrange_tag)
tag.attached_connect_signal(s, "property::nmaster", arrange_tag)
tag.attached_connect_signal(s, "property::ncol", arrange_tag)

View file

@ -104,9 +104,7 @@ function screen.padding(_screen, padding)
return data.padding[_screen]
end
for s = 1, capi.screen.count() do
capi.screen[s]:add_signal("padding")
end
capi.screen.add_signal("padding")
return screen

View file

@ -603,8 +603,8 @@ capi.tag.add_signal("property::windowfact")
capi.tag.add_signal("property::screen")
capi.tag.add_signal("property::index")
capi.screen.add_signal("tag::history::update")
for s = 1, capi.screen.count() do
capi.screen[s]:add_signal("tag::history::update")
capi.screen[s]:connect_signal("tag::history::update", tag.history.update)
end

8
luaa.c
View file

@ -57,8 +57,6 @@ extern const struct luaL_Reg awesome_mousegrabber_lib[];
extern const struct luaL_Reg awesome_root_lib[];
extern const struct luaL_Reg awesome_mouse_methods[];
extern const struct luaL_Reg awesome_mouse_meta[];
extern const struct luaL_Reg awesome_screen_methods[];
extern const struct luaL_Reg awesome_screen_meta[];
/** Path to config file */
static char *conffile;
@ -402,12 +400,12 @@ luaA_init(xdgHandle* xdg)
luaA_registerlib(L, "mousegrabber", awesome_mousegrabber_lib);
lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
/* Export screen */
luaA_openlib(L, "screen", awesome_screen_methods, awesome_screen_meta);
/* Export mouse */
luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);
/* Export screen */
screen_class_setup(L);
/* Export button */
button_class_setup(L);

View file

@ -114,14 +114,14 @@ luaA_mouse_index(lua_State *L)
* having lots of lua errors in this case.
*/
if (globalconf.focus.client)
lua_pushnumber(L, screen_array_indexof(&globalconf.screens, globalconf.focus.client->screen) + 1);
lua_pushnumber(L, screen_get_index(globalconf.focus.client->screen));
else
lua_pushnumber(L, 1);
return 1;
}
screen = screen_getbycoord(mouse_x, mouse_y);
lua_pushnumber(L, screen_array_indexof(&globalconf.screens, screen) + 1);
lua_pushnumber(L, screen_get_index(screen));
return 1;
}
@ -142,8 +142,8 @@ luaA_mouse_newindex(lua_State *L)
screen = luaL_checknumber(L, 3) - 1;
luaA_checkscreen(screen);
x = globalconf.screens.tab[screen].geometry.x;
y = globalconf.screens.tab[screen].geometry.y;
x = globalconf.screens.tab[screen]->geometry.x;
y = globalconf.screens.tab[screen]->geometry.y;
mouse_warp_pointer(globalconf.screen->root, x, y);
return 0;

View file

@ -847,6 +847,14 @@ client_resize(client_t *c, area_t geometry, bool honor_hints)
return false;
}
static void
client_emit_property_workarea_on_screen(lua_State *L, client_t *c)
{
luaA_object_push(L, c->screen);
luaA_object_emit_signal(L, -1, "property::workarea", 0);
lua_pop(L, 1);
}
/** Set a client minimized, or not.
* \param L The Lua VM state.
* \param cidx The client index.
@ -866,7 +874,7 @@ client_set_minimized(lua_State *L, int cidx, bool s)
else
xwindow_set_state(c->window, XCB_ICCCM_WM_STATE_NORMAL);
if(strut_has_value(&c->strut))
screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
client_emit_property_workarea_on_screen(L, c);
luaA_object_emit_signal(L, cidx, "property::minimized", 0);
}
}
@ -886,7 +894,7 @@ client_set_hidden(lua_State *L, int cidx, bool s)
c->hidden = s;
banning_need_update();
if(strut_has_value(&c->strut))
screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
client_emit_property_workarea_on_screen(L, c);
luaA_object_emit_signal(L, cidx, "property::hidden", 0);
}
}
@ -1142,7 +1150,7 @@ client_unmanage(client_t *c, bool window_valid)
luaA_class_emit_signal(globalconf.L, &client_class, "list", 0);
if(strut_has_value(&c->strut))
screen_emit_signal(globalconf.L, c->screen, "property::workarea", 0);
client_emit_property_workarea_on_screen(globalconf.L, c);
/* Get rid of all titlebars */
for (client_titlebar_t bar = CLIENT_TITLEBAR_TOP; bar < CLIENT_TITLEBAR_COUNT; bar++) {
@ -1253,7 +1261,7 @@ luaA_client_get(lua_State *L)
{
luaA_checkscreen(screen);
foreach(c, globalconf.clients)
if((*c)->screen == &globalconf.screens.tab[screen])
if((*c)->screen == globalconf.screens.tab[screen])
{
luaA_object_push(L, *c);
lua_rawseti(L, -2, i++);
@ -1676,7 +1684,7 @@ luaA_client_set_screen(lua_State *L, client_t *c)
{
int screen = luaL_checknumber(L, -1) - 1;
luaA_checkscreen(screen);
screen_client_moveto(c, &globalconf.screens.tab[screen], true);
screen_client_moveto(c, globalconf.screens.tab[screen], true);
return 0;
}
@ -1858,7 +1866,7 @@ luaA_client_get_screen(lua_State *L, client_t *c)
{
if(!c->screen)
return 0;
lua_pushnumber(L, 1 + screen_array_indexof(&globalconf.screens, c->screen));
lua_pushnumber(L, screen_get_index(c->screen));
return 1;
}

View file

@ -265,9 +265,9 @@ drawin_set_visible(lua_State *L, int udx, bool v)
luaA_object_emit_signal(L, udx, "property::visible", 0);
if(strut_has_value(&drawin->strut))
{
screen_t *screen =
screen_getbycoord(drawin->geometry.x, drawin->geometry.y);
screen_emit_signal(globalconf.L, screen, "property::workarea", 0);
luaA_object_push(L, screen_getbycoord(drawin->geometry.x, drawin->geometry.y));
luaA_object_emit_signal(L, -1, "property::workarea", 0);
lua_pop(L, 1);
}
}
}

View file

@ -41,7 +41,23 @@ struct screen_output_t
uint32_t mm_width, mm_height;
};
ARRAY_FUNCS(screen_output_t, screen_output, DO_NOTHING)
static void
screen_output_wipe(screen_output_t *output)
{
p_delete(&output);
}
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);
}
static inline area_t
screen_xsitoarea(xcb_xinerama_screen_info_t si)
@ -57,31 +73,26 @@ screen_xsitoarea(xcb_xinerama_screen_info_t si)
}
static void
screen_add(screen_t new_screen)
screen_add(lua_State *L, int sidx)
{
screen_t *new_screen = luaA_checkudata(L, sidx, &screen_class);
foreach(screen_to_test, globalconf.screens)
if(new_screen.geometry.x == screen_to_test->geometry.x
&& new_screen.geometry.y == screen_to_test->geometry.y)
if(new_screen->geometry.x == (*screen_to_test)->geometry.x
&& new_screen->geometry.y == (*screen_to_test)->geometry.y)
{
/* we already have a screen for this area, just check if
* it's not bigger and drop it */
screen_to_test->geometry.width =
MAX(new_screen.geometry.width, screen_to_test->geometry.width);
screen_to_test->geometry.height =
MAX(new_screen.geometry.height, screen_to_test->geometry.height);
(*screen_to_test)->geometry.width =
MAX(new_screen->geometry.width, (*screen_to_test)->geometry.width);
(*screen_to_test)->geometry.height =
MAX(new_screen->geometry.height, (*screen_to_test)->geometry.height);
lua_remove(L, sidx);
return;
}
signal_add(&new_screen.signals, "property::workarea");
luaA_object_ref(L, sidx);
screen_array_append(&globalconf.screens, new_screen);
/* Allocate the lua userdata object representing this screen */
screen_t *s = &globalconf.screens.tab[globalconf.screens.len-1];
screen_t **ps = lua_newuserdata(globalconf.L, sizeof(*ps));
*ps = s;
luaL_getmetatable(globalconf.L, "screen");
lua_setmetatable(globalconf.L, -2);
s->userdata = luaA_object_ref(globalconf.L, -1);
}
static bool
@ -131,12 +142,11 @@ screen_scan_randr(void)
continue;
/* Prepare the new screen */
screen_t new_screen;
p_clear(&new_screen, 1);
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;
screen_t *new_screen = screen_new(globalconf.L);
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;
xcb_randr_output_t *randr_outputs = xcb_randr_get_crtc_info_outputs(crtc_info_r);
@ -150,7 +160,7 @@ screen_scan_randr(void)
char *name = memcpy(p_new(char *, len + 1), xcb_randr_get_output_info_name(output_info_r), len);
name[len] = '\0';
screen_output_array_append(&new_screen.outputs,
screen_output_array_append(&new_screen->outputs,
(screen_output_t) { .name = name,
.mm_width = output_info_r->mm_width,
.mm_height = output_info_r->mm_height });
@ -158,7 +168,7 @@ screen_scan_randr(void)
p_delete(&output_info_r);
}
screen_add(new_screen);
screen_add(globalconf.L, -1);
p_delete(&crtc_info_r);
}
@ -202,10 +212,9 @@ screen_scan_xinerama(void)
/* now check if screens overlaps (same x,y): if so, we take only the biggest one */
for(int screen = 0; screen < xinerama_screen_number; screen++)
{
screen_t s;
p_clear(&s, 1);
s.geometry = screen_xsitoarea(xsi[screen]);
screen_add(s);
screen_t *s = screen_new(globalconf.L);
s->geometry = screen_xsitoarea(xsi[screen]);
screen_add(globalconf.L, -1);
}
p_delete(&xsq);
@ -220,13 +229,12 @@ static void screen_scan_x11(void)
{
/* One screen only / Zaphod mode */
xcb_screen_t *xcb_screen = globalconf.screen;
screen_t s;
p_clear(&s, 1);
s.geometry.x = 0;
s.geometry.y = 0;
s.geometry.width = xcb_screen->width_in_pixels;
s.geometry.height = xcb_screen->height_in_pixels;
screen_add(s);
screen_t *s = screen_new(globalconf.L);
s->geometry.x = 0;
s->geometry.y = 0;
s->geometry.width = xcb_screen->width_in_pixels;
s->geometry.height = xcb_screen->height_in_pixels;
screen_add(globalconf.L, -1);
}
/** Get screens informations and fill global configuration.
@ -248,12 +256,12 @@ screen_t *
screen_getbycoord(int x, int y)
{
foreach(s, globalconf.screens)
if((x < 0 || (x >= s->geometry.x && x < s->geometry.x + s->geometry.width))
&& (y < 0 || (y >= s->geometry.y && y < s->geometry.y + s->geometry.height)))
return s;
if((x < 0 || (x >= (*s)->geometry.x && x < (*s)->geometry.x + (*s)->geometry.width))
&& (y < 0 || (y >= (*s)->geometry.y && y < (*s)->geometry.y + (*s)->geometry.height)))
return *s;
/* No screen found, let's be creative. */
return &globalconf.screens.tab[0];
return globalconf.screens.tab[0];
}
/** Get screens info.
@ -261,7 +269,7 @@ screen_getbycoord(int x, int y)
* \param strut Honor windows strut.
* \return The screen area.
*/
area_t
static area_t
screen_area_get(screen_t *screen, bool strut)
{
if(!strut)
@ -399,16 +407,19 @@ screen_client_moveto(client_t *c, screen_t *new_screen, bool doresize)
client_focus(c);
}
/** Push a screen onto the stack.
* \param L The Lua VM state.
* \param s The screen to push.
* \return The number of elements pushed on stack.
*/
static int
luaA_pushscreen(lua_State *L, screen_t *s)
/** Get a screen's index. */
int
screen_get_index(screen_t *s)
{
luaA_object_push(L, s->userdata);
return 1;
int res = 0;
foreach(screen, globalconf.screens)
{
res++;
if (*screen == s)
return res;
}
return 0;
}
/** Screen module.
@ -424,172 +435,48 @@ luaA_screen_module_index(lua_State *L)
if((name = lua_tostring(L, 2)))
foreach(screen, globalconf.screens)
foreach(output, screen->outputs)
foreach(output, (*screen)->outputs)
if(A_STREQ(output->name, name))
return luaA_pushscreen(L, screen);
return luaA_object_push(L, screen);
int screen = luaL_checknumber(L, 2) - 1;
luaA_checkscreen(screen);
return luaA_pushscreen(L, &globalconf.screens.tab[screen]);
return luaA_object_push(L, globalconf.screens.tab[screen]);
}
/** A screen.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lfield coords The screen coordinates. Immutable.
* \lfield workarea The screen workarea.
*/
LUA_OBJECT_EXPORT_PROPERTY(screen, screen_t, geometry, luaA_pusharea)
static int
luaA_screen_index(lua_State *L)
luaA_screen_get_index(lua_State *L, screen_t *s)
{
const char *buf;
screen_t **ps;
screen_t *s;
/* Get metatable of the screen. */
lua_getmetatable(L, 1);
/* Get the field */
lua_pushvalue(L, 2);
lua_rawget(L, -2);
/* Do we have a field like that? */
if(!lua_isnil(L, -1))
{
/* Yes, so return it! */
lua_remove(L, -2);
return 1;
}
/* No, so remove everything. */
lua_pop(L, 2);
buf = luaL_checkstring(L, 2);
ps = luaL_checkudata(L, 1, "screen");
s = *ps;
if(A_STREQ(buf, "index"))
{
lua_pushinteger(L, screen_array_indexof(&globalconf.screens, s) + 1);
return 1;
}
if(A_STREQ(buf, "geometry"))
{
luaA_pusharea(L, s->geometry);
return 1;
}
if(A_STREQ(buf, "workarea"))
{
luaA_pusharea(L, screen_area_get(s, true));
return 1;
}
if(A_STREQ(buf, "outputs"))
{
lua_createtable(L, 0, s->outputs.len);
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. */
return 1;
}
return luaA_default_index(L);
lua_pushinteger(L, screen_get_index(s));
return 1;
}
/** Add a signal to a screen.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lvalue A screen.
* \lparam A signal name.
*/
static int
luaA_screen_add_signal(lua_State *L)
luaA_screen_get_outputs(lua_State *L, screen_t *s)
{
screen_t **ps = luaL_checkudata(L, 1, "screen");
screen_t *s = *ps;
const char *name = luaL_checkstring(L, 2);
signal_add(&s->signals, name);
return 0;
lua_createtable(L, 0, s->outputs.len);
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. */
return 1;
}
/** Connect a screen's signal.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lvalue A screen.
* \lparam A signal name.
* \lparam A function to call when the signal is emitted.
*/
static int
luaA_screen_connect_signal(lua_State *L)
luaA_screen_get_workarea(lua_State *L, screen_t *s)
{
screen_t **ps = luaL_checkudata(L, 1, "screen");
screen_t *s = *ps;
const char *name = luaL_checkstring(L, 2);
luaA_checkfunction(L, 3);
signal_connect(&s->signals, name, luaA_object_ref(L, 3));
return 0;
}
/** Remove a signal to a screen.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lvalue A screen.
* \lparam A signal name.
* \lparam A function to remove
*/
static int
luaA_screen_disconnect_signal(lua_State *L)
{
screen_t **ps = luaL_checkudata(L, 1, "screen");
screen_t *s = *ps;
const char *name = luaL_checkstring(L, 2);
luaA_checkfunction(L, 3);
const void *ref = lua_topointer(L, 3);
signal_disconnect(&s->signals, name, ref);
luaA_object_unref(L, (void *) ref);
return 0;
}
/** Emit a signal to a screen.
* \param L The Lua VM state.
* \param screen The screen.
* \param name The signal name.
* \param nargs The number of arguments to the signal function.
*/
void
screen_emit_signal(lua_State *L, screen_t *screen, const char *name, int nargs)
{
luaA_pushscreen(L, screen);
lua_insert(L, - nargs - 1);
signal_object_emit(L, &screen->signals, name, nargs + 1);
}
/** Emit a signal to a screen.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lvalue A screen.
* \lparam A signal name.
* \lparam Various arguments, optional.
*/
static int
luaA_screen_emit_signal(lua_State *L)
{
screen_t **ps = luaL_checkudata(L, 1, "screen");
screen_emit_signal(L, *ps, luaL_checkstring(L, 2), lua_gettop(L) - 2);
return 0;
luaA_pusharea(L, screen_area_get(s, true));
return 1;
}
/** Get the screen count.
@ -606,23 +493,48 @@ luaA_screen_count(lua_State *L)
return 1;
}
const struct luaL_Reg awesome_screen_methods[] =
void
screen_class_setup(lua_State *L)
{
{ "count", luaA_screen_count },
{ "__index", luaA_screen_module_index },
{ "__newindex", luaA_default_newindex },
{ NULL, NULL }
};
static const struct luaL_Reg screen_methods[] =
{
LUA_CLASS_METHODS(screen)
{ "count", luaA_screen_count },
{ "__index", luaA_screen_module_index },
{ "__newindex", luaA_default_newindex },
{ NULL, NULL }
};
const struct luaL_Reg awesome_screen_meta[] =
{
{ "add_signal", luaA_screen_add_signal },
{ "connect_signal", luaA_screen_connect_signal },
{ "disconnect_signal", luaA_screen_disconnect_signal },
{ "emit_signal", luaA_screen_emit_signal },
{ "__index", luaA_screen_index },
{ "__newindex", luaA_default_newindex },
{ NULL, NULL }
};
static const struct luaL_Reg screen_meta[] =
{
LUA_OBJECT_META(screen)
LUA_CLASS_META
{ NULL, NULL },
};
luaA_class_setup(L, &screen_class, "screen", NULL,
(lua_class_allocator_t) screen_new,
(lua_class_collector_t) screen_wipe,
NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
screen_methods, screen_meta);
luaA_class_add_property(&screen_class, "geometry",
NULL,
(lua_class_propfunc_t) luaA_screen_get_geometry,
NULL);
luaA_class_add_property(&screen_class, "index",
NULL,
(lua_class_propfunc_t) luaA_screen_get_index,
NULL);
luaA_class_add_property(&screen_class, "outputs",
NULL,
(lua_class_propfunc_t) luaA_screen_get_outputs,
NULL);
luaA_class_add_property(&screen_class, "workarea",
NULL,
(lua_class_propfunc_t) luaA_screen_get_workarea,
NULL);
signal_add(&screen_class.signals, "property::workarea");
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View file

@ -30,21 +30,18 @@ ARRAY_TYPE(screen_output_t, screen_output)
struct a_screen
{
LUA_OBJECT_HEADER
/** Screen geometry */
area_t geometry;
/** The signals emitted by screen objects */
signal_array_t signals;
/** The screen outputs informations */
screen_output_array_t outputs;
/** The lua userdata representing this screen */
void *userdata;
};
ARRAY_FUNCS(screen_t, screen, DO_NOTHING)
ARRAY_FUNCS(screen_t *, screen, DO_NOTHING)
void screen_emit_signal(lua_State *, screen_t *, const char *, int);
void screen_class_setup(lua_State *L);
void screen_scan(void);
screen_t *screen_getbycoord(int, int);
area_t screen_area_get(screen_t *, bool);
int screen_get_index(screen_t *);
area_t display_area_get(void);
void screen_client_moveto(client_t *, screen_t *, bool);

View file

@ -80,7 +80,11 @@ luaA_window_struts(lua_State *L)
/* FIXME: Only emit if the workarea actually changed
* (= window is visible, only on the right screen)? */
foreach(s, globalconf.screens)
screen_emit_signal(L, s, "property::workarea", 0);
{
luaA_object_push(L, *s);
luaA_object_emit_signal(L, -1, "property::workarea", 0);
lua_pop(L, 1);
}
}
return luaA_pushstrut(L, window->strut);