blob: b915723899b88795a20c1e22603f2dace0de95ac [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
61static void
62sigchild_handler(int s)
63{
64 int status;
65 pid_t pid;
66
67 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
68 fprintf(stderr, "child %d exited\n", pid);
69}
70
71static void
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -040072show_menu(struct panel *panel, struct input *input)
73{
74 int32_t x, y, width = 200, height = 200;
75 struct display *display;
76
77 input_get_position(input, &x, &y);
78 display = window_get_display(panel->window);
79 panel->menu = window_create_transient(display, panel->window,
80 x - 10, y - 10, width, height);
81
82 window_draw(panel->menu);
83 window_flush(panel->menu);
84}
85
86static void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040087panel_activate_item(struct panel *panel, struct panel_item *item)
88{
89 pid_t pid;
90
91 pid = fork();
92 if (pid < 0) {
93 fprintf(stderr, "fork failed: %m\n");
94 return;
95 }
96
97 if (pid)
98 return;
99
100 if (execl(item->path, item->path, NULL) < 0) {
101 fprintf(stderr, "execl failed: %m\n");
102 exit(1);
103 }
104}
105
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400106static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400107panel_draw_item(struct item *item, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400108{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400109 cairo_t *cr = data;
110 struct panel_item *pi;
111 int x, y, width, height;
112 double dx, dy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400113
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400114 pi = item_get_user_data(item);
115 width = cairo_image_surface_get_width(pi->icon);
116 height = cairo_image_surface_get_height(pi->icon);
117 x = 0;
118 y = -height / 2;
119 if (pi->pressed) {
120 x++;
121 y++;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400122 }
123
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400124 dx = x;
125 dy = y;
126 cairo_user_to_device(cr, &dx, &dy);
127 item_set_allocation(item, dx, dy, width, height);
128
129 cairo_set_source_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400130 cairo_paint(cr);
131
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400132 if (window_get_focus_item(pi->panel->window) == item) {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400133 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400134 cairo_mask_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400135 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400136
137 cairo_translate(cr, width + 10, 0);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400138}
139
140static void
141panel_redraw_handler(struct window *window, void *data)
142{
143 cairo_surface_t *surface;
144 cairo_t *cr;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400145
146 window_draw(window);
147 surface = window_get_surface(window);
148 cr = cairo_create(surface);
149 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
150 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.9);
151 cairo_paint(cr);
152
153 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400154 cairo_translate(cr, 10, 32 / 2);
155 window_for_each_item(window, panel_draw_item, cr);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400156
157 cairo_destroy(cr);
158 cairo_surface_destroy(surface);
159 window_flush(window);
160}
161
162static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400163panel_item_focus_handler(struct window *window,
164 struct item *focus, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400165{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400166 window_schedule_redraw(window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400167}
168
169static void
170panel_button_handler(struct window *window,
171 struct input *input, uint32_t time,
172 int button, int state, void *data)
173{
174 struct panel *panel = data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400175 struct panel_item *pi;
176 struct item *focus;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400177
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400178 focus = window_get_focus_item(panel->window);
179 if (focus && button == BTN_LEFT) {
180 pi = item_get_user_data(focus);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400181 window_schedule_redraw(panel->window);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400182 if (state == 0)
183 panel_activate_item(panel, pi);
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -0400184 } else if (button == BTN_RIGHT) {
185 if (state)
186 show_menu(panel, input);
187 else
188 window_destroy(panel->menu);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400189 }
190}
191
192static struct panel *
193panel_create(struct display *display)
194{
195 struct panel *panel;
196
197 panel = malloc(sizeof *panel);
198 memset(panel, 0, sizeof *panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400199
200 panel->window = window_create(display, 0, 0);
201
202 window_set_title(panel->window, "panel");
203 window_set_decoration(panel->window, 0);
204 window_set_redraw_handler(panel->window, panel_redraw_handler);
205 window_set_custom(panel->window);
206 window_set_user_data(panel->window, panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400207 window_set_button_handler(panel->window, panel_button_handler);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400208 window_set_item_focus_handler(panel->window, panel_item_focus_handler);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400209
210 return panel;
211}
212
213static void
214panel_add_item(struct panel *panel, const char *icon, const char *path)
215{
216 struct panel_item *item;
217
218 item = malloc(sizeof *item);
219 memset(item, 0, sizeof *item);
220 item->icon = cairo_image_surface_create_from_png(icon);
221 item->path = strdup(path);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400222 item->panel = panel;
223 window_add_item(panel->window, item);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400224}
225
226static void
227background_draw(struct window *window, int width, int height, const char *path)
228{
229 cairo_surface_t *surface, *image;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400230 cairo_pattern_t *pattern;
231 cairo_matrix_t matrix;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400232 cairo_t *cr;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400233 double sx, sy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400234
235 window_set_child_size(window, width, height);
236 window_draw(window);
237 surface = window_get_surface(window);
238
239 cr = cairo_create(surface);
240 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
241 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
242 cairo_paint(cr);
243
244 if (path) {
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400245 image = load_jpeg(path);
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400246 pattern = cairo_pattern_create_for_surface(image);
247 sx = (double) cairo_image_surface_get_width(image) / width;
248 sy = (double) cairo_image_surface_get_height(image) / height;
249 cairo_matrix_init_scale(&matrix, sx, sy);
250 cairo_pattern_set_matrix(pattern, &matrix);
251 cairo_set_source(cr, pattern);
252 cairo_pattern_destroy (pattern);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400253 cairo_paint(cr);
Kristian Høgsberg27d38662011-10-20 13:11:12 -0400254 cairo_surface_destroy(image);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400255 }
256
257 cairo_destroy(cr);
258 cairo_surface_destroy(surface);
259 window_flush(window);
260}
261
262static void
263desktop_shell_configure(void *data,
264 struct desktop_shell *desktop_shell,
265 uint32_t time, uint32_t edges,
266 struct wl_surface *surface,
267 int32_t width, int32_t height)
268{
269 struct desktop *desktop = data;
270
271 if (surface == window_get_wl_surface(desktop->panel->window)) {
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400272 window_set_child_size(desktop->panel->window, width, 32);
273 window_schedule_redraw(desktop->panel->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400274 } else if (surface == window_get_wl_surface(desktop->background)) {
275 background_draw(desktop->background,
276 width, height, desktop->background_path);
277 }
278}
279
280static const struct desktop_shell_listener listener = {
281 desktop_shell_configure
282};
283
284static void
285global_handler(struct wl_display *display, uint32_t id,
286 const char *interface, uint32_t version, void *data)
287{
288 struct desktop *desktop = data;
289
290 if (!strcmp(interface, "desktop_shell")) {
291 desktop->shell =
292 wl_display_bind(display, id, &desktop_shell_interface);
293 desktop_shell_add_listener(desktop->shell, &listener, desktop);
294 }
295}
296
297static const struct {
298 const char *icon;
299 const char *path;
300} launchers[] = {
301 {
302 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
303 "/usr/bin/gnome-terminal"
304 },
305 {
Kristian Høgsberg67680c12011-09-08 11:48:53 -0400306 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
307 "./clients/terminal"
308 },
309 {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400310 "/usr/share/icons/hicolor/24x24/apps/google-chrome.png",
311 "/usr/bin/google-chrome"
312 },
313};
314
315int main(int argc, char *argv[])
316{
317 struct desktop desktop;
318 int i;
319
320 desktop.display = display_create(&argc, &argv, NULL);
321 if (desktop.display == NULL) {
322 fprintf(stderr, "failed to create display: %m\n");
323 return -1;
324 }
325
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200326 /* The fd is our private, do not confuse our children with it. */
327 unsetenv("WAYLAND_SOCKET");
328
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400329 wl_display_add_global_listener(display_get_display(desktop.display),
330 global_handler, &desktop);
331
332 desktop.panel = panel_create(desktop.display);
333
334 for (i = 0; i < ARRAY_LENGTH(launchers); i++)
335 panel_add_item(desktop.panel,
336 launchers[i].icon, launchers[i].path);
337
338 desktop_shell_set_panel(desktop.shell,
339 window_get_wl_surface(desktop.panel->window));
340
341 desktop.background = window_create(desktop.display, 0, 0);
342 window_set_decoration(desktop.background, 0);
343 window_set_custom(desktop.background);
344 desktop.background_path = argv[1];
345 desktop_shell_set_background(desktop.shell,
346 window_get_wl_surface(desktop.background));
347
348 signal(SIGCHLD, sigchild_handler);
349
350 display_run(desktop.display);
351
352 return 0;
353}