1 /*
2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2012-2013 Collabora, Ltd.
4 * Copyright © 2013 Jason Ekstrand
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 #include "config.h"
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <wayland-util.h>
34 #include <linux/input.h>
35
36 #include "cairo-util.h"
37 #include "shared/file-util.h"
38
39 enum frame_button_flags {
40 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
41 FRAME_BUTTON_DECORATED = 0x2,
42 FRAME_BUTTON_CLICK_DOWN = 0x4,
43 };
44
45 struct frame_button {
46 struct frame *frame;
47 struct wl_list link; /* buttons_list */
48
49 cairo_surface_t *icon;
50 enum frame_button_flags flags;
51 int hover_count;
52 int press_count;
53
54 struct {
55 int x, y;
56 int width, height;
57 } allocation;
58
59 enum frame_status status_effect;
60 };
61
62 struct frame_pointer_button {
63 struct wl_list link;
64 uint32_t button;
65 enum theme_location press_location;
66 struct frame_button *frame_button;
67 };
68
69 struct frame_pointer {
70 struct wl_list link;
71 void *data;
72
73 int x, y;
74
75 struct frame_button *hover_button;
76 struct wl_list down_buttons;
77 };
78
79 struct frame_touch {
80 struct wl_list link;
81 void *data;
82
83 int x, y;
84
85 struct frame_button *button;
86 };
87
88 struct frame {
89 int32_t width, height;
90 char *title;
91 uint32_t flags;
92 struct theme *theme;
93
94 struct {
95 int32_t x, y;
96 int32_t width, height;
97 } interior;
98 int shadow_margin;
99 int opaque_margin;
100 int geometry_dirty;
101
102 cairo_rectangle_int_t title_rect;
103
104 uint32_t status;
105
106 struct wl_list buttons;
107 struct wl_list pointers;
108 struct wl_list touches;
109 };
110
111 static struct frame_button *
frame_button_create_from_surface(struct frame * frame,cairo_surface_t * icon,enum frame_status status_effect,enum frame_button_flags flags)112 frame_button_create_from_surface(struct frame *frame, cairo_surface_t *icon,
113 enum frame_status status_effect,
114 enum frame_button_flags flags)
115 {
116 struct frame_button *button;
117
118 button = calloc(1, sizeof *button);
119 if (!button)
120 return NULL;
121
122 button->icon = icon;
123 button->frame = frame;
124 button->flags = flags;
125 button->status_effect = status_effect;
126
127 wl_list_insert(frame->buttons.prev, &button->link);
128
129 return button;
130 }
131
132 static struct frame_button *
frame_button_create(struct frame * frame,const char * icon_name,enum frame_status status_effect,enum frame_button_flags flags)133 frame_button_create(struct frame *frame, const char *icon_name,
134 enum frame_status status_effect,
135 enum frame_button_flags flags)
136 {
137 struct frame_button *button;
138 cairo_surface_t *icon;
139
140 icon = cairo_image_surface_create_from_png(icon_name);
141 if (cairo_surface_status(icon) != CAIRO_STATUS_SUCCESS)
142 goto error;
143
144 button = frame_button_create_from_surface(frame, icon, status_effect,
145 flags);
146 if (!button)
147 goto error;
148
149 return button;
150
151 error:
152 cairo_surface_destroy(icon);
153 return NULL;
154 }
155
156 static void
frame_button_destroy(struct frame_button * button)157 frame_button_destroy(struct frame_button *button)
158 {
159 cairo_surface_destroy(button->icon);
160 free(button);
161 }
162
163 static void
frame_button_enter(struct frame_button * button)164 frame_button_enter(struct frame_button *button)
165 {
166 if (!button->hover_count)
167 button->frame->status |= FRAME_STATUS_REPAINT;
168 button->hover_count++;
169 }
170
171 static void
frame_button_leave(struct frame_button * button,struct frame_pointer * pointer)172 frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
173 {
174 button->hover_count--;
175 if (!button->hover_count)
176 button->frame->status |= FRAME_STATUS_REPAINT;
177 }
178
179 static void
frame_button_press(struct frame_button * button)180 frame_button_press(struct frame_button *button)
181 {
182 if (!button->press_count)
183 button->frame->status |= FRAME_STATUS_REPAINT;
184 button->press_count++;
185
186 if (button->flags & FRAME_BUTTON_CLICK_DOWN)
187 button->frame->status |= button->status_effect;
188 }
189
190 static void
frame_button_release(struct frame_button * button)191 frame_button_release(struct frame_button *button)
192 {
193 button->press_count--;
194 if (button->press_count)
195 return;
196
197 button->frame->status |= FRAME_STATUS_REPAINT;
198
199 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
200 button->frame->status |= button->status_effect;
201 }
202
203 static void
frame_button_cancel(struct frame_button * button)204 frame_button_cancel(struct frame_button *button)
205 {
206 button->press_count--;
207 if (!button->press_count)
208 button->frame->status |= FRAME_STATUS_REPAINT;
209 }
210
211 static void
frame_button_repaint(struct frame_button * button,cairo_t * cr)212 frame_button_repaint(struct frame_button *button, cairo_t *cr)
213 {
214 int x, y;
215
216 if (!button->allocation.width)
217 return;
218 if (!button->allocation.height)
219 return;
220
221 x = button->allocation.x;
222 y = button->allocation.y;
223
224 cairo_save(cr);
225
226 if (button->flags & FRAME_BUTTON_DECORATED) {
227 cairo_set_line_width(cr, 1);
228
229 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
230 cairo_rectangle(cr, x, y, 25, 16);
231
232 cairo_stroke_preserve(cr);
233
234 if (button->press_count) {
235 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
236 } else if (button->hover_count) {
237 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
238 } else {
239 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
240 }
241
242 cairo_fill (cr);
243
244 x += 4;
245 }
246
247 cairo_set_source_surface(cr, button->icon, x, y);
248 cairo_paint(cr);
249
250 cairo_restore(cr);
251 }
252
253 static struct frame_pointer *
frame_pointer_get(struct frame * frame,void * data)254 frame_pointer_get(struct frame *frame, void *data)
255 {
256 struct frame_pointer *pointer;
257
258 wl_list_for_each(pointer, &frame->pointers, link)
259 if (pointer->data == data)
260 return pointer;
261
262 pointer = calloc(1, sizeof *pointer);
263 if (!pointer)
264 return NULL;
265
266 pointer->data = data;
267 wl_list_init(&pointer->down_buttons);
268 wl_list_insert(&frame->pointers, &pointer->link);
269
270 return pointer;
271 }
272
273 static void
frame_pointer_destroy(struct frame_pointer * pointer)274 frame_pointer_destroy(struct frame_pointer *pointer)
275 {
276 wl_list_remove(&pointer->link);
277 free(pointer);
278 }
279
280 static struct frame_touch *
frame_touch_get(struct frame * frame,void * data)281 frame_touch_get(struct frame *frame, void *data)
282 {
283 struct frame_touch *touch;
284
285 wl_list_for_each(touch, &frame->touches, link)
286 if (touch->data == data)
287 return touch;
288
289 touch = calloc(1, sizeof *touch);
290 if (!touch)
291 return NULL;
292
293 touch->data = data;
294 wl_list_insert(&frame->touches, &touch->link);
295
296 return touch;
297 }
298
299 static void
frame_touch_destroy(struct frame_touch * touch)300 frame_touch_destroy(struct frame_touch *touch)
301 {
302 wl_list_remove(&touch->link);
303 free(touch);
304 }
305
306 void
frame_destroy(struct frame * frame)307 frame_destroy(struct frame *frame)
308 {
309 struct frame_button *button, *next;
310 struct frame_touch *touch, *next_touch;
311 struct frame_pointer *pointer, *next_pointer;
312
313 wl_list_for_each_safe(button, next, &frame->buttons, link)
314 frame_button_destroy(button);
315
316 wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
317 frame_touch_destroy(touch);
318
319 wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
320 frame_pointer_destroy(pointer);
321
322 free(frame->title);
323 free(frame);
324 }
325
326 struct frame *
frame_create(struct theme * t,int32_t width,int32_t height,uint32_t buttons,const char * title,cairo_surface_t * icon)327 frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
328 const char *title, cairo_surface_t *icon)
329 {
330 struct frame *frame;
331 struct frame_button *button;
332
333 frame = calloc(1, sizeof *frame);
334 if (!frame)
335 return NULL;
336
337 frame->width = width;
338 frame->height = height;
339 frame->flags = 0;
340 frame->theme = t;
341 frame->status = FRAME_STATUS_REPAINT;
342 frame->geometry_dirty = 1;
343
344 wl_list_init(&frame->buttons);
345 wl_list_init(&frame->pointers);
346 wl_list_init(&frame->touches);
347
348 if (title) {
349 frame->title = strdup(title);
350 if (!frame->title)
351 goto free_frame;
352 }
353
354 if (title) {
355 if (icon) {
356 button = frame_button_create_from_surface(frame,
357 icon,
358 FRAME_STATUS_MENU,
359 FRAME_BUTTON_CLICK_DOWN);
360 } else {
361 char *name = file_name_with_datadir("icon_window.png");
362
363 if (!name)
364 goto free_frame;
365
366 button = frame_button_create(frame,
367 name,
368 FRAME_STATUS_MENU,
369 FRAME_BUTTON_CLICK_DOWN);
370 free(name);
371 }
372 if (!button)
373 goto free_frame;
374 }
375
376 if (buttons & FRAME_BUTTON_CLOSE) {
377 char *name = file_name_with_datadir("sign_close.png");
378
379 if (!name)
380 goto free_frame;
381
382 button = frame_button_create(frame,
383 name,
384 FRAME_STATUS_CLOSE,
385 FRAME_BUTTON_ALIGN_RIGHT |
386 FRAME_BUTTON_DECORATED);
387 free(name);
388 if (!button)
389 goto free_frame;
390 }
391
392 if (buttons & FRAME_BUTTON_MAXIMIZE) {
393 char *name = file_name_with_datadir("sign_maximize.png");
394
395 if (!name)
396 goto free_frame;
397
398 button = frame_button_create(frame,
399 name,
400 FRAME_STATUS_MAXIMIZE,
401 FRAME_BUTTON_ALIGN_RIGHT |
402 FRAME_BUTTON_DECORATED);
403 free(name);
404 if (!button)
405 goto free_frame;
406 }
407
408 if (buttons & FRAME_BUTTON_MINIMIZE) {
409 char *name = file_name_with_datadir("sign_minimize.png");
410
411 if (!name)
412 goto free_frame;
413
414 button = frame_button_create(frame,
415 name,
416 FRAME_STATUS_MINIMIZE,
417 FRAME_BUTTON_ALIGN_RIGHT |
418 FRAME_BUTTON_DECORATED);
419 free(name);
420 if (!button)
421 goto free_frame;
422 }
423
424 return frame;
425
426 free_frame:
427 frame_destroy(frame);
428 return NULL;
429 }
430
431 int
frame_set_title(struct frame * frame,const char * title)432 frame_set_title(struct frame *frame, const char *title)
433 {
434 char *dup = NULL;
435
436 if (title) {
437 dup = strdup(title);
438 if (!dup)
439 return -1;
440 }
441
442 free(frame->title);
443 frame->title = dup;
444
445 frame->geometry_dirty = 1;
446 frame->status |= FRAME_STATUS_REPAINT;
447
448 return 0;
449 }
450
451 void
frame_set_icon(struct frame * frame,cairo_surface_t * icon)452 frame_set_icon(struct frame *frame, cairo_surface_t *icon)
453 {
454 struct frame_button *button;
455 wl_list_for_each(button, &frame->buttons, link) {
456 if (button->status_effect != FRAME_STATUS_MENU)
457 continue;
458 if (button->icon)
459 cairo_surface_destroy(button->icon);
460 button->icon = icon;
461 frame->status |= FRAME_STATUS_REPAINT;
462 }
463 }
464
465 void
frame_set_flag(struct frame * frame,enum frame_flag flag)466 frame_set_flag(struct frame *frame, enum frame_flag flag)
467 {
468 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
469 frame->geometry_dirty = 1;
470
471 frame->flags |= flag;
472 frame->status |= FRAME_STATUS_REPAINT;
473 }
474
475 void
frame_unset_flag(struct frame * frame,enum frame_flag flag)476 frame_unset_flag(struct frame *frame, enum frame_flag flag)
477 {
478 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
479 frame->geometry_dirty = 1;
480
481 frame->flags &= ~flag;
482 frame->status |= FRAME_STATUS_REPAINT;
483 }
484
485 void
frame_resize(struct frame * frame,int32_t width,int32_t height)486 frame_resize(struct frame *frame, int32_t width, int32_t height)
487 {
488 frame->width = width;
489 frame->height = height;
490
491 frame->geometry_dirty = 1;
492 frame->status |= FRAME_STATUS_REPAINT;
493 }
494
495 void
frame_resize_inside(struct frame * frame,int32_t width,int32_t height)496 frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
497 {
498 struct theme *t = frame->theme;
499 int decoration_width, decoration_height, titlebar_height;
500
501 if (frame->title || !wl_list_empty(&frame->buttons))
502 titlebar_height = t->titlebar_height;
503 else
504 titlebar_height = t->width;
505
506 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
507 decoration_width = t->width * 2;
508 decoration_height = t->width + titlebar_height;
509 } else {
510 decoration_width = (t->width + t->margin) * 2;
511 decoration_height = t->width +
512 titlebar_height + t->margin * 2;
513 }
514
515 frame_resize(frame, width + decoration_width,
516 height + decoration_height);
517 }
518
519 int32_t
frame_width(struct frame * frame)520 frame_width(struct frame *frame)
521 {
522 return frame->width;
523 }
524
525 int32_t
frame_height(struct frame * frame)526 frame_height(struct frame *frame)
527 {
528 return frame->height;
529 }
530
531 static void
frame_refresh_geometry(struct frame * frame)532 frame_refresh_geometry(struct frame *frame)
533 {
534 struct frame_button *button;
535 struct theme *t = frame->theme;
536 int x_l, x_r, y, w, h, titlebar_height;
537 int32_t decoration_width, decoration_height;
538
539 if (!frame->geometry_dirty)
540 return;
541
542 if (frame->title || !wl_list_empty(&frame->buttons))
543 titlebar_height = t->titlebar_height;
544 else
545 titlebar_height = t->width;
546
547 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
548 decoration_width = t->width * 2;
549 decoration_height = t->width + titlebar_height;
550
551 frame->interior.x = t->width;
552 frame->interior.y = titlebar_height;
553 frame->interior.width = frame->width - decoration_width;
554 frame->interior.height = frame->height - decoration_height;
555
556 frame->opaque_margin = 0;
557 frame->shadow_margin = 0;
558 } else {
559 decoration_width = (t->width + t->margin) * 2;
560 decoration_height = t->width + titlebar_height + t->margin * 2;
561
562 frame->interior.x = t->width + t->margin;
563 frame->interior.y = titlebar_height + t->margin;
564 frame->interior.width = frame->width - decoration_width;
565 frame->interior.height = frame->height - decoration_height;
566
567 frame->opaque_margin = t->margin + t->frame_radius;
568 frame->shadow_margin = t->margin;
569 }
570
571 x_r = frame->width - t->width - frame->shadow_margin;
572 x_l = t->width + frame->shadow_margin;
573 y = t->width + frame->shadow_margin;
574 wl_list_for_each(button, &frame->buttons, link) {
575 const int button_padding = 4;
576 w = cairo_image_surface_get_width(button->icon);
577 h = cairo_image_surface_get_height(button->icon);
578
579 if (button->flags & FRAME_BUTTON_DECORATED)
580 w += 10;
581
582 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
583 x_r -= w;
584
585 button->allocation.x = x_r;
586 button->allocation.y = y;
587 button->allocation.width = w + 1;
588 button->allocation.height = h + 1;
589
590 x_r -= button_padding;
591 } else {
592 button->allocation.x = x_l;
593 button->allocation.y = y;
594 button->allocation.width = w + 1;
595 button->allocation.height = h + 1;
596
597 x_l += w;
598 x_l += button_padding;
599 }
600 }
601
602 frame->title_rect.x = x_l;
603 frame->title_rect.y = y;
604 frame->title_rect.width = x_r - x_l;
605 frame->title_rect.height = titlebar_height;
606
607 frame->geometry_dirty = 0;
608 }
609
610 void
frame_interior(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)611 frame_interior(struct frame *frame, int32_t *x, int32_t *y,
612 int32_t *width, int32_t *height)
613 {
614 frame_refresh_geometry(frame);
615
616 if (x)
617 *x = frame->interior.x;
618 if (y)
619 *y = frame->interior.y;
620 if (width)
621 *width = frame->interior.width;
622 if (height)
623 *height = frame->interior.height;
624 }
625
626 void
frame_input_rect(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)627 frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
628 int32_t *width, int32_t *height)
629 {
630 frame_refresh_geometry(frame);
631
632 if (x)
633 *x = frame->shadow_margin;
634 if (y)
635 *y = frame->shadow_margin;
636 if (width)
637 *width = frame->width - frame->shadow_margin * 2;
638 if (height)
639 *height = frame->height - frame->shadow_margin * 2;
640 }
641
642 void
frame_opaque_rect(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)643 frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
644 int32_t *width, int32_t *height)
645 {
646 frame_refresh_geometry(frame);
647
648 if (x)
649 *x = frame->opaque_margin;
650 if (y)
651 *y = frame->opaque_margin;
652 if (width)
653 *width = frame->width - frame->opaque_margin * 2;
654 if (height)
655 *height = frame->height - frame->opaque_margin * 2;
656 }
657
658 int
frame_get_shadow_margin(struct frame * frame)659 frame_get_shadow_margin(struct frame *frame)
660 {
661 frame_refresh_geometry(frame);
662
663 return frame->shadow_margin;
664 }
665
666 uint32_t
frame_status(struct frame * frame)667 frame_status(struct frame *frame)
668 {
669 return frame->status;
670 }
671
672 void
frame_status_clear(struct frame * frame,enum frame_status status)673 frame_status_clear(struct frame *frame, enum frame_status status)
674 {
675 frame->status &= ~status;
676 }
677
678 static struct frame_button *
frame_find_button(struct frame * frame,int x,int y)679 frame_find_button(struct frame *frame, int x, int y)
680 {
681 struct frame_button *button;
682 int rel_x, rel_y;
683
684 wl_list_for_each(button, &frame->buttons, link) {
685 rel_x = x - button->allocation.x;
686 rel_y = y - button->allocation.y;
687
688 if (0 <= rel_x && rel_x < button->allocation.width &&
689 0 <= rel_y && rel_y < button->allocation.height)
690 return button;
691 }
692
693 return NULL;
694 }
695
696 enum theme_location
frame_pointer_enter(struct frame * frame,void * data,int x,int y)697 frame_pointer_enter(struct frame *frame, void *data, int x, int y)
698 {
699 return frame_pointer_motion(frame, data, x, y);
700 }
701
702 enum theme_location
frame_pointer_motion(struct frame * frame,void * data,int x,int y)703 frame_pointer_motion(struct frame *frame, void *data, int x, int y)
704 {
705 struct frame_pointer *pointer = frame_pointer_get(frame, data);
706 struct frame_button *button = frame_find_button(frame, x, y);
707 enum theme_location location;
708
709 location = theme_get_location(frame->theme, x, y,
710 frame->width, frame->height,
711 frame->flags & FRAME_FLAG_MAXIMIZED ?
712 THEME_FRAME_MAXIMIZED : 0);
713 if (!pointer)
714 return location;
715
716 pointer->x = x;
717 pointer->y = y;
718
719 if (pointer->hover_button == button)
720 return location;
721
722 if (pointer->hover_button)
723 frame_button_leave(pointer->hover_button, pointer);
724
725 pointer->hover_button = button;
726
727 if (pointer->hover_button)
728 frame_button_enter(pointer->hover_button);
729
730 return location;
731 }
732
733 static void
frame_pointer_button_destroy(struct frame_pointer_button * button)734 frame_pointer_button_destroy(struct frame_pointer_button *button)
735 {
736 wl_list_remove(&button->link);
737 free(button);
738 }
739
740 static void
frame_pointer_button_press(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)741 frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
742 struct frame_pointer_button *button)
743 {
744 if (button->button == BTN_RIGHT) {
745 if (button->press_location == THEME_LOCATION_TITLEBAR)
746 frame->status |= FRAME_STATUS_MENU;
747
748 frame_pointer_button_destroy(button);
749
750 } else if (button->button == BTN_LEFT) {
751 if (pointer->hover_button) {
752 frame_button_press(pointer->hover_button);
753 } else {
754 switch (button->press_location) {
755 case THEME_LOCATION_TITLEBAR:
756 frame->status |= FRAME_STATUS_MOVE;
757
758 frame_pointer_button_destroy(button);
759 break;
760 case THEME_LOCATION_RESIZING_TOP:
761 case THEME_LOCATION_RESIZING_BOTTOM:
762 case THEME_LOCATION_RESIZING_LEFT:
763 case THEME_LOCATION_RESIZING_RIGHT:
764 case THEME_LOCATION_RESIZING_TOP_LEFT:
765 case THEME_LOCATION_RESIZING_TOP_RIGHT:
766 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
767 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
768 frame->status |= FRAME_STATUS_RESIZE;
769
770 frame_pointer_button_destroy(button);
771 break;
772 default:
773 break;
774 }
775 }
776 }
777 }
778
779 static void
frame_pointer_button_release(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)780 frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
781 struct frame_pointer_button *button)
782 {
783 if (button->button == BTN_LEFT && button->frame_button) {
784 if (button->frame_button == pointer->hover_button)
785 frame_button_release(button->frame_button);
786 else
787 frame_button_cancel(button->frame_button);
788 }
789 }
790
791 static void
frame_pointer_button_cancel(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)792 frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
793 struct frame_pointer_button *button)
794 {
795 if (button->frame_button)
796 frame_button_cancel(button->frame_button);
797 }
798
799 void
frame_pointer_leave(struct frame * frame,void * data)800 frame_pointer_leave(struct frame *frame, void *data)
801 {
802 struct frame_pointer *pointer = frame_pointer_get(frame, data);
803 struct frame_pointer_button *button, *next;
804 if (!pointer)
805 return;
806
807 if (pointer->hover_button)
808 frame_button_leave(pointer->hover_button, pointer);
809
810 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
811 frame_pointer_button_cancel(frame, pointer, button);
812 frame_pointer_button_destroy(button);
813 }
814
815 frame_pointer_destroy(pointer);
816 }
817
818 enum theme_location
frame_pointer_button(struct frame * frame,void * data,uint32_t btn,enum wl_pointer_button_state state)819 frame_pointer_button(struct frame *frame, void *data,
820 uint32_t btn, enum wl_pointer_button_state state)
821 {
822 struct frame_pointer *pointer = frame_pointer_get(frame, data);
823 struct frame_pointer_button *button;
824 enum theme_location location = THEME_LOCATION_EXTERIOR;
825
826 if (!pointer)
827 return location;
828
829 location = theme_get_location(frame->theme, pointer->x, pointer->y,
830 frame->width, frame->height,
831 frame->flags & FRAME_FLAG_MAXIMIZED ?
832 THEME_FRAME_MAXIMIZED : 0);
833
834 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
835 button = malloc(sizeof *button);
836 if (!button)
837 return location;
838
839 button->button = btn;
840 button->press_location = location;
841 button->frame_button = pointer->hover_button;
842 wl_list_insert(&pointer->down_buttons, &button->link);
843
844 frame_pointer_button_press(frame, pointer, button);
845 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
846 button = NULL;
847 wl_list_for_each(button, &pointer->down_buttons, link)
848 if (button->button == btn)
849 break;
850 /* Make sure we didn't hit the end */
851 if (&button->link == &pointer->down_buttons)
852 return location;
853
854 location = button->press_location;
855 frame_pointer_button_release(frame, pointer, button);
856 frame_pointer_button_destroy(button);
857 }
858
859 return location;
860 }
861
862 enum theme_location
frame_touch_down(struct frame * frame,void * data,int32_t id,int x,int y)863 frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
864 {
865 struct frame_touch *touch = frame_touch_get(frame, data);
866 struct frame_button *button = frame_find_button(frame, x, y);
867 enum theme_location location;
868
869 location = theme_get_location(frame->theme, x, y,
870 frame->width, frame->height,
871 frame->flags & FRAME_FLAG_MAXIMIZED ?
872 THEME_FRAME_MAXIMIZED : 0);
873
874 if (id > 0)
875 return location;
876
877 if (touch && button) {
878 touch->button = button;
879 frame_button_press(touch->button);
880 return location;
881 }
882
883 switch (location) {
884 case THEME_LOCATION_TITLEBAR:
885 frame->status |= FRAME_STATUS_MOVE;
886 break;
887 case THEME_LOCATION_RESIZING_TOP:
888 case THEME_LOCATION_RESIZING_BOTTOM:
889 case THEME_LOCATION_RESIZING_LEFT:
890 case THEME_LOCATION_RESIZING_RIGHT:
891 case THEME_LOCATION_RESIZING_TOP_LEFT:
892 case THEME_LOCATION_RESIZING_TOP_RIGHT:
893 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
894 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
895 frame->status |= FRAME_STATUS_RESIZE;
896 break;
897 default:
898 break;
899 }
900 return location;
901 }
902
903 void
frame_touch_up(struct frame * frame,void * data,int32_t id)904 frame_touch_up(struct frame *frame, void *data, int32_t id)
905 {
906 struct frame_touch *touch = frame_touch_get(frame, data);
907
908 if (id > 0)
909 return;
910
911 if (touch && touch->button) {
912 frame_button_release(touch->button);
913 frame_touch_destroy(touch);
914 }
915 }
916
917 enum theme_location
frame_double_click(struct frame * frame,void * data,uint32_t btn,enum wl_pointer_button_state state)918 frame_double_click(struct frame *frame, void *data,
919 uint32_t btn, enum wl_pointer_button_state state)
920 {
921 struct frame_pointer *pointer = frame_pointer_get(frame, data);
922 struct frame_button *button;
923 enum theme_location location = THEME_LOCATION_EXTERIOR;
924
925 location = theme_get_location(frame->theme, pointer->x, pointer->y,
926 frame->width, frame->height,
927 frame->flags & FRAME_FLAG_MAXIMIZED ?
928 THEME_FRAME_MAXIMIZED : 0);
929
930 button = frame_find_button(frame, pointer->x, pointer->y);
931
932 if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
933 return location;
934
935 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
936 if (button)
937 frame_button_press(button);
938 else
939 frame->status |= FRAME_STATUS_MAXIMIZE;
940 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
941 if (button)
942 frame_button_release(button);
943 }
944
945 return location;
946 }
947
948 void
frame_double_touch_down(struct frame * frame,void * data,int32_t id,int x,int y)949 frame_double_touch_down(struct frame *frame, void *data, int32_t id,
950 int x, int y)
951 {
952 struct frame_touch *touch = frame_touch_get(frame, data);
953 struct frame_button *button = frame_find_button(frame, x, y);
954 enum theme_location location;
955
956 if (touch && button) {
957 touch->button = button;
958 frame_button_press(touch->button);
959 return;
960 }
961
962 location = theme_get_location(frame->theme, x, y,
963 frame->width, frame->height,
964 frame->flags & FRAME_FLAG_MAXIMIZED ?
965 THEME_FRAME_MAXIMIZED : 0);
966
967 switch (location) {
968 case THEME_LOCATION_TITLEBAR:
969 frame->status |= FRAME_STATUS_MAXIMIZE;
970 break;
971 case THEME_LOCATION_RESIZING_TOP:
972 case THEME_LOCATION_RESIZING_BOTTOM:
973 case THEME_LOCATION_RESIZING_LEFT:
974 case THEME_LOCATION_RESIZING_RIGHT:
975 case THEME_LOCATION_RESIZING_TOP_LEFT:
976 case THEME_LOCATION_RESIZING_TOP_RIGHT:
977 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
978 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
979 frame->status |= FRAME_STATUS_RESIZE;
980 break;
981 default:
982 break;
983 }
984 }
985
986 void
frame_double_touch_up(struct frame * frame,void * data,int32_t id)987 frame_double_touch_up(struct frame *frame, void *data, int32_t id)
988 {
989 struct frame_touch *touch = frame_touch_get(frame, data);
990
991 if (touch && touch->button) {
992 frame_button_release(touch->button);
993 frame_touch_destroy(touch);
994 }
995 }
996
997 void
frame_repaint(struct frame * frame,cairo_t * cr)998 frame_repaint(struct frame *frame, cairo_t *cr)
999 {
1000 struct frame_button *button;
1001 uint32_t flags = 0;
1002
1003 frame_refresh_geometry(frame);
1004
1005 if (frame->flags & FRAME_FLAG_MAXIMIZED)
1006 flags |= THEME_FRAME_MAXIMIZED;
1007
1008 if (frame->flags & FRAME_FLAG_ACTIVE)
1009 flags |= THEME_FRAME_ACTIVE;
1010
1011 cairo_save(cr);
1012 theme_render_frame(frame->theme, cr, frame->width, frame->height,
1013 frame->title, &frame->title_rect,
1014 &frame->buttons, flags);
1015 cairo_restore(cr);
1016
1017 wl_list_for_each(button, &frame->buttons, link)
1018 frame_button_repaint(button, cr);
1019
1020 frame_status_clear(frame, FRAME_STATUS_REPAINT);
1021 }
1022