blob: a501649f681782dc2fe48c16d2bd7d190ca6097b [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
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500280struct frame *
281frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
282 const char *title)
283{
284 struct frame *frame;
285 struct frame_button *button;
286
287 frame = calloc(1, sizeof *frame);
288 if (!frame)
289 return NULL;
290
291 frame->width = width;
292 frame->height = height;
293 frame->flags = 0;
294 frame->theme = t;
295 frame->status = FRAME_STATUS_REPAINT;
296 frame->geometry_dirty = 1;
297
298 if (title) {
299 frame->title = strdup(title);
300 if (!frame->title)
301 goto free_frame;
302 }
303
304 wl_list_init(&frame->buttons);
305 wl_list_init(&frame->pointers);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500306 wl_list_init(&frame->touches);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500307
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700308 if (title) {
309 button = frame_button_create(frame,
310 DATADIR "/weston/icon_window.png",
311 FRAME_STATUS_MENU,
312 FRAME_BUTTON_CLICK_DOWN);
313 if (!button)
314 goto free_frame;
315 }
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500316
317 if (buttons & FRAME_BUTTON_CLOSE) {
318 button = frame_button_create(frame,
319 DATADIR "/weston/sign_close.png",
320 FRAME_STATUS_CLOSE,
321 FRAME_BUTTON_ALIGN_RIGHT |
322 FRAME_BUTTON_DECORATED);
323 if (!button)
324 goto free_frame;
325 }
326
327 if (buttons & FRAME_BUTTON_MAXIMIZE) {
328 button = frame_button_create(frame,
329 DATADIR "/weston/sign_maximize.png",
330 FRAME_STATUS_MAXIMIZE,
331 FRAME_BUTTON_ALIGN_RIGHT |
332 FRAME_BUTTON_DECORATED);
333 if (!button)
334 goto free_frame;
335 }
336
337 if (buttons & FRAME_BUTTON_MINIMIZE) {
338 button = frame_button_create(frame,
339 DATADIR "/weston/sign_minimize.png",
340 FRAME_STATUS_MINIMIZE,
341 FRAME_BUTTON_ALIGN_RIGHT |
342 FRAME_BUTTON_DECORATED);
343 if (!button)
344 goto free_frame;
345 }
346
347 return frame;
348
349free_frame:
350 free(frame->title);
351 free(frame);
352 return NULL;
353}
354
355void
356frame_destroy(struct frame *frame)
357{
358 struct frame_button *button, *next;
359
360 wl_list_for_each_safe(button, next, &frame->buttons, link)
361 frame_button_destroy(button);
362
363 free(frame->title);
364 free(frame);
365}
366
367int
368frame_set_title(struct frame *frame, const char *title)
369{
370 char *dup = NULL;
371
372 if (title) {
373 dup = strdup(title);
374 if (!dup)
375 return -1;
376 }
377
378 free(frame->title);
379 frame->title = dup;
380
381 frame->status |= FRAME_STATUS_REPAINT;
382
383 return 0;
384}
385
386void
387frame_set_flag(struct frame *frame, enum frame_flag flag)
388{
389 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
390 frame->geometry_dirty = 1;
391
392 frame->flags |= flag;
393 frame->status |= FRAME_STATUS_REPAINT;
394}
395
396void
397frame_unset_flag(struct frame *frame, enum frame_flag flag)
398{
399 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
400 frame->geometry_dirty = 1;
401
402 frame->flags &= ~flag;
403 frame->status |= FRAME_STATUS_REPAINT;
404}
405
406void
407frame_resize(struct frame *frame, int32_t width, int32_t height)
408{
409 frame->width = width;
410 frame->height = height;
411
412 frame->geometry_dirty = 1;
413 frame->status |= FRAME_STATUS_REPAINT;
414}
415
416void
417frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
418{
419 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700420 int decoration_width, decoration_height, titlebar_height;
421
422 if (frame->title)
423 titlebar_height = t->titlebar_height;
424 else
425 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500426
427 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
428 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700429 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500430 } else {
431 decoration_width = (t->width + t->margin) * 2;
432 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700433 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500434 }
435
436 frame_resize(frame, width + decoration_width,
437 height + decoration_height);
438}
439
440int32_t
441frame_width(struct frame *frame)
442{
443 return frame->width;
444}
445
446int32_t
447frame_height(struct frame *frame)
448{
449 return frame->height;
450}
451
452static void
453frame_refresh_geometry(struct frame *frame)
454{
455 struct frame_button *button;
456 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700457 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500458 int32_t decoration_width, decoration_height;
459
460 if (!frame->geometry_dirty)
461 return;
462
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700463 if (frame->title)
464 titlebar_height = t->titlebar_height;
465 else
466 titlebar_height = t->width;
467
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500468 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
469 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700470 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500471
472 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700473 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500474 frame->interior.width = frame->width - decoration_width;
475 frame->interior.height = frame->height - decoration_height;
476
477 frame->opaque_margin = 0;
478 frame->shadow_margin = 0;
479 } else {
480 decoration_width = (t->width + t->margin) * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700481 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500482
483 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700484 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500485 frame->interior.width = frame->width - decoration_width;
486 frame->interior.height = frame->height - decoration_height;
487
488 frame->opaque_margin = t->margin + t->frame_radius;
489 frame->shadow_margin = t->margin;
490 }
491
492 x_r = frame->width - t->width - frame->shadow_margin;
493 x_l = t->width + frame->shadow_margin;
494 y = t->width + frame->shadow_margin;
495 wl_list_for_each(button, &frame->buttons, link) {
496 const int button_padding = 4;
497 w = cairo_image_surface_get_width(button->icon);
498 h = cairo_image_surface_get_height(button->icon);
499
500 if (button->flags & FRAME_BUTTON_DECORATED)
501 w += 10;
502
503 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
504 x_r -= w;
505
506 button->allocation.x = x_r;
507 button->allocation.y = y;
508 button->allocation.width = w + 1;
509 button->allocation.height = h + 1;
510
511 x_r -= button_padding;
512 } else {
513 button->allocation.x = x_l;
514 button->allocation.y = y;
515 button->allocation.width = w + 1;
516 button->allocation.height = h + 1;
517
518 x_l += w;
519 x_l += button_padding;
520 }
521 }
522
523 frame->geometry_dirty = 0;
524}
525
526void
527frame_interior(struct frame *frame, int32_t *x, int32_t *y,
528 int32_t *width, int32_t *height)
529{
530 frame_refresh_geometry(frame);
531
532 if (x)
533 *x = frame->interior.x;
534 if (y)
535 *y = frame->interior.y;
536 if (width)
537 *width = frame->interior.width;
538 if (height)
539 *height = frame->interior.height;
540}
541
542void
543frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
544 int32_t *width, int32_t *height)
545{
546 frame_refresh_geometry(frame);
547
548 if (x)
549 *x = frame->shadow_margin;
550 if (y)
551 *y = frame->shadow_margin;
552 if (width)
553 *width = frame->width - frame->shadow_margin * 2;
554 if (height)
555 *height = frame->height - frame->shadow_margin * 2;
556}
557
558void
559frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
560 int32_t *width, int32_t *height)
561{
562 frame_refresh_geometry(frame);
563
564 if (x)
565 *x = frame->opaque_margin;
566 if (y)
567 *y = frame->opaque_margin;
568 if (width)
569 *width = frame->width - frame->opaque_margin * 2;
570 if (height)
571 *height = frame->height - frame->opaque_margin * 2;
572}
573
574uint32_t
575frame_status(struct frame *frame)
576{
577 return frame->status;
578}
579
580void
581frame_status_clear(struct frame *frame, enum frame_status status)
582{
583 frame->status &= ~status;
584}
585
586static struct frame_button *
587frame_find_button(struct frame *frame, int x, int y)
588{
589 struct frame_button *button;
590 int rel_x, rel_y;
591
592 wl_list_for_each(button, &frame->buttons, link) {
593 rel_x = x - button->allocation.x;
594 rel_y = y - button->allocation.y;
595
596 if (0 <= rel_x && rel_x < button->allocation.width &&
597 0 <= rel_y && rel_y < button->allocation.height)
598 return button;
599 }
600
601 return NULL;
602}
603
604enum theme_location
605frame_pointer_enter(struct frame *frame, void *data, int x, int y)
606{
607 return frame_pointer_motion(frame, data, x, y);
608}
609
610enum theme_location
611frame_pointer_motion(struct frame *frame, void *data, int x, int y)
612{
613 struct frame_pointer *pointer = frame_pointer_get(frame, data);
614 struct frame_button *button = frame_find_button(frame, x, y);
615 enum theme_location location;
616
617 location = theme_get_location(frame->theme, x, y,
618 frame->width, frame->height,
619 frame->flags & FRAME_FLAG_MAXIMIZED ?
620 THEME_FRAME_MAXIMIZED : 0);
621 if (!pointer)
622 return location;
623
624 pointer->x = x;
625 pointer->y = y;
626
627 if (pointer->hover_button == button)
628 return location;
629
630 if (pointer->hover_button)
631 frame_button_leave(pointer->hover_button, pointer);
632
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500633 pointer->hover_button = button;
634
635 if (pointer->hover_button)
636 frame_button_enter(pointer->hover_button);
637
638 return location;
639}
640
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500641static void
642frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500643{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500644 wl_list_remove(&button->link);
645 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500646}
647
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500648static void
649frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
650 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500651{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500652 if (button->button == BTN_RIGHT) {
653 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500654 frame->status |= FRAME_STATUS_MENU;
655
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500656 frame_pointer_button_destroy(button);
657
658 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500659 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500660 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500661 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500662 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500663 case THEME_LOCATION_TITLEBAR:
664 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500665
666 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500667 break;
668 case THEME_LOCATION_RESIZING_TOP:
669 case THEME_LOCATION_RESIZING_BOTTOM:
670 case THEME_LOCATION_RESIZING_LEFT:
671 case THEME_LOCATION_RESIZING_RIGHT:
672 case THEME_LOCATION_RESIZING_TOP_LEFT:
673 case THEME_LOCATION_RESIZING_TOP_RIGHT:
674 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
675 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
676 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500677
678 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500679 break;
680 default:
681 break;
682 }
683 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500684 }
685}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500686
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500687static void
688frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
689 struct frame_pointer_button *button)
690{
691 if (button->button == BTN_LEFT && button->frame_button) {
692 if (button->frame_button == pointer->hover_button)
693 frame_button_release(button->frame_button);
694 else
695 frame_button_cancel(button->frame_button);
696 }
697}
698
699static void
700frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
701 struct frame_pointer_button *button)
702{
703 if (button->frame_button)
704 frame_button_cancel(button->frame_button);
705}
706
707void
708frame_pointer_leave(struct frame *frame, void *data)
709{
710 struct frame_pointer *pointer = frame_pointer_get(frame, data);
711 struct frame_pointer_button *button, *next;
712 if (!pointer)
713 return;
714
715 if (pointer->hover_button)
716 frame_button_leave(pointer->hover_button, pointer);
717
718 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
719 frame_pointer_button_cancel(frame, pointer, button);
720 frame_pointer_button_destroy(button);
721 }
722
723 frame_pointer_destroy(pointer);
724}
725
726enum theme_location
727frame_pointer_button(struct frame *frame, void *data,
728 uint32_t btn, enum frame_button_state state)
729{
730 struct frame_pointer *pointer = frame_pointer_get(frame, data);
731 struct frame_pointer_button *button;
732 enum theme_location location;
733
734 location = theme_get_location(frame->theme, pointer->x, pointer->y,
735 frame->width, frame->height,
736 frame->flags & FRAME_FLAG_MAXIMIZED ?
737 THEME_FRAME_MAXIMIZED : 0);
738
739 if (!pointer)
740 return location;
741
742 if (state == FRAME_BUTTON_PRESSED) {
743 button = malloc(sizeof *button);
744 if (!button)
745 return location;
746
747 button->button = btn;
748 button->press_location = location;
749 button->frame_button = pointer->hover_button;
750 wl_list_insert(&pointer->down_buttons, &button->link);
751
752 frame_pointer_button_press(frame, pointer, button);
753 } else if (state == FRAME_BUTTON_RELEASED) {
754 button = NULL;
755 wl_list_for_each(button, &pointer->down_buttons, link)
756 if (button->button == btn)
757 break;
758 /* Make sure we didn't hit the end */
759 if (&button->link == &pointer->down_buttons)
760 return location;
761
762 location = button->press_location;
763 frame_pointer_button_release(frame, pointer, button);
764 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500765 }
766
767 return location;
768}
769
770void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500771frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
772{
773 struct frame_touch *touch = frame_touch_get(frame, data);
774 struct frame_button *button = frame_find_button(frame, x, y);
775 enum theme_location location;
776
777 if (id > 0)
778 return;
779
780 if (button) {
781 touch->button = button;
782 frame_button_press(touch->button);
783 return;
784 }
785
786 location = theme_get_location(frame->theme, x, y,
787 frame->width, frame->height,
788 frame->flags & FRAME_FLAG_MAXIMIZED ?
789 THEME_FRAME_MAXIMIZED : 0);
790
791 switch (location) {
792 case THEME_LOCATION_TITLEBAR:
793 frame->status |= FRAME_STATUS_MOVE;
794 break;
795 case THEME_LOCATION_RESIZING_TOP:
796 case THEME_LOCATION_RESIZING_BOTTOM:
797 case THEME_LOCATION_RESIZING_LEFT:
798 case THEME_LOCATION_RESIZING_RIGHT:
799 case THEME_LOCATION_RESIZING_TOP_LEFT:
800 case THEME_LOCATION_RESIZING_TOP_RIGHT:
801 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
802 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
803 frame->status |= FRAME_STATUS_RESIZE;
804 break;
805 default:
806 break;
807 }
808}
809
810void
811frame_touch_up(struct frame *frame, void *data, int32_t id)
812{
813 struct frame_touch *touch = frame_touch_get(frame, data);
814
815 if (id > 0)
816 return;
817
818 if (touch->button) {
819 frame_button_release(touch->button);
820 frame_touch_destroy(touch);
821 return;
822 }
823}
824
825void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500826frame_repaint(struct frame *frame, cairo_t *cr)
827{
828 struct frame_button *button;
829 uint32_t flags = 0;
830
831 frame_refresh_geometry(frame);
832
833 if (frame->flags & FRAME_FLAG_MAXIMIZED)
834 flags |= THEME_FRAME_MAXIMIZED;
835
836 if (frame->flags & FRAME_FLAG_ACTIVE)
837 flags |= THEME_FRAME_ACTIVE;
838
839 cairo_save(cr);
840 theme_render_frame(frame->theme, cr, frame->width, frame->height,
841 frame->title, flags);
842 cairo_restore(cr);
843
844 wl_list_for_each(button, &frame->buttons, link)
845 frame_button_repaint(button, cr);
846
847 frame_status_clear(frame, FRAME_STATUS_REPAINT);
848}