blob: 3f773e9d9b3b4194d9dccc4b40c242bcaf25fb74 [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"
35#include "wayland-glib.h"
36#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;
50 struct wl_list item_list;
51 struct panel_item *focus;
52};
53
54struct panel_item {
55 struct wl_list link;
56 cairo_surface_t *icon;
57 int x, y, width, height;
58 int pressed;
59 const char *path;
60};
61
62static void
63sigchild_handler(int s)
64{
65 int status;
66 pid_t pid;
67
68 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
69 fprintf(stderr, "child %d exited\n", pid);
70}
71
72static void
73panel_activate_item(struct panel *panel, struct panel_item *item)
74{
75 pid_t pid;
76
77 pid = fork();
78 if (pid < 0) {
79 fprintf(stderr, "fork failed: %m\n");
80 return;
81 }
82
83 if (pid)
84 return;
85
86 if (execl(item->path, item->path, NULL) < 0) {
87 fprintf(stderr, "execl failed: %m\n");
88 exit(1);
89 }
90}
91
92static struct panel_item *
93panel_find_item(struct panel *panel, int32_t x, int32_t y)
94{
95 struct panel_item *item;
96
97 wl_list_for_each(item, &panel->item_list, link) {
98 if (item->x <= x && x < item->x + item->width &&
99 item->y <= y && y < item->y + item->height) {
100 return item;
101 }
102 }
103
104 return NULL;
105}
106
107static void
108panel_draw_item(struct panel *panel, cairo_t *cr, struct panel_item *item)
109{
110 int x, y;
111
112 if (item->pressed) {
113 x = item->x + 1;
114 y = item->y + 1;
115 } else {
116 x = item->x;
117 y = item->y;
118 }
119
120 cairo_set_source_surface(cr, item->icon, x, y);
121 cairo_paint(cr);
122
123 if (panel->focus == item) {
124 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
125 cairo_mask_surface(cr, item->icon, x, y);
126 }
127}
128
129static void
130panel_redraw_handler(struct window *window, void *data)
131{
132 cairo_surface_t *surface;
133 cairo_t *cr;
134 struct panel *panel = window_get_user_data(window);
135 struct panel_item *item;
136
137 window_draw(window);
138 surface = window_get_surface(window);
139 cr = cairo_create(surface);
140 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
141 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.9);
142 cairo_paint(cr);
143
144 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
145 wl_list_for_each(item, &panel->item_list, link)
146 panel_draw_item(panel, cr, item);
147
148 cairo_destroy(cr);
149 cairo_surface_destroy(surface);
150 window_flush(window);
151}
152
153static void
154panel_set_focus(struct panel *panel, struct panel_item *focus)
155{
156 if (focus == panel->focus)
157 return;
158
159 panel->focus = focus;
160 window_schedule_redraw(panel->window);
161}
162
163static int
164panel_enter_handler(struct window *window,
165 struct input *input, uint32_t time,
166 int32_t x, int32_t y, void *data)
167{
168 struct panel *panel = data;
169 struct panel_item *item;
170
171 item = panel_find_item(panel, x, y);
172 panel_set_focus(panel, item);
173
174 return POINTER_LEFT_PTR;
175}
176
177static void
178panel_leave_handler(struct window *window,
179 struct input *input, uint32_t time, void *data)
180{
181 struct panel *panel = data;
182
183 panel_set_focus(panel, NULL);
184}
185
186static int
187panel_motion_handler(struct window *window,
188 struct input *input, uint32_t time,
189 int32_t x, int32_t y,
190 int32_t sx, int32_t sy, void *data)
191{
192 struct panel *panel = data;
193 struct panel_item *item;
194
195 if (panel->focus && panel->focus->pressed)
196 return POINTER_LEFT_PTR;
197
198 item = panel_find_item(panel, sx, sy);
199 panel_set_focus(panel, item);
200
201 return POINTER_LEFT_PTR;
202}
203
204static void
205panel_button_handler(struct window *window,
206 struct input *input, uint32_t time,
207 int button, int state, void *data)
208{
209 struct panel *panel = data;
210 struct panel_item *item;
211 int32_t x, y;
212
213 if (panel->focus && button == BTN_LEFT) {
214 panel->focus->pressed = state;
215 window_schedule_redraw(panel->window);
216
217 if (state == 0) {
218 panel_activate_item(panel, panel->focus);
219
220 input_get_position(input, &x, &y);
221 item = panel_find_item(panel, x, y);
222 panel_set_focus(panel, item);
223 }
224 }
225}
226
227static struct panel *
228panel_create(struct display *display)
229{
230 struct panel *panel;
231
232 panel = malloc(sizeof *panel);
233 memset(panel, 0, sizeof *panel);
234 wl_list_init(&panel->item_list);
235
236 panel->window = window_create(display, 0, 0);
237
238 window_set_title(panel->window, "panel");
239 window_set_decoration(panel->window, 0);
240 window_set_redraw_handler(panel->window, panel_redraw_handler);
241 window_set_custom(panel->window);
242 window_set_user_data(panel->window, panel);
243 window_set_enter_handler(panel->window, panel_enter_handler);
244 window_set_leave_handler(panel->window, panel_leave_handler);
245 window_set_motion_handler(panel->window, panel_motion_handler);
246 window_set_button_handler(panel->window, panel_button_handler);
247
248 return panel;
249}
250
251static void
252panel_add_item(struct panel *panel, const char *icon, const char *path)
253{
254 struct panel_item *item;
255
256 item = malloc(sizeof *item);
257 memset(item, 0, sizeof *item);
258 item->icon = cairo_image_surface_create_from_png(icon);
259 item->path = strdup(path);
260 wl_list_insert(panel->item_list.prev, &item->link);
261
262 item->width = cairo_image_surface_get_width(item->icon);
263 item->height = cairo_image_surface_get_height(item->icon);
264}
265
266static void
267panel_allocate(struct panel *panel, int width, int height)
268{
269 struct panel_item *item;
270 int x;
271
272 window_set_child_size(panel->window, width, height);
273 window_schedule_redraw(panel->window);
274
275 x = 10;
276 wl_list_for_each(item, &panel->item_list, link) {
277 item->x = x;
278 item->y = (height - item->height) / 2;
279 x += item->width + 10;
280 }
281}
282
283static void
284background_draw(struct window *window, int width, int height, const char *path)
285{
286 cairo_surface_t *surface, *image;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400287 cairo_pattern_t *pattern;
288 cairo_matrix_t matrix;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400289 cairo_t *cr;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400290 double sx, sy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400291
292 window_set_child_size(window, width, height);
293 window_draw(window);
294 surface = window_get_surface(window);
295
296 cr = cairo_create(surface);
297 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
298 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
299 cairo_paint(cr);
300
301 if (path) {
302 image = cairo_image_surface_create_from_png(path);
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400303 pattern = cairo_pattern_create_for_surface(image);
304 sx = (double) cairo_image_surface_get_width(image) / width;
305 sy = (double) cairo_image_surface_get_height(image) / height;
306 cairo_matrix_init_scale(&matrix, sx, sy);
307 cairo_pattern_set_matrix(pattern, &matrix);
308 cairo_set_source(cr, pattern);
309 cairo_pattern_destroy (pattern);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400310 cairo_paint(cr);
311 }
312
313 cairo_destroy(cr);
314 cairo_surface_destroy(surface);
315 window_flush(window);
316}
317
318static void
319desktop_shell_configure(void *data,
320 struct desktop_shell *desktop_shell,
321 uint32_t time, uint32_t edges,
322 struct wl_surface *surface,
323 int32_t width, int32_t height)
324{
325 struct desktop *desktop = data;
326
327 if (surface == window_get_wl_surface(desktop->panel->window)) {
328 panel_allocate(desktop->panel, width, 32);
329 } else if (surface == window_get_wl_surface(desktop->background)) {
330 background_draw(desktop->background,
331 width, height, desktop->background_path);
332 }
333}
334
335static const struct desktop_shell_listener listener = {
336 desktop_shell_configure
337};
338
339static void
340global_handler(struct wl_display *display, uint32_t id,
341 const char *interface, uint32_t version, void *data)
342{
343 struct desktop *desktop = data;
344
345 if (!strcmp(interface, "desktop_shell")) {
346 desktop->shell =
347 wl_display_bind(display, id, &desktop_shell_interface);
348 desktop_shell_add_listener(desktop->shell, &listener, desktop);
349 }
350}
351
352static const struct {
353 const char *icon;
354 const char *path;
355} launchers[] = {
356 {
357 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
358 "/usr/bin/gnome-terminal"
359 },
360 {
Kristian Høgsberg67680c12011-09-08 11:48:53 -0400361 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
362 "./clients/terminal"
363 },
364 {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400365 "/usr/share/icons/hicolor/24x24/apps/google-chrome.png",
366 "/usr/bin/google-chrome"
367 },
368};
369
370int main(int argc, char *argv[])
371{
372 struct desktop desktop;
373 int i;
374
375 desktop.display = display_create(&argc, &argv, NULL);
376 if (desktop.display == NULL) {
377 fprintf(stderr, "failed to create display: %m\n");
378 return -1;
379 }
380
381 wl_display_add_global_listener(display_get_display(desktop.display),
382 global_handler, &desktop);
383
384 desktop.panel = panel_create(desktop.display);
385
386 for (i = 0; i < ARRAY_LENGTH(launchers); i++)
387 panel_add_item(desktop.panel,
388 launchers[i].icon, launchers[i].path);
389
390 desktop_shell_set_panel(desktop.shell,
391 window_get_wl_surface(desktop.panel->window));
392
393 desktop.background = window_create(desktop.display, 0, 0);
394 window_set_decoration(desktop.background, 0);
395 window_set_custom(desktop.background);
396 desktop.background_path = argv[1];
397 desktop_shell_set_background(desktop.shell,
398 window_get_wl_surface(desktop.background));
399
400 signal(SIGCHLD, sigchild_handler);
401
402 display_run(desktop.display);
403
404 return 0;
405}