blob: 2dbf7d57f62392570d93440a5794821322d21520 [file] [log] [blame]
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001/*
2 * Copyright © 2011 Kristian Høgsberg
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02003 * Copyright © 2011 Collabora, Ltd.
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04004 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07005 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040011 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070012 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040023 */
24
U. Artie Eoff3c946772014-01-15 10:59:50 -080025#include "config.h"
26
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040027#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <fcntl.h>
32#include <unistd.h>
U. Artie Eoff3c946772014-01-15 10:59:50 -080033#include <errno.h>
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040034#include <math.h>
35#include <cairo.h>
36#include <sys/wait.h>
37#include <linux/input.h>
Tiago Vignatti61500722012-05-23 22:06:28 +030038#include <libgen.h>
Kristian Høgsbergd1936b92012-07-23 22:59:33 -040039#include <ctype.h>
Martin Minarik1e51a872012-06-08 00:39:11 +020040#include <time.h>
Quentin Glidicf9574f22016-06-23 18:55:21 +020041#include <assert.h>
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040042
Pekka Paalanen50719bc2011-11-22 14:18:50 +020043#include <wayland-client.h>
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040044#include "window.h"
Jon Cruz4678bab2015-06-15 15:37:07 -070045#include "shared/cairo-util.h"
Pekka Paalanen91b10102019-04-04 14:27:31 +030046#include <libweston/config-parser.h>
Jon Cruz867d50e2015-06-15 15:37:10 -070047#include "shared/helpers.h"
Bryce Harringtone99e4bf2016-03-16 14:15:18 -070048#include "shared/xalloc.h"
Pekka Paalanenecbdcfd2019-04-04 14:46:00 +030049#include <libweston/zalloc.h>
Derek Foremane2772762018-02-06 15:18:38 -060050#include "shared/file-util.h"
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040051
Jonas Ådahl6d6fb612015-11-17 16:00:33 +080052#include "weston-desktop-shell-client-protocol.h"
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040053
Armin Krezovićc6a55db2016-03-10 18:02:34 +010054#define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES
-c505af82019-06-26 21:00:43 +000055#define DEFAULT_SPACING 10
Armin Krezovićc6a55db2016-03-10 18:02:34 +010056
Pekka Paalanenb6df4f72012-08-03 14:39:15 +030057extern char **environ; /* defined by libc */
58
Quentin Glidicf9574f22016-06-23 18:55:21 +020059enum clock_format {
60 CLOCK_FORMAT_MINUTES,
61 CLOCK_FORMAT_SECONDS,
62 CLOCK_FORMAT_NONE
63};
64
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040065struct desktop {
66 struct display *display;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +080067 struct weston_desktop_shell *shell;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +020068 struct unlock_dialog *unlock_dialog;
69 struct task unlock_task;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010070 struct wl_list outputs;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -040071
Quentin Glidic55d57012016-06-23 18:55:18 +020072 int want_panel;
73 enum weston_desktop_shell_panel_position panel_position;
Quentin Glidic3e37b342016-06-23 18:55:22 +020074 enum clock_format clock_format;
Quentin Glidic55d57012016-06-23 18:55:18 +020075
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +030076 struct window *grab_window;
77 struct widget *grab_widget;
78
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +030079 struct weston_config *config;
Daniel Stone51d995a2019-11-26 00:14:24 +000080 bool locking;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +030081
Scott Moreauec116022012-07-22 18:23:52 -060082 enum cursor_type grab_cursor;
Pekka Paalanen79346ab2013-05-22 18:03:09 +030083
84 int painted;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010085};
86
87struct surface {
88 void (*configure)(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +080089 struct weston_desktop_shell *desktop_shell,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -040090 uint32_t edges, struct window *window,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010091 int32_t width, int32_t height);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040092};
93
Pekka Paalanencb115382017-12-07 12:15:01 +020094struct output;
95
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040096struct panel {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010097 struct surface base;
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +020098
99 struct output *owner;
100
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400101 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500102 struct widget *widget;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500103 struct wl_list launcher_list;
Martin Minarik1e51a872012-06-08 00:39:11 +0200104 struct panel_clock *clock;
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300105 int painted;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200106 enum weston_desktop_shell_panel_position panel_position;
Quentin Glidicf9574f22016-06-23 18:55:21 +0200107 enum clock_format clock_format;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300108 uint32_t color;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400109};
110
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100111struct background {
112 struct surface base;
Pekka Paalanencb115382017-12-07 12:15:01 +0200113
114 struct output *owner;
115
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100116 struct window *window;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500117 struct widget *widget;
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300118 int painted;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300119
120 char *image;
121 int type;
122 uint32_t color;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100123};
124
125struct output {
126 struct wl_output *output;
Xiong Zhang83d8ee72013-10-23 13:58:35 +0800127 uint32_t server_output_id;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100128 struct wl_list link;
129
Pekka Paalanenc1bcce62017-12-07 15:30:18 +0200130 int x;
131 int y;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100132 struct panel *panel;
133 struct background *background;
134};
135
Kristian Høgsberg53880802012-01-09 11:16:50 -0500136struct panel_launcher {
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500137 struct widget *widget;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400138 struct panel *panel;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400139 cairo_surface_t *icon;
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500140 int focused, pressed;
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400141 char *path;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500142 struct wl_list link;
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400143 struct wl_array envp;
144 struct wl_array argv;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400145};
146
Martin Minarik1e51a872012-06-08 00:39:11 +0200147struct panel_clock {
148 struct widget *widget;
149 struct panel *panel;
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200150 struct toytimer timer;
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100151 char *format_string;
152 time_t refresh_timer;
Martin Minarik1e51a872012-06-08 00:39:11 +0200153};
154
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200155struct unlock_dialog {
156 struct window *window;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500157 struct widget *widget;
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500158 struct widget *button;
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500159 int button_focused;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200160 int closing;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200161 struct desktop *desktop;
162};
163
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300164static void
165panel_add_launchers(struct panel *panel, struct desktop *desktop);
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500166
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400167static void
168sigchild_handler(int s)
169{
170 int status;
171 pid_t pid;
172
173 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
174 fprintf(stderr, "child %d exited\n", pid);
175}
176
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300177static int
178is_desktop_painted(struct desktop *desktop)
179{
180 struct output *output;
181
182 wl_list_for_each(output, &desktop->outputs, link) {
183 if (output->panel && !output->panel->painted)
184 return 0;
185 if (output->background && !output->background->painted)
186 return 0;
187 }
188
189 return 1;
190}
191
192static void
193check_desktop_ready(struct window *window)
194{
195 struct display *display;
196 struct desktop *desktop;
197
198 display = window_get_display(window);
199 desktop = display_get_user_data(display);
200
201 if (!desktop->painted && is_desktop_painted(desktop)) {
202 desktop->painted = 1;
203
Jonas Ådahl6d6fb612015-11-17 16:00:33 +0800204 weston_desktop_shell_desktop_ready(desktop->shell);
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300205 }
206}
207
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -0400208static void
Kristian Høgsberg53880802012-01-09 11:16:50 -0500209panel_launcher_activate(struct panel_launcher *widget)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400210{
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400211 char **argv;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400212 pid_t pid;
213
214 pid = fork();
215 if (pid < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200216 fprintf(stderr, "fork failed: %s\n", strerror(errno));
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400217 return;
218 }
219
220 if (pid)
221 return;
Benjamin Franzked7759712011-11-22 12:38:48 +0100222
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400223 argv = widget->argv.data;
Derek Foreman091c8012017-03-24 09:41:13 -0500224
225 if (setsid() == -1)
226 exit(EXIT_FAILURE);
227
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400228 if (execve(argv[0], argv, widget->envp.data) < 0) {
Antonio Borneo39578632019-04-26 23:57:31 +0200229 fprintf(stderr, "execl '%s' failed: %s\n", argv[0],
230 strerror(errno));
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400231 exit(1);
232 }
233}
234
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400235static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500236panel_launcher_redraw_handler(struct widget *widget, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400237{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500238 struct panel_launcher *launcher = data;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500239 struct rectangle allocation;
240 cairo_t *cr;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400241
Alexander Larssonc584fa62013-05-22 14:41:32 +0200242 cr = widget_cairo_create(launcher->panel->widget);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500243
244 widget_get_allocation(widget, &allocation);
-c505af82019-06-26 21:00:43 +0000245 allocation.x += allocation.width / 2 -
246 cairo_image_surface_get_width(launcher->icon) / 2;
247 if (allocation.width > allocation.height)
248 allocation.x += allocation.width / 2 - allocation.height / 2;
249 allocation.y += allocation.height / 2 -
250 cairo_image_surface_get_height(launcher->icon) / 2;
251 if (allocation.height > allocation.width)
252 allocation.y += allocation.height / 2 - allocation.width / 2;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500253 if (launcher->pressed) {
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500254 allocation.x++;
255 allocation.y++;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400256 }
257
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500258 cairo_set_source_surface(cr, launcher->icon,
259 allocation.x, allocation.y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400260 cairo_paint(cr);
261
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500262 if (launcher->focused) {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400263 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500264 cairo_mask_surface(cr, launcher->icon,
265 allocation.x, allocation.y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400266 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400267
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500268 cairo_destroy(cr);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400269}
270
Tiago Vignatti61500722012-05-23 22:06:28 +0300271static int
272panel_launcher_motion_handler(struct widget *widget, struct input *input,
273 uint32_t time, float x, float y, void *data)
274{
275 struct panel_launcher *launcher = data;
276
277 widget_set_tooltip(widget, basename((char *)launcher->path), x, y);
278
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300279 return CURSOR_LEFT_PTR;
Tiago Vignatti61500722012-05-23 22:06:28 +0300280}
281
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400282static void
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500283set_hex_color(cairo_t *cr, uint32_t color)
284{
Michael Vetter2a18a522015-05-15 17:17:47 +0200285 cairo_set_source_rgba(cr,
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500286 ((color >> 16) & 0xff) / 255.0,
287 ((color >> 8) & 0xff) / 255.0,
288 ((color >> 0) & 0xff) / 255.0,
289 ((color >> 24) & 0xff) / 255.0);
290}
291
292static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500293panel_redraw_handler(struct widget *widget, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400294{
295 cairo_surface_t *surface;
296 cairo_t *cr;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500297 struct panel *panel = data;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400298
Alexander Larssonc584fa62013-05-22 14:41:32 +0200299 cr = widget_cairo_create(panel->widget);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400300 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300301 set_hex_color(cr, panel->color);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400302 cairo_paint(cr);
303
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400304 cairo_destroy(cr);
Alexander Larssonc584fa62013-05-22 14:41:32 +0200305 surface = window_get_surface(panel->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400306 cairo_surface_destroy(surface);
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300307 panel->painted = 1;
308 check_desktop_ready(panel->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400309}
310
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -0500311static int
Kristian Høgsberg53880802012-01-09 11:16:50 -0500312panel_launcher_enter_handler(struct widget *widget, struct input *input,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400313 float x, float y, void *data)
Kristian Høgsbergee143232012-01-09 08:42:24 -0500314{
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500315 struct panel_launcher *launcher = data;
316
317 launcher->focused = 1;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500318 widget_schedule_redraw(widget);
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -0500319
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300320 return CURSOR_LEFT_PTR;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500321}
322
323static void
Kristian Høgsberg53880802012-01-09 11:16:50 -0500324panel_launcher_leave_handler(struct widget *widget,
325 struct input *input, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400326{
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500327 struct panel_launcher *launcher = data;
328
329 launcher->focused = 0;
Tiago Vignatti61500722012-05-23 22:06:28 +0300330 widget_destroy_tooltip(widget);
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500331 widget_schedule_redraw(widget);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400332}
333
334static void
Kristian Høgsberg53880802012-01-09 11:16:50 -0500335panel_launcher_button_handler(struct widget *widget,
336 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100337 uint32_t button,
338 enum wl_pointer_button_state state, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400339{
Kristian Høgsberg53880802012-01-09 11:16:50 -0500340 struct panel_launcher *launcher;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400341
Kristian Høgsberg53880802012-01-09 11:16:50 -0500342 launcher = widget_get_user_data(widget);
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500343 widget_schedule_redraw(widget);
Daniel Stone4dbadb12012-05-30 16:31:51 +0100344 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Kristian Høgsberg53880802012-01-09 11:16:50 -0500345 panel_launcher_activate(launcher);
Rusty Lynch4384a242013-08-08 21:28:22 -0700346
347}
348
349static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700350panel_launcher_touch_down_handler(struct widget *widget, struct input *input,
351 uint32_t serial, uint32_t time, int32_t id,
Rusty Lynch4384a242013-08-08 21:28:22 -0700352 float x, float y, void *data)
353{
354 struct panel_launcher *launcher;
355
356 launcher = widget_get_user_data(widget);
357 launcher->focused = 1;
358 widget_schedule_redraw(widget);
359}
360
361static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700362panel_launcher_touch_up_handler(struct widget *widget, struct input *input,
Michael Vetter2a18a522015-05-15 17:17:47 +0200363 uint32_t serial, uint32_t time, int32_t id,
Rusty Lynch1084da52013-08-15 09:10:08 -0700364 void *data)
Rusty Lynch4384a242013-08-08 21:28:22 -0700365{
366 struct panel_launcher *launcher;
367
368 launcher = widget_get_user_data(widget);
369 launcher->focused = 0;
370 widget_schedule_redraw(widget);
371 panel_launcher_activate(launcher);
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500372}
373
Martin Minarik1e51a872012-06-08 00:39:11 +0200374static void
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200375clock_func(struct toytimer *tt)
Martin Minarik1e51a872012-06-08 00:39:11 +0200376{
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200377 struct panel_clock *clock = container_of(tt, struct panel_clock, timer);
Martin Minarik1e51a872012-06-08 00:39:11 +0200378
Kristian Høgsberg92a984a2012-06-11 11:10:57 -0400379 widget_schedule_redraw(clock->widget);
Martin Minarik1e51a872012-06-08 00:39:11 +0200380}
381
382static void
383panel_clock_redraw_handler(struct widget *widget, void *data)
384{
Martin Minarik1e51a872012-06-08 00:39:11 +0200385 struct panel_clock *clock = data;
386 cairo_t *cr;
387 struct rectangle allocation;
388 cairo_text_extents_t extents;
Martin Minarik1e51a872012-06-08 00:39:11 +0200389 time_t rawtime;
390 struct tm * timeinfo;
Kristian Høgsberg92a984a2012-06-11 11:10:57 -0400391 char string[128];
Martin Minarik1e51a872012-06-08 00:39:11 +0200392
Kristian Høgsbergbb262cf2012-06-11 11:03:03 -0400393 time(&rawtime);
394 timeinfo = localtime(&rawtime);
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100395 strftime(string, sizeof string, clock->format_string, timeinfo);
Martin Minarik1e51a872012-06-08 00:39:11 +0200396
397 widget_get_allocation(widget, &allocation);
Kristian Høgsbergbb262cf2012-06-11 11:03:03 -0400398 if (allocation.width == 0)
399 return;
Martin Minarik1e51a872012-06-08 00:39:11 +0200400
Alexander Larssonc584fa62013-05-22 14:41:32 +0200401 cr = widget_cairo_create(clock->panel->widget);
Martin Minarik1e51a872012-06-08 00:39:11 +0200402 cairo_set_font_size(cr, 14);
Kristian Høgsberg92a984a2012-06-11 11:10:57 -0400403 cairo_text_extents(cr, string, &extents);
-c505af82019-06-26 21:00:43 +0000404 if (allocation.x > 0)
405 allocation.x +=
406 allocation.width - DEFAULT_SPACING * 1.5 - extents.width;
407 else
408 allocation.x +=
409 allocation.width / 2 - extents.width / 2;
410 allocation.y += allocation.height / 2 - 1 + extents.height / 2;
411 cairo_move_to(cr, allocation.x + 1, allocation.y + 1);
412 cairo_set_source_rgba(cr, 0, 0, 0, 0.85);
Kristian Høgsberg92a984a2012-06-11 11:10:57 -0400413 cairo_show_text(cr, string);
-c505af82019-06-26 21:00:43 +0000414 cairo_move_to(cr, allocation.x, allocation.y);
415 cairo_set_source_rgba(cr, 1, 1, 1, 0.85);
Kristian Høgsberg92a984a2012-06-11 11:10:57 -0400416 cairo_show_text(cr, string);
Martin Minarik1e51a872012-06-08 00:39:11 +0200417 cairo_destroy(cr);
418}
419
420static int
421clock_timer_reset(struct panel_clock *clock)
422{
423 struct itimerspec its;
Kristian Høgsbergbb262cf2012-06-11 11:03:03 -0400424
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100425 its.it_interval.tv_sec = clock->refresh_timer;
Martin Minarik1e51a872012-06-08 00:39:11 +0200426 its.it_interval.tv_nsec = 0;
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100427 its.it_value.tv_sec = clock->refresh_timer;
Martin Minarik1e51a872012-06-08 00:39:11 +0200428 its.it_value.tv_nsec = 0;
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200429 toytimer_arm(&clock->timer, &its);
Martin Minarik1e51a872012-06-08 00:39:11 +0200430
431 return 0;
432}
433
434static void
U. Artie Eoff44874d92012-10-02 21:12:35 -0700435panel_destroy_clock(struct panel_clock *clock)
436{
437 widget_destroy(clock->widget);
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200438 toytimer_fini(&clock->timer);
U. Artie Eoff44874d92012-10-02 21:12:35 -0700439 free(clock);
440}
441
442static void
Martin Minarik1e51a872012-06-08 00:39:11 +0200443panel_add_clock(struct panel *panel)
444{
445 struct panel_clock *clock;
Martin Minarik1e51a872012-06-08 00:39:11 +0200446
Peter Huttererf3d62272013-08-08 11:57:05 +1000447 clock = xzalloc(sizeof *clock);
Martin Minarik1e51a872012-06-08 00:39:11 +0200448 clock->panel = panel;
449 panel->clock = clock;
Martin Minarik1e51a872012-06-08 00:39:11 +0200450
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100451 switch (panel->clock_format) {
452 case CLOCK_FORMAT_MINUTES:
453 clock->format_string = "%a %b %d, %I:%M %p";
454 clock->refresh_timer = 60;
455 break;
456 case CLOCK_FORMAT_SECONDS:
457 clock->format_string = "%a %b %d, %I:%M:%S %p";
458 clock->refresh_timer = 1;
459 break;
Quentin Glidicf9574f22016-06-23 18:55:21 +0200460 case CLOCK_FORMAT_NONE:
461 assert(!"not reached");
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100462 }
463
Pekka Paalanen64a26bc2018-03-09 13:17:26 +0200464 toytimer_init(&clock->timer, CLOCK_MONOTONIC,
465 window_get_display(panel->window), clock_func);
Martin Minarik1e51a872012-06-08 00:39:11 +0200466 clock_timer_reset(clock);
467
468 clock->widget = widget_add_widget(panel->widget, clock);
Kristian Høgsbergbb262cf2012-06-11 11:03:03 -0400469 widget_set_redraw_handler(clock->widget, panel_clock_redraw_handler);
Martin Minarik1e51a872012-06-08 00:39:11 +0200470}
471
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500472static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500473panel_resize_handler(struct widget *widget,
474 int32_t width, int32_t height, void *data)
475{
476 struct panel_launcher *launcher;
477 struct panel *panel = data;
-c505af82019-06-26 21:00:43 +0000478 int x = 0;
479 int y = 0;
480 int w = height > width ? width : height;
481 int h = w;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200482 int horizontal = panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP || panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM;
-c505af82019-06-26 21:00:43 +0000483 int first_pad_h = horizontal ? 0 : DEFAULT_SPACING / 2;
484 int first_pad_w = horizontal ? DEFAULT_SPACING / 2 : 0;
Michael Vetter2a18a522015-05-15 17:17:47 +0200485
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500486 wl_list_for_each(launcher, &panel->launcher_list, link) {
-c505af82019-06-26 21:00:43 +0000487 widget_set_allocation(launcher->widget, x, y,
488 w + first_pad_w + 1, h + first_pad_h + 1);
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200489 if (horizontal)
-c505af82019-06-26 21:00:43 +0000490 x += w + first_pad_w;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200491 else
-c505af82019-06-26 21:00:43 +0000492 y += h + first_pad_h;
493 first_pad_h = first_pad_w = 0;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500494 }
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100495
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100496 if (panel->clock_format == CLOCK_FORMAT_SECONDS)
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100497 w = 170;
-c505af82019-06-26 21:00:43 +0000498 else /* CLOCK_FORMAT_MINUTES */
499 w = 150;
Pekka Paalanen01b17252012-06-12 17:42:26 +0300500
-c505af82019-06-26 21:00:43 +0000501 if (horizontal)
502 x = width - w;
503 else
504 y = height - (h = DEFAULT_SPACING * 3);
Quentin Glidic51c2c372016-06-23 18:55:23 +0200505
Pekka Paalanen01b17252012-06-12 17:42:26 +0300506 if (panel->clock)
507 widget_set_allocation(panel->clock->widget,
Quentin Glidic51c2c372016-06-23 18:55:23 +0200508 x, y, w + 1, h + 1);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500509}
510
511static void
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +0200512panel_destroy(struct panel *panel);
513
514static void
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100515panel_configure(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +0800516 struct weston_desktop_shell *desktop_shell,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400517 uint32_t edges, struct window *window,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100518 int32_t width, int32_t height)
519{
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200520 struct desktop *desktop = data;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500521 struct surface *surface = window_get_user_data(window);
522 struct panel *panel = container_of(surface, struct panel, base);
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +0200523 struct output *owner;
524
525 if (width < 1 || height < 1) {
526 /* Shell plugin configures 0x0 for redundant panel. */
527 owner = panel->owner;
528 panel_destroy(panel);
529 owner->panel = NULL;
530 return;
531 }
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500532
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200533 switch (desktop->panel_position) {
534 case WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP:
535 case WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
Quentin Glidic51c2c372016-06-23 18:55:23 +0200536 height = 32;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200537 break;
538 case WESTON_DESKTOP_SHELL_PANEL_POSITION_LEFT:
539 case WESTON_DESKTOP_SHELL_PANEL_POSITION_RIGHT:
540 switch (desktop->clock_format) {
541 case CLOCK_FORMAT_NONE:
542 width = 32;
543 break;
544 case CLOCK_FORMAT_MINUTES:
-c505af82019-06-26 21:00:43 +0000545 width = 150;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200546 break;
547 case CLOCK_FORMAT_SECONDS:
-c505af82019-06-26 21:00:43 +0000548 width = 170;
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200549 break;
550 }
551 break;
552 }
Quentin Glidic51c2c372016-06-23 18:55:23 +0200553 window_schedule_resize(panel->window, width, height);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100554}
555
U. Artie Eoff44874d92012-10-02 21:12:35 -0700556static void
557panel_destroy_launcher(struct panel_launcher *launcher)
558{
559 wl_array_release(&launcher->argv);
560 wl_array_release(&launcher->envp);
561
562 free(launcher->path);
563
564 cairo_surface_destroy(launcher->icon);
565
566 widget_destroy(launcher->widget);
567 wl_list_remove(&launcher->link);
568
569 free(launcher);
570}
571
572static void
573panel_destroy(struct panel *panel)
574{
575 struct panel_launcher *tmp;
576 struct panel_launcher *launcher;
577
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100578 if (panel->clock)
579 panel_destroy_clock(panel->clock);
U. Artie Eoff44874d92012-10-02 21:12:35 -0700580
581 wl_list_for_each_safe(launcher, tmp, &panel->launcher_list, link)
582 panel_destroy_launcher(launcher);
583
584 widget_destroy(panel->widget);
585 window_destroy(panel->window);
586
587 free(panel);
588}
589
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400590static struct panel *
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +0200591panel_create(struct desktop *desktop, struct output *output)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400592{
593 struct panel *panel;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300594 struct weston_config_section *s;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400595
Peter Huttererf3d62272013-08-08 11:57:05 +1000596 panel = xzalloc(sizeof *panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400597
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +0200598 panel->owner = output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100599 panel->base.configure = panel_configure;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300600 panel->window = window_create_custom(desktop->display);
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500601 panel->widget = window_add_widget(panel->window, panel);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500602 wl_list_init(&panel->launcher_list);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400603
604 window_set_title(panel->window, "panel");
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400605 window_set_user_data(panel->window, panel);
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500606
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500607 widget_set_redraw_handler(panel->widget, panel_redraw_handler);
608 widget_set_resize_handler(panel->widget, panel_resize_handler);
Michael Vetter2a18a522015-05-15 17:17:47 +0200609
Quentin Glidice7ed60f2016-06-23 18:55:24 +0200610 panel->panel_position = desktop->panel_position;
Quentin Glidic3e37b342016-06-23 18:55:22 +0200611 panel->clock_format = desktop->clock_format;
Armin Krezovićc6a55db2016-03-10 18:02:34 +0100612 if (panel->clock_format != CLOCK_FORMAT_NONE)
613 panel_add_clock(panel);
614
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300615 s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700616 weston_config_section_get_color(s, "panel-color",
617 &panel->color, 0xaa000000);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300618
619 panel_add_launchers(panel, desktop);
620
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400621 return panel;
622}
623
Philipp Brüschweiler467668c2012-08-29 10:53:36 +0200624static cairo_surface_t *
625load_icon_or_fallback(const char *icon)
626{
627 cairo_surface_t *surface = cairo_image_surface_create_from_png(icon);
Philipp Brüschweiler96386b82013-04-15 20:10:40 +0200628 cairo_status_t status;
Philipp Brüschweiler467668c2012-08-29 10:53:36 +0200629 cairo_t *cr;
630
Philipp Brüschweiler96386b82013-04-15 20:10:40 +0200631 status = cairo_surface_status(surface);
632 if (status == CAIRO_STATUS_SUCCESS)
Philipp Brüschweiler467668c2012-08-29 10:53:36 +0200633 return surface;
634
635 cairo_surface_destroy(surface);
Philipp Brüschweiler96386b82013-04-15 20:10:40 +0200636 fprintf(stderr, "ERROR loading icon from file '%s', error: '%s'\n",
637 icon, cairo_status_to_string(status));
Philipp Brüschweiler467668c2012-08-29 10:53:36 +0200638
639 /* draw fallback icon */
640 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
641 20, 20);
642 cr = cairo_create(surface);
643
644 cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
645 cairo_paint(cr);
646
647 cairo_set_source_rgba(cr, 0, 0, 0, 1);
648 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
649 cairo_rectangle(cr, 0, 0, 20, 20);
650 cairo_move_to(cr, 4, 4);
651 cairo_line_to(cr, 16, 16);
652 cairo_move_to(cr, 4, 16);
653 cairo_line_to(cr, 16, 4);
654 cairo_stroke(cr);
655
656 cairo_destroy(cr);
657
658 return surface;
659}
660
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400661static void
Kristian Høgsberg53880802012-01-09 11:16:50 -0500662panel_add_launcher(struct panel *panel, const char *icon, const char *path)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400663{
Kristian Høgsberg53880802012-01-09 11:16:50 -0500664 struct panel_launcher *launcher;
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400665 char *start, *p, *eq, **ps;
666 int i, j, k;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400667
Peter Huttererf3d62272013-08-08 11:57:05 +1000668 launcher = xzalloc(sizeof *launcher);
Philipp Brüschweiler467668c2012-08-29 10:53:36 +0200669 launcher->icon = load_icon_or_fallback(icon);
U. Artie Eoff3c946772014-01-15 10:59:50 -0800670 launcher->path = xstrdup(path);
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400671
672 wl_array_init(&launcher->envp);
673 wl_array_init(&launcher->argv);
Pekka Paalanenb6df4f72012-08-03 14:39:15 +0300674 for (i = 0; environ[i]; i++) {
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400675 ps = wl_array_add(&launcher->envp, sizeof *ps);
Pekka Paalanenb6df4f72012-08-03 14:39:15 +0300676 *ps = environ[i];
Kristian Høgsbergd1936b92012-07-23 22:59:33 -0400677 }
678 j = 0;
679
680 start = launcher->path;
681 while (*start) {
682 for (p = start, eq = NULL; *p && !isspace(*p); p++)
683 if (*p == '=')
684 eq = p;
685
686 if (eq && j == 0) {
687 ps = launcher->envp.data;
688 for (k = 0; k < i; k++)
689 if (strncmp(ps[k], start, eq - start) == 0) {
690 ps[k] = start;
691 break;
692 }
693 if (k == i) {
694 ps = wl_array_add(&launcher->envp, sizeof *ps);
695 *ps = start;
696 i++;
697 }
698 } else {
699 ps = wl_array_add(&launcher->argv, sizeof *ps);
700 *ps = start;
701 j++;
702 }
703
704 while (*p && isspace(*p))
705 *p++ = '\0';
706
707 start = p;
708 }
709
710 ps = wl_array_add(&launcher->envp, sizeof *ps);
711 *ps = NULL;
712 ps = wl_array_add(&launcher->argv, sizeof *ps);
713 *ps = NULL;
714
Kristian Høgsberg53880802012-01-09 11:16:50 -0500715 launcher->panel = panel;
Kristian Høgsberg75bc6672012-01-10 09:43:58 -0500716 wl_list_insert(panel->launcher_list.prev, &launcher->link);
717
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500718 launcher->widget = widget_add_widget(panel->widget, launcher);
Kristian Høgsberg53880802012-01-09 11:16:50 -0500719 widget_set_enter_handler(launcher->widget,
720 panel_launcher_enter_handler);
721 widget_set_leave_handler(launcher->widget,
722 panel_launcher_leave_handler);
723 widget_set_button_handler(launcher->widget,
724 panel_launcher_button_handler);
Rusty Lynch4384a242013-08-08 21:28:22 -0700725 widget_set_touch_down_handler(launcher->widget,
726 panel_launcher_touch_down_handler);
727 widget_set_touch_up_handler(launcher->widget,
728 panel_launcher_touch_up_handler);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500729 widget_set_redraw_handler(launcher->widget,
730 panel_launcher_redraw_handler);
Tiago Vignatti61500722012-05-23 22:06:28 +0300731 widget_set_motion_handler(launcher->widget,
732 panel_launcher_motion_handler);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400733}
734
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500735enum {
736 BACKGROUND_SCALE,
Pekka Paalanena402b052013-05-22 18:03:10 +0300737 BACKGROUND_SCALE_CROP,
Stefan Agner20b24162018-08-22 23:56:07 +0200738 BACKGROUND_TILE,
739 BACKGROUND_CENTERED
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500740};
741
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400742static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500743background_draw(struct widget *widget, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400744{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500745 struct background *background = data;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400746 cairo_surface_t *surface, *image;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400747 cairo_pattern_t *pattern;
748 cairo_matrix_t matrix;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400749 cairo_t *cr;
Pekka Paalanena402b052013-05-22 18:03:10 +0300750 double im_w, im_h;
751 double sx, sy, s;
752 double tx, ty;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500753 struct rectangle allocation;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400754
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500755 surface = window_get_surface(background->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400756
Alexander Larssonc584fa62013-05-22 14:41:32 +0200757 cr = widget_cairo_create(background->widget);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400758 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Stefan Agner1c1e4fd2018-08-22 23:33:10 +0200759 if (background->color == 0)
760 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
761 else
762 set_hex_color(cr, background->color);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400763 cairo_paint(cr);
764
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500765 widget_get_allocation(widget, &allocation);
Kristian Høgsberg8129bc02012-01-25 14:55:33 -0500766 image = NULL;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300767 if (background->image)
768 image = load_cairo_surface(background->image);
Derek Foremane2772762018-02-06 15:18:38 -0600769 else if (background->color == 0) {
770 char *name = file_name_with_datadir("pattern.png");
771
772 image = load_cairo_surface(name);
773 free(name);
774 }
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500775
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300776 if (image && background->type != -1) {
Pekka Paalanena402b052013-05-22 18:03:10 +0300777 im_w = cairo_image_surface_get_width(image);
778 im_h = cairo_image_surface_get_height(image);
779 sx = im_w / allocation.width;
780 sy = im_h / allocation.height;
781
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400782 pattern = cairo_pattern_create_for_surface(image);
Pekka Paalanena402b052013-05-22 18:03:10 +0300783
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +0300784 switch (background->type) {
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500785 case BACKGROUND_SCALE:
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500786 cairo_matrix_init_scale(&matrix, sx, sy);
787 cairo_pattern_set_matrix(pattern, &matrix);
Bill Spitzak79b7cb32014-05-08 20:00:35 -0700788 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500789 break;
Pekka Paalanena402b052013-05-22 18:03:10 +0300790 case BACKGROUND_SCALE_CROP:
791 s = (sx < sy) ? sx : sy;
792 /* align center */
793 tx = (im_w - s * allocation.width) * 0.5;
794 ty = (im_h - s * allocation.height) * 0.5;
795 cairo_matrix_init_translate(&matrix, tx, ty);
796 cairo_matrix_scale(&matrix, s, s);
797 cairo_pattern_set_matrix(pattern, &matrix);
Bill Spitzak79b7cb32014-05-08 20:00:35 -0700798 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
Pekka Paalanena402b052013-05-22 18:03:10 +0300799 break;
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500800 case BACKGROUND_TILE:
801 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
802 break;
Stefan Agner20b24162018-08-22 23:56:07 +0200803 case BACKGROUND_CENTERED:
804 s = (sx < sy) ? sx : sy;
805 if (s < 1.0)
806 s = 1.0;
807
808 /* align center */
809 tx = (im_w - s * allocation.width) * 0.5;
810 ty = (im_h - s * allocation.height) * 0.5;
811
812 cairo_matrix_init_translate(&matrix, tx, ty);
813 cairo_matrix_scale(&matrix, s, s);
814 cairo_pattern_set_matrix(pattern, &matrix);
815 break;
Kristian Høgsberg07f72942012-01-25 16:34:36 -0500816 }
Pekka Paalanena402b052013-05-22 18:03:10 +0300817
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400818 cairo_set_source(cr, pattern);
819 cairo_pattern_destroy (pattern);
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400820 cairo_surface_destroy(image);
Stefan Agner20b24162018-08-22 23:56:07 +0200821 cairo_mask(cr, pattern);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400822 }
823
824 cairo_destroy(cr);
825 cairo_surface_destroy(surface);
Pekka Paalanen9564c752012-10-24 09:43:08 +0300826
Pekka Paalanen79346ab2013-05-22 18:03:09 +0300827 background->painted = 1;
828 check_desktop_ready(background->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400829}
830
831static void
Pekka Paalanencb115382017-12-07 12:15:01 +0200832background_destroy(struct background *background);
833
834static void
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100835background_configure(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +0800836 struct weston_desktop_shell *desktop_shell,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400837 uint32_t edges, struct window *window,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100838 int32_t width, int32_t height)
839{
Pekka Paalanencb115382017-12-07 12:15:01 +0200840 struct output *owner;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500841 struct background *background =
842 (struct background *) window_get_user_data(window);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100843
Pekka Paalanencb115382017-12-07 12:15:01 +0200844 if (width < 1 || height < 1) {
845 /* Shell plugin configures 0x0 for redundant background. */
846 owner = background->owner;
847 background_destroy(background);
848 owner->background = NULL;
849 return;
850 }
851
Tanmay Shah8ef3ce52020-10-16 06:05:45 +0000852 if (!background->image && background->color) {
Harish Krupo3623e462018-12-11 13:59:07 +0530853 widget_set_viewport_destination(background->widget, width, height);
854 width = 1;
855 height = 1;
856 }
857
Kristian Høgsberg4598f962014-01-01 16:32:09 -0800858 widget_schedule_resize(background->widget, width, height);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100859}
860
861static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500862unlock_dialog_redraw_handler(struct widget *widget, void *data)
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200863{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500864 struct unlock_dialog *dialog = data;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200865 struct rectangle allocation;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200866 cairo_surface_t *surface;
Alexander Larssonc584fa62013-05-22 14:41:32 +0200867 cairo_t *cr;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200868 cairo_pattern_t *pat;
869 double cx, cy, r, f;
870
Alexander Larssonc584fa62013-05-22 14:41:32 +0200871 cr = widget_cairo_create(widget);
Kristian Høgsberg41c5c4e2012-03-05 20:37:51 -0500872
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500873 widget_get_allocation(dialog->widget, &allocation);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200874 cairo_rectangle(cr, allocation.x, allocation.y,
875 allocation.width, allocation.height);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200876 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
877 cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
Kristian Høgsberg41c5c4e2012-03-05 20:37:51 -0500878 cairo_fill(cr);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200879
Kristian Høgsberg41c5c4e2012-03-05 20:37:51 -0500880 cairo_translate(cr, allocation.x, allocation.y);
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500881 if (dialog->button_focused)
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200882 f = 1.0;
883 else
884 f = 0.7;
885
886 cx = allocation.width / 2.0;
887 cy = allocation.height / 2.0;
888 r = (cx < cy ? cx : cy) * 0.4;
889 pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
890 cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
891 cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
892 cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
893 cairo_set_source(cr, pat);
Kristian Høgsberg41c5c4e2012-03-05 20:37:51 -0500894 cairo_pattern_destroy(pat);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200895 cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
896 cairo_fill(cr);
897
Kristian Høgsbergc51f7992012-01-08 15:09:53 -0500898 widget_set_allocation(dialog->button,
Kristian Høgsberg41c5c4e2012-03-05 20:37:51 -0500899 allocation.x + cx - r,
900 allocation.y + cy - r, 2 * r, 2 * r);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200901
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200902 cairo_destroy(cr);
903
Alexander Larssonc584fa62013-05-22 14:41:32 +0200904 surface = window_get_surface(dialog->window);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200905 cairo_surface_destroy(surface);
906}
907
908static void
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500909unlock_dialog_button_handler(struct widget *widget,
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200910 struct input *input, uint32_t time,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100911 uint32_t button,
912 enum wl_pointer_button_state state, void *data)
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200913{
914 struct unlock_dialog *dialog = data;
915 struct desktop *desktop = dialog->desktop;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200916
Kristian Høgsberga8a0db32012-01-09 11:12:05 -0500917 if (button == BTN_LEFT) {
Daniel Stone4dbadb12012-05-30 16:31:51 +0100918 if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
919 !dialog->closing) {
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200920 display_defer(desktop->display, &desktop->unlock_task);
921 dialog->closing = 1;
922 }
923 }
924}
925
926static void
Brian J Lovinc4df4082013-08-26 15:58:22 -0700927unlock_dialog_touch_down_handler(struct widget *widget, struct input *input,
928 uint32_t serial, uint32_t time, int32_t id,
929 float x, float y, void *data)
930{
931 struct unlock_dialog *dialog = data;
932
933 dialog->button_focused = 1;
934 widget_schedule_redraw(widget);
935}
936
937static void
938unlock_dialog_touch_up_handler(struct widget *widget, struct input *input,
939 uint32_t serial, uint32_t time, int32_t id,
940 void *data)
941{
942 struct unlock_dialog *dialog = data;
943 struct desktop *desktop = dialog->desktop;
944
945 dialog->button_focused = 0;
946 widget_schedule_redraw(widget);
947 display_defer(desktop->display, &desktop->unlock_task);
948 dialog->closing = 1;
949}
950
951static void
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200952unlock_dialog_keyboard_focus_handler(struct window *window,
953 struct input *device, void *data)
954{
955 window_schedule_redraw(window);
956}
957
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -0500958static int
Kristian Høgsbergee143232012-01-09 08:42:24 -0500959unlock_dialog_widget_enter_handler(struct widget *widget,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -0400960 struct input *input,
Kristian Høgsberg80680c72012-05-10 12:21:37 -0400961 float x, float y, void *data)
Kristian Høgsbergee143232012-01-09 08:42:24 -0500962{
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500963 struct unlock_dialog *dialog = data;
964
965 dialog->button_focused = 1;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500966 widget_schedule_redraw(widget);
Kristian Høgsbergbb901fa2012-01-09 11:22:32 -0500967
Ander Conselvan de Oliveiradc8c8fc2012-05-25 16:01:41 +0300968 return CURSOR_LEFT_PTR;
Kristian Høgsbergee143232012-01-09 08:42:24 -0500969}
970
971static void
972unlock_dialog_widget_leave_handler(struct widget *widget,
973 struct input *input, void *data)
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200974{
Kristian Høgsbergb6323512012-01-11 00:04:42 -0500975 struct unlock_dialog *dialog = data;
976
977 dialog->button_focused = 0;
Kristian Høgsberg9a13dab2012-01-08 15:18:19 -0500978 widget_schedule_redraw(widget);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200979}
980
981static struct unlock_dialog *
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500982unlock_dialog_create(struct desktop *desktop)
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200983{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500984 struct display *display = desktop->display;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200985 struct unlock_dialog *dialog;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +0800986 struct wl_surface *surface;
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200987
Peter Huttererf3d62272013-08-08 11:57:05 +1000988 dialog = xzalloc(sizeof *dialog);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200989
Kristian Høgsberg730c94d2012-06-26 21:44:35 -0400990 dialog->window = window_create_custom(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500991 dialog->widget = window_frame_create(dialog->window, dialog);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200992 window_set_title(dialog->window, "Unlock your desktop");
993
994 window_set_user_data(dialog->window, dialog);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +0200995 window_set_keyboard_focus_handler(dialog->window,
996 unlock_dialog_keyboard_focus_handler);
Kristian Høgsberg441338c2012-01-10 13:52:34 -0500997 dialog->button = widget_add_widget(dialog->widget, dialog);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500998 widget_set_redraw_handler(dialog->widget,
999 unlock_dialog_redraw_handler);
Kristian Høgsbergee143232012-01-09 08:42:24 -05001000 widget_set_enter_handler(dialog->button,
1001 unlock_dialog_widget_enter_handler);
1002 widget_set_leave_handler(dialog->button,
1003 unlock_dialog_widget_leave_handler);
Kristian Høgsberga8a0db32012-01-09 11:12:05 -05001004 widget_set_button_handler(dialog->button,
1005 unlock_dialog_button_handler);
Brian J Lovinc4df4082013-08-26 15:58:22 -07001006 widget_set_touch_down_handler(dialog->button,
1007 unlock_dialog_touch_down_handler);
1008 widget_set_touch_up_handler(dialog->button,
1009 unlock_dialog_touch_up_handler);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001010
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001011 surface = window_get_wl_surface(dialog->window);
1012 weston_desktop_shell_set_lock_surface(desktop->shell, surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001013
Pekka Paalanen40e49ac2012-01-18 16:51:30 +02001014 window_schedule_resize(dialog->window, 260, 230);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001015
1016 return dialog;
1017}
1018
1019static void
1020unlock_dialog_destroy(struct unlock_dialog *dialog)
1021{
1022 window_destroy(dialog->window);
1023 free(dialog);
1024}
1025
1026static void
1027unlock_dialog_finish(struct task *task, uint32_t events)
1028{
1029 struct desktop *desktop =
Benjamin Franzked7759712011-11-22 12:38:48 +01001030 container_of(task, struct desktop, unlock_task);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001031
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001032 weston_desktop_shell_unlock(desktop->shell);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001033 unlock_dialog_destroy(desktop->unlock_dialog);
1034 desktop->unlock_dialog = NULL;
1035}
1036
1037static void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001038desktop_shell_configure(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001039 struct weston_desktop_shell *desktop_shell,
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001040 uint32_t edges,
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001041 struct wl_surface *surface,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001042 int32_t width, int32_t height)
1043{
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001044 struct window *window = wl_surface_get_user_data(surface);
Pekka Paalanen068ae942011-11-28 14:11:15 +02001045 struct surface *s = window_get_user_data(window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001046
Kristian Høgsbergeae5de72012-04-11 22:42:15 -04001047 s->configure(data, desktop_shell, edges, window, width, height);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001048}
1049
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001050static void
1051desktop_shell_prepare_lock_surface(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001052 struct weston_desktop_shell *desktop_shell)
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001053{
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001054 struct desktop *desktop = data;
1055
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001056 if (!desktop->locking) {
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001057 weston_desktop_shell_unlock(desktop->shell);
Pekka Paalanenfd83b6d2011-12-08 10:06:53 +02001058 return;
1059 }
1060
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001061 if (!desktop->unlock_dialog) {
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -05001062 desktop->unlock_dialog = unlock_dialog_create(desktop);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001063 desktop->unlock_dialog->desktop = desktop;
1064 }
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001065}
1066
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001067static void
1068desktop_shell_grab_cursor(void *data,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001069 struct weston_desktop_shell *desktop_shell,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001070 uint32_t cursor)
1071{
1072 struct desktop *desktop = data;
1073
1074 switch (cursor) {
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001075 case WESTON_DESKTOP_SHELL_CURSOR_NONE:
Philipp Brüschweiler16d59d72012-08-24 15:43:55 +02001076 desktop->grab_cursor = CURSOR_BLANK;
1077 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001078 case WESTON_DESKTOP_SHELL_CURSOR_BUSY:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001079 desktop->grab_cursor = CURSOR_WATCH;
1080 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001081 case WESTON_DESKTOP_SHELL_CURSOR_MOVE:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001082 desktop->grab_cursor = CURSOR_DRAGGING;
1083 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001084 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_TOP:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001085 desktop->grab_cursor = CURSOR_TOP;
1086 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001087 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001088 desktop->grab_cursor = CURSOR_BOTTOM;
1089 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001090 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_LEFT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001091 desktop->grab_cursor = CURSOR_LEFT;
1092 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001093 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_RIGHT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001094 desktop->grab_cursor = CURSOR_RIGHT;
1095 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001096 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_TOP_LEFT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001097 desktop->grab_cursor = CURSOR_TOP_LEFT;
1098 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001099 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_TOP_RIGHT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001100 desktop->grab_cursor = CURSOR_TOP_RIGHT;
1101 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001102 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_LEFT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001103 desktop->grab_cursor = CURSOR_BOTTOM_LEFT;
1104 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001105 case WESTON_DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_RIGHT:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001106 desktop->grab_cursor = CURSOR_BOTTOM_RIGHT;
1107 break;
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001108 case WESTON_DESKTOP_SHELL_CURSOR_ARROW:
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001109 default:
1110 desktop->grab_cursor = CURSOR_LEFT_PTR;
1111 }
1112}
1113
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001114static const struct weston_desktop_shell_listener listener = {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02001115 desktop_shell_configure,
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001116 desktop_shell_prepare_lock_surface,
1117 desktop_shell_grab_cursor
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001118};
1119
U. Artie Eoff44874d92012-10-02 21:12:35 -07001120static void
1121background_destroy(struct background *background)
1122{
1123 widget_destroy(background->widget);
1124 window_destroy(background->window);
1125
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001126 free(background->image);
U. Artie Eoff44874d92012-10-02 21:12:35 -07001127 free(background);
1128}
1129
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001130static struct background *
Pekka Paalanencb115382017-12-07 12:15:01 +02001131background_create(struct desktop *desktop, struct output *output)
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001132{
1133 struct background *background;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001134 struct weston_config_section *s;
1135 char *type;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001136
Peter Huttererf3d62272013-08-08 11:57:05 +10001137 background = xzalloc(sizeof *background);
Pekka Paalanencb115382017-12-07 12:15:01 +02001138 background->owner = output;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001139 background->base.configure = background_configure;
Kristian Høgsberg962342c2012-06-26 16:29:50 -04001140 background->window = window_create_custom(desktop->display);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05001141 background->widget = window_add_widget(background->window, background);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001142 window_set_user_data(background->window, background);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -05001143 widget_set_redraw_handler(background->widget, background_draw);
Arnaud Vracfb754a02014-08-25 20:56:49 +02001144 widget_set_transparent(background->widget, 0);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001145
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001146 s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
1147 weston_config_section_get_string(s, "background-image",
Kristian Høgsberg4c3661f2014-04-21 22:54:37 -07001148 &background->image, NULL);
Bryce Harringtone776f2a2016-07-14 18:28:03 -07001149 weston_config_section_get_color(s, "background-color",
1150 &background->color, 0x00000000);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001151
1152 weston_config_section_get_string(s, "background-type",
1153 &type, "tile");
U. Artie Eoff3c946772014-01-15 10:59:50 -08001154 if (type == NULL) {
1155 fprintf(stderr, "%s: out of memory\n", program_invocation_short_name);
1156 exit(EXIT_FAILURE);
1157 }
1158
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001159 if (strcmp(type, "scale") == 0) {
1160 background->type = BACKGROUND_SCALE;
1161 } else if (strcmp(type, "scale-crop") == 0) {
1162 background->type = BACKGROUND_SCALE_CROP;
1163 } else if (strcmp(type, "tile") == 0) {
1164 background->type = BACKGROUND_TILE;
Stefan Agner20b24162018-08-22 23:56:07 +02001165 } else if (strcmp(type, "centered") == 0) {
1166 background->type = BACKGROUND_CENTERED;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001167 } else {
1168 background->type = -1;
1169 fprintf(stderr, "invalid background-type: %s\n",
1170 type);
1171 }
1172
1173 free(type);
1174
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001175 return background;
1176}
1177
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001178static int
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001179grab_surface_enter_handler(struct widget *widget, struct input *input,
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001180 float x, float y, void *data)
1181{
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001182 struct desktop *desktop = data;
1183
1184 return desktop->grab_cursor;
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001185}
1186
1187static void
U. Artie Eoff44874d92012-10-02 21:12:35 -07001188grab_surface_destroy(struct desktop *desktop)
1189{
1190 widget_destroy(desktop->grab_widget);
1191 window_destroy(desktop->grab_window);
1192}
1193
1194static void
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001195grab_surface_create(struct desktop *desktop)
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001196{
1197 struct wl_surface *s;
1198
Ander Conselvan de Oliveira07a91cd2012-07-16 14:15:50 +03001199 desktop->grab_window = window_create_custom(desktop->display);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001200 window_set_user_data(desktop->grab_window, desktop);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001201
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001202 s = window_get_wl_surface(desktop->grab_window);
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001203 weston_desktop_shell_set_grab_surface(desktop->shell, s);
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001204
1205 desktop->grab_widget =
1206 window_add_widget(desktop->grab_window, desktop);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001207 /* We set the allocation to 1x1 at 0,0 so the fake enter event
1208 * at 0,0 will go to this widget. */
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001209 widget_set_allocation(desktop->grab_widget, 0, 0, 1, 1);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001210
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001211 widget_set_enter_handler(desktop->grab_widget,
1212 grab_surface_enter_handler);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001213}
1214
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001215static void
U. Artie Eoff44874d92012-10-02 21:12:35 -07001216output_destroy(struct output *output)
1217{
Pekka Paalanencb115382017-12-07 12:15:01 +02001218 if (output->background)
1219 background_destroy(output->background);
Jonny Lambe67118c2014-08-12 15:07:51 +02001220 if (output->panel)
1221 panel_destroy(output->panel);
U. Artie Eoff44874d92012-10-02 21:12:35 -07001222 wl_output_destroy(output->output);
1223 wl_list_remove(&output->link);
1224
1225 free(output);
1226}
1227
1228static void
1229desktop_destroy_outputs(struct desktop *desktop)
1230{
1231 struct output *tmp;
1232 struct output *output;
1233
1234 wl_list_for_each_safe(output, tmp, &desktop->outputs, link)
1235 output_destroy(output);
1236}
1237
1238static void
Alexander Larssonc584fa62013-05-22 14:41:32 +02001239output_handle_geometry(void *data,
1240 struct wl_output *wl_output,
1241 int x, int y,
1242 int physical_width,
1243 int physical_height,
1244 int subpixel,
1245 const char *make,
1246 const char *model,
1247 int transform)
1248{
1249 struct output *output = data;
1250
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001251 output->x = x;
1252 output->y = y;
1253
Jonny Lambe67118c2014-08-12 15:07:51 +02001254 if (output->panel)
1255 window_set_buffer_transform(output->panel->window, transform);
Pekka Paalanencb115382017-12-07 12:15:01 +02001256 if (output->background)
1257 window_set_buffer_transform(output->background->window, transform);
Alexander Larssonc584fa62013-05-22 14:41:32 +02001258}
1259
1260static void
1261output_handle_mode(void *data,
1262 struct wl_output *wl_output,
1263 uint32_t flags,
1264 int width,
1265 int height,
1266 int refresh)
1267{
1268}
1269
1270static void
1271output_handle_done(void *data,
1272 struct wl_output *wl_output)
1273{
1274}
1275
1276static void
1277output_handle_scale(void *data,
1278 struct wl_output *wl_output,
Alexander Larssonedddbd12013-05-24 13:09:43 +02001279 int32_t scale)
Alexander Larssonc584fa62013-05-22 14:41:32 +02001280{
1281 struct output *output = data;
1282
Jonny Lambe67118c2014-08-12 15:07:51 +02001283 if (output->panel)
1284 window_set_buffer_scale(output->panel->window, scale);
Pekka Paalanencb115382017-12-07 12:15:01 +02001285 if (output->background)
1286 window_set_buffer_scale(output->background->window, scale);
Alexander Larssonc584fa62013-05-22 14:41:32 +02001287}
1288
1289static const struct wl_output_listener output_listener = {
1290 output_handle_geometry,
1291 output_handle_mode,
1292 output_handle_done,
1293 output_handle_scale
1294};
1295
1296static void
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001297output_init(struct output *output, struct desktop *desktop)
1298{
1299 struct wl_surface *surface;
1300
Quentin Glidic55d57012016-06-23 18:55:18 +02001301 if (desktop->want_panel) {
Pekka Paalanen1cbfcf42017-12-07 12:39:15 +02001302 output->panel = panel_create(desktop, output);
Jonny Lambe67118c2014-08-12 15:07:51 +02001303 surface = window_get_wl_surface(output->panel->window);
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001304 weston_desktop_shell_set_panel(desktop->shell,
1305 output->output, surface);
Jonny Lambe67118c2014-08-12 15:07:51 +02001306 }
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001307
Pekka Paalanencb115382017-12-07 12:15:01 +02001308 output->background = background_create(desktop, output);
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001309 surface = window_get_wl_surface(output->background->window);
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001310 weston_desktop_shell_set_background(desktop->shell,
1311 output->output, surface);
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001312}
1313
1314static void
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001315create_output(struct desktop *desktop, uint32_t id)
1316{
1317 struct output *output;
1318
Bryce Harrington0d1a6222016-02-11 16:42:49 -08001319 output = zalloc(sizeof *output);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001320 if (!output)
1321 return;
1322
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001323 output->output =
Alexander Larssonc584fa62013-05-22 14:41:32 +02001324 display_bind(desktop->display, id, &wl_output_interface, 2);
Xiong Zhang83d8ee72013-10-23 13:58:35 +08001325 output->server_output_id = id;
Alexander Larssonc584fa62013-05-22 14:41:32 +02001326
1327 wl_output_add_listener(output->output, &output_listener, output);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001328
1329 wl_list_insert(&desktop->outputs, &output->link);
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001330
1331 /* On start up we may process an output global before the shell global
1332 * in which case we can't create the panel and background just yet */
1333 if (desktop->shell)
1334 output_init(output, desktop);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001335}
1336
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001337static void
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001338output_remove(struct desktop *desktop, struct output *output)
1339{
1340 struct output *cur;
1341 struct output *rep = NULL;
1342
1343 if (!output->background) {
1344 output_destroy(output);
1345 return;
1346 }
1347
1348 /* Find a wl_output that is a clone of the removed wl_output.
1349 * We don't want to leave the clone without a background or panel. */
1350 wl_list_for_each(cur, &desktop->outputs, link) {
1351 if (cur == output)
1352 continue;
1353
1354 /* XXX: Assumes size matches. */
1355 if (cur->x == output->x && cur->y == output->y) {
1356 rep = cur;
1357 break;
1358 }
1359 }
1360
1361 if (rep) {
Pekka Paalanen82dd54d2018-06-21 15:38:56 +03001362 /* If found and it does not already have a background or panel,
1363 * hand over the background and panel so they don't get
1364 * destroyed.
1365 *
1366 * We never create multiple backgrounds or panels for clones,
1367 * but if the compositor moves outputs, a pair of wl_outputs
1368 * might become "clones". This may happen temporarily when
1369 * an output is about to be removed and the rest are reflowed.
1370 * In this case it is correct to let the background/panel be
1371 * destroyed.
1372 */
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001373
Pekka Paalanen82dd54d2018-06-21 15:38:56 +03001374 if (!rep->background) {
1375 rep->background = output->background;
1376 output->background = NULL;
1377 rep->background->owner = rep;
1378 }
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001379
Pekka Paalanen82dd54d2018-06-21 15:38:56 +03001380 if (!rep->panel) {
1381 rep->panel = output->panel;
1382 output->panel = NULL;
1383 if (rep->panel)
1384 rep->panel->owner = rep;
1385 }
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001386 }
1387
1388 output_destroy(output);
1389}
1390
1391static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001392global_handler(struct display *display, uint32_t id,
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001393 const char *interface, uint32_t version, void *data)
1394{
1395 struct desktop *desktop = data;
1396
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001397 if (!strcmp(interface, "weston_desktop_shell")) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001398 desktop->shell = display_bind(desktop->display,
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001399 id,
1400 &weston_desktop_shell_interface,
1401 1);
1402 weston_desktop_shell_add_listener(desktop->shell,
1403 &listener,
1404 desktop);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001405 } else if (!strcmp(interface, "wl_output")) {
1406 create_output(desktop, id);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001407 }
1408}
1409
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001410static void
Xiong Zhang83d8ee72013-10-23 13:58:35 +08001411global_handler_remove(struct display *display, uint32_t id,
1412 const char *interface, uint32_t version, void *data)
1413{
1414 struct desktop *desktop = data;
1415 struct output *output;
1416
1417 if (!strcmp(interface, "wl_output")) {
1418 wl_list_for_each(output, &desktop->outputs, link) {
1419 if (output->server_output_id == id) {
Pekka Paalanenc1bcce62017-12-07 15:30:18 +02001420 output_remove(desktop, output);
Xiong Zhang83d8ee72013-10-23 13:58:35 +08001421 break;
1422 }
1423 }
1424 }
1425}
1426
1427static void
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001428panel_add_launchers(struct panel *panel, struct desktop *desktop)
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001429{
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001430 struct weston_config_section *s;
1431 char *icon, *path;
1432 const char *name;
1433 int count;
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001434
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001435 count = 0;
1436 s = NULL;
1437 while (weston_config_next_section(desktop->config, &s, &name)) {
1438 if (strcmp(name, "launcher") != 0)
1439 continue;
1440
1441 weston_config_section_get_string(s, "icon", &icon, NULL);
1442 weston_config_section_get_string(s, "path", &path, NULL);
1443
1444 if (icon != NULL && path != NULL) {
1445 panel_add_launcher(panel, icon, path);
Rob Bradford09252d42013-07-26 16:29:45 +01001446 count++;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001447 } else {
1448 fprintf(stderr, "invalid launcher section\n");
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001449 }
1450
1451 free(icon);
1452 free(path);
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001453 }
1454
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001455 if (count == 0) {
Derek Foremane2772762018-02-06 15:18:38 -06001456 char *name = file_name_with_datadir("terminal.png");
1457
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001458 /* add default launcher */
1459 panel_add_launcher(panel,
Derek Foremane2772762018-02-06 15:18:38 -06001460 name,
Rodney Lorrimar99ff01b2012-02-29 17:31:03 +01001461 BINDIR "/weston-terminal");
Derek Foremane2772762018-02-06 15:18:38 -06001462 free(name);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001463 }
Kristian Høgsberg6af8eb92012-01-25 16:57:11 -05001464}
1465
Quentin Glidic55d57012016-06-23 18:55:18 +02001466static void
1467parse_panel_position(struct desktop *desktop, struct weston_config_section *s)
1468{
1469 char *position;
1470
Daniel Stone08cf24b2017-01-16 13:18:21 +00001471 desktop->want_panel = 1;
Quentin Glidic55d57012016-06-23 18:55:18 +02001472
Daniel Stone08cf24b2017-01-16 13:18:21 +00001473 weston_config_section_get_string(s, "panel-position", &position, "top");
1474 if (strcmp(position, "top") == 0) {
1475 desktop->panel_position = WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP;
1476 } else if (strcmp(position, "bottom") == 0) {
1477 desktop->panel_position = WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM;
1478 } else if (strcmp(position, "left") == 0) {
1479 desktop->panel_position = WESTON_DESKTOP_SHELL_PANEL_POSITION_LEFT;
1480 } else if (strcmp(position, "right") == 0) {
1481 desktop->panel_position = WESTON_DESKTOP_SHELL_PANEL_POSITION_RIGHT;
1482 } else {
1483 /* 'none' is valid here */
1484 if (strcmp(position, "none") != 0)
1485 fprintf(stderr, "Wrong panel position: %s\n", position);
1486 desktop->want_panel = 0;
Quentin Glidic55d57012016-06-23 18:55:18 +02001487 }
Daniel Stone08cf24b2017-01-16 13:18:21 +00001488 free(position);
Quentin Glidic55d57012016-06-23 18:55:18 +02001489}
1490
Quentin Glidic3e37b342016-06-23 18:55:22 +02001491static void
1492parse_clock_format(struct desktop *desktop, struct weston_config_section *s)
1493{
1494 char *clock_format;
1495
1496 weston_config_section_get_string(s, "clock-format", &clock_format, "");
1497 if (strcmp(clock_format, "minutes") == 0)
1498 desktop->clock_format = CLOCK_FORMAT_MINUTES;
1499 else if (strcmp(clock_format, "seconds") == 0)
1500 desktop->clock_format = CLOCK_FORMAT_SECONDS;
1501 else if (strcmp(clock_format, "none") == 0)
1502 desktop->clock_format = CLOCK_FORMAT_NONE;
1503 else
1504 desktop->clock_format = DEFAULT_CLOCK_FORMAT;
1505 free(clock_format);
1506}
1507
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001508int main(int argc, char *argv[])
1509{
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001510 struct desktop desktop = { 0 };
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001511 struct output *output;
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001512 struct weston_config_section *s;
Pekka Paalanen6c71aae2015-03-24 15:56:19 +02001513 const char *config_file;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001514
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001515 desktop.unlock_task.run = unlock_dialog_finish;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +01001516 wl_list_init(&desktop.outputs);
Pekka Paalanenbfbb26b2011-11-15 13:34:56 +02001517
Pekka Paalanen6c71aae2015-03-24 15:56:19 +02001518 config_file = weston_config_get_name_from_env();
1519 desktop.config = weston_config_parse(config_file);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001520 s = weston_config_get_section(desktop.config, "shell", NULL, NULL);
Daniel Stone51d995a2019-11-26 00:14:24 +00001521 weston_config_section_get_bool(s, "locking", &desktop.locking, true);
Quentin Glidic55d57012016-06-23 18:55:18 +02001522 parse_panel_position(&desktop, s);
Quentin Glidic3e37b342016-06-23 18:55:22 +02001523 parse_clock_format(&desktop, s);
Ander Conselvan de Oliveira6d75da72013-07-05 16:05:27 +03001524
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001525 desktop.display = display_create(&argc, argv);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001526 if (desktop.display == NULL) {
Antonio Borneo39578632019-04-26 23:57:31 +02001527 fprintf(stderr, "failed to create display: %s\n",
1528 strerror(errno));
Anurup Mc640cb62020-11-25 06:35:40 +05301529 weston_config_destroy(desktop.config);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001530 return -1;
1531 }
1532
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001533 display_set_user_data(desktop.display, &desktop);
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001534 display_set_global_handler(desktop.display, global_handler);
Xiong Zhang83d8ee72013-10-23 13:58:35 +08001535 display_set_global_handler_remove(desktop.display, global_handler_remove);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001536
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001537 /* Create panel and background for outputs processed before the shell
1538 * global interface was processed */
Quentin Glidic55d57012016-06-23 18:55:18 +02001539 if (desktop.want_panel)
1540 weston_desktop_shell_set_panel_position(desktop.shell, desktop.panel_position);
Ander Conselvan de Oliveirae4925492013-07-05 16:05:28 +03001541 wl_list_for_each(output, &desktop.outputs, link)
1542 if (!output->panel)
1543 output_init(output, &desktop);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001544
Ander Conselvan de Oliveirab9d2a0f2012-06-28 18:08:05 +03001545 grab_surface_create(&desktop);
Kristian Høgsbergd56bd902012-06-05 09:58:51 -04001546
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001547 signal(SIGCHLD, sigchild_handler);
1548
1549 display_run(desktop.display);
1550
U. Artie Eoff44874d92012-10-02 21:12:35 -07001551 /* Cleanup */
1552 grab_surface_destroy(&desktop);
1553 desktop_destroy_outputs(&desktop);
1554 if (desktop.unlock_dialog)
1555 unlock_dialog_destroy(desktop.unlock_dialog);
Jonas Ådahl6d6fb612015-11-17 16:00:33 +08001556 weston_desktop_shell_destroy(desktop.shell);
U. Artie Eoff44874d92012-10-02 21:12:35 -07001557 display_destroy(desktop.display);
Anurup Mc640cb62020-11-25 06:35:40 +05301558 weston_config_destroy(desktop.config);
U. Artie Eoff44874d92012-10-02 21:12:35 -07001559
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001560 return 0;
1561}