blob: 35e6b65ea1095aa8232c5a60d2d894444aea2684 [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
Jasper St. Pierre74073452014-02-01 18:36:41 -0500581int
582frame_get_shadow_margin(struct frame *frame)
583{
584 frame_refresh_geometry(frame);
585
586 return frame->shadow_margin;
587}
588
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500589uint32_t
590frame_status(struct frame *frame)
591{
592 return frame->status;
593}
594
595void
596frame_status_clear(struct frame *frame, enum frame_status status)
597{
598 frame->status &= ~status;
599}
600
601static struct frame_button *
602frame_find_button(struct frame *frame, int x, int y)
603{
604 struct frame_button *button;
605 int rel_x, rel_y;
606
607 wl_list_for_each(button, &frame->buttons, link) {
608 rel_x = x - button->allocation.x;
609 rel_y = y - button->allocation.y;
610
611 if (0 <= rel_x && rel_x < button->allocation.width &&
612 0 <= rel_y && rel_y < button->allocation.height)
613 return button;
614 }
615
616 return NULL;
617}
618
619enum theme_location
620frame_pointer_enter(struct frame *frame, void *data, int x, int y)
621{
622 return frame_pointer_motion(frame, data, x, y);
623}
624
625enum theme_location
626frame_pointer_motion(struct frame *frame, void *data, int x, int y)
627{
628 struct frame_pointer *pointer = frame_pointer_get(frame, data);
629 struct frame_button *button = frame_find_button(frame, x, y);
630 enum theme_location location;
631
632 location = theme_get_location(frame->theme, x, y,
633 frame->width, frame->height,
634 frame->flags & FRAME_FLAG_MAXIMIZED ?
635 THEME_FRAME_MAXIMIZED : 0);
636 if (!pointer)
637 return location;
638
639 pointer->x = x;
640 pointer->y = y;
641
642 if (pointer->hover_button == button)
643 return location;
644
645 if (pointer->hover_button)
646 frame_button_leave(pointer->hover_button, pointer);
647
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500648 pointer->hover_button = button;
649
650 if (pointer->hover_button)
651 frame_button_enter(pointer->hover_button);
652
653 return location;
654}
655
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500656static void
657frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500658{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500659 wl_list_remove(&button->link);
660 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500661}
662
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500663static void
664frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
665 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500666{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500667 if (button->button == BTN_RIGHT) {
668 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500669 frame->status |= FRAME_STATUS_MENU;
670
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500671 frame_pointer_button_destroy(button);
672
673 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500674 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500675 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500676 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500677 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500678 case THEME_LOCATION_TITLEBAR:
679 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500680
681 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500682 break;
683 case THEME_LOCATION_RESIZING_TOP:
684 case THEME_LOCATION_RESIZING_BOTTOM:
685 case THEME_LOCATION_RESIZING_LEFT:
686 case THEME_LOCATION_RESIZING_RIGHT:
687 case THEME_LOCATION_RESIZING_TOP_LEFT:
688 case THEME_LOCATION_RESIZING_TOP_RIGHT:
689 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
690 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
691 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500692
693 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500694 break;
695 default:
696 break;
697 }
698 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500699 }
700}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500701
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500702static void
703frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
704 struct frame_pointer_button *button)
705{
706 if (button->button == BTN_LEFT && button->frame_button) {
707 if (button->frame_button == pointer->hover_button)
708 frame_button_release(button->frame_button);
709 else
710 frame_button_cancel(button->frame_button);
711 }
712}
713
714static void
715frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
716 struct frame_pointer_button *button)
717{
718 if (button->frame_button)
719 frame_button_cancel(button->frame_button);
720}
721
722void
723frame_pointer_leave(struct frame *frame, void *data)
724{
725 struct frame_pointer *pointer = frame_pointer_get(frame, data);
726 struct frame_pointer_button *button, *next;
727 if (!pointer)
728 return;
729
730 if (pointer->hover_button)
731 frame_button_leave(pointer->hover_button, pointer);
732
733 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
734 frame_pointer_button_cancel(frame, pointer, button);
735 frame_pointer_button_destroy(button);
736 }
737
738 frame_pointer_destroy(pointer);
739}
740
741enum theme_location
742frame_pointer_button(struct frame *frame, void *data,
743 uint32_t btn, enum frame_button_state state)
744{
745 struct frame_pointer *pointer = frame_pointer_get(frame, data);
746 struct frame_pointer_button *button;
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800747 enum theme_location location = THEME_LOCATION_EXTERIOR;
748
749 if (!pointer)
750 return location;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500751
752 location = theme_get_location(frame->theme, pointer->x, pointer->y,
753 frame->width, frame->height,
754 frame->flags & FRAME_FLAG_MAXIMIZED ?
755 THEME_FRAME_MAXIMIZED : 0);
756
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500757 if (state == FRAME_BUTTON_PRESSED) {
758 button = malloc(sizeof *button);
759 if (!button)
760 return location;
761
762 button->button = btn;
763 button->press_location = location;
764 button->frame_button = pointer->hover_button;
765 wl_list_insert(&pointer->down_buttons, &button->link);
766
767 frame_pointer_button_press(frame, pointer, button);
768 } else if (state == FRAME_BUTTON_RELEASED) {
769 button = NULL;
770 wl_list_for_each(button, &pointer->down_buttons, link)
771 if (button->button == btn)
772 break;
773 /* Make sure we didn't hit the end */
774 if (&button->link == &pointer->down_buttons)
775 return location;
776
777 location = button->press_location;
778 frame_pointer_button_release(frame, pointer, button);
779 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500780 }
781
782 return location;
783}
784
785void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500786frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
787{
788 struct frame_touch *touch = frame_touch_get(frame, data);
789 struct frame_button *button = frame_find_button(frame, x, y);
790 enum theme_location location;
791
792 if (id > 0)
793 return;
794
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800795 if (touch && button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500796 touch->button = button;
797 frame_button_press(touch->button);
798 return;
799 }
800
801 location = theme_get_location(frame->theme, x, y,
802 frame->width, frame->height,
803 frame->flags & FRAME_FLAG_MAXIMIZED ?
804 THEME_FRAME_MAXIMIZED : 0);
805
806 switch (location) {
807 case THEME_LOCATION_TITLEBAR:
808 frame->status |= FRAME_STATUS_MOVE;
809 break;
810 case THEME_LOCATION_RESIZING_TOP:
811 case THEME_LOCATION_RESIZING_BOTTOM:
812 case THEME_LOCATION_RESIZING_LEFT:
813 case THEME_LOCATION_RESIZING_RIGHT:
814 case THEME_LOCATION_RESIZING_TOP_LEFT:
815 case THEME_LOCATION_RESIZING_TOP_RIGHT:
816 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
817 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
818 frame->status |= FRAME_STATUS_RESIZE;
819 break;
820 default:
821 break;
822 }
823}
824
825void
826frame_touch_up(struct frame *frame, void *data, int32_t id)
827{
828 struct frame_touch *touch = frame_touch_get(frame, data);
829
830 if (id > 0)
831 return;
832
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800833 if (touch && touch->button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500834 frame_button_release(touch->button);
835 frame_touch_destroy(touch);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500836 }
837}
838
839void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500840frame_repaint(struct frame *frame, cairo_t *cr)
841{
842 struct frame_button *button;
843 uint32_t flags = 0;
844
845 frame_refresh_geometry(frame);
846
847 if (frame->flags & FRAME_FLAG_MAXIMIZED)
848 flags |= THEME_FRAME_MAXIMIZED;
849
850 if (frame->flags & FRAME_FLAG_ACTIVE)
851 flags |= THEME_FRAME_ACTIVE;
852
853 cairo_save(cr);
854 theme_render_frame(frame->theme, cr, frame->width, frame->height,
855 frame->title, flags);
856 cairo_restore(cr);
857
858 wl_list_for_each(button, &frame->buttons, link)
859 frame_button_repaint(button, cr);
860
861 frame_status_clear(frame, FRAME_STATUS_REPAINT);
862}