4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Wayland Terminal theme/decoration drawing helper
31 #include <linux/input.h>
34 #include <wayland-client.h>
36 #include "wlt_theme.h"
37 #include "wlt_toolkit.h"
39 #define LOG_SUBSYSTEM "wlt_theme"
50 LOC_RESIZE_BOTTOM_LEFT,
51 LOC_RESIZE_BOTTOM_RIGHT,
59 struct wlt_window *wnd;
60 struct wlt_widget *widget;
61 struct wlt_shm_buffer buffer;
62 struct wlt_rect alloc;
63 unsigned int control_height;
64 unsigned int frame_width;
65 unsigned int resize_margin;
66 unsigned int button_size;
67 unsigned int button_padding;
68 unsigned int button_margin;
70 unsigned int pointer_x;
71 unsigned int pointer_y;
72 unsigned int pointer_loc;
74 unsigned int pointer_grabbed;
77 static void draw_control(struct wlt_theme *theme)
80 uint32_t *line, backcol;
82 unsigned int b1off, b2off, b3off;
85 if (theme->pointer_loc == LOC_NOWHERE)
86 backcol = (0x60 << 24) | (0xaa << 16) |
89 backcol = (0x20 << 24) | (0xee << 16) |
91 dst = theme->buffer.data;
92 for (i = 0; i < theme->control_height; ++i) {
93 line = (uint32_t*)dst;
94 for (j = 0; j < theme->buffer.width; ++j) {
95 if (i == 0 || i == theme->control_height - 1 ||
96 j == 0 || j == theme->buffer.width - 1)
101 dst += theme->buffer.stride;
105 b1off = theme->buffer.width - theme->button_margin - theme->button_size;
106 b2off = b1off - theme->button_padding - theme->button_size;
107 b3off = b2off - theme->button_padding - theme->button_size;
108 dst = theme->buffer.data + theme->buffer.stride * theme->button_margin;
109 for (i = 0; i < theme->button_size; ++i) {
110 line = (uint32_t*)dst;
111 for (j = 0; j < theme->buffer.width; ++j) {
113 j < b1off + theme->button_size) {
115 i == theme->button_size - 1 ||
117 j == b1off + theme->button_size - 1)
118 line[j] = 0xff << 24;
119 else if (theme->pointer_loc == LOC_CLOSE &&
120 theme->pointer_pressed &&
121 theme->pointer_grabbed == LOC_CLOSE)
122 line[j] = (0xff << 24) | 0x1f1f1f1f;
123 else if (theme->pointer_loc == LOC_CLOSE &&
124 !theme->pointer_pressed)
125 line[j] = 0xffffffff;
127 line[j] = (0xff << 24) | 0x33333333;
128 } else if (j >= b2off &&
129 j < b2off + theme->button_size) {
131 i == theme->button_size - 1 ||
133 j == b2off + theme->button_size - 1)
134 line[j] = 0xff << 24;
135 else if (theme->pointer_loc == LOC_MAXIMIZE &&
136 theme->pointer_pressed &&
137 theme->pointer_grabbed == LOC_MAXIMIZE)
138 line[j] = (0xff << 24) | 0x1f1f1f1f;
139 else if (theme->pointer_loc == LOC_MAXIMIZE &&
140 !theme->pointer_pressed)
141 line[j] = 0xffffffff;
143 line[j] = (0xff << 24) | 0x66666666;
144 } else if (j >= b3off &&
145 j < b3off + theme->button_size) {
147 i == theme->button_size - 1 ||
149 j == b3off + theme->button_size - 1)
150 line[j] = 0xff << 24;
151 else if (theme->pointer_loc == LOC_MINIMIZE &&
152 theme->pointer_pressed &&
153 theme->pointer_grabbed == LOC_MINIMIZE)
154 line[j] = (0xff << 24) | 0x1f1f1f1f;
155 else if (theme->pointer_loc == LOC_MINIMIZE &&
156 !theme->pointer_pressed)
157 line[j] = 0xffffffff;
159 line[j] = (0xff << 24) | 0xaaaaaaaa;
162 dst += theme->buffer.stride;
166 static void draw_frame(struct wlt_theme *theme)
170 unsigned int i, j, height;
173 dst = theme->buffer.data + theme->buffer.stride *
174 theme->control_height;
175 for (i = 0; i < theme->frame_width; ++i) {
176 line = (uint32_t*)dst;
177 for (j = 0; j < theme->buffer.width; ++j)
178 line[j] = 0xa0 << 24;
179 dst += theme->buffer.stride;
183 dst = theme->buffer.data + theme->buffer.stride *
184 (theme->buffer.height - theme->frame_width);
185 for (i = 0; i < theme->frame_width; ++i) {
186 line = (uint32_t*)dst;
187 for (j = 0; j < theme->buffer.width; ++j)
188 line[j] = 0xa0 << 24;
189 dst += theme->buffer.stride;
193 dst = theme->buffer.data + theme->buffer.stride *
194 (theme->control_height + theme->frame_width);
195 height = theme->buffer.height - theme->control_height -
196 theme->frame_width * 2;
197 for (i = 0; i < height; ++i) {
198 line = (uint32_t*)dst;
199 for (j = 0; j < theme->frame_width; ++j)
200 line[j] = 0xa0 << 24;
201 dst += theme->buffer.stride;
205 dst = theme->buffer.data + theme->buffer.stride *
206 (theme->control_height + theme->frame_width);
207 height = theme->buffer.height - theme->control_height -
208 theme->frame_width * 2;
209 for (i = 0; i < height; ++i) {
210 line = (uint32_t*)dst;
211 line += theme->buffer.width - theme->frame_width;
212 for (j = 0; j < theme->frame_width; ++j)
213 line[j] = 0xa0 << 24;
214 dst += theme->buffer.stride;
218 static void widget_draw_fallback(struct wlt_theme *theme)
224 dst = theme->buffer.data;
225 for (i = 0; i < theme->buffer.height; ++i) {
226 line = (uint32_t*)dst;
227 for (j = 0; j < theme->buffer.width; ++j) {
228 line[j] = 0xff << 24;
230 dst += theme->buffer.stride;
234 static void widget_redraw(struct wlt_widget *widget, void *data)
236 struct wlt_theme *theme = data;
237 unsigned int width, height;
239 width = theme->buffer.width;
240 height = theme->buffer.height;
242 width < 2 * theme->frame_width) {
243 widget_draw_fallback(theme);
244 } else if (height < theme->control_height + 2 * theme->frame_width) {
245 widget_draw_fallback(theme);
252 static void widget_prepare_resize(struct wlt_widget *widget,
253 unsigned int *width, unsigned int *height,
256 struct wlt_theme *theme = data;
257 unsigned int minw, minh;
259 minw = theme->frame_width * 2;
260 minh = theme->control_height + theme->frame_width * 2;
267 static void widget_resize(struct wlt_widget *widget, struct wlt_rect *alloc,
270 struct wlt_theme *theme = data;
271 unsigned int nwidth, nheight;
273 wlt_window_get_buffer(theme->wnd, alloc, &theme->buffer);
274 memcpy(&theme->alloc, alloc, sizeof(*alloc));
276 alloc->x = theme->frame_width;
277 alloc->y = theme->control_height + theme->frame_width;
278 nwidth = alloc->width - 2 * theme->frame_width;
279 nheight = alloc->height;
280 nheight -= (theme->control_height + 2 * theme->frame_width);
282 if (nwidth > alloc->width || nheight > alloc->height) {
286 alloc->width = nwidth;
287 alloc->height = nheight;
291 static unsigned int get_pointer_location(struct wlt_theme *theme)
293 unsigned int m = theme->resize_margin;
294 unsigned int b1off, b2off, b3off;
296 if (theme->pointer_y < m) {
297 if (theme->pointer_x < m)
298 return LOC_RESIZE_TOP_LEFT;
299 else if (theme->pointer_x >= theme->buffer.width - m)
300 return LOC_RESIZE_TOP_RIGHT;
302 return LOC_RESIZE_TOP;
305 if (theme->pointer_y >= theme->buffer.height - m) {
306 if (theme->pointer_x < m)
307 return LOC_RESIZE_BOTTOM_LEFT;
308 else if (theme->pointer_x >= theme->buffer.width - m)
309 return LOC_RESIZE_BOTTOM_RIGHT;
311 return LOC_RESIZE_BOTTOM;
314 if (theme->pointer_x < m)
315 return LOC_RESIZE_LEFT;
317 if (theme->pointer_x >= theme->buffer.width - m)
318 return LOC_RESIZE_RIGHT;
320 if (theme->pointer_y < theme->control_height) {
321 b1off = theme->buffer.width - theme->button_margin -
323 b2off = b1off - theme->button_padding - theme->button_size;
324 b3off = b2off - theme->button_padding - theme->button_size;
326 if (theme->pointer_y >= theme->button_margin &&
327 theme->pointer_y < theme->control_height -
328 theme->button_margin) {
329 if (theme->pointer_x >= b1off &&
330 theme->pointer_x < b1off + theme->button_size)
332 if (theme->pointer_x >= b2off &&
333 theme->pointer_x < b2off + theme->button_size)
335 if (theme->pointer_x >= b3off &&
336 theme->pointer_x < b3off + theme->button_size)
343 return LOC_SOMEWHERE;
346 static void set_pointer_location(struct wlt_theme *theme, unsigned int loc)
348 if (theme->pointer_loc == loc)
351 theme->pointer_loc = loc;
352 if (loc == LOC_NOWHERE) {
353 theme->pointer_x = -1;
354 theme->pointer_y = -1;
357 wlt_window_schedule_redraw(theme->wnd);
360 static void widget_pointer_motion(struct wlt_widget *widget,
361 unsigned int x, unsigned int y, void *data)
363 struct wlt_theme *theme = data;
365 if (!wlt_rect_contains(&theme->alloc, x, y)) {
366 set_pointer_location(theme, LOC_NOWHERE);
369 theme->pointer_x = x + theme->alloc.x;
370 theme->pointer_y = y + theme->alloc.y;
371 set_pointer_location(theme, get_pointer_location(theme));
374 switch (theme->pointer_loc) {
375 case LOC_RESIZE_LEFT:
376 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_LEFT);
378 case LOC_RESIZE_RIGHT:
379 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_RIGHT);
382 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_TOP);
384 case LOC_RESIZE_BOTTOM:
385 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_BOTTOM);
387 case LOC_RESIZE_TOP_LEFT:
388 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_TOP_LEFT);
390 case LOC_RESIZE_TOP_RIGHT:
391 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_TOP_RIGHT);
393 case LOC_RESIZE_BOTTOM_LEFT:
394 wlt_window_set_cursor(theme->wnd,
395 WLT_CURSOR_BOTTOM_LEFT);
397 case LOC_RESIZE_BOTTOM_RIGHT:
398 wlt_window_set_cursor(theme->wnd,
399 WLT_CURSOR_BOTTOM_RIGHT);
402 wlt_window_set_cursor(theme->wnd, WLT_CURSOR_LEFT_PTR);
406 static void widget_pointer_enter(struct wlt_widget *widget,
407 unsigned int x, unsigned int y, void *data)
409 struct wlt_theme *theme = data;
411 widget_pointer_motion(widget, x, y, theme);
414 static void widget_pointer_leave(struct wlt_widget *widget, void *data)
416 struct wlt_theme *theme = data;
418 if (theme->pointer_pressed) {
419 theme->pointer_pressed = false;
420 wlt_window_schedule_redraw(theme->wnd);
423 set_pointer_location(theme, LOC_NOWHERE);
426 static void button_action(struct wlt_theme *theme)
428 if (theme->pointer_grabbed != theme->pointer_loc)
431 switch (theme->pointer_loc) {
433 wlt_window_close(theme->wnd);
442 static void widget_pointer_button(struct wlt_widget *widget,
443 uint32_t button, uint32_t state, void *data)
445 struct wlt_theme *theme = data;
447 if (button != BTN_LEFT)
450 if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
451 if (theme->pointer_pressed) {
452 button_action(theme);
453 theme->pointer_pressed = false;
454 theme->pointer_grabbed = LOC_NOWHERE;
455 wlt_window_schedule_redraw(theme->wnd);
460 if (!theme->pointer_pressed) {
461 theme->pointer_pressed = true;
462 theme->pointer_grabbed = theme->pointer_loc;
463 wlt_window_schedule_redraw(theme->wnd);
466 switch (theme->pointer_loc) {
467 case LOC_RESIZE_LEFT:
468 wlt_window_resize(theme->wnd, WL_SHELL_SURFACE_RESIZE_LEFT);
470 case LOC_RESIZE_RIGHT:
471 wlt_window_resize(theme->wnd, WL_SHELL_SURFACE_RESIZE_RIGHT);
474 wlt_window_resize(theme->wnd,
475 WL_SHELL_SURFACE_RESIZE_TOP);
477 case LOC_RESIZE_BOTTOM:
478 wlt_window_resize(theme->wnd,
479 WL_SHELL_SURFACE_RESIZE_BOTTOM);
481 case LOC_RESIZE_TOP_LEFT:
482 wlt_window_resize(theme->wnd,
483 WL_SHELL_SURFACE_RESIZE_TOP_LEFT);
485 case LOC_RESIZE_TOP_RIGHT:
486 wlt_window_resize(theme->wnd,
487 WL_SHELL_SURFACE_RESIZE_TOP_RIGHT);
489 case LOC_RESIZE_BOTTOM_LEFT:
490 wlt_window_resize(theme->wnd,
491 WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT);
493 case LOC_RESIZE_BOTTOM_RIGHT:
494 wlt_window_resize(theme->wnd,
495 WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT);
498 wlt_window_move(theme->wnd);
503 static void widget_destroy(struct wlt_widget *widget, void *data)
505 struct wlt_theme *theme = data;
507 log_debug("destroy theme");
512 int wlt_theme_new(struct wlt_theme **out, struct wlt_window *wnd)
514 struct wlt_theme *theme;
520 log_debug("create new theme");
522 theme = malloc(sizeof(*theme));
525 memset(theme, 0, sizeof(*theme));
527 theme->control_height = 25;
528 theme->frame_width = 5;
529 theme->resize_margin = 5;
530 theme->button_size = 15;
531 theme->button_padding = 3;
532 theme->button_margin = 5;
533 theme->pointer_grabbed = LOC_NOWHERE;
534 set_pointer_location(theme, LOC_NOWHERE);
536 ret = wlt_window_create_widget(wnd, &theme->widget, theme);
538 log_error("cannot create widget");
542 wlt_widget_set_destroy_cb(theme->widget, widget_destroy);
543 wlt_widget_set_redraw_cb(theme->widget, widget_redraw);
544 wlt_widget_set_resize_cb(theme->widget, widget_prepare_resize,
546 wlt_widget_set_pointer_cb(theme->widget, widget_pointer_enter,
547 widget_pointer_leave, widget_pointer_motion,
548 widget_pointer_button);
557 void wlt_theme_destroy(struct wlt_theme *theme)
562 wlt_widget_destroy(theme->widget);