blob: 53f3f5f7c18eea809b2f694278478399ae1836ff [file] [log] [blame]
Jason Ekstrand01c9ec32013-10-13 19:08:39 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2012-2013 Collabora, Ltd.
4 * Copyright © 2013 Jason Ekstrand
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25#include "config.h"
26
27#include <stdlib.h>
28#include <string.h>
29#include <wayland-util.h>
30#include <linux/input.h>
31
32#include "cairo-util.h"
33
34enum frame_button_flags {
35 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
36 FRAME_BUTTON_DECORATED = 0x2,
37 FRAME_BUTTON_CLICK_DOWN = 0x4,
38};
39
40struct frame_button {
41 struct frame *frame;
42 struct wl_list link; /* buttons_list */
43
44 cairo_surface_t *icon;
45 enum frame_button_flags flags;
46 int hover_count;
47 int press_count;
48
49 struct {
50 int x, y;
51 int width, height;
52 } allocation;
53
54 enum frame_status status_effect;
55};
56
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050057struct frame_pointer_button {
58 struct wl_list link;
59 uint32_t button;
60 enum theme_location press_location;
61 struct frame_button *frame_button;
62};
63
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050064struct frame_pointer {
65 struct wl_list link;
66 void *data;
67
68 int x, y;
69
70 struct frame_button *hover_button;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050071 struct wl_list down_buttons;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050072};
73
Jason Ekstrand3f66cf92013-10-13 19:08:40 -050074struct frame_touch {
75 struct wl_list link;
76 void *data;
77
78 int x, y;
79
80 struct frame_button *button;
81};
82
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050083struct frame {
84 int32_t width, height;
85 char *title;
86 uint32_t flags;
87 struct theme *theme;
88
89 struct {
90 int32_t x, y;
91 int32_t width, height;
92 } interior;
93 int shadow_margin;
94 int opaque_margin;
95 int geometry_dirty;
96
97 uint32_t status;
98
99 struct wl_list buttons;
100 struct wl_list pointers;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500101 struct wl_list touches;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500102};
103
104static struct frame_button *
105frame_button_create(struct frame *frame, const char *icon,
106 enum frame_status status_effect,
107 enum frame_button_flags flags)
108{
109 struct frame_button *button;
110
111 button = calloc(1, sizeof *button);
112 if (!button)
113 return NULL;
114
115 button->icon = cairo_image_surface_create_from_png(icon);
116 if (!button->icon) {
117 free(button);
118 return NULL;
119 }
120
121 button->frame = frame;
122 button->flags = flags;
123 button->status_effect = status_effect;
124
125 wl_list_insert(frame->buttons.prev, &button->link);
126
127 return button;
128}
129
130static void
131frame_button_destroy(struct frame_button *button)
132{
133 cairo_surface_destroy(button->icon);
134 free(button);
135}
136
137static void
138frame_button_enter(struct frame_button *button)
139{
140 if (!button->hover_count)
141 button->frame->status |= FRAME_STATUS_REPAINT;
142 button->hover_count++;
143}
144
145static void
146frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
147{
148 button->hover_count--;
149 if (!button->hover_count)
150 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500151}
152
153static void
154frame_button_press(struct frame_button *button)
155{
156 if (!button->press_count)
157 button->frame->status |= FRAME_STATUS_REPAINT;
158 button->press_count++;
159
160 if (button->flags & FRAME_BUTTON_CLICK_DOWN)
161 button->frame->status |= button->status_effect;
162}
163
164static void
165frame_button_release(struct frame_button *button)
166{
167 button->press_count--;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500168 if (button->press_count)
169 return;
170
171 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500172
173 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
174 button->frame->status |= button->status_effect;
175}
176
177static void
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500178frame_button_cancel(struct frame_button *button)
179{
180 button->press_count--;
181 if (!button->press_count)
182 button->frame->status |= FRAME_STATUS_REPAINT;
183}
184
185static void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500186frame_button_repaint(struct frame_button *button, cairo_t *cr)
187{
188 int x, y;
189
190 if (!button->allocation.width)
191 return;
192 if (!button->allocation.height)
193 return;
194
195 x = button->allocation.x;
196 y = button->allocation.y;
197
198 cairo_save(cr);
199
200 if (button->flags & FRAME_BUTTON_DECORATED) {
201 cairo_set_line_width(cr, 1);
202
203 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
204 cairo_rectangle(cr, x, y, 25, 16);
205
206 cairo_stroke_preserve(cr);
207
208 if (button->press_count) {
209 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
210 } else if (button->hover_count) {
211 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
212 } else {
213 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
214 }
215
216 cairo_fill (cr);
217
218 x += 4;
219 }
220
221 cairo_set_source_surface(cr, button->icon, x, y);
222 cairo_paint(cr);
223
224 cairo_restore(cr);
225}
226
227static struct frame_pointer *
228frame_pointer_get(struct frame *frame, void *data)
229{
230 struct frame_pointer *pointer;
231
232 wl_list_for_each(pointer, &frame->pointers, link)
233 if (pointer->data == data)
234 return pointer;
235
236 pointer = calloc(1, sizeof *pointer);
237 if (!pointer)
238 return NULL;
239
240 pointer->data = data;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500241 wl_list_init(&pointer->down_buttons);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500242 wl_list_insert(&frame->pointers, &pointer->link);
243
244 return pointer;
245}
246
247static void
248frame_pointer_destroy(struct frame_pointer *pointer)
249{
250 wl_list_remove(&pointer->link);
251 free(pointer);
252}
253
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500254static struct frame_touch *
255frame_touch_get(struct frame *frame, void *data)
256{
257 struct frame_touch *touch;
258
259 wl_list_for_each(touch, &frame->touches, link)
260 if (touch->data == data)
261 return touch;
262
263 touch = calloc(1, sizeof *touch);
264 if (!touch)
265 return NULL;
266
267 touch->data = data;
268 wl_list_insert(&frame->touches, &touch->link);
269
270 return touch;
271}
272
273static void
274frame_touch_destroy(struct frame_touch *touch)
275{
276 wl_list_remove(&touch->link);
277 free(touch);
278}
279
U. Artie Eoff107de962014-01-17 11:19:46 -0800280void
281frame_destroy(struct frame *frame)
282{
283 struct frame_button *button, *next;
284 struct frame_touch *touch, *next_touch;
285 struct frame_pointer *pointer, *next_pointer;
286
287 wl_list_for_each_safe(button, next, &frame->buttons, link)
288 frame_button_destroy(button);
289
290 wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
291 frame_touch_destroy(touch);
292
293 wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
294 frame_pointer_destroy(pointer);
295
296 free(frame->title);
297 free(frame);
298}
299
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500300struct frame *
301frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
302 const char *title)
303{
304 struct frame *frame;
305 struct frame_button *button;
306
307 frame = calloc(1, sizeof *frame);
308 if (!frame)
309 return NULL;
310
311 frame->width = width;
312 frame->height = height;
313 frame->flags = 0;
314 frame->theme = t;
315 frame->status = FRAME_STATUS_REPAINT;
316 frame->geometry_dirty = 1;
317
U. Artie Eoff107de962014-01-17 11:19:46 -0800318 wl_list_init(&frame->buttons);
319 wl_list_init(&frame->pointers);
320 wl_list_init(&frame->touches);
321
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500322 if (title) {
323 frame->title = strdup(title);
324 if (!frame->title)
325 goto free_frame;
326 }
327
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700328 if (title) {
329 button = frame_button_create(frame,
330 DATADIR "/weston/icon_window.png",
331 FRAME_STATUS_MENU,
332 FRAME_BUTTON_CLICK_DOWN);
333 if (!button)
334 goto free_frame;
335 }
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500336
337 if (buttons & FRAME_BUTTON_CLOSE) {
338 button = frame_button_create(frame,
339 DATADIR "/weston/sign_close.png",
340 FRAME_STATUS_CLOSE,
341 FRAME_BUTTON_ALIGN_RIGHT |
342 FRAME_BUTTON_DECORATED);
343 if (!button)
344 goto free_frame;
345 }
346
347 if (buttons & FRAME_BUTTON_MAXIMIZE) {
348 button = frame_button_create(frame,
349 DATADIR "/weston/sign_maximize.png",
350 FRAME_STATUS_MAXIMIZE,
351 FRAME_BUTTON_ALIGN_RIGHT |
352 FRAME_BUTTON_DECORATED);
353 if (!button)
354 goto free_frame;
355 }
356
357 if (buttons & FRAME_BUTTON_MINIMIZE) {
358 button = frame_button_create(frame,
359 DATADIR "/weston/sign_minimize.png",
360 FRAME_STATUS_MINIMIZE,
361 FRAME_BUTTON_ALIGN_RIGHT |
362 FRAME_BUTTON_DECORATED);
363 if (!button)
364 goto free_frame;
365 }
366
367 return frame;
368
369free_frame:
U. Artie Eoff107de962014-01-17 11:19:46 -0800370 frame_destroy(frame);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500371 return NULL;
372}
373
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500374int
375frame_set_title(struct frame *frame, const char *title)
376{
377 char *dup = NULL;
378
379 if (title) {
380 dup = strdup(title);
381 if (!dup)
382 return -1;
383 }
384
385 free(frame->title);
386 frame->title = dup;
387
Boyan Ding9c5aedf2014-07-04 15:19:23 +0800388 frame->geometry_dirty = 1;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500389 frame->status |= FRAME_STATUS_REPAINT;
390
391 return 0;
392}
393
394void
395frame_set_flag(struct frame *frame, enum frame_flag flag)
396{
397 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
398 frame->geometry_dirty = 1;
399
400 frame->flags |= flag;
401 frame->status |= FRAME_STATUS_REPAINT;
402}
403
404void
405frame_unset_flag(struct frame *frame, enum frame_flag flag)
406{
407 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
408 frame->geometry_dirty = 1;
409
410 frame->flags &= ~flag;
411 frame->status |= FRAME_STATUS_REPAINT;
412}
413
414void
415frame_resize(struct frame *frame, int32_t width, int32_t height)
416{
417 frame->width = width;
418 frame->height = height;
419
420 frame->geometry_dirty = 1;
421 frame->status |= FRAME_STATUS_REPAINT;
422}
423
424void
425frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
426{
427 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700428 int decoration_width, decoration_height, titlebar_height;
429
Boyan Dingc4902122014-07-04 15:19:22 +0800430 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700431 titlebar_height = t->titlebar_height;
432 else
433 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500434
435 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
436 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700437 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500438 } else {
439 decoration_width = (t->width + t->margin) * 2;
440 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700441 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500442 }
443
444 frame_resize(frame, width + decoration_width,
445 height + decoration_height);
446}
447
448int32_t
449frame_width(struct frame *frame)
450{
451 return frame->width;
452}
453
454int32_t
455frame_height(struct frame *frame)
456{
457 return frame->height;
458}
459
460static void
461frame_refresh_geometry(struct frame *frame)
462{
463 struct frame_button *button;
464 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700465 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500466 int32_t decoration_width, decoration_height;
467
468 if (!frame->geometry_dirty)
469 return;
470
Boyan Dingc4902122014-07-04 15:19:22 +0800471 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700472 titlebar_height = t->titlebar_height;
473 else
474 titlebar_height = t->width;
475
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500476 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
477 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700478 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500479
480 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700481 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500482 frame->interior.width = frame->width - decoration_width;
483 frame->interior.height = frame->height - decoration_height;
484
485 frame->opaque_margin = 0;
486 frame->shadow_margin = 0;
487 } else {
488 decoration_width = (t->width + t->margin) * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700489 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500490
491 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700492 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500493 frame->interior.width = frame->width - decoration_width;
494 frame->interior.height = frame->height - decoration_height;
495
496 frame->opaque_margin = t->margin + t->frame_radius;
497 frame->shadow_margin = t->margin;
498 }
499
500 x_r = frame->width - t->width - frame->shadow_margin;
501 x_l = t->width + frame->shadow_margin;
502 y = t->width + frame->shadow_margin;
503 wl_list_for_each(button, &frame->buttons, link) {
504 const int button_padding = 4;
505 w = cairo_image_surface_get_width(button->icon);
506 h = cairo_image_surface_get_height(button->icon);
507
508 if (button->flags & FRAME_BUTTON_DECORATED)
509 w += 10;
510
511 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
512 x_r -= w;
513
514 button->allocation.x = x_r;
515 button->allocation.y = y;
516 button->allocation.width = w + 1;
517 button->allocation.height = h + 1;
518
519 x_r -= button_padding;
520 } else {
521 button->allocation.x = x_l;
522 button->allocation.y = y;
523 button->allocation.width = w + 1;
524 button->allocation.height = h + 1;
525
526 x_l += w;
527 x_l += button_padding;
528 }
529 }
530
531 frame->geometry_dirty = 0;
532}
533
534void
535frame_interior(struct frame *frame, int32_t *x, int32_t *y,
536 int32_t *width, int32_t *height)
537{
538 frame_refresh_geometry(frame);
539
540 if (x)
541 *x = frame->interior.x;
542 if (y)
543 *y = frame->interior.y;
544 if (width)
545 *width = frame->interior.width;
546 if (height)
547 *height = frame->interior.height;
548}
549
550void
551frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
552 int32_t *width, int32_t *height)
553{
554 frame_refresh_geometry(frame);
555
556 if (x)
557 *x = frame->shadow_margin;
558 if (y)
559 *y = frame->shadow_margin;
560 if (width)
561 *width = frame->width - frame->shadow_margin * 2;
562 if (height)
563 *height = frame->height - frame->shadow_margin * 2;
564}
565
566void
567frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
568 int32_t *width, int32_t *height)
569{
570 frame_refresh_geometry(frame);
571
572 if (x)
573 *x = frame->opaque_margin;
574 if (y)
575 *y = frame->opaque_margin;
576 if (width)
577 *width = frame->width - frame->opaque_margin * 2;
578 if (height)
579 *height = frame->height - frame->opaque_margin * 2;
580}
581
Jasper St. Pierre74073452014-02-01 18:36:41 -0500582int
583frame_get_shadow_margin(struct frame *frame)
584{
585 frame_refresh_geometry(frame);
586
587 return frame->shadow_margin;
588}
589
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500590uint32_t
591frame_status(struct frame *frame)
592{
593 return frame->status;
594}
595
596void
597frame_status_clear(struct frame *frame, enum frame_status status)
598{
599 frame->status &= ~status;
600}
601
602static struct frame_button *
603frame_find_button(struct frame *frame, int x, int y)
604{
605 struct frame_button *button;
606 int rel_x, rel_y;
607
608 wl_list_for_each(button, &frame->buttons, link) {
609 rel_x = x - button->allocation.x;
610 rel_y = y - button->allocation.y;
611
612 if (0 <= rel_x && rel_x < button->allocation.width &&
613 0 <= rel_y && rel_y < button->allocation.height)
614 return button;
615 }
616
617 return NULL;
618}
619
620enum theme_location
621frame_pointer_enter(struct frame *frame, void *data, int x, int y)
622{
623 return frame_pointer_motion(frame, data, x, y);
624}
625
626enum theme_location
627frame_pointer_motion(struct frame *frame, void *data, int x, int y)
628{
629 struct frame_pointer *pointer = frame_pointer_get(frame, data);
630 struct frame_button *button = frame_find_button(frame, x, y);
631 enum theme_location location;
632
633 location = theme_get_location(frame->theme, x, y,
634 frame->width, frame->height,
635 frame->flags & FRAME_FLAG_MAXIMIZED ?
636 THEME_FRAME_MAXIMIZED : 0);
637 if (!pointer)
638 return location;
639
640 pointer->x = x;
641 pointer->y = y;
642
643 if (pointer->hover_button == button)
644 return location;
645
646 if (pointer->hover_button)
647 frame_button_leave(pointer->hover_button, pointer);
648
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500649 pointer->hover_button = button;
650
651 if (pointer->hover_button)
652 frame_button_enter(pointer->hover_button);
653
654 return location;
655}
656
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500657static void
658frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500659{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500660 wl_list_remove(&button->link);
661 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500662}
663
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500664static void
665frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
666 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500667{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500668 if (button->button == BTN_RIGHT) {
669 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500670 frame->status |= FRAME_STATUS_MENU;
671
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500672 frame_pointer_button_destroy(button);
673
674 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500675 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500676 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500677 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500678 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500679 case THEME_LOCATION_TITLEBAR:
680 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500681
682 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500683 break;
684 case THEME_LOCATION_RESIZING_TOP:
685 case THEME_LOCATION_RESIZING_BOTTOM:
686 case THEME_LOCATION_RESIZING_LEFT:
687 case THEME_LOCATION_RESIZING_RIGHT:
688 case THEME_LOCATION_RESIZING_TOP_LEFT:
689 case THEME_LOCATION_RESIZING_TOP_RIGHT:
690 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
691 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
692 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500693
694 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500695 break;
696 default:
697 break;
698 }
699 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500700 }
701}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500702
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500703static void
704frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
705 struct frame_pointer_button *button)
706{
707 if (button->button == BTN_LEFT && button->frame_button) {
708 if (button->frame_button == pointer->hover_button)
709 frame_button_release(button->frame_button);
710 else
711 frame_button_cancel(button->frame_button);
712 }
713}
714
715static void
716frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
717 struct frame_pointer_button *button)
718{
719 if (button->frame_button)
720 frame_button_cancel(button->frame_button);
721}
722
723void
724frame_pointer_leave(struct frame *frame, void *data)
725{
726 struct frame_pointer *pointer = frame_pointer_get(frame, data);
727 struct frame_pointer_button *button, *next;
728 if (!pointer)
729 return;
730
731 if (pointer->hover_button)
732 frame_button_leave(pointer->hover_button, pointer);
733
734 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
735 frame_pointer_button_cancel(frame, pointer, button);
736 frame_pointer_button_destroy(button);
737 }
738
739 frame_pointer_destroy(pointer);
740}
741
742enum theme_location
743frame_pointer_button(struct frame *frame, void *data,
744 uint32_t btn, enum frame_button_state state)
745{
746 struct frame_pointer *pointer = frame_pointer_get(frame, data);
747 struct frame_pointer_button *button;
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800748 enum theme_location location = THEME_LOCATION_EXTERIOR;
749
750 if (!pointer)
751 return location;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500752
753 location = theme_get_location(frame->theme, pointer->x, pointer->y,
754 frame->width, frame->height,
755 frame->flags & FRAME_FLAG_MAXIMIZED ?
756 THEME_FRAME_MAXIMIZED : 0);
757
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500758 if (state == FRAME_BUTTON_PRESSED) {
759 button = malloc(sizeof *button);
760 if (!button)
761 return location;
762
763 button->button = btn;
764 button->press_location = location;
765 button->frame_button = pointer->hover_button;
766 wl_list_insert(&pointer->down_buttons, &button->link);
767
768 frame_pointer_button_press(frame, pointer, button);
769 } else if (state == FRAME_BUTTON_RELEASED) {
770 button = NULL;
771 wl_list_for_each(button, &pointer->down_buttons, link)
772 if (button->button == btn)
773 break;
774 /* Make sure we didn't hit the end */
775 if (&button->link == &pointer->down_buttons)
776 return location;
777
778 location = button->press_location;
779 frame_pointer_button_release(frame, pointer, button);
780 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500781 }
782
783 return location;
784}
785
786void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500787frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
788{
789 struct frame_touch *touch = frame_touch_get(frame, data);
790 struct frame_button *button = frame_find_button(frame, x, y);
791 enum theme_location location;
792
793 if (id > 0)
794 return;
795
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800796 if (touch && button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500797 touch->button = button;
798 frame_button_press(touch->button);
799 return;
800 }
801
802 location = theme_get_location(frame->theme, x, y,
803 frame->width, frame->height,
804 frame->flags & FRAME_FLAG_MAXIMIZED ?
805 THEME_FRAME_MAXIMIZED : 0);
806
807 switch (location) {
808 case THEME_LOCATION_TITLEBAR:
809 frame->status |= FRAME_STATUS_MOVE;
810 break;
811 case THEME_LOCATION_RESIZING_TOP:
812 case THEME_LOCATION_RESIZING_BOTTOM:
813 case THEME_LOCATION_RESIZING_LEFT:
814 case THEME_LOCATION_RESIZING_RIGHT:
815 case THEME_LOCATION_RESIZING_TOP_LEFT:
816 case THEME_LOCATION_RESIZING_TOP_RIGHT:
817 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
818 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
819 frame->status |= FRAME_STATUS_RESIZE;
820 break;
821 default:
822 break;
823 }
824}
825
826void
827frame_touch_up(struct frame *frame, void *data, int32_t id)
828{
829 struct frame_touch *touch = frame_touch_get(frame, data);
830
831 if (id > 0)
832 return;
833
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800834 if (touch && touch->button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500835 frame_button_release(touch->button);
836 frame_touch_destroy(touch);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500837 }
838}
839
840void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500841frame_repaint(struct frame *frame, cairo_t *cr)
842{
843 struct frame_button *button;
844 uint32_t flags = 0;
845
846 frame_refresh_geometry(frame);
847
848 if (frame->flags & FRAME_FLAG_MAXIMIZED)
849 flags |= THEME_FRAME_MAXIMIZED;
850
851 if (frame->flags & FRAME_FLAG_ACTIVE)
852 flags |= THEME_FRAME_ACTIVE;
853
854 cairo_save(cr);
855 theme_render_frame(frame->theme, cr, frame->width, frame->height,
856 frame->title, flags);
857 cairo_restore(cr);
858
859 wl_list_for_each(button, &frame->buttons, link)
860 frame_button_repaint(button, cr);
861
862 frame_status_clear(frame, FRAME_STATUS_REPAINT);
863}