blob: 2f24f82ea9f46400e0e56fca9d38efc38c9ad6ee [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
388 frame->status |= FRAME_STATUS_REPAINT;
389
390 return 0;
391}
392
393void
394frame_set_flag(struct frame *frame, enum frame_flag flag)
395{
396 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
397 frame->geometry_dirty = 1;
398
399 frame->flags |= flag;
400 frame->status |= FRAME_STATUS_REPAINT;
401}
402
403void
404frame_unset_flag(struct frame *frame, enum frame_flag flag)
405{
406 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
407 frame->geometry_dirty = 1;
408
409 frame->flags &= ~flag;
410 frame->status |= FRAME_STATUS_REPAINT;
411}
412
413void
414frame_resize(struct frame *frame, int32_t width, int32_t height)
415{
416 frame->width = width;
417 frame->height = height;
418
419 frame->geometry_dirty = 1;
420 frame->status |= FRAME_STATUS_REPAINT;
421}
422
423void
424frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
425{
426 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700427 int decoration_width, decoration_height, titlebar_height;
428
429 if (frame->title)
430 titlebar_height = t->titlebar_height;
431 else
432 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500433
434 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
435 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700436 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500437 } else {
438 decoration_width = (t->width + t->margin) * 2;
439 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700440 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500441 }
442
443 frame_resize(frame, width + decoration_width,
444 height + decoration_height);
445}
446
447int32_t
448frame_width(struct frame *frame)
449{
450 return frame->width;
451}
452
453int32_t
454frame_height(struct frame *frame)
455{
456 return frame->height;
457}
458
459static void
460frame_refresh_geometry(struct frame *frame)
461{
462 struct frame_button *button;
463 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700464 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500465 int32_t decoration_width, decoration_height;
466
467 if (!frame->geometry_dirty)
468 return;
469
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700470 if (frame->title)
471 titlebar_height = t->titlebar_height;
472 else
473 titlebar_height = t->width;
474
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500475 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
476 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700477 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500478
479 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700480 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500481 frame->interior.width = frame->width - decoration_width;
482 frame->interior.height = frame->height - decoration_height;
483
484 frame->opaque_margin = 0;
485 frame->shadow_margin = 0;
486 } else {
487 decoration_width = (t->width + t->margin) * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700488 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500489
490 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700491 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500492 frame->interior.width = frame->width - decoration_width;
493 frame->interior.height = frame->height - decoration_height;
494
495 frame->opaque_margin = t->margin + t->frame_radius;
496 frame->shadow_margin = t->margin;
497 }
498
499 x_r = frame->width - t->width - frame->shadow_margin;
500 x_l = t->width + frame->shadow_margin;
501 y = t->width + frame->shadow_margin;
502 wl_list_for_each(button, &frame->buttons, link) {
503 const int button_padding = 4;
504 w = cairo_image_surface_get_width(button->icon);
505 h = cairo_image_surface_get_height(button->icon);
506
507 if (button->flags & FRAME_BUTTON_DECORATED)
508 w += 10;
509
510 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
511 x_r -= w;
512
513 button->allocation.x = x_r;
514 button->allocation.y = y;
515 button->allocation.width = w + 1;
516 button->allocation.height = h + 1;
517
518 x_r -= button_padding;
519 } else {
520 button->allocation.x = x_l;
521 button->allocation.y = y;
522 button->allocation.width = w + 1;
523 button->allocation.height = h + 1;
524
525 x_l += w;
526 x_l += button_padding;
527 }
528 }
529
530 frame->geometry_dirty = 0;
531}
532
533void
534frame_interior(struct frame *frame, int32_t *x, int32_t *y,
535 int32_t *width, int32_t *height)
536{
537 frame_refresh_geometry(frame);
538
539 if (x)
540 *x = frame->interior.x;
541 if (y)
542 *y = frame->interior.y;
543 if (width)
544 *width = frame->interior.width;
545 if (height)
546 *height = frame->interior.height;
547}
548
549void
550frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
551 int32_t *width, int32_t *height)
552{
553 frame_refresh_geometry(frame);
554
555 if (x)
556 *x = frame->shadow_margin;
557 if (y)
558 *y = frame->shadow_margin;
559 if (width)
560 *width = frame->width - frame->shadow_margin * 2;
561 if (height)
562 *height = frame->height - frame->shadow_margin * 2;
563}
564
565void
566frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
567 int32_t *width, int32_t *height)
568{
569 frame_refresh_geometry(frame);
570
571 if (x)
572 *x = frame->opaque_margin;
573 if (y)
574 *y = frame->opaque_margin;
575 if (width)
576 *width = frame->width - frame->opaque_margin * 2;
577 if (height)
578 *height = frame->height - frame->opaque_margin * 2;
579}
580
581uint32_t
582frame_status(struct frame *frame)
583{
584 return frame->status;
585}
586
587void
588frame_status_clear(struct frame *frame, enum frame_status status)
589{
590 frame->status &= ~status;
591}
592
593static struct frame_button *
594frame_find_button(struct frame *frame, int x, int y)
595{
596 struct frame_button *button;
597 int rel_x, rel_y;
598
599 wl_list_for_each(button, &frame->buttons, link) {
600 rel_x = x - button->allocation.x;
601 rel_y = y - button->allocation.y;
602
603 if (0 <= rel_x && rel_x < button->allocation.width &&
604 0 <= rel_y && rel_y < button->allocation.height)
605 return button;
606 }
607
608 return NULL;
609}
610
611enum theme_location
612frame_pointer_enter(struct frame *frame, void *data, int x, int y)
613{
614 return frame_pointer_motion(frame, data, x, y);
615}
616
617enum theme_location
618frame_pointer_motion(struct frame *frame, void *data, int x, int y)
619{
620 struct frame_pointer *pointer = frame_pointer_get(frame, data);
621 struct frame_button *button = frame_find_button(frame, x, y);
622 enum theme_location location;
623
624 location = theme_get_location(frame->theme, x, y,
625 frame->width, frame->height,
626 frame->flags & FRAME_FLAG_MAXIMIZED ?
627 THEME_FRAME_MAXIMIZED : 0);
628 if (!pointer)
629 return location;
630
631 pointer->x = x;
632 pointer->y = y;
633
634 if (pointer->hover_button == button)
635 return location;
636
637 if (pointer->hover_button)
638 frame_button_leave(pointer->hover_button, pointer);
639
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500640 pointer->hover_button = button;
641
642 if (pointer->hover_button)
643 frame_button_enter(pointer->hover_button);
644
645 return location;
646}
647
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500648static void
649frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500650{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500651 wl_list_remove(&button->link);
652 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500653}
654
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500655static void
656frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
657 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500658{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500659 if (button->button == BTN_RIGHT) {
660 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500661 frame->status |= FRAME_STATUS_MENU;
662
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500663 frame_pointer_button_destroy(button);
664
665 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500666 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500667 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500668 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500669 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500670 case THEME_LOCATION_TITLEBAR:
671 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500672
673 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500674 break;
675 case THEME_LOCATION_RESIZING_TOP:
676 case THEME_LOCATION_RESIZING_BOTTOM:
677 case THEME_LOCATION_RESIZING_LEFT:
678 case THEME_LOCATION_RESIZING_RIGHT:
679 case THEME_LOCATION_RESIZING_TOP_LEFT:
680 case THEME_LOCATION_RESIZING_TOP_RIGHT:
681 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
682 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
683 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500684
685 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500686 break;
687 default:
688 break;
689 }
690 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500691 }
692}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500693
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500694static void
695frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
696 struct frame_pointer_button *button)
697{
698 if (button->button == BTN_LEFT && button->frame_button) {
699 if (button->frame_button == pointer->hover_button)
700 frame_button_release(button->frame_button);
701 else
702 frame_button_cancel(button->frame_button);
703 }
704}
705
706static void
707frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
708 struct frame_pointer_button *button)
709{
710 if (button->frame_button)
711 frame_button_cancel(button->frame_button);
712}
713
714void
715frame_pointer_leave(struct frame *frame, void *data)
716{
717 struct frame_pointer *pointer = frame_pointer_get(frame, data);
718 struct frame_pointer_button *button, *next;
719 if (!pointer)
720 return;
721
722 if (pointer->hover_button)
723 frame_button_leave(pointer->hover_button, pointer);
724
725 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
726 frame_pointer_button_cancel(frame, pointer, button);
727 frame_pointer_button_destroy(button);
728 }
729
730 frame_pointer_destroy(pointer);
731}
732
733enum theme_location
734frame_pointer_button(struct frame *frame, void *data,
735 uint32_t btn, enum frame_button_state state)
736{
737 struct frame_pointer *pointer = frame_pointer_get(frame, data);
738 struct frame_pointer_button *button;
739 enum theme_location location;
740
741 location = theme_get_location(frame->theme, pointer->x, pointer->y,
742 frame->width, frame->height,
743 frame->flags & FRAME_FLAG_MAXIMIZED ?
744 THEME_FRAME_MAXIMIZED : 0);
745
746 if (!pointer)
747 return location;
748
749 if (state == FRAME_BUTTON_PRESSED) {
750 button = malloc(sizeof *button);
751 if (!button)
752 return location;
753
754 button->button = btn;
755 button->press_location = location;
756 button->frame_button = pointer->hover_button;
757 wl_list_insert(&pointer->down_buttons, &button->link);
758
759 frame_pointer_button_press(frame, pointer, button);
760 } else if (state == FRAME_BUTTON_RELEASED) {
761 button = NULL;
762 wl_list_for_each(button, &pointer->down_buttons, link)
763 if (button->button == btn)
764 break;
765 /* Make sure we didn't hit the end */
766 if (&button->link == &pointer->down_buttons)
767 return location;
768
769 location = button->press_location;
770 frame_pointer_button_release(frame, pointer, button);
771 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500772 }
773
774 return location;
775}
776
777void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500778frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
779{
780 struct frame_touch *touch = frame_touch_get(frame, data);
781 struct frame_button *button = frame_find_button(frame, x, y);
782 enum theme_location location;
783
784 if (id > 0)
785 return;
786
787 if (button) {
788 touch->button = button;
789 frame_button_press(touch->button);
790 return;
791 }
792
793 location = theme_get_location(frame->theme, x, y,
794 frame->width, frame->height,
795 frame->flags & FRAME_FLAG_MAXIMIZED ?
796 THEME_FRAME_MAXIMIZED : 0);
797
798 switch (location) {
799 case THEME_LOCATION_TITLEBAR:
800 frame->status |= FRAME_STATUS_MOVE;
801 break;
802 case THEME_LOCATION_RESIZING_TOP:
803 case THEME_LOCATION_RESIZING_BOTTOM:
804 case THEME_LOCATION_RESIZING_LEFT:
805 case THEME_LOCATION_RESIZING_RIGHT:
806 case THEME_LOCATION_RESIZING_TOP_LEFT:
807 case THEME_LOCATION_RESIZING_TOP_RIGHT:
808 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
809 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
810 frame->status |= FRAME_STATUS_RESIZE;
811 break;
812 default:
813 break;
814 }
815}
816
817void
818frame_touch_up(struct frame *frame, void *data, int32_t id)
819{
820 struct frame_touch *touch = frame_touch_get(frame, data);
821
822 if (id > 0)
823 return;
824
825 if (touch->button) {
826 frame_button_release(touch->button);
827 frame_touch_destroy(touch);
828 return;
829 }
830}
831
832void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500833frame_repaint(struct frame *frame, cairo_t *cr)
834{
835 struct frame_button *button;
836 uint32_t flags = 0;
837
838 frame_refresh_geometry(frame);
839
840 if (frame->flags & FRAME_FLAG_MAXIMIZED)
841 flags |= THEME_FRAME_MAXIMIZED;
842
843 if (frame->flags & FRAME_FLAG_ACTIVE)
844 flags |= THEME_FRAME_ACTIVE;
845
846 cairo_save(cr);
847 theme_render_frame(frame->theme, cr, frame->width, frame->height,
848 frame->title, flags);
849 cairo_restore(cr);
850
851 wl_list_for_each(button, &frame->buttons, link)
852 frame_button_repaint(button, cr);
853
854 frame_status_clear(frame, FRAME_STATUS_REPAINT);
855}