blob: b437ed8cfa34520fffe82bf6674047cbd9849764 [file] [log] [blame]
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -04001/*
2 * Copyright © 2011 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <math.h>
30#include <cairo.h>
31#include <sys/wait.h>
32#include <linux/input.h>
33
34#include "wayland-client.h"
Kristian Høgsberg27d38662011-10-20 13:11:12 -040035#include "cairo-util.h"
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040036#include "window.h"
37
38#include <desktop-shell-client-protocol.h>
39
40struct desktop {
41 struct display *display;
42 struct desktop_shell *shell;
43 struct panel *panel;
44 struct window *background;
45 const char *background_path;
46};
47
48struct panel {
49 struct window *window;
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -040050 struct window *menu;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040051};
52
53struct panel_item {
Kristian Høgsberge28d05b2011-09-20 21:43:54 -040054 struct item *item;
55 struct panel *panel;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040056 cairo_surface_t *icon;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040057 int pressed;
58 const char *path;
59};
60
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050061static char *key_background_image;
62static uint32_t key_panel_color;
63static char *key_launcher_icon;
64static char *key_launcher_path;
65static void launcher_section_done(void *data);
66
67static const struct config_key shell_config_keys[] = {
68 { "background-image", CONFIG_KEY_STRING, &key_background_image },
69 { "panel-color", CONFIG_KEY_INTEGER, &key_panel_color },
70};
71
72static const struct config_key launcher_config_keys[] = {
73 { "icon", CONFIG_KEY_STRING, &key_launcher_icon },
74 { "path", CONFIG_KEY_STRING, &key_launcher_path },
75};
76
77static const struct config_section config_sections[] = {
78 { "wayland-desktop-shell",
79 shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
80 { "launcher",
81 launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
82 launcher_section_done }
83};
84
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040085static void
86sigchild_handler(int s)
87{
88 int status;
89 pid_t pid;
90
91 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
92 fprintf(stderr, "child %d exited\n", pid);
93}
94
95static void
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -040096show_menu(struct panel *panel, struct input *input)
97{
98 int32_t x, y, width = 200, height = 200;
99 struct display *display;
100
101 input_get_position(input, &x, &y);
102 display = window_get_display(panel->window);
103 panel->menu = window_create_transient(display, panel->window,
104 x - 10, y - 10, width, height);
105
106 window_draw(panel->menu);
107 window_flush(panel->menu);
108}
109
110static void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400111panel_activate_item(struct panel *panel, struct panel_item *item)
112{
113 pid_t pid;
114
115 pid = fork();
116 if (pid < 0) {
117 fprintf(stderr, "fork failed: %m\n");
118 return;
119 }
120
121 if (pid)
122 return;
123
124 if (execl(item->path, item->path, NULL) < 0) {
125 fprintf(stderr, "execl failed: %m\n");
126 exit(1);
127 }
128}
129
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400130static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400131panel_draw_item(struct item *item, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400132{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400133 cairo_t *cr = data;
134 struct panel_item *pi;
135 int x, y, width, height;
136 double dx, dy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400137
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400138 pi = item_get_user_data(item);
139 width = cairo_image_surface_get_width(pi->icon);
140 height = cairo_image_surface_get_height(pi->icon);
141 x = 0;
142 y = -height / 2;
143 if (pi->pressed) {
144 x++;
145 y++;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400146 }
147
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400148 dx = x;
149 dy = y;
150 cairo_user_to_device(cr, &dx, &dy);
151 item_set_allocation(item, dx, dy, width, height);
152
153 cairo_set_source_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400154 cairo_paint(cr);
155
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400156 if (window_get_focus_item(pi->panel->window) == item) {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400157 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400158 cairo_mask_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400159 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400160
161 cairo_translate(cr, width + 10, 0);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400162}
163
164static void
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500165set_hex_color(cairo_t *cr, uint32_t color)
166{
167 cairo_set_source_rgba(cr,
168 ((color >> 16) & 0xff) / 255.0,
169 ((color >> 8) & 0xff) / 255.0,
170 ((color >> 0) & 0xff) / 255.0,
171 ((color >> 24) & 0xff) / 255.0);
172}
173
174static void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400175panel_redraw_handler(struct window *window, void *data)
176{
177 cairo_surface_t *surface;
178 cairo_t *cr;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400179
180 window_draw(window);
181 surface = window_get_surface(window);
182 cr = cairo_create(surface);
183 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500184 set_hex_color(cr, key_panel_color);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400185 cairo_paint(cr);
186
187 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400188 cairo_translate(cr, 10, 32 / 2);
189 window_for_each_item(window, panel_draw_item, cr);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400190
191 cairo_destroy(cr);
192 cairo_surface_destroy(surface);
193 window_flush(window);
194}
195
196static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400197panel_item_focus_handler(struct window *window,
198 struct item *focus, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400199{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400200 window_schedule_redraw(window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400201}
202
203static void
204panel_button_handler(struct window *window,
205 struct input *input, uint32_t time,
206 int button, int state, void *data)
207{
208 struct panel *panel = data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400209 struct panel_item *pi;
210 struct item *focus;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400211
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400212 focus = window_get_focus_item(panel->window);
213 if (focus && button == BTN_LEFT) {
214 pi = item_get_user_data(focus);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400215 window_schedule_redraw(panel->window);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400216 if (state == 0)
217 panel_activate_item(panel, pi);
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -0400218 } else if (button == BTN_RIGHT) {
219 if (state)
220 show_menu(panel, input);
221 else
222 window_destroy(panel->menu);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400223 }
224}
225
226static struct panel *
227panel_create(struct display *display)
228{
229 struct panel *panel;
230
231 panel = malloc(sizeof *panel);
232 memset(panel, 0, sizeof *panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400233
234 panel->window = window_create(display, 0, 0);
235
236 window_set_title(panel->window, "panel");
237 window_set_decoration(panel->window, 0);
238 window_set_redraw_handler(panel->window, panel_redraw_handler);
239 window_set_custom(panel->window);
240 window_set_user_data(panel->window, panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400241 window_set_button_handler(panel->window, panel_button_handler);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400242 window_set_item_focus_handler(panel->window, panel_item_focus_handler);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400243
244 return panel;
245}
246
247static void
248panel_add_item(struct panel *panel, const char *icon, const char *path)
249{
250 struct panel_item *item;
251
252 item = malloc(sizeof *item);
253 memset(item, 0, sizeof *item);
254 item->icon = cairo_image_surface_create_from_png(icon);
255 item->path = strdup(path);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400256 item->panel = panel;
257 window_add_item(panel->window, item);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400258}
259
260static void
261background_draw(struct window *window, int width, int height, const char *path)
262{
263 cairo_surface_t *surface, *image;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400264 cairo_pattern_t *pattern;
265 cairo_matrix_t matrix;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400266 cairo_t *cr;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400267 double sx, sy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400268
269 window_set_child_size(window, width, height);
270 window_draw(window);
271 surface = window_get_surface(window);
272
273 cr = cairo_create(surface);
274 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
275 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
276 cairo_paint(cr);
277
278 if (path) {
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400279 image = load_jpeg(path);
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400280 pattern = cairo_pattern_create_for_surface(image);
281 sx = (double) cairo_image_surface_get_width(image) / width;
282 sy = (double) cairo_image_surface_get_height(image) / height;
283 cairo_matrix_init_scale(&matrix, sx, sy);
284 cairo_pattern_set_matrix(pattern, &matrix);
285 cairo_set_source(cr, pattern);
286 cairo_pattern_destroy (pattern);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400287 cairo_paint(cr);
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400288 cairo_surface_destroy(image);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400289 }
290
291 cairo_destroy(cr);
292 cairo_surface_destroy(surface);
293 window_flush(window);
294}
295
296static void
297desktop_shell_configure(void *data,
298 struct desktop_shell *desktop_shell,
299 uint32_t time, uint32_t edges,
300 struct wl_surface *surface,
301 int32_t width, int32_t height)
302{
303 struct desktop *desktop = data;
304
305 if (surface == window_get_wl_surface(desktop->panel->window)) {
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400306 window_set_child_size(desktop->panel->window, width, 32);
307 window_schedule_redraw(desktop->panel->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400308 } else if (surface == window_get_wl_surface(desktop->background)) {
309 background_draw(desktop->background,
310 width, height, desktop->background_path);
311 }
312}
313
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200314static void
315desktop_shell_prepare_lock_surface(void *data,
316 struct desktop_shell *desktop_shell)
317{
318 /* no-op for now */
319 desktop_shell_unlock(desktop_shell);
320}
321
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400322static const struct desktop_shell_listener listener = {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200323 desktop_shell_configure,
324 desktop_shell_prepare_lock_surface
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400325};
326
327static void
328global_handler(struct wl_display *display, uint32_t id,
329 const char *interface, uint32_t version, void *data)
330{
331 struct desktop *desktop = data;
332
333 if (!strcmp(interface, "desktop_shell")) {
334 desktop->shell =
335 wl_display_bind(display, id, &desktop_shell_interface);
336 desktop_shell_add_listener(desktop->shell, &listener, desktop);
337 }
338}
339
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500340static void
341launcher_section_done(void *data)
342{
343 struct desktop *desktop = data;
344
345 if (key_launcher_icon == NULL || key_launcher_path == NULL) {
346 fprintf(stderr, "invalid launcher section\n");
347 return;
348 }
349
350 panel_add_item(desktop->panel, key_launcher_icon, key_launcher_path);
351 free(key_launcher_icon);
352 key_launcher_icon = NULL;
353 free(key_launcher_path);
354 key_launcher_path = NULL;
355}
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400356
357int main(int argc, char *argv[])
358{
359 struct desktop desktop;
Pekka Paalanen668dd562011-11-15 11:45:40 +0200360 char *config_file;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400361
362 desktop.display = display_create(&argc, &argv, NULL);
363 if (desktop.display == NULL) {
364 fprintf(stderr, "failed to create display: %m\n");
365 return -1;
366 }
367
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200368 /* The fd is our private, do not confuse our children with it. */
369 unsetenv("WAYLAND_SOCKET");
370
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400371 wl_display_add_global_listener(display_get_display(desktop.display),
372 global_handler, &desktop);
373
374 desktop.panel = panel_create(desktop.display);
375
Pekka Paalanen668dd562011-11-15 11:45:40 +0200376 config_file = config_file_path("wayland-desktop-shell.ini");
377 parse_config_file(config_file,
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500378 config_sections, ARRAY_LENGTH(config_sections),
379 &desktop);
Pekka Paalanen668dd562011-11-15 11:45:40 +0200380 free(config_file);
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500381
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400382 desktop_shell_set_panel(desktop.shell,
383 window_get_wl_surface(desktop.panel->window));
384
385 desktop.background = window_create(desktop.display, 0, 0);
386 window_set_decoration(desktop.background, 0);
387 window_set_custom(desktop.background);
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -0500388 desktop.background_path = key_background_image;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400389 desktop_shell_set_background(desktop.shell,
390 window_get_wl_surface(desktop.background));
391
392 signal(SIGCHLD, sigchild_handler);
393
394 display_run(desktop.display);
395
396 return 0;
397}