blob: 5ca7e08b820bae86268ddd7568a6c9b3ccb10d7d [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 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -07006 * 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:
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050013 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -070014 * 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.
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050026 */
27
28#include "config.h"
29
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050031#include <stdlib.h>
32#include <string.h>
33#include <wayland-util.h>
34#include <linux/input.h>
35
36#include "cairo-util.h"
37
38enum frame_button_flags {
39 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
40 FRAME_BUTTON_DECORATED = 0x2,
41 FRAME_BUTTON_CLICK_DOWN = 0x4,
42};
43
44struct frame_button {
45 struct frame *frame;
46 struct wl_list link; /* buttons_list */
47
48 cairo_surface_t *icon;
49 enum frame_button_flags flags;
50 int hover_count;
51 int press_count;
52
53 struct {
54 int x, y;
55 int width, height;
56 } allocation;
57
58 enum frame_status status_effect;
59};
60
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050061struct frame_pointer_button {
62 struct wl_list link;
63 uint32_t button;
64 enum theme_location press_location;
65 struct frame_button *frame_button;
66};
67
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050068struct frame_pointer {
69 struct wl_list link;
70 void *data;
71
72 int x, y;
73
74 struct frame_button *hover_button;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050075 struct wl_list down_buttons;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050076};
77
Jason Ekstrand3f66cf92013-10-13 19:08:40 -050078struct frame_touch {
79 struct wl_list link;
80 void *data;
81
82 int x, y;
83
84 struct frame_button *button;
85};
86
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050087struct frame {
88 int32_t width, height;
89 char *title;
90 uint32_t flags;
91 struct theme *theme;
92
93 struct {
94 int32_t x, y;
95 int32_t width, height;
96 } interior;
97 int shadow_margin;
98 int opaque_margin;
99 int geometry_dirty;
100
Louis-Francis Ratté-Boulianne864e39b2017-11-13 16:20:55 -0500101 cairo_rectangle_int_t title_rect;
102
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500103 uint32_t status;
104
105 struct wl_list buttons;
106 struct wl_list pointers;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500107 struct wl_list touches;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500108};
109
110static struct frame_button *
111frame_button_create(struct frame *frame, const char *icon,
112 enum frame_status status_effect,
113 enum frame_button_flags flags)
114{
115 struct frame_button *button;
116
117 button = calloc(1, sizeof *button);
118 if (!button)
119 return NULL;
120
121 button->icon = cairo_image_surface_create_from_png(icon);
122 if (!button->icon) {
123 free(button);
124 return NULL;
125 }
126
127 button->frame = frame;
128 button->flags = flags;
129 button->status_effect = status_effect;
130
131 wl_list_insert(frame->buttons.prev, &button->link);
132
133 return button;
134}
135
136static void
137frame_button_destroy(struct frame_button *button)
138{
139 cairo_surface_destroy(button->icon);
140 free(button);
141}
142
143static void
144frame_button_enter(struct frame_button *button)
145{
146 if (!button->hover_count)
147 button->frame->status |= FRAME_STATUS_REPAINT;
148 button->hover_count++;
149}
150
151static void
152frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
153{
154 button->hover_count--;
155 if (!button->hover_count)
156 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500157}
158
159static void
160frame_button_press(struct frame_button *button)
161{
162 if (!button->press_count)
163 button->frame->status |= FRAME_STATUS_REPAINT;
164 button->press_count++;
165
166 if (button->flags & FRAME_BUTTON_CLICK_DOWN)
167 button->frame->status |= button->status_effect;
168}
169
170static void
171frame_button_release(struct frame_button *button)
172{
173 button->press_count--;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500174 if (button->press_count)
175 return;
176
177 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500178
179 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
180 button->frame->status |= button->status_effect;
181}
182
183static void
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500184frame_button_cancel(struct frame_button *button)
185{
186 button->press_count--;
187 if (!button->press_count)
188 button->frame->status |= FRAME_STATUS_REPAINT;
189}
190
191static void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500192frame_button_repaint(struct frame_button *button, cairo_t *cr)
193{
194 int x, y;
195
196 if (!button->allocation.width)
197 return;
198 if (!button->allocation.height)
199 return;
200
201 x = button->allocation.x;
202 y = button->allocation.y;
203
204 cairo_save(cr);
205
206 if (button->flags & FRAME_BUTTON_DECORATED) {
207 cairo_set_line_width(cr, 1);
208
209 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
210 cairo_rectangle(cr, x, y, 25, 16);
211
212 cairo_stroke_preserve(cr);
213
214 if (button->press_count) {
215 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
216 } else if (button->hover_count) {
217 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
218 } else {
219 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
220 }
221
222 cairo_fill (cr);
223
224 x += 4;
225 }
226
227 cairo_set_source_surface(cr, button->icon, x, y);
228 cairo_paint(cr);
229
230 cairo_restore(cr);
231}
232
233static struct frame_pointer *
234frame_pointer_get(struct frame *frame, void *data)
235{
236 struct frame_pointer *pointer;
237
238 wl_list_for_each(pointer, &frame->pointers, link)
239 if (pointer->data == data)
240 return pointer;
241
242 pointer = calloc(1, sizeof *pointer);
243 if (!pointer)
244 return NULL;
245
246 pointer->data = data;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500247 wl_list_init(&pointer->down_buttons);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500248 wl_list_insert(&frame->pointers, &pointer->link);
249
250 return pointer;
251}
252
253static void
254frame_pointer_destroy(struct frame_pointer *pointer)
255{
256 wl_list_remove(&pointer->link);
257 free(pointer);
258}
259
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500260static struct frame_touch *
261frame_touch_get(struct frame *frame, void *data)
262{
263 struct frame_touch *touch;
264
265 wl_list_for_each(touch, &frame->touches, link)
266 if (touch->data == data)
267 return touch;
268
269 touch = calloc(1, sizeof *touch);
270 if (!touch)
271 return NULL;
272
273 touch->data = data;
274 wl_list_insert(&frame->touches, &touch->link);
275
276 return touch;
277}
278
279static void
280frame_touch_destroy(struct frame_touch *touch)
281{
282 wl_list_remove(&touch->link);
283 free(touch);
284}
285
U. Artie Eoff107de962014-01-17 11:19:46 -0800286void
287frame_destroy(struct frame *frame)
288{
289 struct frame_button *button, *next;
290 struct frame_touch *touch, *next_touch;
291 struct frame_pointer *pointer, *next_pointer;
292
293 wl_list_for_each_safe(button, next, &frame->buttons, link)
294 frame_button_destroy(button);
295
296 wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
297 frame_touch_destroy(touch);
298
299 wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
300 frame_pointer_destroy(pointer);
301
302 free(frame->title);
303 free(frame);
304}
305
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500306struct frame *
307frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
308 const char *title)
309{
310 struct frame *frame;
311 struct frame_button *button;
312
313 frame = calloc(1, sizeof *frame);
314 if (!frame)
315 return NULL;
316
317 frame->width = width;
318 frame->height = height;
319 frame->flags = 0;
320 frame->theme = t;
321 frame->status = FRAME_STATUS_REPAINT;
322 frame->geometry_dirty = 1;
323
U. Artie Eoff107de962014-01-17 11:19:46 -0800324 wl_list_init(&frame->buttons);
325 wl_list_init(&frame->pointers);
326 wl_list_init(&frame->touches);
327
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500328 if (title) {
329 frame->title = strdup(title);
330 if (!frame->title)
331 goto free_frame;
332 }
333
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700334 if (title) {
335 button = frame_button_create(frame,
336 DATADIR "/weston/icon_window.png",
337 FRAME_STATUS_MENU,
338 FRAME_BUTTON_CLICK_DOWN);
339 if (!button)
340 goto free_frame;
341 }
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500342
343 if (buttons & FRAME_BUTTON_CLOSE) {
344 button = frame_button_create(frame,
345 DATADIR "/weston/sign_close.png",
346 FRAME_STATUS_CLOSE,
347 FRAME_BUTTON_ALIGN_RIGHT |
348 FRAME_BUTTON_DECORATED);
349 if (!button)
350 goto free_frame;
351 }
352
353 if (buttons & FRAME_BUTTON_MAXIMIZE) {
354 button = frame_button_create(frame,
355 DATADIR "/weston/sign_maximize.png",
356 FRAME_STATUS_MAXIMIZE,
357 FRAME_BUTTON_ALIGN_RIGHT |
358 FRAME_BUTTON_DECORATED);
359 if (!button)
360 goto free_frame;
361 }
362
363 if (buttons & FRAME_BUTTON_MINIMIZE) {
364 button = frame_button_create(frame,
365 DATADIR "/weston/sign_minimize.png",
366 FRAME_STATUS_MINIMIZE,
367 FRAME_BUTTON_ALIGN_RIGHT |
368 FRAME_BUTTON_DECORATED);
369 if (!button)
370 goto free_frame;
371 }
372
373 return frame;
374
375free_frame:
U. Artie Eoff107de962014-01-17 11:19:46 -0800376 frame_destroy(frame);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500377 return NULL;
378}
379
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500380int
381frame_set_title(struct frame *frame, const char *title)
382{
383 char *dup = NULL;
384
385 if (title) {
386 dup = strdup(title);
387 if (!dup)
388 return -1;
389 }
390
391 free(frame->title);
392 frame->title = dup;
393
Boyan Ding9c5aedf2014-07-04 15:19:23 +0800394 frame->geometry_dirty = 1;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500395 frame->status |= FRAME_STATUS_REPAINT;
396
397 return 0;
398}
399
400void
401frame_set_flag(struct frame *frame, enum frame_flag flag)
402{
403 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
404 frame->geometry_dirty = 1;
405
406 frame->flags |= flag;
407 frame->status |= FRAME_STATUS_REPAINT;
408}
409
410void
411frame_unset_flag(struct frame *frame, enum frame_flag flag)
412{
413 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
414 frame->geometry_dirty = 1;
415
416 frame->flags &= ~flag;
417 frame->status |= FRAME_STATUS_REPAINT;
418}
419
420void
421frame_resize(struct frame *frame, int32_t width, int32_t height)
422{
423 frame->width = width;
424 frame->height = height;
425
426 frame->geometry_dirty = 1;
427 frame->status |= FRAME_STATUS_REPAINT;
428}
429
430void
431frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
432{
433 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700434 int decoration_width, decoration_height, titlebar_height;
435
Boyan Dingc4902122014-07-04 15:19:22 +0800436 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700437 titlebar_height = t->titlebar_height;
438 else
439 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500440
441 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
442 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700443 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500444 } else {
445 decoration_width = (t->width + t->margin) * 2;
446 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700447 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500448 }
449
450 frame_resize(frame, width + decoration_width,
451 height + decoration_height);
452}
453
454int32_t
455frame_width(struct frame *frame)
456{
457 return frame->width;
458}
459
460int32_t
461frame_height(struct frame *frame)
462{
463 return frame->height;
464}
465
466static void
467frame_refresh_geometry(struct frame *frame)
468{
469 struct frame_button *button;
470 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700471 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500472 int32_t decoration_width, decoration_height;
473
474 if (!frame->geometry_dirty)
475 return;
476
Boyan Dingc4902122014-07-04 15:19:22 +0800477 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700478 titlebar_height = t->titlebar_height;
479 else
480 titlebar_height = t->width;
481
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500482 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
483 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700484 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500485
486 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700487 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500488 frame->interior.width = frame->width - decoration_width;
489 frame->interior.height = frame->height - decoration_height;
490
491 frame->opaque_margin = 0;
492 frame->shadow_margin = 0;
493 } else {
494 decoration_width = (t->width + t->margin) * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700495 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500496
497 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700498 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500499 frame->interior.width = frame->width - decoration_width;
500 frame->interior.height = frame->height - decoration_height;
501
502 frame->opaque_margin = t->margin + t->frame_radius;
503 frame->shadow_margin = t->margin;
504 }
505
506 x_r = frame->width - t->width - frame->shadow_margin;
507 x_l = t->width + frame->shadow_margin;
508 y = t->width + frame->shadow_margin;
509 wl_list_for_each(button, &frame->buttons, link) {
510 const int button_padding = 4;
511 w = cairo_image_surface_get_width(button->icon);
512 h = cairo_image_surface_get_height(button->icon);
513
514 if (button->flags & FRAME_BUTTON_DECORATED)
515 w += 10;
516
517 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
518 x_r -= w;
519
520 button->allocation.x = x_r;
521 button->allocation.y = y;
522 button->allocation.width = w + 1;
523 button->allocation.height = h + 1;
524
525 x_r -= button_padding;
526 } else {
527 button->allocation.x = x_l;
528 button->allocation.y = y;
529 button->allocation.width = w + 1;
530 button->allocation.height = h + 1;
531
532 x_l += w;
533 x_l += button_padding;
534 }
535 }
536
Louis-Francis Ratté-Boulianne864e39b2017-11-13 16:20:55 -0500537 frame->title_rect.x = x_l;
538 frame->title_rect.y = y;
539 frame->title_rect.width = x_r - x_l;
540 frame->title_rect.height = titlebar_height;
541
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500542 frame->geometry_dirty = 0;
543}
544
545void
546frame_interior(struct frame *frame, int32_t *x, int32_t *y,
547 int32_t *width, int32_t *height)
548{
549 frame_refresh_geometry(frame);
550
551 if (x)
552 *x = frame->interior.x;
553 if (y)
554 *y = frame->interior.y;
555 if (width)
556 *width = frame->interior.width;
557 if (height)
558 *height = frame->interior.height;
559}
560
561void
562frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
563 int32_t *width, int32_t *height)
564{
565 frame_refresh_geometry(frame);
566
567 if (x)
568 *x = frame->shadow_margin;
569 if (y)
570 *y = frame->shadow_margin;
571 if (width)
572 *width = frame->width - frame->shadow_margin * 2;
573 if (height)
574 *height = frame->height - frame->shadow_margin * 2;
575}
576
577void
578frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
579 int32_t *width, int32_t *height)
580{
581 frame_refresh_geometry(frame);
582
583 if (x)
584 *x = frame->opaque_margin;
585 if (y)
586 *y = frame->opaque_margin;
587 if (width)
588 *width = frame->width - frame->opaque_margin * 2;
589 if (height)
590 *height = frame->height - frame->opaque_margin * 2;
591}
592
Jasper St. Pierre74073452014-02-01 18:36:41 -0500593int
594frame_get_shadow_margin(struct frame *frame)
595{
596 frame_refresh_geometry(frame);
597
598 return frame->shadow_margin;
599}
600
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500601uint32_t
602frame_status(struct frame *frame)
603{
604 return frame->status;
605}
606
607void
608frame_status_clear(struct frame *frame, enum frame_status status)
609{
610 frame->status &= ~status;
611}
612
613static struct frame_button *
614frame_find_button(struct frame *frame, int x, int y)
615{
616 struct frame_button *button;
617 int rel_x, rel_y;
618
619 wl_list_for_each(button, &frame->buttons, link) {
620 rel_x = x - button->allocation.x;
621 rel_y = y - button->allocation.y;
622
623 if (0 <= rel_x && rel_x < button->allocation.width &&
624 0 <= rel_y && rel_y < button->allocation.height)
625 return button;
626 }
627
628 return NULL;
629}
630
631enum theme_location
632frame_pointer_enter(struct frame *frame, void *data, int x, int y)
633{
634 return frame_pointer_motion(frame, data, x, y);
635}
636
637enum theme_location
638frame_pointer_motion(struct frame *frame, void *data, int x, int y)
639{
640 struct frame_pointer *pointer = frame_pointer_get(frame, data);
641 struct frame_button *button = frame_find_button(frame, x, y);
642 enum theme_location location;
643
644 location = theme_get_location(frame->theme, x, y,
645 frame->width, frame->height,
646 frame->flags & FRAME_FLAG_MAXIMIZED ?
647 THEME_FRAME_MAXIMIZED : 0);
648 if (!pointer)
649 return location;
650
651 pointer->x = x;
652 pointer->y = y;
653
654 if (pointer->hover_button == button)
655 return location;
656
657 if (pointer->hover_button)
658 frame_button_leave(pointer->hover_button, pointer);
659
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500660 pointer->hover_button = button;
661
662 if (pointer->hover_button)
663 frame_button_enter(pointer->hover_button);
664
665 return location;
666}
667
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500668static void
669frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500670{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500671 wl_list_remove(&button->link);
672 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500673}
674
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500675static void
676frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
677 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500678{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500679 if (button->button == BTN_RIGHT) {
680 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500681 frame->status |= FRAME_STATUS_MENU;
682
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500683 frame_pointer_button_destroy(button);
684
685 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500686 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500687 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500688 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500689 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500690 case THEME_LOCATION_TITLEBAR:
691 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500692
693 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500694 break;
695 case THEME_LOCATION_RESIZING_TOP:
696 case THEME_LOCATION_RESIZING_BOTTOM:
697 case THEME_LOCATION_RESIZING_LEFT:
698 case THEME_LOCATION_RESIZING_RIGHT:
699 case THEME_LOCATION_RESIZING_TOP_LEFT:
700 case THEME_LOCATION_RESIZING_TOP_RIGHT:
701 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
702 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
703 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500704
705 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500706 break;
707 default:
708 break;
709 }
710 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500711 }
712}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500713
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500714static void
715frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
716 struct frame_pointer_button *button)
717{
718 if (button->button == BTN_LEFT && button->frame_button) {
719 if (button->frame_button == pointer->hover_button)
720 frame_button_release(button->frame_button);
721 else
722 frame_button_cancel(button->frame_button);
723 }
724}
725
726static void
727frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
728 struct frame_pointer_button *button)
729{
730 if (button->frame_button)
731 frame_button_cancel(button->frame_button);
732}
733
734void
735frame_pointer_leave(struct frame *frame, void *data)
736{
737 struct frame_pointer *pointer = frame_pointer_get(frame, data);
738 struct frame_pointer_button *button, *next;
739 if (!pointer)
740 return;
741
742 if (pointer->hover_button)
743 frame_button_leave(pointer->hover_button, pointer);
744
745 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
746 frame_pointer_button_cancel(frame, pointer, button);
747 frame_pointer_button_destroy(button);
748 }
749
750 frame_pointer_destroy(pointer);
751}
752
753enum theme_location
754frame_pointer_button(struct frame *frame, void *data,
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200755 uint32_t btn, enum wl_pointer_button_state state)
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500756{
757 struct frame_pointer *pointer = frame_pointer_get(frame, data);
758 struct frame_pointer_button *button;
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800759 enum theme_location location = THEME_LOCATION_EXTERIOR;
760
761 if (!pointer)
762 return location;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500763
764 location = theme_get_location(frame->theme, pointer->x, pointer->y,
765 frame->width, frame->height,
766 frame->flags & FRAME_FLAG_MAXIMIZED ?
767 THEME_FRAME_MAXIMIZED : 0);
768
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200769 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500770 button = malloc(sizeof *button);
771 if (!button)
772 return location;
773
774 button->button = btn;
775 button->press_location = location;
776 button->frame_button = pointer->hover_button;
777 wl_list_insert(&pointer->down_buttons, &button->link);
778
779 frame_pointer_button_press(frame, pointer, button);
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200780 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500781 button = NULL;
782 wl_list_for_each(button, &pointer->down_buttons, link)
783 if (button->button == btn)
784 break;
785 /* Make sure we didn't hit the end */
786 if (&button->link == &pointer->down_buttons)
787 return location;
788
789 location = button->press_location;
790 frame_pointer_button_release(frame, pointer, button);
791 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500792 }
793
794 return location;
795}
796
Derek Foreman96906412015-11-06 15:56:07 -0600797enum theme_location
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500798frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
799{
800 struct frame_touch *touch = frame_touch_get(frame, data);
801 struct frame_button *button = frame_find_button(frame, x, y);
802 enum theme_location location;
803
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500804 location = theme_get_location(frame->theme, x, y,
805 frame->width, frame->height,
806 frame->flags & FRAME_FLAG_MAXIMIZED ?
807 THEME_FRAME_MAXIMIZED : 0);
808
Derek Foreman96906412015-11-06 15:56:07 -0600809 if (id > 0)
810 return location;
811
812 if (touch && button) {
813 touch->button = button;
814 frame_button_press(touch->button);
815 return location;
816 }
817
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500818 switch (location) {
819 case THEME_LOCATION_TITLEBAR:
820 frame->status |= FRAME_STATUS_MOVE;
821 break;
822 case THEME_LOCATION_RESIZING_TOP:
823 case THEME_LOCATION_RESIZING_BOTTOM:
824 case THEME_LOCATION_RESIZING_LEFT:
825 case THEME_LOCATION_RESIZING_RIGHT:
826 case THEME_LOCATION_RESIZING_TOP_LEFT:
827 case THEME_LOCATION_RESIZING_TOP_RIGHT:
828 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
829 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
830 frame->status |= FRAME_STATUS_RESIZE;
831 break;
832 default:
833 break;
834 }
Derek Foreman96906412015-11-06 15:56:07 -0600835 return location;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500836}
837
838void
839frame_touch_up(struct frame *frame, void *data, int32_t id)
840{
841 struct frame_touch *touch = frame_touch_get(frame, data);
842
843 if (id > 0)
844 return;
845
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800846 if (touch && touch->button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500847 frame_button_release(touch->button);
848 frame_touch_destroy(touch);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500849 }
850}
851
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800852enum theme_location
853frame_double_click(struct frame *frame, void *data,
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200854 uint32_t btn, enum wl_pointer_button_state state)
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800855{
856 struct frame_pointer *pointer = frame_pointer_get(frame, data);
857 struct frame_button *button;
858 enum theme_location location = THEME_LOCATION_EXTERIOR;
859
860 location = theme_get_location(frame->theme, pointer->x, pointer->y,
861 frame->width, frame->height,
862 frame->flags & FRAME_FLAG_MAXIMIZED ?
863 THEME_FRAME_MAXIMIZED : 0);
864
865 button = frame_find_button(frame, pointer->x, pointer->y);
866
867 if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
868 return location;
869
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200870 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800871 if (button)
872 frame_button_press(button);
873 else
874 frame->status |= FRAME_STATUS_MAXIMIZE;
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200875 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800876 if (button)
877 frame_button_release(button);
878 }
879
880 return location;
881}
882
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500883void
Xiong Zhang382de462014-06-12 11:06:26 +0800884frame_double_touch_down(struct frame *frame, void *data, int32_t id,
885 int x, int y)
886{
887 struct frame_touch *touch = frame_touch_get(frame, data);
888 struct frame_button *button = frame_find_button(frame, x, y);
889 enum theme_location location;
890
891 if (touch && button) {
892 touch->button = button;
893 frame_button_press(touch->button);
894 return;
895 }
896
897 location = theme_get_location(frame->theme, x, y,
898 frame->width, frame->height,
899 frame->flags & FRAME_FLAG_MAXIMIZED ?
900 THEME_FRAME_MAXIMIZED : 0);
901
902 switch (location) {
903 case THEME_LOCATION_TITLEBAR:
904 frame->status |= FRAME_STATUS_MAXIMIZE;
905 break;
906 case THEME_LOCATION_RESIZING_TOP:
907 case THEME_LOCATION_RESIZING_BOTTOM:
908 case THEME_LOCATION_RESIZING_LEFT:
909 case THEME_LOCATION_RESIZING_RIGHT:
910 case THEME_LOCATION_RESIZING_TOP_LEFT:
911 case THEME_LOCATION_RESIZING_TOP_RIGHT:
912 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
913 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
914 frame->status |= FRAME_STATUS_RESIZE;
915 break;
916 default:
917 break;
918 }
919}
920
921void
922frame_double_touch_up(struct frame *frame, void *data, int32_t id)
923{
924 struct frame_touch *touch = frame_touch_get(frame, data);
925
926 if (touch && touch->button) {
927 frame_button_release(touch->button);
928 frame_touch_destroy(touch);
929 }
930}
931
932void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500933frame_repaint(struct frame *frame, cairo_t *cr)
934{
935 struct frame_button *button;
936 uint32_t flags = 0;
937
938 frame_refresh_geometry(frame);
939
940 if (frame->flags & FRAME_FLAG_MAXIMIZED)
941 flags |= THEME_FRAME_MAXIMIZED;
942
943 if (frame->flags & FRAME_FLAG_ACTIVE)
944 flags |= THEME_FRAME_ACTIVE;
945
946 cairo_save(cr);
947 theme_render_frame(frame->theme, cr, frame->width, frame->height,
Louis-Francis Ratté-Boulianne864e39b2017-11-13 16:20:55 -0500948 frame->title, &frame->title_rect,
949 &frame->buttons, flags);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500950 cairo_restore(cr);
951
952 wl_list_for_each(button, &frame->buttons, link)
953 frame_button_repaint(button, cr);
954
955 frame_status_clear(frame, FRAME_STATUS_REPAINT);
956}