blob: 7ad6f029d5b2381828514fef8885b8e91df1e148 [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øgsberg0c29eb22011-09-06 18:02:34 -040035#include "window.h"
36
37#include <desktop-shell-client-protocol.h>
38
39struct desktop {
40 struct display *display;
41 struct desktop_shell *shell;
42 struct panel *panel;
43 struct window *background;
44 const char *background_path;
45};
46
47struct panel {
48 struct window *window;
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -040049 struct window *menu;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040050};
51
52struct panel_item {
Kristian Høgsberge28d05b2011-09-20 21:43:54 -040053 struct item *item;
54 struct panel *panel;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040055 cairo_surface_t *icon;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040056 int pressed;
57 const char *path;
58};
59
60static void
61sigchild_handler(int s)
62{
63 int status;
64 pid_t pid;
65
66 while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
67 fprintf(stderr, "child %d exited\n", pid);
68}
69
70static void
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -040071show_menu(struct panel *panel, struct input *input)
72{
73 int32_t x, y, width = 200, height = 200;
74 struct display *display;
75
76 input_get_position(input, &x, &y);
77 display = window_get_display(panel->window);
78 panel->menu = window_create_transient(display, panel->window,
79 x - 10, y - 10, width, height);
80
81 window_draw(panel->menu);
82 window_flush(panel->menu);
83}
84
85static void
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -040086panel_activate_item(struct panel *panel, struct panel_item *item)
87{
88 pid_t pid;
89
90 pid = fork();
91 if (pid < 0) {
92 fprintf(stderr, "fork failed: %m\n");
93 return;
94 }
95
96 if (pid)
97 return;
98
99 if (execl(item->path, item->path, NULL) < 0) {
100 fprintf(stderr, "execl failed: %m\n");
101 exit(1);
102 }
103}
104
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400105static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400106panel_draw_item(struct item *item, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400107{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400108 cairo_t *cr = data;
109 struct panel_item *pi;
110 int x, y, width, height;
111 double dx, dy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400112
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400113 pi = item_get_user_data(item);
114 width = cairo_image_surface_get_width(pi->icon);
115 height = cairo_image_surface_get_height(pi->icon);
116 x = 0;
117 y = -height / 2;
118 if (pi->pressed) {
119 x++;
120 y++;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400121 }
122
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400123 dx = x;
124 dy = y;
125 cairo_user_to_device(cr, &dx, &dy);
126 item_set_allocation(item, dx, dy, width, height);
127
128 cairo_set_source_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400129 cairo_paint(cr);
130
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400131 if (window_get_focus_item(pi->panel->window) == item) {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400132 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400133 cairo_mask_surface(cr, pi->icon, x, y);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400134 }
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400135
136 cairo_translate(cr, width + 10, 0);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400137}
138
139static void
140panel_redraw_handler(struct window *window, void *data)
141{
142 cairo_surface_t *surface;
143 cairo_t *cr;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400144
145 window_draw(window);
146 surface = window_get_surface(window);
147 cr = cairo_create(surface);
148 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
149 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.9);
150 cairo_paint(cr);
151
152 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400153 cairo_translate(cr, 10, 32 / 2);
154 window_for_each_item(window, panel_draw_item, cr);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400155
156 cairo_destroy(cr);
157 cairo_surface_destroy(surface);
158 window_flush(window);
159}
160
161static void
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400162panel_item_focus_handler(struct window *window,
163 struct item *focus, void *data)
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400164{
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400165 window_schedule_redraw(window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400166}
167
168static void
169panel_button_handler(struct window *window,
170 struct input *input, uint32_t time,
171 int button, int state, void *data)
172{
173 struct panel *panel = data;
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400174 struct panel_item *pi;
175 struct item *focus;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400176
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400177 focus = window_get_focus_item(panel->window);
178 if (focus && button == BTN_LEFT) {
179 pi = item_get_user_data(focus);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400180 window_schedule_redraw(panel->window);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400181 if (state == 0)
182 panel_activate_item(panel, pi);
Kristian Høgsbergbcee9a42011-10-12 00:36:16 -0400183 } else if (button == BTN_RIGHT) {
184 if (state)
185 show_menu(panel, input);
186 else
187 window_destroy(panel->menu);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400188 }
189}
190
191static struct panel *
192panel_create(struct display *display)
193{
194 struct panel *panel;
195
196 panel = malloc(sizeof *panel);
197 memset(panel, 0, sizeof *panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400198
199 panel->window = window_create(display, 0, 0);
200
201 window_set_title(panel->window, "panel");
202 window_set_decoration(panel->window, 0);
203 window_set_redraw_handler(panel->window, panel_redraw_handler);
204 window_set_custom(panel->window);
205 window_set_user_data(panel->window, panel);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400206 window_set_button_handler(panel->window, panel_button_handler);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400207 window_set_item_focus_handler(panel->window, panel_item_focus_handler);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400208
209 return panel;
210}
211
212static void
213panel_add_item(struct panel *panel, const char *icon, const char *path)
214{
215 struct panel_item *item;
216
217 item = malloc(sizeof *item);
218 memset(item, 0, sizeof *item);
219 item->icon = cairo_image_surface_create_from_png(icon);
220 item->path = strdup(path);
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400221 item->panel = panel;
222 window_add_item(panel->window, item);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400223}
224
225static void
226background_draw(struct window *window, int width, int height, const char *path)
227{
228 cairo_surface_t *surface, *image;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400229 cairo_pattern_t *pattern;
230 cairo_matrix_t matrix;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400231 cairo_t *cr;
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400232 double sx, sy;
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400233
234 window_set_child_size(window, width, height);
235 window_draw(window);
236 surface = window_get_surface(window);
237
238 cr = cairo_create(surface);
239 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
240 cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
241 cairo_paint(cr);
242
243 if (path) {
244 image = cairo_image_surface_create_from_png(path);
Kristian Høgsberg7e690002011-09-08 18:18:02 -0400245 pattern = cairo_pattern_create_for_surface(image);
246 sx = (double) cairo_image_surface_get_width(image) / width;
247 sy = (double) cairo_image_surface_get_height(image) / height;
248 cairo_matrix_init_scale(&matrix, sx, sy);
249 cairo_pattern_set_matrix(pattern, &matrix);
250 cairo_set_source(cr, pattern);
251 cairo_pattern_destroy (pattern);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400252 cairo_paint(cr);
253 }
254
255 cairo_destroy(cr);
256 cairo_surface_destroy(surface);
257 window_flush(window);
258}
259
260static void
261desktop_shell_configure(void *data,
262 struct desktop_shell *desktop_shell,
263 uint32_t time, uint32_t edges,
264 struct wl_surface *surface,
265 int32_t width, int32_t height)
266{
267 struct desktop *desktop = data;
268
269 if (surface == window_get_wl_surface(desktop->panel->window)) {
Kristian Høgsberge28d05b2011-09-20 21:43:54 -0400270 window_set_child_size(desktop->panel->window, width, 32);
271 window_schedule_redraw(desktop->panel->window);
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400272 } else if (surface == window_get_wl_surface(desktop->background)) {
273 background_draw(desktop->background,
274 width, height, desktop->background_path);
275 }
276}
277
278static const struct desktop_shell_listener listener = {
279 desktop_shell_configure
280};
281
282static void
283global_handler(struct wl_display *display, uint32_t id,
284 const char *interface, uint32_t version, void *data)
285{
286 struct desktop *desktop = data;
287
288 if (!strcmp(interface, "desktop_shell")) {
289 desktop->shell =
290 wl_display_bind(display, id, &desktop_shell_interface);
291 desktop_shell_add_listener(desktop->shell, &listener, desktop);
292 }
293}
294
295static const struct {
296 const char *icon;
297 const char *path;
298} launchers[] = {
299 {
300 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
301 "/usr/bin/gnome-terminal"
302 },
303 {
Kristian Høgsberg67680c12011-09-08 11:48:53 -0400304 "/usr/share/icons/gnome/24x24/apps/utilities-terminal.png",
305 "./clients/terminal"
306 },
307 {
Kristian Høgsberg0c29eb22011-09-06 18:02:34 -0400308 "/usr/share/icons/hicolor/24x24/apps/google-chrome.png",
309 "/usr/bin/google-chrome"
310 },
311};
312
313int main(int argc, char *argv[])
314{
315 struct desktop desktop;
316 int i;
317
318 desktop.display = display_create(&argc, &argv, NULL);
319 if (desktop.display == NULL) {
320 fprintf(stderr, "failed to create display: %m\n");
321 return -1;
322 }
323
324 wl_display_add_global_listener(display_get_display(desktop.display),
325 global_handler, &desktop);
326
327 desktop.panel = panel_create(desktop.display);
328
329 for (i = 0; i < ARRAY_LENGTH(launchers); i++)
330 panel_add_item(desktop.panel,
331 launchers[i].icon, launchers[i].path);
332
333 desktop_shell_set_panel(desktop.shell,
334 window_get_wl_surface(desktop.panel->window));
335
336 desktop.background = window_create(desktop.display, 0, 0);
337 window_set_decoration(desktop.background, 0);
338 window_set_custom(desktop.background);
339 desktop.background_path = argv[1];
340 desktop_shell_set_background(desktop.shell,
341 window_get_wl_surface(desktop.background));
342
343 signal(SIGCHLD, sigchild_handler);
344
345 display_run(desktop.display);
346
347 return 0;
348}