2010-10-06 13:35:14 +02:00
|
|
|
/*
|
|
|
|
* drawin.c - drawin functions
|
|
|
|
*
|
|
|
|
* Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
|
|
|
|
* Copyright © 2010 Uli Schlachter <psychon@znc.in>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-02-27 00:24:23 +01:00
|
|
|
/** awesome drawin API
|
|
|
|
*
|
|
|
|
* Furthermore to the classes described here, one can also use signals as
|
|
|
|
* described in @{signals} and X properties as described in @{xproperties}.
|
|
|
|
*
|
|
|
|
* @author Julien Danjou <julien@danjou.info>
|
|
|
|
* @copyright 2008-2009 Julien Danjou
|
|
|
|
* @release @AWESOME_VERSION@
|
|
|
|
* @classmod drawin
|
|
|
|
*/
|
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
#include "drawin.h"
|
2014-03-30 20:07:48 +02:00
|
|
|
#include "common/atoms.h"
|
|
|
|
#include "common/xcursor.h"
|
2015-08-14 14:39:43 +02:00
|
|
|
#include "event.h"
|
2014-03-30 20:07:48 +02:00
|
|
|
#include "ewmh.h"
|
2010-10-06 13:35:14 +02:00
|
|
|
#include "objects/client.h"
|
2014-03-30 15:12:47 +02:00
|
|
|
#include "objects/screen.h"
|
2010-10-06 15:38:44 +02:00
|
|
|
#include "systray.h"
|
2014-03-30 20:07:48 +02:00
|
|
|
#include "xwindow.h"
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2010-10-06 13:49:50 +02:00
|
|
|
#include <cairo-xcb.h>
|
2012-11-05 17:56:56 +01:00
|
|
|
#include <xcb/shape.h>
|
2010-10-06 13:49:50 +02:00
|
|
|
|
2015-02-27 00:24:23 +01:00
|
|
|
/** Drawin object.
|
|
|
|
*
|
|
|
|
* @field border_width Border width.
|
|
|
|
* @field border_color Border color.
|
|
|
|
* @field ontop On top of other windows.
|
|
|
|
* @field cursor The mouse cursor.
|
|
|
|
* @field visible Visibility.
|
|
|
|
* @field opacity The opacity of the drawin, between 0 and 1.
|
|
|
|
* @field type The window type (desktop, normal, dock, …).
|
|
|
|
* @field x The x coordinates.
|
|
|
|
* @field y The y coordinates.
|
|
|
|
* @field width The width of the drawin.
|
|
|
|
* @field height The height of the drawin.
|
|
|
|
* @field drawable The drawin's drawable.
|
|
|
|
* @field window The X window id.
|
|
|
|
* @field shape_bounding The drawin's bounding shape as a (native) cairo surface.
|
|
|
|
* @field shape_clip The drawin's clip shape as a (native) cairo surface.
|
|
|
|
* @table drawin
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** Get or set mouse buttons bindings to a drawin.
|
|
|
|
*
|
|
|
|
* @param buttons_table A table of buttons objects, or nothing.
|
|
|
|
* @function buttons
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** Get or set drawin struts.
|
|
|
|
*
|
|
|
|
* @param strut A table with new strut, or nothing
|
|
|
|
* @return The drawin strut in a table.
|
|
|
|
* @function struts
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** Get the number of instances.
|
|
|
|
*
|
|
|
|
* @return The number of drawin objects alive.
|
|
|
|
* @function instances
|
|
|
|
*/
|
|
|
|
|
2015-03-14 10:06:53 +01:00
|
|
|
/** Set a __index metamethod for all drawin instances.
|
|
|
|
* @tparam function cb The meta-method
|
|
|
|
* @function set_index_miss_handler
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** Set a __newindex metamethod for all drawin instances.
|
|
|
|
* @tparam function cb The meta-method
|
|
|
|
* @function set_newindex_miss_handler
|
|
|
|
*/
|
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
LUA_OBJECT_FUNCS(drawin_class, drawin_t, drawin)
|
|
|
|
|
|
|
|
/** Kick out systray windows.
|
|
|
|
*/
|
|
|
|
static void
|
2010-10-06 15:38:44 +02:00
|
|
|
drawin_systray_kickout(drawin_t *w)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2010-10-06 15:38:44 +02:00
|
|
|
if(globalconf.systray.parent == w)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
|
|
|
/* Who! Check that we're not deleting a drawin with a systray, because it
|
|
|
|
* may be its parent. If so, we reparent to root before, otherwise it will
|
|
|
|
* hurt very much. */
|
2010-10-06 15:38:44 +02:00
|
|
|
systray_cleanup();
|
2010-10-06 13:35:14 +02:00
|
|
|
xcb_reparent_window(globalconf.connection,
|
|
|
|
globalconf.systray.window,
|
2010-10-06 15:38:44 +02:00
|
|
|
globalconf.screen->root,
|
|
|
|
-512, -512);
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2010-10-06 15:38:44 +02:00
|
|
|
globalconf.systray.parent = NULL;
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-03-09 15:55:20 +01:00
|
|
|
drawin_wipe(drawin_t *w)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2011-03-27 16:21:49 +02:00
|
|
|
/* The drawin must already be unmapped, else it
|
|
|
|
* couldn't be garbage collected -> no unmap needed */
|
2011-03-09 15:55:20 +01:00
|
|
|
p_delete(&w->cursor);
|
2010-10-06 13:35:14 +02:00
|
|
|
if(w->window)
|
|
|
|
{
|
|
|
|
/* Make sure we don't accidentally kill the systray window */
|
2010-10-06 15:38:44 +02:00
|
|
|
drawin_systray_kickout(w);
|
2010-10-06 13:35:14 +02:00
|
|
|
xcb_destroy_window(globalconf.connection, w->window);
|
|
|
|
w->window = XCB_NONE;
|
|
|
|
}
|
2014-03-16 17:08:36 +01:00
|
|
|
/* No unref needed because we are being garbage collected */
|
2012-10-14 17:14:22 +02:00
|
|
|
w->drawable = NULL;
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_update_drawing(lua_State *L, int widx)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_t *w = luaA_checkudata(L, widx, &drawin_class);
|
|
|
|
luaA_object_push_item(L, widx, w->drawable);
|
|
|
|
drawable_set_geometry(L, -1, w->geometry);
|
|
|
|
lua_pop(L, 1);
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Refresh the window content by copying its pixmap data to its window.
|
|
|
|
* \param w The drawin to refresh.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
drawin_refresh_pixmap(drawin_t *w)
|
|
|
|
{
|
|
|
|
drawin_refresh_pixmap_partial(w, 0, 0, w->geometry.width, w->geometry.height);
|
|
|
|
}
|
|
|
|
|
2015-08-14 14:39:43 +02:00
|
|
|
static void
|
|
|
|
drawin_apply_moveresize(drawin_t *w)
|
|
|
|
{
|
|
|
|
if (!w->geometry_dirty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
w->geometry_dirty = false;
|
|
|
|
client_ignore_enterleave_events();
|
|
|
|
xcb_configure_window(globalconf.connection, w->window,
|
|
|
|
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
|
|
|
|
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
|
|
|
(const uint32_t [])
|
|
|
|
{
|
|
|
|
w->geometry.x,
|
|
|
|
w->geometry.y,
|
|
|
|
w->geometry.width,
|
|
|
|
w->geometry.height
|
|
|
|
});
|
|
|
|
client_restore_enterleave_events();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
drawin_refresh(void)
|
|
|
|
{
|
|
|
|
foreach(item, globalconf.drawins)
|
2016-02-28 16:24:30 +01:00
|
|
|
{
|
2015-08-14 14:39:43 +02:00
|
|
|
drawin_apply_moveresize(*item);
|
2016-02-28 16:24:30 +01:00
|
|
|
window_border_refresh((window_t *) *item);
|
|
|
|
}
|
2015-08-14 14:39:43 +02:00
|
|
|
}
|
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
/** Move and/or resize a drawin
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param udx The index of the drawin.
|
|
|
|
* \param geometry The new geometry.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
drawin_moveresize(lua_State *L, int udx, area_t geometry)
|
|
|
|
{
|
|
|
|
drawin_t *w = luaA_checkudata(L, udx, &drawin_class);
|
2015-08-14 14:39:43 +02:00
|
|
|
area_t old_geometry = w->geometry;
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2015-08-14 14:39:43 +02:00
|
|
|
w->geometry = geometry;
|
|
|
|
if(w->geometry.width <= 0)
|
|
|
|
w->geometry.width = old_geometry.width;
|
|
|
|
if(w->geometry.height <= 0)
|
|
|
|
w->geometry.height = old_geometry.height;
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2015-08-14 14:39:43 +02:00
|
|
|
w->geometry_dirty = true;
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_update_drawing(L, udx);
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2015-10-14 19:40:18 +02:00
|
|
|
if (!AREA_EQUAL(old_geometry, w->geometry))
|
|
|
|
luaA_object_emit_signal(L, udx, "property::geometry", 0);
|
2015-08-14 14:39:43 +02:00
|
|
|
if (old_geometry.x != w->geometry.x)
|
2011-03-09 16:18:29 +01:00
|
|
|
luaA_object_emit_signal(L, udx, "property::x", 0);
|
2015-08-14 14:39:43 +02:00
|
|
|
if (old_geometry.y != w->geometry.y)
|
2011-03-09 16:18:29 +01:00
|
|
|
luaA_object_emit_signal(L, udx, "property::y", 0);
|
2015-08-14 14:39:43 +02:00
|
|
|
if (old_geometry.width != w->geometry.width)
|
2011-03-09 16:18:29 +01:00
|
|
|
luaA_object_emit_signal(L, udx, "property::width", 0);
|
2015-08-14 14:39:43 +02:00
|
|
|
if (old_geometry.height != w->geometry.height)
|
2011-03-09 16:18:29 +01:00
|
|
|
luaA_object_emit_signal(L, udx, "property::height", 0);
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Refresh the window content by copying its pixmap data to its window.
|
|
|
|
* \param drawin The drawin to refresh.
|
|
|
|
* \param x The copy starting point x component.
|
|
|
|
* \param y The copy starting point y component.
|
|
|
|
* \param w The copy width from the x component.
|
|
|
|
* \param h The copy height from the y component.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
drawin_refresh_pixmap_partial(drawin_t *drawin,
|
2010-10-06 13:50:59 +02:00
|
|
|
int16_t x, int16_t y,
|
|
|
|
uint16_t w, uint16_t h)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2014-03-17 16:27:10 +01:00
|
|
|
if (!drawin->drawable || !drawin->drawable->pixmap || !drawin->drawable->refreshed)
|
2012-10-14 17:14:22 +02:00
|
|
|
return;
|
|
|
|
|
2015-08-14 14:39:43 +02:00
|
|
|
/* Make sure it really has the size it should have */
|
|
|
|
drawin_apply_moveresize(drawin);
|
|
|
|
|
2010-10-06 14:15:34 +02:00
|
|
|
/* Make cairo do all pending drawing */
|
2012-10-14 17:14:22 +02:00
|
|
|
cairo_surface_flush(drawin->drawable->surface);
|
2014-03-16 17:08:36 +01:00
|
|
|
xcb_copy_area(globalconf.connection, drawin->drawable->pixmap,
|
2010-10-06 13:35:14 +02:00
|
|
|
drawin->window, globalconf.gc, x, y, x, y,
|
|
|
|
w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_map(lua_State *L, int widx)
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_t *drawin = luaA_checkudata(L, widx, &drawin_class);
|
2010-10-06 13:35:14 +02:00
|
|
|
/* Activate BMA */
|
|
|
|
client_ignore_enterleave_events();
|
2015-08-14 14:39:43 +02:00
|
|
|
/* Apply any pending changes */
|
|
|
|
drawin_apply_moveresize(drawin);
|
2010-10-06 13:35:14 +02:00
|
|
|
/* Map the drawin */
|
|
|
|
xcb_map_window(globalconf.connection, drawin->window);
|
|
|
|
/* Deactivate BMA */
|
|
|
|
client_restore_enterleave_events();
|
|
|
|
/* Stack this drawin correctly */
|
|
|
|
stack_windows();
|
2011-03-28 08:29:30 +02:00
|
|
|
/* Add it to the list of visible drawins */
|
|
|
|
drawin_array_append(&globalconf.drawins, drawin);
|
2014-03-16 09:11:00 +01:00
|
|
|
/* Make sure it has a surface */
|
|
|
|
if(drawin->drawable->surface == NULL)
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_update_drawing(L, widx);
|
2011-03-28 08:29:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drawin_unmap(drawin_t *drawin)
|
|
|
|
{
|
|
|
|
xcb_unmap_window(globalconf.connection, drawin->window);
|
|
|
|
foreach(item, globalconf.drawins)
|
|
|
|
if(*item == drawin)
|
|
|
|
{
|
|
|
|
drawin_array_remove(&globalconf.drawins, item);
|
|
|
|
break;
|
|
|
|
}
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Get a drawin by its window.
|
|
|
|
* \param win The window id.
|
|
|
|
* \return A drawin if found, NULL otherwise.
|
|
|
|
*/
|
|
|
|
drawin_t *
|
|
|
|
drawin_getbywin(xcb_window_t win)
|
|
|
|
{
|
|
|
|
foreach(w, globalconf.drawins)
|
|
|
|
if((*w)->window == win)
|
|
|
|
return *w;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set a drawin visible or not.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param udx The drawin.
|
|
|
|
* \param v The visible value.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
drawin_set_visible(lua_State *L, int udx, bool v)
|
|
|
|
{
|
|
|
|
drawin_t *drawin = luaA_checkudata(L, udx, &drawin_class);
|
|
|
|
if(v != drawin->visible)
|
|
|
|
{
|
|
|
|
drawin->visible = v;
|
|
|
|
|
2011-03-27 16:21:49 +02:00
|
|
|
if(drawin->visible)
|
|
|
|
{
|
2014-12-06 10:46:45 +01:00
|
|
|
drawin_map(L, udx);
|
2011-03-27 16:21:49 +02:00
|
|
|
/* duplicate drawin */
|
|
|
|
lua_pushvalue(L, udx);
|
|
|
|
/* ref it */
|
2014-12-06 10:55:21 +01:00
|
|
|
luaA_object_ref_class(L, -1, &drawin_class);
|
2011-03-27 16:21:49 +02:00
|
|
|
}
|
|
|
|
else
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
2011-03-27 16:21:49 +02:00
|
|
|
/* Active BMA */
|
|
|
|
client_ignore_enterleave_events();
|
|
|
|
/* Unmap window */
|
2011-03-28 08:29:30 +02:00
|
|
|
drawin_unmap(drawin);
|
2011-03-27 16:21:49 +02:00
|
|
|
/* Active BMA */
|
|
|
|
client_restore_enterleave_events();
|
|
|
|
/* unref it */
|
2014-12-06 10:55:21 +01:00
|
|
|
luaA_object_unref(L, drawin);
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
luaA_object_emit_signal(L, udx, "property::visible", 0);
|
2011-05-14 16:54:33 +02:00
|
|
|
if(strut_has_value(&drawin->strut))
|
|
|
|
{
|
2014-03-30 16:37:19 +02:00
|
|
|
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);
|
2011-05-14 16:54:33 +02:00
|
|
|
}
|
2010-10-06 13:35:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-12 19:38:20 +02:00
|
|
|
static drawin_t *
|
|
|
|
drawin_allocator(lua_State *L)
|
|
|
|
{
|
2014-03-16 08:56:55 +01:00
|
|
|
xcb_screen_t *s = globalconf.screen;
|
2011-09-12 19:38:20 +02:00
|
|
|
drawin_t *w = drawin_new(L);
|
|
|
|
|
|
|
|
w->visible = false;
|
|
|
|
|
|
|
|
w->opacity = -1;
|
|
|
|
w->cursor = a_strdup("left_ptr");
|
|
|
|
w->geometry.width = 1;
|
|
|
|
w->geometry.height = 1;
|
2015-08-14 14:39:43 +02:00
|
|
|
w->geometry_dirty = false;
|
2011-09-12 19:38:20 +02:00
|
|
|
w->type = _NET_WM_WINDOW_TYPE_NORMAL;
|
|
|
|
|
2012-10-20 22:51:52 +02:00
|
|
|
drawable_allocator(L, (drawable_refresh_callback *) drawin_refresh_pixmap, w);
|
2012-10-14 17:14:22 +02:00
|
|
|
w->drawable = luaA_object_ref_item(L, -2, -1);
|
|
|
|
|
2014-03-16 08:56:55 +01:00
|
|
|
w->window = xcb_generate_id(globalconf.connection);
|
|
|
|
xcb_create_window(globalconf.connection, globalconf.default_depth, w->window, s->root,
|
|
|
|
w->geometry.x, w->geometry.y,
|
|
|
|
w->geometry.width, w->geometry.height,
|
|
|
|
w->border_width, XCB_COPY_FROM_PARENT, globalconf.visual->visual_id,
|
|
|
|
XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY
|
|
|
|
| XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP
|
|
|
|
| XCB_CW_CURSOR,
|
|
|
|
(const uint32_t [])
|
|
|
|
{
|
|
|
|
w->border_color.pixel,
|
|
|
|
XCB_GRAVITY_NORTH_WEST,
|
|
|
|
1,
|
|
|
|
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
|
|
|
|
| XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW
|
|
|
|
| XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
Select button press/release events on drawins
Some words about X11 event handling: Every X11 client can select input on any
window. For this, inside the X11 server each window has for each client a
bitmask for the kind of events that this client is interested in. When a mouse
button is pressed inside of a window, a corresponding event is generated for
that window and sent to all X11 clients which asked for
XCB_EVENT_MASK_BUTTON_PRESS. When no client is interested in this event, the
event is propagated to the parent window and the same procedure is done again
here. This continues up until the root window is reached.
Some words about the event masks that awesome uses: For clients, we ask for
button press events on the frame window that we reparent the client window into
so that we get any kind of press on the titlebar (and also events inside of the
client window if the client itself doesn't care for click events?). We are also
interested in button presses / releases on the root window. However, before this
commit, we didn't actually ask for button events on drawins (e.g. the wibox).
This worked fine, because no one asked for these events and the event propagated
to the root window where it was then sent to awesome.
However, newer Qt versions do something weird and the above broke. I don't
actually know what is going on. I know about the above propagation rules, but
looking at protocol traces of what Qt does, awesome should still get the button
events. During startup, Qt asks for button events on its own windows. After a
hotplug event, it asks the same again, but now also includes the root window.
So... how can Qt asking for button events on the root window cause awesome not
to get them? I have no idea.
(And yes, I guess that Qt asking for mouse events on the root window is a bug,
but I have no idea how exactly this happens nor about any other side effects of
it).
This commit makes us ask for button events on our drawins so that the server
will send them to us. This is the right thing to do anyway and it was reported
to have some positive effects.
Ref: https://github.com/awesomeWM/awesome/issues/415
Signed-off-by: Uli Schlachter <psychon@znc.in>
2015-12-13 17:54:37 +01:00
|
|
|
| XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS
|
|
|
|
| XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE
|
2014-03-16 08:56:55 +01:00
|
|
|
| XCB_EVENT_MASK_PROPERTY_CHANGE,
|
|
|
|
globalconf.default_cmap,
|
|
|
|
xcursor_new(globalconf.cursor_ctx, xcursor_font_fromstr(w->cursor))
|
|
|
|
});
|
2015-11-07 11:48:10 +01:00
|
|
|
xwindow_set_class_instance(w->window);
|
|
|
|
xwindow_set_name_static(w->window, "Awesome drawin");
|
2014-03-16 08:56:55 +01:00
|
|
|
|
|
|
|
/* Set the right properties */
|
|
|
|
ewmh_update_window_type(w->window, window_translate_type(w->type));
|
|
|
|
ewmh_update_strut(w->window, &w->strut);
|
2011-09-12 19:38:20 +02:00
|
|
|
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
/** Create a new drawin.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_new(lua_State *L)
|
|
|
|
{
|
|
|
|
luaA_class_new(L, &drawin_class);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-27 00:24:23 +01:00
|
|
|
/** Get or set drawin geometry. That's the same as accessing or setting the x,
|
|
|
|
* y, width or height properties of a drawin.
|
|
|
|
*
|
|
|
|
* @param A table with coordinates to modify.
|
|
|
|
* @return A table with drawin coordinates and geometry.
|
|
|
|
* @function geometry
|
2010-10-06 13:35:14 +02:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_geometry(lua_State *L)
|
|
|
|
{
|
|
|
|
drawin_t *drawin = luaA_checkudata(L, 1, &drawin_class);
|
|
|
|
|
|
|
|
if(lua_gettop(L) == 2)
|
|
|
|
{
|
|
|
|
area_t wingeom;
|
|
|
|
|
|
|
|
luaA_checktable(L, 2);
|
2016-03-04 08:41:59 +01:00
|
|
|
wingeom.x = luaA_getopt_number(L, 2, "x", drawin->geometry.x);
|
|
|
|
wingeom.y = luaA_getopt_number(L, 2, "y", drawin->geometry.y);
|
|
|
|
wingeom.width = luaA_getopt_number(L, 2, "width", drawin->geometry.width);
|
|
|
|
wingeom.height = luaA_getopt_number(L, 2, "height", drawin->geometry.height);
|
2010-10-06 13:35:14 +02:00
|
|
|
|
|
|
|
if(wingeom.width > 0 && wingeom.height > 0)
|
|
|
|
drawin_moveresize(L, 1, wingeom);
|
|
|
|
}
|
|
|
|
|
|
|
|
return luaA_pusharea(L, drawin->geometry);
|
|
|
|
}
|
|
|
|
|
2010-12-12 21:14:04 +01:00
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, ontop, lua_pushboolean)
|
|
|
|
LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, cursor, lua_pushstring)
|
|
|
|
LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, visible, lua_pushboolean)
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_x(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-07-16 15:33:20 +02:00
|
|
|
drawin_moveresize(L, -3, (area_t) { .x = luaA_checkinteger(L, -1),
|
2010-10-06 13:50:59 +02:00
|
|
|
.y = drawin->geometry.y,
|
|
|
|
.width = drawin->geometry.width,
|
|
|
|
.height = drawin->geometry.height });
|
2010-10-06 13:35:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_x(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-05-26 07:09:12 +02:00
|
|
|
lua_pushinteger(L, drawin->geometry.x);
|
2010-10-06 13:35:14 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_y(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
|
2015-07-16 15:33:20 +02:00
|
|
|
.y = luaA_checkinteger(L, -1),
|
2010-10-06 13:50:59 +02:00
|
|
|
.width = drawin->geometry.width,
|
|
|
|
.height = drawin->geometry.height });
|
2010-10-06 13:35:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_y(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-05-26 07:09:12 +02:00
|
|
|
lua_pushinteger(L, drawin->geometry.y);
|
2010-10-06 13:35:14 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_width(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-07-16 15:33:20 +02:00
|
|
|
int width = luaA_checkinteger(L, -1);
|
2010-10-06 13:35:14 +02:00
|
|
|
if(width <= 0)
|
|
|
|
luaL_error(L, "invalid width");
|
|
|
|
drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
|
2010-10-06 13:50:59 +02:00
|
|
|
.y = drawin->geometry.y,
|
|
|
|
.width = width,
|
|
|
|
.height = drawin->geometry.height });
|
2010-10-06 13:35:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_width(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-05-26 07:09:12 +02:00
|
|
|
lua_pushinteger(L, drawin->geometry.width);
|
2010-10-06 13:35:14 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_height(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-07-16 15:33:20 +02:00
|
|
|
int height = luaA_checkinteger(L, -1);
|
2010-10-06 13:35:14 +02:00
|
|
|
if(height <= 0)
|
|
|
|
luaL_error(L, "invalid height");
|
|
|
|
drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
|
|
|
|
.y = drawin->geometry.y,
|
|
|
|
.width = drawin->geometry.width,
|
|
|
|
.height = height });
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_height(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
2015-05-26 07:09:12 +02:00
|
|
|
lua_pushinteger(L, drawin->geometry.height);
|
2010-10-06 13:35:14 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set the drawin on top status.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_ontop(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
bool b = luaA_checkboolean(L, -1);
|
|
|
|
if(b != drawin->ontop)
|
|
|
|
{
|
|
|
|
drawin->ontop = b;
|
|
|
|
stack_windows();
|
|
|
|
luaA_object_emit_signal(L, -3, "property::ontop", 0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set the drawin cursor.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_cursor(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
const char *buf = luaL_checkstring(L, -1);
|
|
|
|
if(buf)
|
|
|
|
{
|
|
|
|
uint16_t cursor_font = xcursor_font_fromstr(buf);
|
|
|
|
if(cursor_font)
|
|
|
|
{
|
2013-09-19 16:48:10 +02:00
|
|
|
xcb_cursor_t cursor = xcursor_new(globalconf.cursor_ctx, cursor_font);
|
2010-10-06 13:35:14 +02:00
|
|
|
p_delete(&drawin->cursor);
|
|
|
|
drawin->cursor = a_strdup(buf);
|
|
|
|
xwindow_set_cursor(drawin->window, cursor);
|
|
|
|
luaA_object_emit_signal(L, -3, "property::cursor", 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set the drawin visibility.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_visible(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
drawin_set_visible(L, -3, luaA_checkboolean(L, -1));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-14 17:14:22 +02:00
|
|
|
/** Get a drawin's drawable
|
2010-10-06 14:15:34 +02:00
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
2012-10-14 17:14:22 +02:00
|
|
|
luaA_drawin_get_drawable(lua_State *L, drawin_t *drawin)
|
2010-10-06 14:15:34 +02:00
|
|
|
{
|
2012-10-14 17:14:22 +02:00
|
|
|
luaA_object_push_item(L, -2, drawin->drawable);
|
2012-05-27 19:20:34 +02:00
|
|
|
return 1;
|
2010-10-06 14:15:34 +02:00
|
|
|
}
|
|
|
|
|
2014-01-03 16:51:16 +01:00
|
|
|
/** Get the drawin's bounding shape.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_shape_bounding(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_BOUNDING);
|
|
|
|
if (!surf)
|
|
|
|
return 0;
|
|
|
|
/* lua has to make sure to free the ref or we have a leak */
|
|
|
|
lua_pushlightuserdata(L, surf);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-11-05 17:56:56 +01:00
|
|
|
/** Set the drawin's bounding shape.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_shape_bounding(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surf = NULL;
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
2015-08-14 14:39:43 +02:00
|
|
|
|
|
|
|
/* The drawin might have been resized to a larger size. Apply that. */
|
|
|
|
drawin_apply_moveresize(drawin);
|
|
|
|
|
2014-01-03 16:51:16 +01:00
|
|
|
xwindow_set_shape(drawin->window,
|
|
|
|
drawin->geometry.width + 2*drawin->border_width,
|
|
|
|
drawin->geometry.height + 2*drawin->border_width,
|
2012-11-05 17:56:56 +01:00
|
|
|
XCB_SHAPE_SK_BOUNDING, surf, -drawin->border_width);
|
2014-01-03 16:51:16 +01:00
|
|
|
luaA_object_emit_signal(L, -3, "property::shape_bounding", 0);
|
2012-11-05 17:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-03 16:51:16 +01:00
|
|
|
/** Get the drawin's clip shape.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_get_shape_clip(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_CLIP);
|
|
|
|
if (!surf)
|
|
|
|
return 0;
|
|
|
|
/* lua has to make sure to free the ref or we have a leak */
|
|
|
|
lua_pushlightuserdata(L, surf);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-11-05 17:56:56 +01:00
|
|
|
/** Set the drawin's clip shape.
|
|
|
|
* \param L The Lua VM state.
|
|
|
|
* \param drawin The drawin object.
|
|
|
|
* \return The number of elements pushed on stack.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
luaA_drawin_set_shape_clip(lua_State *L, drawin_t *drawin)
|
|
|
|
{
|
|
|
|
cairo_surface_t *surf = NULL;
|
|
|
|
if(!lua_isnil(L, -1))
|
|
|
|
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
2015-08-14 14:39:43 +02:00
|
|
|
|
|
|
|
/* The drawin might have been resized to a larger size. Apply that. */
|
|
|
|
drawin_apply_moveresize(drawin);
|
|
|
|
|
2012-11-06 20:43:05 +01:00
|
|
|
xwindow_set_shape(drawin->window, drawin->geometry.width, drawin->geometry.height,
|
2012-11-05 17:56:56 +01:00
|
|
|
XCB_SHAPE_SK_CLIP, surf, 0);
|
2014-01-03 16:51:16 +01:00
|
|
|
luaA_object_emit_signal(L, -3, "property::shape_clip", 0);
|
2012-11-05 17:56:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-06 13:35:14 +02:00
|
|
|
void
|
|
|
|
drawin_class_setup(lua_State *L)
|
|
|
|
{
|
2012-06-06 23:07:07 +02:00
|
|
|
static const struct luaL_Reg drawin_methods[] =
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
|
|
|
LUA_CLASS_METHODS(drawin)
|
|
|
|
{ "__call", luaA_drawin_new },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
2012-06-06 23:07:07 +02:00
|
|
|
static const struct luaL_Reg drawin_meta[] =
|
2010-10-06 13:35:14 +02:00
|
|
|
{
|
|
|
|
LUA_OBJECT_META(drawin)
|
|
|
|
LUA_CLASS_META
|
|
|
|
{ "geometry", luaA_drawin_geometry },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
luaA_class_setup(L, &drawin_class, "drawin", &window_class,
|
2011-09-12 19:38:20 +02:00
|
|
|
(lua_class_allocator_t) drawin_allocator,
|
2010-10-06 13:35:14 +02:00
|
|
|
(lua_class_collector_t) drawin_wipe,
|
|
|
|
NULL,
|
|
|
|
luaA_class_index_miss_property, luaA_class_newindex_miss_property,
|
|
|
|
drawin_methods, drawin_meta);
|
2012-10-14 17:14:22 +02:00
|
|
|
luaA_class_add_property(&drawin_class, "drawable",
|
2010-10-06 14:15:34 +02:00
|
|
|
NULL,
|
2012-10-14 17:14:22 +02:00
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_drawable,
|
2010-10-06 14:15:34 +02:00
|
|
|
NULL);
|
2010-10-06 13:35:14 +02:00
|
|
|
luaA_class_add_property(&drawin_class, "visible",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_visible,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_visible,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_visible);
|
|
|
|
luaA_class_add_property(&drawin_class, "ontop",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_ontop,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_ontop,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_ontop);
|
|
|
|
luaA_class_add_property(&drawin_class, "cursor",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_cursor,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_cursor,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_cursor);
|
|
|
|
luaA_class_add_property(&drawin_class, "x",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_x,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_x,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_x);
|
|
|
|
luaA_class_add_property(&drawin_class, "y",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_y,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_y,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_y);
|
|
|
|
luaA_class_add_property(&drawin_class, "width",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_width,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_width,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_width);
|
|
|
|
luaA_class_add_property(&drawin_class, "height",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_height,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_height,
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_height);
|
|
|
|
luaA_class_add_property(&drawin_class, "type",
|
|
|
|
(lua_class_propfunc_t) luaA_window_set_type,
|
|
|
|
(lua_class_propfunc_t) luaA_window_get_type,
|
|
|
|
(lua_class_propfunc_t) luaA_window_set_type);
|
2012-11-05 17:56:56 +01:00
|
|
|
luaA_class_add_property(&drawin_class, "shape_bounding",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding,
|
2014-01-03 16:51:16 +01:00
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_shape_bounding,
|
2012-11-05 17:56:56 +01:00
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding);
|
|
|
|
luaA_class_add_property(&drawin_class, "shape_clip",
|
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_shape_clip,
|
2014-01-03 16:51:16 +01:00
|
|
|
(lua_class_propfunc_t) luaA_drawin_get_shape_clip,
|
2012-11-05 17:56:56 +01:00
|
|
|
(lua_class_propfunc_t) luaA_drawin_set_shape_clip);
|
2010-10-06 13:35:14 +02:00
|
|
|
|
2015-10-14 19:35:23 +02:00
|
|
|
/**
|
|
|
|
* @signal property::geometry
|
|
|
|
*/
|
|
|
|
signal_add(&drawin_class.signals, "property::geometry");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::shape_bounding
|
|
|
|
*/
|
2014-03-23 22:41:49 +01:00
|
|
|
signal_add(&drawin_class.signals, "property::shape_bounding");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::shape_clip
|
|
|
|
*/
|
2014-03-23 22:41:49 +01:00
|
|
|
signal_add(&drawin_class.signals, "property::shape_clip");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::border_width
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::border_width");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::cursor
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::cursor");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::height
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::height");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::ontop
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::ontop");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::visible
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::visible");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::width
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::width");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::x
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::x");
|
2015-02-27 00:24:23 +01:00
|
|
|
/**
|
|
|
|
* @signal property::y
|
|
|
|
*/
|
2010-10-06 13:35:14 +02:00
|
|
|
signal_add(&drawin_class.signals, "property::y");
|
|
|
|
}
|
|
|
|
|
2011-09-11 16:50:01 +02:00
|
|
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|