You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1298 lines
						
					
					
						
							32 KiB
						
					
					
				
			
		
		
	
	
							1298 lines
						
					
					
						
							32 KiB
						
					
					
				| /*
 | |
|  * Copyright © 2011 Kristian Høgsberg
 | |
|  * Copyright © 2011 Collabora, Ltd.
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <fcntl.h>
 | |
| #include <unistd.h>
 | |
| #include <math.h>
 | |
| #include <cairo.h>
 | |
| #include <sys/wait.h>
 | |
| #include <sys/timerfd.h>
 | |
| #include <sys/epoll.h> 
 | |
| #include <linux/input.h>
 | |
| #include <libgen.h>
 | |
| #include <ctype.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #include <wayland-client.h>
 | |
| #include "window.h"
 | |
| #include "../shared/cairo-util.h"
 | |
| #include "../shared/config-parser.h"
 | |
| 
 | |
| #include "desktop-shell-client-protocol.h"
 | |
| 
 | |
| extern char **environ; /* defined by libc */
 | |
| 
 | |
| struct desktop {
 | |
| 	struct display *display;
 | |
| 	struct desktop_shell *shell;
 | |
| 	uint32_t interface_version;
 | |
| 	struct unlock_dialog *unlock_dialog;
 | |
| 	struct task unlock_task;
 | |
| 	struct wl_list outputs;
 | |
| 
 | |
| 	struct window *grab_window;
 | |
| 	struct widget *grab_widget;
 | |
| 
 | |
| 	struct weston_config *config;
 | |
| 	int locking;
 | |
| 
 | |
| 	enum cursor_type grab_cursor;
 | |
| 
 | |
| 	int painted;
 | |
| };
 | |
| 
 | |
| struct surface {
 | |
| 	void (*configure)(void *data,
 | |
| 			  struct desktop_shell *desktop_shell,
 | |
| 			  uint32_t edges, struct window *window,
 | |
| 			  int32_t width, int32_t height);
 | |
| };
 | |
| 
 | |
| struct panel {
 | |
| 	struct surface base;
 | |
| 	struct window *window;
 | |
| 	struct widget *widget;
 | |
| 	struct wl_list launcher_list;
 | |
| 	struct panel_clock *clock;
 | |
| 	int painted;
 | |
| 	uint32_t color;
 | |
| };
 | |
| 
 | |
| struct background {
 | |
| 	struct surface base;
 | |
| 	struct window *window;
 | |
| 	struct widget *widget;
 | |
| 	int painted;
 | |
| 
 | |
| 	char *image;
 | |
| 	int type;
 | |
| 	uint32_t color;
 | |
| };
 | |
| 
 | |
| struct output {
 | |
| 	struct wl_output *output;
 | |
| 	struct wl_list link;
 | |
| 
 | |
| 	struct panel *panel;
 | |
| 	struct background *background;
 | |
| };
 | |
| 
 | |
| struct panel_launcher {
 | |
| 	struct widget *widget;
 | |
| 	struct panel *panel;
 | |
| 	cairo_surface_t *icon;
 | |
| 	int focused, pressed;
 | |
| 	char *path;
 | |
| 	struct wl_list link;
 | |
| 	struct wl_array envp;
 | |
| 	struct wl_array argv;
 | |
| };
 | |
| 
 | |
| struct panel_clock {
 | |
| 	struct widget *widget;
 | |
| 	struct panel *panel;
 | |
| 	struct task clock_task;
 | |
| 	int clock_fd;
 | |
| };
 | |
| 
 | |
| struct unlock_dialog {
 | |
| 	struct window *window;
 | |
| 	struct widget *widget;
 | |
| 	struct widget *button;
 | |
| 	int button_focused;
 | |
| 	int closing;
 | |
| 	struct desktop *desktop;
 | |
| };
 | |
| 
 | |
| static void
 | |
| panel_add_launchers(struct panel *panel, struct desktop *desktop);
 | |
| 
 | |
| static void
 | |
| sigchild_handler(int s)
 | |
| {
 | |
| 	int status;
 | |
| 	pid_t pid;
 | |
| 
 | |
| 	while (pid = waitpid(-1, &status, WNOHANG), pid > 0)
 | |
| 		fprintf(stderr, "child %d exited\n", pid);
 | |
| }
 | |
| 
 | |
| static void
 | |
| menu_func(struct window *window, int index, void *data)
 | |
| {
 | |
| 	printf("Selected index %d from a panel menu.\n", index);
 | |
| }
 | |
| 
 | |
| static void
 | |
| show_menu(struct panel *panel, struct input *input, uint32_t time)
 | |
| {
 | |
| 	int32_t x, y;
 | |
| 	static const char *entries[] = {
 | |
| 		"Roy", "Pris", "Leon", "Zhora"
 | |
| 	};
 | |
| 
 | |
| 	input_get_position(input, &x, &y);
 | |
| 	window_show_menu(window_get_display(panel->window),
 | |
| 			 input, time, panel->window,
 | |
| 			 x - 10, y - 10, menu_func, entries, 4);
 | |
| }
 | |
| 
 | |
| static int
 | |
| is_desktop_painted(struct desktop *desktop)
 | |
| {
 | |
| 	struct output *output;
 | |
| 
 | |
| 	wl_list_for_each(output, &desktop->outputs, link) {
 | |
| 		if (output->panel && !output->panel->painted)
 | |
| 			return 0;
 | |
| 		if (output->background && !output->background->painted)
 | |
| 			return 0;
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| check_desktop_ready(struct window *window)
 | |
| {
 | |
| 	struct display *display;
 | |
| 	struct desktop *desktop;
 | |
| 
 | |
| 	display = window_get_display(window);
 | |
| 	desktop = display_get_user_data(display);
 | |
| 
 | |
| 	if (!desktop->painted && is_desktop_painted(desktop)) {
 | |
| 		desktop->painted = 1;
 | |
| 
 | |
| 		if (desktop->interface_version >= 2)
 | |
| 			desktop_shell_desktop_ready(desktop->shell);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_activate(struct panel_launcher *widget)
 | |
| {
 | |
| 	char **argv;
 | |
| 	pid_t pid;
 | |
| 
 | |
| 	pid = fork();
 | |
| 	if (pid < 0) {
 | |
| 		fprintf(stderr, "fork failed: %m\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (pid)
 | |
| 		return;
 | |
| 
 | |
| 	argv = widget->argv.data;
 | |
| 	if (execve(argv[0], argv, widget->envp.data) < 0) {
 | |
| 		fprintf(stderr, "execl '%s' failed: %m\n", argv[0]);
 | |
| 		exit(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_redraw_handler(struct widget *widget, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher = data;
 | |
| 	struct rectangle allocation;
 | |
| 	cairo_t *cr;
 | |
| 
 | |
| 	cr = widget_cairo_create(launcher->panel->widget);
 | |
| 
 | |
| 	widget_get_allocation(widget, &allocation);
 | |
| 	if (launcher->pressed) {
 | |
| 		allocation.x++;
 | |
| 		allocation.y++;
 | |
| 	}
 | |
| 
 | |
| 	cairo_set_source_surface(cr, launcher->icon,
 | |
| 				 allocation.x, allocation.y);
 | |
| 	cairo_paint(cr);
 | |
| 
 | |
| 	if (launcher->focused) {
 | |
| 		cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
 | |
| 		cairo_mask_surface(cr, launcher->icon,
 | |
| 				   allocation.x, allocation.y);
 | |
| 	}
 | |
| 
 | |
| 	cairo_destroy(cr);
 | |
| }
 | |
| 
 | |
| static int
 | |
| panel_launcher_motion_handler(struct widget *widget, struct input *input,
 | |
| 			      uint32_t time, float x, float y, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher = data;
 | |
| 
 | |
| 	widget_set_tooltip(widget, basename((char *)launcher->path), x, y);
 | |
| 
 | |
| 	return CURSOR_LEFT_PTR;
 | |
| }
 | |
| 
 | |
| static void
 | |
| set_hex_color(cairo_t *cr, uint32_t color)
 | |
| {
 | |
| 	cairo_set_source_rgba(cr, 
 | |
| 			      ((color >> 16) & 0xff) / 255.0,
 | |
| 			      ((color >>  8) & 0xff) / 255.0,
 | |
| 			      ((color >>  0) & 0xff) / 255.0,
 | |
| 			      ((color >> 24) & 0xff) / 255.0);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_redraw_handler(struct widget *widget, void *data)
 | |
| {
 | |
| 	cairo_surface_t *surface;
 | |
| 	cairo_t *cr;
 | |
| 	struct panel *panel = data;
 | |
| 
 | |
| 	cr = widget_cairo_create(panel->widget);
 | |
| 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 | |
| 	set_hex_color(cr, panel->color);
 | |
| 	cairo_paint(cr);
 | |
| 
 | |
| 	cairo_destroy(cr);
 | |
| 	surface = window_get_surface(panel->window);
 | |
| 	cairo_surface_destroy(surface);
 | |
| 	panel->painted = 1;
 | |
| 	check_desktop_ready(panel->window);
 | |
| }
 | |
| 
 | |
| static int
 | |
| panel_launcher_enter_handler(struct widget *widget, struct input *input,
 | |
| 			     float x, float y, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher = data;
 | |
| 
 | |
| 	launcher->focused = 1;
 | |
| 	widget_schedule_redraw(widget);
 | |
| 
 | |
| 	return CURSOR_LEFT_PTR;
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_leave_handler(struct widget *widget,
 | |
| 			     struct input *input, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher = data;
 | |
| 
 | |
| 	launcher->focused = 0;
 | |
| 	widget_destroy_tooltip(widget);
 | |
| 	widget_schedule_redraw(widget);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_button_handler(struct widget *widget,
 | |
| 			      struct input *input, uint32_t time,
 | |
| 			      uint32_t button,
 | |
| 			      enum wl_pointer_button_state state, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher;
 | |
| 
 | |
| 	launcher = widget_get_user_data(widget);
 | |
| 	widget_schedule_redraw(widget);
 | |
| 	if (state == WL_POINTER_BUTTON_STATE_RELEASED)
 | |
| 		panel_launcher_activate(launcher);
 | |
| 
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_touch_down_handler(struct widget *widget, struct input *input,
 | |
| 				  uint32_t serial, uint32_t time, int32_t id,
 | |
| 				  float x, float y, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher;
 | |
| 
 | |
| 	launcher = widget_get_user_data(widget);
 | |
| 	launcher->focused = 1;
 | |
| 	widget_schedule_redraw(widget);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_launcher_touch_up_handler(struct widget *widget, struct input *input,
 | |
| 				uint32_t serial, uint32_t time, int32_t id, 
 | |
| 				void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher;
 | |
| 
 | |
| 	launcher = widget_get_user_data(widget);
 | |
| 	launcher->focused = 0;
 | |
| 	widget_schedule_redraw(widget);
 | |
| 	panel_launcher_activate(launcher);
 | |
| }
 | |
| 
 | |
| static void
 | |
| clock_func(struct task *task, uint32_t events)
 | |
| {
 | |
| 	struct panel_clock *clock =
 | |
| 		container_of(task, struct panel_clock, clock_task);
 | |
| 	uint64_t exp;
 | |
| 
 | |
| 	if (read(clock->clock_fd, &exp, sizeof exp) != sizeof exp)
 | |
| 		abort();
 | |
| 	widget_schedule_redraw(clock->widget);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_clock_redraw_handler(struct widget *widget, void *data)
 | |
| {
 | |
| 	struct panel_clock *clock = data;
 | |
| 	cairo_t *cr;
 | |
| 	struct rectangle allocation;
 | |
| 	cairo_text_extents_t extents;
 | |
| 	cairo_font_extents_t font_extents;
 | |
| 	time_t rawtime;
 | |
| 	struct tm * timeinfo;
 | |
| 	char string[128];
 | |
| 
 | |
| 	time(&rawtime);
 | |
| 	timeinfo = localtime(&rawtime);
 | |
| 	strftime(string, sizeof string, "%a %b %d, %I:%M %p", timeinfo);
 | |
| 
 | |
| 	widget_get_allocation(widget, &allocation);
 | |
| 	if (allocation.width == 0)
 | |
| 		return;
 | |
| 
 | |
| 	cr = widget_cairo_create(clock->panel->widget);
 | |
| 	cairo_select_font_face(cr, "sans",
 | |
| 			       CAIRO_FONT_SLANT_NORMAL,
 | |
| 			       CAIRO_FONT_WEIGHT_NORMAL);
 | |
| 	cairo_set_font_size(cr, 14);
 | |
| 	cairo_text_extents(cr, string, &extents);
 | |
| 	cairo_font_extents (cr, &font_extents);
 | |
| 	cairo_move_to(cr, allocation.x + 5,
 | |
| 		      allocation.y + 3 * (allocation.height >> 2) + 1);
 | |
| 	cairo_set_source_rgb(cr, 0, 0, 0);
 | |
| 	cairo_show_text(cr, string);
 | |
| 	cairo_move_to(cr, allocation.x + 4,
 | |
| 		      allocation.y + 3 * (allocation.height >> 2));
 | |
| 	cairo_set_source_rgb(cr, 1, 1, 1);
 | |
| 	cairo_show_text(cr, string);
 | |
| 	cairo_destroy(cr);
 | |
| }
 | |
| 
 | |
| static int
 | |
| clock_timer_reset(struct panel_clock *clock)
 | |
| {
 | |
| 	struct itimerspec its;
 | |
| 
 | |
| 	its.it_interval.tv_sec = 60;
 | |
| 	its.it_interval.tv_nsec = 0;
 | |
| 	its.it_value.tv_sec = 60;
 | |
| 	its.it_value.tv_nsec = 0;
 | |
| 	if (timerfd_settime(clock->clock_fd, 0, &its, NULL) < 0) {
 | |
| 		fprintf(stderr, "could not set timerfd\n: %m");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_destroy_clock(struct panel_clock *clock)
 | |
| {
 | |
| 	widget_destroy(clock->widget);
 | |
| 
 | |
| 	close(clock->clock_fd);
 | |
| 
 | |
| 	free(clock);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_add_clock(struct panel *panel)
 | |
| {
 | |
| 	struct panel_clock *clock;
 | |
| 	int timerfd;
 | |
| 
 | |
| 	timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
 | |
| 	if (timerfd < 0) {
 | |
| 		fprintf(stderr, "could not create timerfd\n: %m");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	clock = xzalloc(sizeof *clock);
 | |
| 	clock->panel = panel;
 | |
| 	panel->clock = clock;
 | |
| 	clock->clock_fd = timerfd;
 | |
| 
 | |
| 	clock->clock_task.run = clock_func;
 | |
| 	display_watch_fd(window_get_display(panel->window), clock->clock_fd,
 | |
| 			 EPOLLIN, &clock->clock_task);
 | |
| 	clock_timer_reset(clock);
 | |
| 
 | |
| 	clock->widget = widget_add_widget(panel->widget, clock);
 | |
| 	widget_set_redraw_handler(clock->widget, panel_clock_redraw_handler);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_button_handler(struct widget *widget,
 | |
| 		     struct input *input, uint32_t time,
 | |
| 		     uint32_t button,
 | |
| 		     enum wl_pointer_button_state state, void *data)
 | |
| {
 | |
| 	struct panel *panel = data;
 | |
| 
 | |
| 	if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED)
 | |
| 		show_menu(panel, input, time);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_resize_handler(struct widget *widget,
 | |
| 		     int32_t width, int32_t height, void *data)
 | |
| {
 | |
| 	struct panel_launcher *launcher;
 | |
| 	struct panel *panel = data;
 | |
| 	int x, y, w, h;
 | |
| 	
 | |
| 	x = 10;
 | |
| 	y = 16;
 | |
| 	wl_list_for_each(launcher, &panel->launcher_list, link) {
 | |
| 		w = cairo_image_surface_get_width(launcher->icon);
 | |
| 		h = cairo_image_surface_get_height(launcher->icon);
 | |
| 		widget_set_allocation(launcher->widget,
 | |
| 				      x, y - h / 2, w + 1, h + 1);
 | |
| 		x += w + 10;
 | |
| 	}
 | |
| 	h=20;
 | |
| 	w=170;
 | |
| 
 | |
| 	if (panel->clock)
 | |
| 		widget_set_allocation(panel->clock->widget,
 | |
| 				      width - w - 8, y - h / 2, w + 1, h + 1);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_configure(void *data,
 | |
| 		struct desktop_shell *desktop_shell,
 | |
| 		uint32_t edges, struct window *window,
 | |
| 		int32_t width, int32_t height)
 | |
| {
 | |
| 	struct surface *surface = window_get_user_data(window);
 | |
| 	struct panel *panel = container_of(surface, struct panel, base);
 | |
| 
 | |
| 	window_schedule_resize(panel->window, width, 32);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_destroy_launcher(struct panel_launcher *launcher)
 | |
| {
 | |
| 	wl_array_release(&launcher->argv);
 | |
| 	wl_array_release(&launcher->envp);
 | |
| 
 | |
| 	free(launcher->path);
 | |
| 
 | |
| 	cairo_surface_destroy(launcher->icon);
 | |
| 
 | |
| 	widget_destroy(launcher->widget);
 | |
| 	wl_list_remove(&launcher->link);
 | |
| 
 | |
| 	free(launcher);
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_destroy(struct panel *panel)
 | |
| {
 | |
| 	struct panel_launcher *tmp;
 | |
| 	struct panel_launcher *launcher;
 | |
| 
 | |
| 	panel_destroy_clock(panel->clock);
 | |
| 
 | |
| 	wl_list_for_each_safe(launcher, tmp, &panel->launcher_list, link)
 | |
| 		panel_destroy_launcher(launcher);
 | |
| 
 | |
| 	widget_destroy(panel->widget);
 | |
| 	window_destroy(panel->window);
 | |
| 
 | |
| 	free(panel);
 | |
| }
 | |
| 
 | |
| static struct panel *
 | |
| panel_create(struct desktop *desktop)
 | |
| {
 | |
| 	struct panel *panel;
 | |
| 	struct weston_config_section *s;
 | |
| 
 | |
| 	panel = xzalloc(sizeof *panel);
 | |
| 
 | |
| 	panel->base.configure = panel_configure;
 | |
| 	panel->window = window_create_custom(desktop->display);
 | |
| 	panel->widget = window_add_widget(panel->window, panel);
 | |
| 	wl_list_init(&panel->launcher_list);
 | |
| 
 | |
| 	window_set_title(panel->window, "panel");
 | |
| 	window_set_user_data(panel->window, panel);
 | |
| 
 | |
| 	widget_set_redraw_handler(panel->widget, panel_redraw_handler);
 | |
| 	widget_set_resize_handler(panel->widget, panel_resize_handler);
 | |
| 	widget_set_button_handler(panel->widget, panel_button_handler);
 | |
| 	
 | |
| 	panel_add_clock(panel);
 | |
| 
 | |
| 	s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
 | |
| 	weston_config_section_get_uint(s, "panel-color",
 | |
| 				       &panel->color, 0xaa000000);
 | |
| 
 | |
| 	panel_add_launchers(panel, desktop);
 | |
| 
 | |
| 	return panel;
 | |
| }
 | |
| 
 | |
| static cairo_surface_t *
 | |
| load_icon_or_fallback(const char *icon)
 | |
| {
 | |
| 	cairo_surface_t *surface = cairo_image_surface_create_from_png(icon);
 | |
| 	cairo_status_t status;
 | |
| 	cairo_t *cr;
 | |
| 
 | |
| 	status = cairo_surface_status(surface);
 | |
| 	if (status == CAIRO_STATUS_SUCCESS)
 | |
| 		return surface;
 | |
| 
 | |
| 	cairo_surface_destroy(surface);
 | |
| 	fprintf(stderr, "ERROR loading icon from file '%s', error: '%s'\n",
 | |
| 		icon, cairo_status_to_string(status));
 | |
| 
 | |
| 	/* draw fallback icon */
 | |
| 	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
 | |
| 					     20, 20);
 | |
| 	cr = cairo_create(surface);
 | |
| 
 | |
| 	cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
 | |
| 	cairo_paint(cr);
 | |
| 
 | |
| 	cairo_set_source_rgba(cr, 0, 0, 0, 1);
 | |
| 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
 | |
| 	cairo_rectangle(cr, 0, 0, 20, 20);
 | |
| 	cairo_move_to(cr, 4, 4);
 | |
| 	cairo_line_to(cr, 16, 16);
 | |
| 	cairo_move_to(cr, 4, 16);
 | |
| 	cairo_line_to(cr, 16, 4);
 | |
| 	cairo_stroke(cr);
 | |
| 
 | |
| 	cairo_destroy(cr);
 | |
| 
 | |
| 	return surface;
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_add_launcher(struct panel *panel, const char *icon, const char *path)
 | |
| {
 | |
| 	struct panel_launcher *launcher;
 | |
| 	char *start, *p, *eq, **ps;
 | |
| 	int i, j, k;
 | |
| 
 | |
| 	launcher = xzalloc(sizeof *launcher);
 | |
| 	launcher->icon = load_icon_or_fallback(icon);
 | |
| 	launcher->path = strdup(path);
 | |
| 
 | |
| 	wl_array_init(&launcher->envp);
 | |
| 	wl_array_init(&launcher->argv);
 | |
| 	for (i = 0; environ[i]; i++) {
 | |
| 		ps = wl_array_add(&launcher->envp, sizeof *ps);
 | |
| 		*ps = environ[i];
 | |
| 	}
 | |
| 	j = 0;
 | |
| 
 | |
| 	start = launcher->path;
 | |
| 	while (*start) {
 | |
| 		for (p = start, eq = NULL; *p && !isspace(*p); p++)
 | |
| 			if (*p == '=')
 | |
| 				eq = p;
 | |
| 
 | |
| 		if (eq && j == 0) {
 | |
| 			ps = launcher->envp.data;
 | |
| 			for (k = 0; k < i; k++)
 | |
| 				if (strncmp(ps[k], start, eq - start) == 0) {
 | |
| 					ps[k] = start;
 | |
| 					break;
 | |
| 				}
 | |
| 			if (k == i) {
 | |
| 				ps = wl_array_add(&launcher->envp, sizeof *ps);
 | |
| 				*ps = start;
 | |
| 				i++;
 | |
| 			}
 | |
| 		} else {
 | |
| 			ps = wl_array_add(&launcher->argv, sizeof *ps);
 | |
| 			*ps = start;
 | |
| 			j++;
 | |
| 		}
 | |
| 
 | |
| 		while (*p && isspace(*p))
 | |
| 			*p++ = '\0';
 | |
| 
 | |
| 		start = p;
 | |
| 	}
 | |
| 
 | |
| 	ps = wl_array_add(&launcher->envp, sizeof *ps);
 | |
| 	*ps = NULL;
 | |
| 	ps = wl_array_add(&launcher->argv, sizeof *ps);
 | |
| 	*ps = NULL;
 | |
| 
 | |
| 	launcher->panel = panel;
 | |
| 	wl_list_insert(panel->launcher_list.prev, &launcher->link);
 | |
| 
 | |
| 	launcher->widget = widget_add_widget(panel->widget, launcher);
 | |
| 	widget_set_enter_handler(launcher->widget,
 | |
| 				 panel_launcher_enter_handler);
 | |
| 	widget_set_leave_handler(launcher->widget,
 | |
| 				   panel_launcher_leave_handler);
 | |
| 	widget_set_button_handler(launcher->widget,
 | |
| 				    panel_launcher_button_handler);
 | |
| 	widget_set_touch_down_handler(launcher->widget,
 | |
| 				      panel_launcher_touch_down_handler);
 | |
| 	widget_set_touch_up_handler(launcher->widget,
 | |
| 				    panel_launcher_touch_up_handler);
 | |
| 	widget_set_redraw_handler(launcher->widget,
 | |
| 				  panel_launcher_redraw_handler);
 | |
| 	widget_set_motion_handler(launcher->widget,
 | |
| 				  panel_launcher_motion_handler);
 | |
| }
 | |
| 
 | |
| enum {
 | |
| 	BACKGROUND_SCALE,
 | |
| 	BACKGROUND_SCALE_CROP,
 | |
| 	BACKGROUND_TILE
 | |
| };
 | |
| 
 | |
| static void
 | |
| background_draw(struct widget *widget, void *data)
 | |
| {
 | |
| 	struct background *background = data;
 | |
| 	cairo_surface_t *surface, *image;
 | |
| 	cairo_pattern_t *pattern;
 | |
| 	cairo_matrix_t matrix;
 | |
| 	cairo_t *cr;
 | |
| 	double im_w, im_h;
 | |
| 	double sx, sy, s;
 | |
| 	double tx, ty;
 | |
| 	struct rectangle allocation;
 | |
| 	struct display *display;
 | |
| 	struct wl_region *opaque;
 | |
| 
 | |
| 	surface = window_get_surface(background->window);
 | |
| 
 | |
| 	cr = widget_cairo_create(background->widget);
 | |
| 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 | |
| 	cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
 | |
| 	cairo_paint(cr);
 | |
| 
 | |
| 	widget_get_allocation(widget, &allocation);
 | |
| 	image = NULL;
 | |
| 	if (background->image)
 | |
| 		image = load_cairo_surface(background->image);
 | |
| 
 | |
| 	if (image && background->type != -1) {
 | |
| 		im_w = cairo_image_surface_get_width(image);
 | |
| 		im_h = cairo_image_surface_get_height(image);
 | |
| 		sx = im_w / allocation.width;
 | |
| 		sy = im_h / allocation.height;
 | |
| 
 | |
| 		pattern = cairo_pattern_create_for_surface(image);
 | |
| 
 | |
| 		switch (background->type) {
 | |
| 		case BACKGROUND_SCALE:
 | |
| 			cairo_matrix_init_scale(&matrix, sx, sy);
 | |
| 			cairo_pattern_set_matrix(pattern, &matrix);
 | |
| 			break;
 | |
| 		case BACKGROUND_SCALE_CROP:
 | |
| 			s = (sx < sy) ? sx : sy;
 | |
| 			/* align center */
 | |
| 			tx = (im_w - s * allocation.width) * 0.5;
 | |
| 			ty = (im_h - s * allocation.height) * 0.5;
 | |
| 			cairo_matrix_init_translate(&matrix, tx, ty);
 | |
| 			cairo_matrix_scale(&matrix, s, s);
 | |
| 			cairo_pattern_set_matrix(pattern, &matrix);
 | |
| 			break;
 | |
| 		case BACKGROUND_TILE:
 | |
| 			cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		cairo_set_source(cr, pattern);
 | |
| 		cairo_pattern_destroy (pattern);
 | |
| 		cairo_surface_destroy(image);
 | |
| 	} else {
 | |
| 		set_hex_color(cr, background->color);
 | |
| 	}
 | |
| 
 | |
| 	cairo_paint(cr);
 | |
| 	cairo_destroy(cr);
 | |
| 	cairo_surface_destroy(surface);
 | |
| 
 | |
| 	display = window_get_display(background->window);
 | |
| 	opaque = wl_compositor_create_region(display_get_compositor(display));
 | |
| 	wl_region_add(opaque, allocation.x, allocation.y,
 | |
| 		      allocation.width, allocation.height);
 | |
| 	wl_surface_set_opaque_region(window_get_wl_surface(background->window), opaque);
 | |
| 	wl_region_destroy(opaque);
 | |
| 
 | |
| 	background->painted = 1;
 | |
| 	check_desktop_ready(background->window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| background_configure(void *data,
 | |
| 		     struct desktop_shell *desktop_shell,
 | |
| 		     uint32_t edges, struct window *window,
 | |
| 		     int32_t width, int32_t height)
 | |
| {
 | |
| 	struct background *background =
 | |
| 		(struct background *) window_get_user_data(window);
 | |
| 
 | |
| 	widget_schedule_resize(background->widget, width, height);
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_redraw_handler(struct widget *widget, void *data)
 | |
| {
 | |
| 	struct unlock_dialog *dialog = data;
 | |
| 	struct rectangle allocation;
 | |
| 	cairo_surface_t *surface;
 | |
| 	cairo_t *cr;
 | |
| 	cairo_pattern_t *pat;
 | |
| 	double cx, cy, r, f;
 | |
| 
 | |
| 	cr = widget_cairo_create(widget);
 | |
| 
 | |
| 	widget_get_allocation(dialog->widget, &allocation);
 | |
| 	cairo_rectangle(cr, allocation.x, allocation.y,
 | |
| 			allocation.width, allocation.height);
 | |
| 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 | |
| 	cairo_set_source_rgba(cr, 0, 0, 0, 0.6);
 | |
| 	cairo_fill(cr);
 | |
| 
 | |
| 	cairo_translate(cr, allocation.x, allocation.y);
 | |
| 	if (dialog->button_focused)
 | |
| 		f = 1.0;
 | |
| 	else
 | |
| 		f = 0.7;
 | |
| 
 | |
| 	cx = allocation.width / 2.0;
 | |
| 	cy = allocation.height / 2.0;
 | |
| 	r = (cx < cy ? cx : cy) * 0.4;
 | |
| 	pat = cairo_pattern_create_radial(cx, cy, r * 0.7, cx, cy, r);
 | |
| 	cairo_pattern_add_color_stop_rgb(pat, 0.0, 0, 0.86 * f, 0);
 | |
| 	cairo_pattern_add_color_stop_rgb(pat, 0.85, 0.2 * f, f, 0.2 * f);
 | |
| 	cairo_pattern_add_color_stop_rgb(pat, 1.0, 0, 0.86 * f, 0);
 | |
| 	cairo_set_source(cr, pat);
 | |
| 	cairo_pattern_destroy(pat);
 | |
| 	cairo_arc(cr, cx, cy, r, 0.0, 2.0 * M_PI);
 | |
| 	cairo_fill(cr);
 | |
| 
 | |
| 	widget_set_allocation(dialog->button,
 | |
| 			      allocation.x + cx - r,
 | |
| 			      allocation.y + cy - r, 2 * r, 2 * r);
 | |
| 
 | |
| 	cairo_destroy(cr);
 | |
| 
 | |
| 	surface = window_get_surface(dialog->window);
 | |
| 	cairo_surface_destroy(surface);
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_button_handler(struct widget *widget,
 | |
| 			     struct input *input, uint32_t time,
 | |
| 			     uint32_t button,
 | |
| 			     enum wl_pointer_button_state state, void *data)
 | |
| {
 | |
| 	struct unlock_dialog *dialog = data;
 | |
| 	struct desktop *desktop = dialog->desktop;
 | |
| 
 | |
| 	if (button == BTN_LEFT) {
 | |
| 		if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
 | |
| 		    !dialog->closing) {
 | |
| 			display_defer(desktop->display, &desktop->unlock_task);
 | |
| 			dialog->closing = 1;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_keyboard_focus_handler(struct window *window,
 | |
| 				     struct input *device, void *data)
 | |
| {
 | |
| 	window_schedule_redraw(window);
 | |
| }
 | |
| 
 | |
| static int
 | |
| unlock_dialog_widget_enter_handler(struct widget *widget,
 | |
| 				   struct input *input,
 | |
| 				   float x, float y, void *data)
 | |
| {
 | |
| 	struct unlock_dialog *dialog = data;
 | |
| 
 | |
| 	dialog->button_focused = 1;
 | |
| 	widget_schedule_redraw(widget);
 | |
| 
 | |
| 	return CURSOR_LEFT_PTR;
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_widget_leave_handler(struct widget *widget,
 | |
| 				   struct input *input, void *data)
 | |
| {
 | |
| 	struct unlock_dialog *dialog = data;
 | |
| 
 | |
| 	dialog->button_focused = 0;
 | |
| 	widget_schedule_redraw(widget);
 | |
| }
 | |
| 
 | |
| static struct unlock_dialog *
 | |
| unlock_dialog_create(struct desktop *desktop)
 | |
| {
 | |
| 	struct display *display = desktop->display;
 | |
| 	struct unlock_dialog *dialog;
 | |
| 
 | |
| 	dialog = xzalloc(sizeof *dialog);
 | |
| 
 | |
| 	dialog->window = window_create_custom(display);
 | |
| 	dialog->widget = frame_create(dialog->window, dialog);
 | |
| 	window_set_title(dialog->window, "Unlock your desktop");
 | |
| 
 | |
| 	window_set_user_data(dialog->window, dialog);
 | |
| 	window_set_keyboard_focus_handler(dialog->window,
 | |
| 					  unlock_dialog_keyboard_focus_handler);
 | |
| 	dialog->button = widget_add_widget(dialog->widget, dialog);
 | |
| 	widget_set_redraw_handler(dialog->widget,
 | |
| 				  unlock_dialog_redraw_handler);
 | |
| 	widget_set_enter_handler(dialog->button,
 | |
| 				 unlock_dialog_widget_enter_handler);
 | |
| 	widget_set_leave_handler(dialog->button,
 | |
| 				 unlock_dialog_widget_leave_handler);
 | |
| 	widget_set_button_handler(dialog->button,
 | |
| 				  unlock_dialog_button_handler);
 | |
| 
 | |
| 	desktop_shell_set_lock_surface(desktop->shell,
 | |
| 				       window_get_wl_surface(dialog->window));
 | |
| 
 | |
| 	window_schedule_resize(dialog->window, 260, 230);
 | |
| 
 | |
| 	return dialog;
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_destroy(struct unlock_dialog *dialog)
 | |
| {
 | |
| 	window_destroy(dialog->window);
 | |
| 	free(dialog);
 | |
| }
 | |
| 
 | |
| static void
 | |
| unlock_dialog_finish(struct task *task, uint32_t events)
 | |
| {
 | |
| 	struct desktop *desktop =
 | |
| 		container_of(task, struct desktop, unlock_task);
 | |
| 
 | |
| 	desktop_shell_unlock(desktop->shell);
 | |
| 	unlock_dialog_destroy(desktop->unlock_dialog);
 | |
| 	desktop->unlock_dialog = NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| desktop_shell_configure(void *data,
 | |
| 			struct desktop_shell *desktop_shell,
 | |
| 			uint32_t edges,
 | |
| 			struct wl_surface *surface,
 | |
| 			int32_t width, int32_t height)
 | |
| {
 | |
| 	struct window *window = wl_surface_get_user_data(surface);
 | |
| 	struct surface *s = window_get_user_data(window);
 | |
| 
 | |
| 	s->configure(data, desktop_shell, edges, window, width, height);
 | |
| }
 | |
| 
 | |
| static void
 | |
| desktop_shell_prepare_lock_surface(void *data,
 | |
| 				   struct desktop_shell *desktop_shell)
 | |
| {
 | |
| 	struct desktop *desktop = data;
 | |
| 
 | |
| 	if (!desktop->locking) {
 | |
| 		desktop_shell_unlock(desktop->shell);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (!desktop->unlock_dialog) {
 | |
| 		desktop->unlock_dialog = unlock_dialog_create(desktop);
 | |
| 		desktop->unlock_dialog->desktop = desktop;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| desktop_shell_grab_cursor(void *data,
 | |
| 			  struct desktop_shell *desktop_shell,
 | |
| 			  uint32_t cursor)
 | |
| {
 | |
| 	struct desktop *desktop = data;
 | |
| 
 | |
| 	switch (cursor) {
 | |
| 	case DESKTOP_SHELL_CURSOR_NONE:
 | |
| 		desktop->grab_cursor = CURSOR_BLANK;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_BUSY:
 | |
| 		desktop->grab_cursor = CURSOR_WATCH;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_MOVE:
 | |
| 		desktop->grab_cursor = CURSOR_DRAGGING;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_TOP:
 | |
| 		desktop->grab_cursor = CURSOR_TOP;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM:
 | |
| 		desktop->grab_cursor = CURSOR_BOTTOM;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_LEFT:
 | |
| 		desktop->grab_cursor = CURSOR_LEFT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_RIGHT:
 | |
| 		desktop->grab_cursor = CURSOR_RIGHT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_TOP_LEFT:
 | |
| 		desktop->grab_cursor = CURSOR_TOP_LEFT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_TOP_RIGHT:
 | |
| 		desktop->grab_cursor = CURSOR_TOP_RIGHT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_LEFT:
 | |
| 		desktop->grab_cursor = CURSOR_BOTTOM_LEFT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_RESIZE_BOTTOM_RIGHT:
 | |
| 		desktop->grab_cursor = CURSOR_BOTTOM_RIGHT;
 | |
| 		break;
 | |
| 	case DESKTOP_SHELL_CURSOR_ARROW:
 | |
| 	default:
 | |
| 		desktop->grab_cursor = CURSOR_LEFT_PTR;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static const struct desktop_shell_listener listener = {
 | |
| 	desktop_shell_configure,
 | |
| 	desktop_shell_prepare_lock_surface,
 | |
| 	desktop_shell_grab_cursor
 | |
| };
 | |
| 
 | |
| static void
 | |
| background_destroy(struct background *background)
 | |
| {
 | |
| 	widget_destroy(background->widget);
 | |
| 	window_destroy(background->window);
 | |
| 
 | |
| 	free(background->image);
 | |
| 	free(background);
 | |
| }
 | |
| 
 | |
| static struct background *
 | |
| background_create(struct desktop *desktop)
 | |
| {
 | |
| 	struct background *background;
 | |
| 	struct weston_config_section *s;
 | |
| 	char *type;
 | |
| 
 | |
| 	background = xzalloc(sizeof *background);
 | |
| 	background->base.configure = background_configure;
 | |
| 	background->window = window_create_custom(desktop->display);
 | |
| 	background->widget = window_add_widget(background->window, background);
 | |
| 	window_set_user_data(background->window, background);
 | |
| 	widget_set_redraw_handler(background->widget, background_draw);
 | |
| 	window_set_preferred_format(background->window,
 | |
| 				    WINDOW_PREFERRED_FORMAT_RGB565);
 | |
| 
 | |
| 	s = weston_config_get_section(desktop->config, "shell", NULL, NULL);
 | |
| 	weston_config_section_get_string(s, "background-image",
 | |
| 					 &background->image,
 | |
| 					 DATADIR "/weston/pattern.png");
 | |
| 	weston_config_section_get_uint(s, "background-color",
 | |
| 				       &background->color, 0xff002244);
 | |
| 
 | |
| 	weston_config_section_get_string(s, "background-type",
 | |
| 					 &type, "tile");
 | |
| 	if (strcmp(type, "scale") == 0) {
 | |
| 		background->type = BACKGROUND_SCALE;
 | |
| 	} else if (strcmp(type, "scale-crop") == 0) {
 | |
| 		background->type = BACKGROUND_SCALE_CROP;
 | |
| 	} else if (strcmp(type, "tile") == 0) {
 | |
| 		background->type = BACKGROUND_TILE;
 | |
| 	} else {
 | |
| 		background->type = -1;
 | |
| 		fprintf(stderr, "invalid background-type: %s\n",
 | |
| 			type);
 | |
| 	}
 | |
| 
 | |
| 	free(type);
 | |
| 
 | |
| 	return background;
 | |
| }
 | |
| 
 | |
| static int
 | |
| grab_surface_enter_handler(struct widget *widget, struct input *input,
 | |
| 			   float x, float y, void *data)
 | |
| {
 | |
| 	struct desktop *desktop = data;
 | |
| 
 | |
| 	return desktop->grab_cursor;
 | |
| }
 | |
| 
 | |
| static void
 | |
| grab_surface_destroy(struct desktop *desktop)
 | |
| {
 | |
| 	widget_destroy(desktop->grab_widget);
 | |
| 	window_destroy(desktop->grab_window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| grab_surface_create(struct desktop *desktop)
 | |
| {
 | |
| 	struct wl_surface *s;
 | |
| 
 | |
| 	desktop->grab_window = window_create_custom(desktop->display);
 | |
| 	window_set_user_data(desktop->grab_window, desktop);
 | |
| 
 | |
| 	s = window_get_wl_surface(desktop->grab_window);
 | |
| 	desktop_shell_set_grab_surface(desktop->shell, s);
 | |
| 
 | |
| 	desktop->grab_widget =
 | |
| 		window_add_widget(desktop->grab_window, desktop);
 | |
| 	/* We set the allocation to 1x1 at 0,0 so the fake enter event
 | |
| 	 * at 0,0 will go to this widget. */
 | |
| 	widget_set_allocation(desktop->grab_widget, 0, 0, 1, 1);
 | |
| 
 | |
| 	widget_set_enter_handler(desktop->grab_widget,
 | |
| 				 grab_surface_enter_handler);
 | |
| }
 | |
| 
 | |
| static void
 | |
| output_destroy(struct output *output)
 | |
| {
 | |
| 	background_destroy(output->background);
 | |
| 	panel_destroy(output->panel);
 | |
| 	wl_output_destroy(output->output);
 | |
| 	wl_list_remove(&output->link);
 | |
| 
 | |
| 	free(output);
 | |
| }
 | |
| 
 | |
| static void
 | |
| desktop_destroy_outputs(struct desktop *desktop)
 | |
| {
 | |
| 	struct output *tmp;
 | |
| 	struct output *output;
 | |
| 
 | |
| 	wl_list_for_each_safe(output, tmp, &desktop->outputs, link)
 | |
| 		output_destroy(output);
 | |
| }
 | |
| 
 | |
| static void
 | |
| output_handle_geometry(void *data,
 | |
|                        struct wl_output *wl_output,
 | |
|                        int x, int y,
 | |
|                        int physical_width,
 | |
|                        int physical_height,
 | |
|                        int subpixel,
 | |
|                        const char *make,
 | |
|                        const char *model,
 | |
|                        int transform)
 | |
| {
 | |
| 	struct output *output = data;
 | |
| 
 | |
| 	window_set_buffer_transform(output->panel->window, transform);
 | |
| 	window_set_buffer_transform(output->background->window, transform);
 | |
| }
 | |
| 
 | |
| static void
 | |
| output_handle_mode(void *data,
 | |
| 		   struct wl_output *wl_output,
 | |
| 		   uint32_t flags,
 | |
| 		   int width,
 | |
| 		   int height,
 | |
| 		   int refresh)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| output_handle_done(void *data,
 | |
|                    struct wl_output *wl_output)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| output_handle_scale(void *data,
 | |
|                     struct wl_output *wl_output,
 | |
|                     int32_t scale)
 | |
| {
 | |
| 	struct output *output = data;
 | |
| 
 | |
| 	window_set_buffer_scale(output->panel->window, scale);
 | |
| 	window_set_buffer_scale(output->background->window, scale);
 | |
| }
 | |
| 
 | |
| static const struct wl_output_listener output_listener = {
 | |
| 	output_handle_geometry,
 | |
| 	output_handle_mode,
 | |
| 	output_handle_done,
 | |
| 	output_handle_scale
 | |
| };
 | |
| 
 | |
| static void
 | |
| output_init(struct output *output, struct desktop *desktop)
 | |
| {
 | |
| 	struct wl_surface *surface;
 | |
| 
 | |
| 	output->panel = panel_create(desktop);
 | |
| 	surface = window_get_wl_surface(output->panel->window);
 | |
| 	desktop_shell_set_panel(desktop->shell,
 | |
| 				output->output, surface);
 | |
| 
 | |
| 	output->background = background_create(desktop);
 | |
| 	surface = window_get_wl_surface(output->background->window);
 | |
| 	desktop_shell_set_background(desktop->shell,
 | |
| 				     output->output, surface);
 | |
| }
 | |
| 
 | |
| static void
 | |
| create_output(struct desktop *desktop, uint32_t id)
 | |
| {
 | |
| 	struct output *output;
 | |
| 
 | |
| 	output = calloc(1, sizeof *output);
 | |
| 	if (!output)
 | |
| 		return;
 | |
| 
 | |
| 	output->output =
 | |
| 		display_bind(desktop->display, id, &wl_output_interface, 2);
 | |
| 
 | |
| 	wl_output_add_listener(output->output, &output_listener, output);
 | |
| 
 | |
| 	wl_list_insert(&desktop->outputs, &output->link);
 | |
| 
 | |
| 	/* On start up we may process an output global before the shell global
 | |
| 	 * in which case we can't create the panel and background just yet */
 | |
| 	if (desktop->shell)
 | |
| 		output_init(output, desktop);
 | |
| }
 | |
| 
 | |
| static void
 | |
| global_handler(struct display *display, uint32_t id,
 | |
| 	       const char *interface, uint32_t version, void *data)
 | |
| {
 | |
| 	struct desktop *desktop = data;
 | |
| 
 | |
| 	if (!strcmp(interface, "desktop_shell")) {
 | |
| 		desktop->interface_version = (version < 2) ? version : 2;
 | |
| 		desktop->shell = display_bind(desktop->display,
 | |
| 					      id, &desktop_shell_interface,
 | |
| 					      desktop->interface_version);
 | |
| 		desktop_shell_add_listener(desktop->shell, &listener, desktop);
 | |
| 	} else if (!strcmp(interface, "wl_output")) {
 | |
| 		create_output(desktop, id);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| panel_add_launchers(struct panel *panel, struct desktop *desktop)
 | |
| {
 | |
| 	struct weston_config_section *s;
 | |
| 	char *icon, *path;
 | |
| 	const char *name;
 | |
| 	int count;
 | |
| 
 | |
| 	count = 0;
 | |
| 	s = NULL;
 | |
| 	while (weston_config_next_section(desktop->config, &s, &name)) {
 | |
| 		if (strcmp(name, "launcher") != 0)
 | |
| 			continue;
 | |
| 
 | |
| 		weston_config_section_get_string(s, "icon", &icon, NULL);
 | |
| 		weston_config_section_get_string(s, "path", &path, NULL);
 | |
| 
 | |
| 		if (icon != NULL && path != NULL) {
 | |
| 			panel_add_launcher(panel, icon, path);
 | |
| 			count++;
 | |
| 		} else {
 | |
| 			fprintf(stderr, "invalid launcher section\n");
 | |
| 		}
 | |
| 
 | |
| 		free(icon);
 | |
| 		free(path);
 | |
| 	}
 | |
| 
 | |
| 	if (count == 0) {
 | |
| 		/* add default launcher */
 | |
| 		panel_add_launcher(panel,
 | |
| 				   DATADIR "/weston/terminal.png",
 | |
| 				   BINDIR "/weston-terminal");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
| 	struct desktop desktop = { 0 };
 | |
| 	int config_fd;
 | |
| 	struct output *output;
 | |
| 	struct weston_config_section *s;
 | |
| 
 | |
| 	desktop.unlock_task.run = unlock_dialog_finish;
 | |
| 	wl_list_init(&desktop.outputs);
 | |
| 
 | |
| 	config_fd = open_config_file("weston.ini");
 | |
| 	desktop.config = weston_config_parse(config_fd);
 | |
| 	close(config_fd);
 | |
| 
 | |
| 	s = weston_config_get_section(desktop.config, "shell", NULL, NULL);
 | |
| 	weston_config_section_get_bool(s, "locking", &desktop.locking, 1);
 | |
| 
 | |
| 	desktop.display = display_create(&argc, argv);
 | |
| 	if (desktop.display == NULL) {
 | |
| 		fprintf(stderr, "failed to create display: %m\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	display_set_user_data(desktop.display, &desktop);
 | |
| 	display_set_global_handler(desktop.display, global_handler);
 | |
| 
 | |
| 	/* Create panel and background for outputs processed before the shell
 | |
| 	 * global interface was processed */
 | |
| 	wl_list_for_each(output, &desktop.outputs, link)
 | |
| 		if (!output->panel)
 | |
| 			output_init(output, &desktop);
 | |
| 
 | |
| 	grab_surface_create(&desktop);
 | |
| 
 | |
| 	signal(SIGCHLD, sigchild_handler);
 | |
| 
 | |
| 	display_run(desktop.display);
 | |
| 
 | |
| 	/* Cleanup */
 | |
| 	grab_surface_destroy(&desktop);
 | |
| 	desktop_destroy_outputs(&desktop);
 | |
| 	if (desktop.unlock_dialog)
 | |
| 		unlock_dialog_destroy(desktop.unlock_dialog);
 | |
| 	desktop_shell_destroy(desktop.shell);
 | |
| 	display_destroy(desktop.display);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 |