1 /*
2 * drawin.c - drawin functions
3 *
4 * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
5 * Copyright © 2010 Uli Schlachter <psychon@znc.in>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23 /** awesome drawin API
24 *
25 * Furthermore to the classes described here, one can also use signals as
26 * described in @{signals} and X properties as described in @{xproperties}.
27 *
28 * @author Julien Danjou <julien@danjou.info>
29 * @copyright 2008-2009 Julien Danjou
30 * @classmod drawin
31 */
32
33 #include "drawin.h"
34 #include "common/atoms.h"
35 #include "common/xcursor.h"
36 #include "common/xutil.h"
37 #include "event.h"
38 #include "ewmh.h"
39 #include "objects/client.h"
40 #include "objects/screen.h"
41 #include "systray.h"
42 #include "xwindow.h"
43
44 #include "math.h"
45
46 #include <cairo-xcb.h>
47 #include <xcb/shape.h>
48
49 lua_class_t drawin_class;
50
51 /** Drawin object.
52 *
53 * @field border_width Border width.
54 * @field border_color Border color.
55 * @field ontop On top of other windows.
56 * @field cursor The mouse cursor.
57 * @field visible Visibility.
58 * @field opacity The opacity of the drawin, between 0 and 1.
59 * @field type The window type (desktop, normal, dock, …).
60 * @field x The x coordinates.
61 * @field y The y coordinates.
62 * @field width The width of the drawin.
63 * @field height The height of the drawin.
64 * @field drawable The drawin's drawable.
65 * @field window The X window id.
66 * @field shape_bounding The drawin's bounding shape as a (native) cairo surface.
67 * @field shape_clip The drawin's clip shape as a (native) cairo surface.
68 * @field shape_input The drawin's input shape as a (native) cairo surface.
69 * @table drawin
70 */
71
72 /**
73 * @signal property::geometry
74 */
75
76 /**
77 * @signal property::shape_bounding
78 */
79
80 /**
81 * @signal property::shape_clip
82 */
83
84 /**
85 * @signal property::shape_input
86 */
87
88 /**
89 * @signal property::border_width
90 */
91
92 /**
93 * @signal property::cursor
94 */
95
96 /**
97 * @signal property::height
98 */
99
100 /**
101 * @signal property::ontop
102 */
103
104 /**
105 * @signal property::visible
106 */
107
108 /**
109 * @signal property::width
110 */
111
112 /**
113 * @signal property::x
114 */
115
116 /**
117 * @signal property::y
118 */
119
120 /** Get or set mouse buttons bindings to a drawin.
121 *
122 * @param buttons_table A table of buttons objects, or nothing.
123 * @function buttons
124 */
125
126 /** Get or set drawin struts.
127 *
128 * @param strut A table with new strut, or nothing
129 * @return The drawin strut in a table.
130 * @function struts
131 */
132
133 /** Get the number of instances.
134 *
135 * @return The number of drawin objects alive.
136 * @function instances
137 */
138
139 /** Set a __index metamethod for all drawin instances.
140 * @tparam function cb The meta-method
141 * @function set_index_miss_handler
142 */
143
144 /** Set a __newindex metamethod for all drawin instances.
145 * @tparam function cb The meta-method
146 * @function set_newindex_miss_handler
147 */
148
LUA_OBJECT_FUNCS(drawin_class,drawin_t,drawin)149 LUA_OBJECT_FUNCS(drawin_class, drawin_t, drawin)
150
151 /** Kick out systray windows.
152 */
153 static void
154 drawin_systray_kickout(drawin_t *w)
155 {
156 if(globalconf.systray.parent == w)
157 {
158 /* Who! Check that we're not deleting a drawin with a systray, because it
159 * may be its parent. If so, we reparent to root before, otherwise it will
160 * hurt very much. */
161 xcb_reparent_window(globalconf.connection,
162 globalconf.systray.window,
163 globalconf.screen->root,
164 -512, -512);
165
166 globalconf.systray.parent = NULL;
167 }
168 }
169
170 void
luaA_drawin_systray_kickout(lua_State * L)171 luaA_drawin_systray_kickout(lua_State *L)
172 {
173 drawin_systray_kickout(luaA_checkudata(L, 1, &drawin_class));
174 }
175
176 static void
drawin_wipe(drawin_t * w)177 drawin_wipe(drawin_t *w)
178 {
179 /* The drawin must already be unmapped, else it
180 * couldn't be garbage collected -> no unmap needed */
181 p_delete(&w->cursor);
182 if(w->window)
183 {
184 /* Make sure we don't accidentally kill the systray window */
185 drawin_systray_kickout(w);
186 xcb_destroy_window(globalconf.connection, w->window);
187 w->window = XCB_NONE;
188 }
189 /* No unref needed because we are being garbage collected */
190 w->drawable = NULL;
191 }
192
193 static void
drawin_update_drawing(lua_State * L,int widx)194 drawin_update_drawing(lua_State *L, int widx)
195 {
196 drawin_t *w = luaA_checkudata(L, widx, &drawin_class);
197 luaA_object_push_item(L, widx, w->drawable);
198 drawable_set_geometry(L, -1, w->geometry);
199 lua_pop(L, 1);
200 }
201
202 /** Refresh the window content by copying its pixmap data to its window.
203 * \param w The drawin to refresh.
204 */
205 static inline void
drawin_refresh_pixmap(drawin_t * w)206 drawin_refresh_pixmap(drawin_t *w)
207 {
208 drawin_refresh_pixmap_partial(w, 0, 0, w->geometry.width, w->geometry.height);
209 }
210
211 static void
drawin_apply_moveresize(drawin_t * w)212 drawin_apply_moveresize(drawin_t *w)
213 {
214 if (!w->geometry_dirty)
215 return;
216
217 w->geometry_dirty = false;
218 client_ignore_enterleave_events();
219 xcb_configure_window(globalconf.connection, w->window,
220 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
221 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
222 (const uint32_t [])
223 {
224 w->geometry.x,
225 w->geometry.y,
226 w->geometry.width,
227 w->geometry.height
228 });
229 client_restore_enterleave_events();
230 }
231
232 void
drawin_refresh(void)233 drawin_refresh(void)
234 {
235 foreach(item, globalconf.drawins)
236 {
237 drawin_apply_moveresize(*item);
238 window_border_refresh((window_t *) *item);
239 }
240 }
241
242 /** Get all drawins into a table.
243 * @treturn table A table with drawins.
244 * @function get
245 */
246 static int
luaA_drawin_get(lua_State * L)247 luaA_drawin_get(lua_State *L)
248 {
249 int i = 1;
250
251 lua_newtable(L);
252
253 foreach(d, globalconf.drawins) {
254 luaA_object_push(L, *d);
255 lua_rawseti(L, -2, i++);
256 }
257
258 return 1;
259 }
260
261 /** Move and/or resize a drawin
262 * \param L The Lua VM state.
263 * \param udx The index of the drawin.
264 * \param geometry The new geometry.
265 */
266 static void
drawin_moveresize(lua_State * L,int udx,area_t geometry)267 drawin_moveresize(lua_State *L, int udx, area_t geometry)
268 {
269 drawin_t *w = luaA_checkudata(L, udx, &drawin_class);
270 area_t old_geometry = w->geometry;
271
272 w->geometry = geometry;
273 if(w->geometry.width <= 0)
274 w->geometry.width = old_geometry.width;
275 if(w->geometry.height <= 0)
276 w->geometry.height = old_geometry.height;
277
278 w->geometry_dirty = true;
279 drawin_update_drawing(L, udx);
280
281 if (!AREA_EQUAL(old_geometry, w->geometry))
282 luaA_object_emit_signal(L, udx, "property::geometry", 0);
283 if (old_geometry.x != w->geometry.x)
284 luaA_object_emit_signal(L, udx, "property::x", 0);
285 if (old_geometry.y != w->geometry.y)
286 luaA_object_emit_signal(L, udx, "property::y", 0);
287 if (old_geometry.width != w->geometry.width)
288 luaA_object_emit_signal(L, udx, "property::width", 0);
289 if (old_geometry.height != w->geometry.height)
290 luaA_object_emit_signal(L, udx, "property::height", 0);
291
292 screen_t *old_screen = screen_getbycoord(old_geometry.x, old_geometry.y);
293 screen_t *new_screen = screen_getbycoord(w->geometry.x, w->geometry.y);
294 if (old_screen != new_screen && strut_has_value(&w->strut))
295 {
296 screen_update_workarea(old_screen);
297 screen_update_workarea(new_screen);
298 }
299 }
300
301 /** Refresh the window content by copying its pixmap data to its window.
302 * \param drawin The drawin to refresh.
303 * \param x The copy starting point x component.
304 * \param y The copy starting point y component.
305 * \param w The copy width from the x component.
306 * \param h The copy height from the y component.
307 */
308 void
drawin_refresh_pixmap_partial(drawin_t * drawin,int16_t x,int16_t y,uint16_t w,uint16_t h)309 drawin_refresh_pixmap_partial(drawin_t *drawin,
310 int16_t x, int16_t y,
311 uint16_t w, uint16_t h)
312 {
313 if (!drawin->drawable || !drawin->drawable->pixmap || !drawin->drawable->refreshed)
314 return;
315
316 /* Make sure it really has the size it should have */
317 drawin_apply_moveresize(drawin);
318
319 /* Make cairo do all pending drawing */
320 cairo_surface_flush(drawin->drawable->surface);
321 xcb_copy_area(globalconf.connection, drawin->drawable->pixmap,
322 drawin->window, globalconf.gc, x, y, x, y,
323 w, h);
324 }
325
326 static void
drawin_map(lua_State * L,int widx)327 drawin_map(lua_State *L, int widx)
328 {
329 drawin_t *drawin = luaA_checkudata(L, widx, &drawin_class);
330 /* Apply any pending changes */
331 drawin_apply_moveresize(drawin);
332 /* Activate BMA */
333 client_ignore_enterleave_events();
334 /* Map the drawin */
335 xcb_map_window(globalconf.connection, drawin->window);
336 /* Deactivate BMA */
337 client_restore_enterleave_events();
338 /* Stack this drawin correctly */
339 stack_windows();
340 /* Add it to the list of visible drawins */
341 drawin_array_append(&globalconf.drawins, drawin);
342 /* Make sure it has a surface */
343 if(drawin->drawable->surface == NULL)
344 drawin_update_drawing(L, widx);
345 }
346
347 static void
drawin_unmap(drawin_t * drawin)348 drawin_unmap(drawin_t *drawin)
349 {
350 xcb_unmap_window(globalconf.connection, drawin->window);
351 foreach(item, globalconf.drawins)
352 if(*item == drawin)
353 {
354 drawin_array_remove(&globalconf.drawins, item);
355 break;
356 }
357 }
358
359 /** Get a drawin by its window.
360 * \param win The window id.
361 * \return A drawin if found, NULL otherwise.
362 */
363 drawin_t *
drawin_getbywin(xcb_window_t win)364 drawin_getbywin(xcb_window_t win)
365 {
366 foreach(w, globalconf.drawins)
367 if((*w)->window == win)
368 return *w;
369 return NULL;
370 }
371
372 /** Set a drawin visible or not.
373 * \param L The Lua VM state.
374 * \param udx The drawin.
375 * \param v The visible value.
376 */
377 static void
drawin_set_visible(lua_State * L,int udx,bool v)378 drawin_set_visible(lua_State *L, int udx, bool v)
379 {
380 drawin_t *drawin = luaA_checkudata(L, udx, &drawin_class);
381 if(v != drawin->visible)
382 {
383 drawin->visible = v;
384
385 if(drawin->visible)
386 {
387 drawin_map(L, udx);
388 /* duplicate drawin */
389 lua_pushvalue(L, udx);
390 /* ref it */
391 luaA_object_ref_class(L, -1, &drawin_class);
392 }
393 else
394 {
395 /* Active BMA */
396 client_ignore_enterleave_events();
397 /* Unmap window */
398 drawin_unmap(drawin);
399 /* Active BMA */
400 client_restore_enterleave_events();
401 /* unref it */
402 luaA_object_unref(L, drawin);
403 }
404
405 luaA_object_emit_signal(L, udx, "property::visible", 0);
406 if(strut_has_value(&drawin->strut))
407 {
408 screen_update_workarea(
409 screen_getbycoord(drawin->geometry.x, drawin->geometry.y));
410 }
411 }
412 }
413
414 static drawin_t *
drawin_allocator(lua_State * L)415 drawin_allocator(lua_State *L)
416 {
417 xcb_screen_t *s = globalconf.screen;
418 drawin_t *w = drawin_new(L);
419
420 w->visible = false;
421
422 w->opacity = -1;
423 w->cursor = a_strdup("left_ptr");
424 w->geometry.width = 1;
425 w->geometry.height = 1;
426 w->geometry_dirty = false;
427 w->type = _NET_WM_WINDOW_TYPE_NORMAL;
428
429 drawable_allocator(L, (drawable_refresh_callback *) drawin_refresh_pixmap, w);
430 w->drawable = luaA_object_ref_item(L, -2, -1);
431
432 w->window = xcb_generate_id(globalconf.connection);
433 xcb_create_window(globalconf.connection, globalconf.default_depth, w->window, s->root,
434 w->geometry.x, w->geometry.y,
435 w->geometry.width, w->geometry.height,
436 w->border_width, XCB_COPY_FROM_PARENT, globalconf.visual->visual_id,
437 XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY
438 | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP
439 | XCB_CW_CURSOR,
440 (const uint32_t [])
441 {
442 w->border_color.pixel,
443 XCB_GRAVITY_NORTH_WEST,
444 1,
445 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
446 | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW
447 | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY
448 | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS
449 | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE
450 | XCB_EVENT_MASK_PROPERTY_CHANGE,
451 globalconf.default_cmap,
452 xcursor_new(globalconf.cursor_ctx, xcursor_font_fromstr(w->cursor))
453 });
454 xwindow_set_class_instance(w->window);
455 xwindow_set_name_static(w->window, "Awesome drawin");
456
457 /* Set the right properties */
458 ewmh_update_window_type(w->window, window_translate_type(w->type));
459 ewmh_update_strut(w->window, &w->strut);
460
461 return w;
462 }
463
464 /** Create a new drawin.
465 * \param L The Lua VM state.
466 * \return The number of elements pushed on stack.
467 */
468 static int
luaA_drawin_new(lua_State * L)469 luaA_drawin_new(lua_State *L)
470 {
471 luaA_class_new(L, &drawin_class);
472
473 return 1;
474 }
475
476 /** Get or set drawin geometry. That's the same as accessing or setting the x,
477 * y, width or height properties of a drawin.
478 *
479 * @param A table with coordinates to modify.
480 * @return A table with drawin coordinates and geometry.
481 * @function geometry
482 */
483 static int
luaA_drawin_geometry(lua_State * L)484 luaA_drawin_geometry(lua_State *L)
485 {
486 drawin_t *drawin = luaA_checkudata(L, 1, &drawin_class);
487
488 if(lua_gettop(L) == 2)
489 {
490 area_t wingeom;
491
492 luaA_checktable(L, 2);
493 wingeom.x = round(luaA_getopt_number_range(L, 2, "x", drawin->geometry.x, MIN_X11_COORDINATE, MAX_X11_COORDINATE));
494 wingeom.y = round(luaA_getopt_number_range(L, 2, "y", drawin->geometry.y, MIN_X11_COORDINATE, MAX_X11_COORDINATE));
495 wingeom.width = ceil(luaA_getopt_number_range(L, 2, "width", drawin->geometry.width, MIN_X11_SIZE, MAX_X11_SIZE));
496 wingeom.height = ceil(luaA_getopt_number_range(L, 2, "height", drawin->geometry.height, MIN_X11_SIZE, MAX_X11_SIZE));
497
498 if(wingeom.width > 0 && wingeom.height > 0)
499 drawin_moveresize(L, 1, wingeom);
500 }
501
502 return luaA_pusharea(L, drawin->geometry);
503 }
504
505
LUA_OBJECT_EXPORT_PROPERTY(drawin,drawin_t,ontop,lua_pushboolean)506 LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, ontop, lua_pushboolean)
507 LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, cursor, lua_pushstring)
508 LUA_OBJECT_EXPORT_PROPERTY(drawin, drawin_t, visible, lua_pushboolean)
509
510 static int
511 luaA_drawin_set_x(lua_State *L, drawin_t *drawin)
512 {
513 int x = round(luaA_checknumber_range(L, -1, MIN_X11_COORDINATE, MAX_X11_COORDINATE));
514 drawin_moveresize(L, -3, (area_t) { .x = x,
515 .y = drawin->geometry.y,
516 .width = drawin->geometry.width,
517 .height = drawin->geometry.height });
518 return 0;
519 }
520
521 static int
luaA_drawin_get_x(lua_State * L,drawin_t * drawin)522 luaA_drawin_get_x(lua_State *L, drawin_t *drawin)
523 {
524 lua_pushinteger(L, drawin->geometry.x);
525 return 1;
526 }
527
528 static int
luaA_drawin_set_y(lua_State * L,drawin_t * drawin)529 luaA_drawin_set_y(lua_State *L, drawin_t *drawin)
530 {
531 int y = round(luaA_checknumber_range(L, -1, MIN_X11_COORDINATE, MAX_X11_COORDINATE));
532 drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
533 .y = y,
534 .width = drawin->geometry.width,
535 .height = drawin->geometry.height });
536 return 0;
537 }
538
539 static int
luaA_drawin_get_y(lua_State * L,drawin_t * drawin)540 luaA_drawin_get_y(lua_State *L, drawin_t *drawin)
541 {
542 lua_pushinteger(L, drawin->geometry.y);
543 return 1;
544 }
545
546 static int
luaA_drawin_set_width(lua_State * L,drawin_t * drawin)547 luaA_drawin_set_width(lua_State *L, drawin_t *drawin)
548 {
549 int width = ceil(luaA_checknumber_range(L, -1, MIN_X11_SIZE, MAX_X11_SIZE));
550 drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
551 .y = drawin->geometry.y,
552 .width = width,
553 .height = drawin->geometry.height });
554 return 0;
555 }
556
557 static int
luaA_drawin_get_width(lua_State * L,drawin_t * drawin)558 luaA_drawin_get_width(lua_State *L, drawin_t *drawin)
559 {
560 lua_pushinteger(L, drawin->geometry.width);
561 return 1;
562 }
563
564 static int
luaA_drawin_set_height(lua_State * L,drawin_t * drawin)565 luaA_drawin_set_height(lua_State *L, drawin_t *drawin)
566 {
567 int height = ceil(luaA_checknumber_range(L, -1, MIN_X11_SIZE, MAX_X11_SIZE));
568 drawin_moveresize(L, -3, (area_t) { .x = drawin->geometry.x,
569 .y = drawin->geometry.y,
570 .width = drawin->geometry.width,
571 .height = height });
572 return 0;
573 }
574
575 static int
luaA_drawin_get_height(lua_State * L,drawin_t * drawin)576 luaA_drawin_get_height(lua_State *L, drawin_t *drawin)
577 {
578 lua_pushinteger(L, drawin->geometry.height);
579 return 1;
580 }
581
582 /** Set the drawin on top status.
583 * \param L The Lua VM state.
584 * \param drawin The drawin object.
585 * \return The number of elements pushed on stack.
586 */
587 static int
luaA_drawin_set_ontop(lua_State * L,drawin_t * drawin)588 luaA_drawin_set_ontop(lua_State *L, drawin_t *drawin)
589 {
590 bool b = luaA_checkboolean(L, -1);
591 if(b != drawin->ontop)
592 {
593 drawin->ontop = b;
594 stack_windows();
595 luaA_object_emit_signal(L, -3, "property::ontop", 0);
596 }
597 return 0;
598 }
599
600 /** Set the drawin cursor.
601 * \param L The Lua VM state.
602 * \param drawin The drawin object.
603 * \return The number of elements pushed on stack.
604 */
605 static int
luaA_drawin_set_cursor(lua_State * L,drawin_t * drawin)606 luaA_drawin_set_cursor(lua_State *L, drawin_t *drawin)
607 {
608 const char *buf = luaL_checkstring(L, -1);
609 if(buf)
610 {
611 uint16_t cursor_font = xcursor_font_fromstr(buf);
612 if(cursor_font)
613 {
614 xcb_cursor_t cursor = xcursor_new(globalconf.cursor_ctx, cursor_font);
615 p_delete(&drawin->cursor);
616 drawin->cursor = a_strdup(buf);
617 xwindow_set_cursor(drawin->window, cursor);
618 luaA_object_emit_signal(L, -3, "property::cursor", 0);
619 }
620 }
621 return 0;
622 }
623
624 /** Set the drawin visibility.
625 * \param L The Lua VM state.
626 * \param drawin The drawin object.
627 * \return The number of elements pushed on stack.
628 */
629 static int
luaA_drawin_set_visible(lua_State * L,drawin_t * drawin)630 luaA_drawin_set_visible(lua_State *L, drawin_t *drawin)
631 {
632 drawin_set_visible(L, -3, luaA_checkboolean(L, -1));
633 return 0;
634 }
635
636 /** Get a drawin's drawable
637 * \param L The Lua VM state.
638 * \param drawin The drawin object.
639 * \return The number of elements pushed on stack.
640 */
641 static int
luaA_drawin_get_drawable(lua_State * L,drawin_t * drawin)642 luaA_drawin_get_drawable(lua_State *L, drawin_t *drawin)
643 {
644 luaA_object_push_item(L, -2, drawin->drawable);
645 return 1;
646 }
647
648 /** Get the drawin's bounding shape.
649 * \param L The Lua VM state.
650 * \param drawin The drawin object.
651 * \return The number of elements pushed on stack.
652 */
653 static int
luaA_drawin_get_shape_bounding(lua_State * L,drawin_t * drawin)654 luaA_drawin_get_shape_bounding(lua_State *L, drawin_t *drawin)
655 {
656 cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_BOUNDING);
657 if (!surf)
658 return 0;
659 /* lua has to make sure to free the ref or we have a leak */
660 lua_pushlightuserdata(L, surf);
661 return 1;
662 }
663
664 /** Set the drawin's bounding shape.
665 * \param L The Lua VM state.
666 * \param drawin The drawin object.
667 * \return The number of elements pushed on stack.
668 */
669 static int
luaA_drawin_set_shape_bounding(lua_State * L,drawin_t * drawin)670 luaA_drawin_set_shape_bounding(lua_State *L, drawin_t *drawin)
671 {
672 cairo_surface_t *surf = NULL;
673 if(!lua_isnil(L, -1))
674 surf = (cairo_surface_t *)lua_touserdata(L, -1);
675
676 /* The drawin might have been resized to a larger size. Apply that. */
677 drawin_apply_moveresize(drawin);
678
679 xwindow_set_shape(drawin->window,
680 drawin->geometry.width + 2*drawin->border_width,
681 drawin->geometry.height + 2*drawin->border_width,
682 XCB_SHAPE_SK_BOUNDING, surf, -drawin->border_width);
683 luaA_object_emit_signal(L, -3, "property::shape_bounding", 0);
684 return 0;
685 }
686
687 /** Get the drawin's clip shape.
688 * \param L The Lua VM state.
689 * \param drawin The drawin object.
690 * \return The number of elements pushed on stack.
691 */
692 static int
luaA_drawin_get_shape_clip(lua_State * L,drawin_t * drawin)693 luaA_drawin_get_shape_clip(lua_State *L, drawin_t *drawin)
694 {
695 cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_CLIP);
696 if (!surf)
697 return 0;
698 /* lua has to make sure to free the ref or we have a leak */
699 lua_pushlightuserdata(L, surf);
700 return 1;
701 }
702
703 /** Set the drawin's clip shape.
704 * \param L The Lua VM state.
705 * \param drawin The drawin object.
706 * \return The number of elements pushed on stack.
707 */
708 static int
luaA_drawin_set_shape_clip(lua_State * L,drawin_t * drawin)709 luaA_drawin_set_shape_clip(lua_State *L, drawin_t *drawin)
710 {
711 cairo_surface_t *surf = NULL;
712 if(!lua_isnil(L, -1))
713 surf = (cairo_surface_t *)lua_touserdata(L, -1);
714
715 /* The drawin might have been resized to a larger size. Apply that. */
716 drawin_apply_moveresize(drawin);
717
718 xwindow_set_shape(drawin->window, drawin->geometry.width, drawin->geometry.height,
719 XCB_SHAPE_SK_CLIP, surf, 0);
720 luaA_object_emit_signal(L, -3, "property::shape_clip", 0);
721 return 0;
722 }
723
724 /** Get the drawin's input shape.
725 * \param L The Lua VM state.
726 * \param drawin The drawin object.
727 * \return The number of elements pushed on stack.
728 */
729 static int
luaA_drawin_get_shape_input(lua_State * L,drawin_t * drawin)730 luaA_drawin_get_shape_input(lua_State *L, drawin_t *drawin)
731 {
732 cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_INPUT);
733 if (!surf)
734 return 0;
735 /* lua has to make sure to free the ref or we have a leak */
736 lua_pushlightuserdata(L, surf);
737 return 1;
738 }
739
740 /** Set the drawin's input shape.
741 * \param L The Lua VM state.
742 * \param drawin The drawin object.
743 * \return The number of elements pushed on stack.
744 */
745 static int
luaA_drawin_set_shape_input(lua_State * L,drawin_t * drawin)746 luaA_drawin_set_shape_input(lua_State *L, drawin_t *drawin)
747 {
748 cairo_surface_t *surf = NULL;
749 if(!lua_isnil(L, -1))
750 surf = (cairo_surface_t *)lua_touserdata(L, -1);
751
752 /* The drawin might have been resized to a larger size. Apply that. */
753 drawin_apply_moveresize(drawin);
754
755 xwindow_set_shape(drawin->window,
756 drawin->geometry.width + 2*drawin->border_width,
757 drawin->geometry.height + 2*drawin->border_width,
758 XCB_SHAPE_SK_INPUT, surf, -drawin->border_width);
759 luaA_object_emit_signal(L, -3, "property::shape_input", 0);
760 return 0;
761 }
762
763 void
drawin_class_setup(lua_State * L)764 drawin_class_setup(lua_State *L)
765 {
766 static const struct luaL_Reg drawin_methods[] =
767 {
768 LUA_CLASS_METHODS(drawin)
769 { "get", luaA_drawin_get },
770 { "__call", luaA_drawin_new },
771 { NULL, NULL }
772 };
773
774 static const struct luaL_Reg drawin_meta[] =
775 {
776 LUA_OBJECT_META(drawin)
777 LUA_CLASS_META
778 { "geometry", luaA_drawin_geometry },
779 { NULL, NULL },
780 };
781
782 luaA_class_setup(L, &drawin_class, "drawin", &window_class,
783 (lua_class_allocator_t) drawin_allocator,
784 (lua_class_collector_t) drawin_wipe,
785 NULL,
786 luaA_class_index_miss_property, luaA_class_newindex_miss_property,
787 drawin_methods, drawin_meta);
788 luaA_class_add_property(&drawin_class, "drawable",
789 NULL,
790 (lua_class_propfunc_t) luaA_drawin_get_drawable,
791 NULL);
792 luaA_class_add_property(&drawin_class, "visible",
793 (lua_class_propfunc_t) luaA_drawin_set_visible,
794 (lua_class_propfunc_t) luaA_drawin_get_visible,
795 (lua_class_propfunc_t) luaA_drawin_set_visible);
796 luaA_class_add_property(&drawin_class, "ontop",
797 (lua_class_propfunc_t) luaA_drawin_set_ontop,
798 (lua_class_propfunc_t) luaA_drawin_get_ontop,
799 (lua_class_propfunc_t) luaA_drawin_set_ontop);
800 luaA_class_add_property(&drawin_class, "cursor",
801 (lua_class_propfunc_t) luaA_drawin_set_cursor,
802 (lua_class_propfunc_t) luaA_drawin_get_cursor,
803 (lua_class_propfunc_t) luaA_drawin_set_cursor);
804 luaA_class_add_property(&drawin_class, "x",
805 (lua_class_propfunc_t) luaA_drawin_set_x,
806 (lua_class_propfunc_t) luaA_drawin_get_x,
807 (lua_class_propfunc_t) luaA_drawin_set_x);
808 luaA_class_add_property(&drawin_class, "y",
809 (lua_class_propfunc_t) luaA_drawin_set_y,
810 (lua_class_propfunc_t) luaA_drawin_get_y,
811 (lua_class_propfunc_t) luaA_drawin_set_y);
812 luaA_class_add_property(&drawin_class, "width",
813 (lua_class_propfunc_t) luaA_drawin_set_width,
814 (lua_class_propfunc_t) luaA_drawin_get_width,
815 (lua_class_propfunc_t) luaA_drawin_set_width);
816 luaA_class_add_property(&drawin_class, "height",
817 (lua_class_propfunc_t) luaA_drawin_set_height,
818 (lua_class_propfunc_t) luaA_drawin_get_height,
819 (lua_class_propfunc_t) luaA_drawin_set_height);
820 luaA_class_add_property(&drawin_class, "type",
821 (lua_class_propfunc_t) luaA_window_set_type,
822 (lua_class_propfunc_t) luaA_window_get_type,
823 (lua_class_propfunc_t) luaA_window_set_type);
824 luaA_class_add_property(&drawin_class, "shape_bounding",
825 (lua_class_propfunc_t) luaA_drawin_set_shape_bounding,
826 (lua_class_propfunc_t) luaA_drawin_get_shape_bounding,
827 (lua_class_propfunc_t) luaA_drawin_set_shape_bounding);
828 luaA_class_add_property(&drawin_class, "shape_clip",
829 (lua_class_propfunc_t) luaA_drawin_set_shape_clip,
830 (lua_class_propfunc_t) luaA_drawin_get_shape_clip,
831 (lua_class_propfunc_t) luaA_drawin_set_shape_clip);
832 luaA_class_add_property(&drawin_class, "shape_input",
833 (lua_class_propfunc_t) luaA_drawin_set_shape_input,
834 (lua_class_propfunc_t) luaA_drawin_get_shape_input,
835 (lua_class_propfunc_t) luaA_drawin_set_shape_input);
836 }
837
838 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
839