a50e6e4c50
This set of changes adds support for searching for a given config file in the directories listed in $XDG_CONFIG_DIRS if it wasn't found in $XDG_CONFIG_HOME or ~/.config. This allows packages to install custom config files in /etc/xdg/weston, for example, thus allowing them to avoid dealing with home directories. To avoid a TOCTOU race the config file is actually open()ed during the search. Its file descriptor is returned and stored in the compositor for later use when performing subsequent config file parses. Signed-off-by: Ossama Othman <ossama.othman@intel.com>
498 lines
13 KiB
C
498 lines
13 KiB
C
/*
|
|
* Copyright © 2011, 2012 Intel Corporation
|
|
*
|
|
* 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 <unistd.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include "window.h"
|
|
#include "../shared/cairo-util.h"
|
|
#include "../shared/config-parser.h"
|
|
|
|
#include "tablet-shell-client-protocol.h"
|
|
|
|
struct tablet {
|
|
struct display *display;
|
|
struct tablet_shell *tablet_shell;
|
|
struct rectangle allocation;
|
|
struct window *switcher;
|
|
|
|
struct homescreen *homescreen;
|
|
struct lockscreen *lockscreen;
|
|
};
|
|
|
|
struct homescreen {
|
|
struct window *window;
|
|
struct widget *widget;
|
|
struct wl_list launcher_list;
|
|
};
|
|
|
|
struct lockscreen {
|
|
struct window *window;
|
|
struct widget *widget;
|
|
};
|
|
|
|
struct launcher {
|
|
struct widget *widget;
|
|
struct homescreen *homescreen;
|
|
cairo_surface_t *icon;
|
|
int focused, pressed;
|
|
char *path;
|
|
struct wl_list link;
|
|
};
|
|
|
|
static char *key_lockscreen_icon;
|
|
static char *key_lockscreen_background;
|
|
static char *key_homescreen_background;
|
|
static char *key_launcher_icon;
|
|
static char *key_launcher_path;
|
|
static void launcher_section_done(void *data);
|
|
|
|
static const struct config_key shell_config_keys[] = {
|
|
{ "lockscreen-icon", CONFIG_KEY_STRING, &key_lockscreen_icon },
|
|
{ "lockscreen", CONFIG_KEY_STRING, &key_lockscreen_background },
|
|
{ "homescreen", CONFIG_KEY_STRING, &key_homescreen_background },
|
|
};
|
|
|
|
static const struct config_key launcher_config_keys[] = {
|
|
{ "icon", CONFIG_KEY_STRING, &key_launcher_icon },
|
|
{ "path", CONFIG_KEY_STRING, &key_launcher_path },
|
|
};
|
|
|
|
static const struct config_section config_sections[] = {
|
|
{ "shell",
|
|
shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
|
|
{ "launcher",
|
|
launcher_config_keys, ARRAY_LENGTH(launcher_config_keys),
|
|
launcher_section_done }
|
|
};
|
|
|
|
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
|
|
paint_background(cairo_t *cr, const char *path, struct rectangle *allocation)
|
|
{
|
|
cairo_surface_t *image = NULL;
|
|
cairo_pattern_t *pattern;
|
|
cairo_matrix_t matrix;
|
|
double sx, sy;
|
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
|
if (path)
|
|
image = load_cairo_surface(path);
|
|
if (image) {
|
|
pattern = cairo_pattern_create_for_surface(image);
|
|
sx = (double) cairo_image_surface_get_width(image) /
|
|
allocation->width;
|
|
sy = (double) cairo_image_surface_get_height(image) /
|
|
allocation->height;
|
|
cairo_matrix_init_scale(&matrix, sx, sy);
|
|
cairo_pattern_set_matrix(pattern, &matrix);
|
|
cairo_set_source(cr, pattern);
|
|
cairo_pattern_destroy (pattern);
|
|
cairo_surface_destroy(image);
|
|
cairo_paint(cr);
|
|
} else {
|
|
fprintf(stderr, "couldn't load background image: %s\n", path);
|
|
cairo_set_source_rgb(cr, 0.2, 0, 0);
|
|
cairo_paint(cr);
|
|
}
|
|
}
|
|
|
|
static void
|
|
homescreen_draw(struct widget *widget, void *data)
|
|
{
|
|
struct homescreen *homescreen = data;
|
|
cairo_surface_t *surface;
|
|
struct rectangle allocation;
|
|
cairo_t *cr;
|
|
struct launcher *launcher;
|
|
const int rows = 4, columns = 5, icon_width = 128, icon_height = 128;
|
|
int x, y, i, width, height, vmargin, hmargin, vpadding, hpadding;
|
|
|
|
surface = window_get_surface(homescreen->window);
|
|
cr = cairo_create(surface);
|
|
|
|
widget_get_allocation(widget, &allocation);
|
|
paint_background(cr, key_homescreen_background, &allocation);
|
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
|
|
|
width = allocation.width - columns * icon_width;
|
|
hpadding = width / (columns + 1);
|
|
hmargin = (width - hpadding * (columns - 1)) / 2;
|
|
|
|
height = allocation.height - rows * icon_height;
|
|
vpadding = height / (rows + 1);
|
|
vmargin = (height - vpadding * (rows - 1)) / 2;
|
|
|
|
x = hmargin;
|
|
y = vmargin;
|
|
i = 0;
|
|
|
|
wl_list_for_each(launcher, &homescreen->launcher_list, link) {
|
|
widget_set_allocation(launcher->widget,
|
|
x, y, icon_width, icon_height);
|
|
x += icon_width + hpadding;
|
|
i++;
|
|
if (i == columns) {
|
|
x = hmargin;
|
|
y += icon_height + vpadding;
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
cairo_destroy(cr);
|
|
cairo_surface_destroy(surface);
|
|
}
|
|
|
|
static void
|
|
lockscreen_draw(struct widget *widget, void *data)
|
|
{
|
|
struct lockscreen *lockscreen = data;
|
|
cairo_surface_t *surface;
|
|
cairo_surface_t *icon;
|
|
struct rectangle allocation;
|
|
cairo_t *cr;
|
|
int width, height;
|
|
|
|
surface = window_get_surface(lockscreen->window);
|
|
cr = cairo_create(surface);
|
|
|
|
widget_get_allocation(widget, &allocation);
|
|
paint_background(cr, key_lockscreen_background, &allocation);
|
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
|
|
icon = load_cairo_surface(key_lockscreen_icon);
|
|
if (icon) {
|
|
width = cairo_image_surface_get_width(icon);
|
|
height = cairo_image_surface_get_height(icon);
|
|
cairo_set_source_surface(cr, icon,
|
|
allocation.x + (allocation.width - width) / 2,
|
|
allocation.y + (allocation.height - height) / 2);
|
|
} else {
|
|
fprintf(stderr, "couldn't load lockscreen icon: %s\n",
|
|
key_lockscreen_icon);
|
|
cairo_set_source_rgb(cr, 0.2, 0, 0);
|
|
}
|
|
cairo_paint(cr);
|
|
cairo_destroy(cr);
|
|
cairo_surface_destroy(icon);
|
|
cairo_surface_destroy(surface);
|
|
}
|
|
|
|
static void
|
|
lockscreen_button_handler(struct widget *widget,
|
|
struct input *input, uint32_t time,
|
|
uint32_t button,
|
|
enum wl_pointer_button_state state, void *data)
|
|
{
|
|
struct lockscreen *lockscreen = data;
|
|
|
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED && lockscreen->window) {
|
|
window_destroy(lockscreen->window);
|
|
lockscreen->window = NULL;
|
|
}
|
|
}
|
|
|
|
static struct homescreen *
|
|
homescreen_create(struct tablet *tablet)
|
|
{
|
|
struct homescreen *homescreen;
|
|
|
|
homescreen = malloc (sizeof *homescreen);
|
|
memset(homescreen, 0, sizeof *homescreen);
|
|
|
|
homescreen->window = window_create_custom(tablet->display);
|
|
homescreen->widget =
|
|
window_add_widget(homescreen->window, homescreen);
|
|
window_set_user_data(homescreen->window, homescreen);
|
|
window_set_title(homescreen->window, "homescreen");
|
|
widget_set_redraw_handler(homescreen->widget, homescreen_draw);
|
|
|
|
return homescreen;
|
|
}
|
|
|
|
static struct lockscreen *
|
|
lockscreen_create(struct tablet *tablet)
|
|
{
|
|
struct lockscreen *lockscreen;
|
|
|
|
lockscreen = malloc (sizeof *lockscreen);
|
|
memset(lockscreen, 0, sizeof *lockscreen);
|
|
|
|
lockscreen->window = window_create_custom(tablet->display);
|
|
lockscreen->widget =
|
|
window_add_widget(lockscreen->window, lockscreen);
|
|
window_set_user_data(lockscreen->window, lockscreen);
|
|
window_set_title(lockscreen->window, "lockscreen");
|
|
widget_set_redraw_handler(lockscreen->widget, lockscreen_draw);
|
|
widget_set_button_handler(lockscreen->widget,
|
|
lockscreen_button_handler);
|
|
|
|
return lockscreen;
|
|
}
|
|
|
|
static void
|
|
show_lockscreen(void *data, struct tablet_shell *tablet_shell)
|
|
{
|
|
struct tablet *tablet = data;
|
|
|
|
tablet->lockscreen = lockscreen_create(tablet);
|
|
tablet_shell_set_lockscreen(tablet->tablet_shell,
|
|
window_get_wl_surface(tablet->lockscreen->window));
|
|
|
|
widget_schedule_resize(tablet->lockscreen->widget,
|
|
tablet->allocation.width,
|
|
tablet->allocation.height);
|
|
}
|
|
|
|
static void
|
|
show_switcher(void *data, struct tablet_shell *tablet_shell)
|
|
{
|
|
struct tablet *tablet = data;
|
|
|
|
tablet->switcher = window_create_custom(tablet->display);
|
|
window_set_user_data(tablet->switcher, tablet);
|
|
tablet_shell_set_switcher(tablet->tablet_shell,
|
|
window_get_wl_surface(tablet->switcher));
|
|
}
|
|
|
|
static void
|
|
hide_switcher(void *data, struct tablet_shell *tablet_shell)
|
|
{
|
|
}
|
|
|
|
static const struct tablet_shell_listener tablet_shell_listener = {
|
|
show_lockscreen,
|
|
show_switcher,
|
|
hide_switcher
|
|
};
|
|
|
|
static int
|
|
launcher_enter_handler(struct widget *widget, struct input *input,
|
|
float x, float y, void *data)
|
|
{
|
|
struct launcher *launcher = data;
|
|
|
|
launcher->focused = 1;
|
|
widget_schedule_redraw(widget);
|
|
|
|
return CURSOR_LEFT_PTR;
|
|
}
|
|
|
|
static void
|
|
launcher_leave_handler(struct widget *widget,
|
|
struct input *input, void *data)
|
|
{
|
|
struct launcher *launcher = data;
|
|
|
|
launcher->focused = 0;
|
|
widget_schedule_redraw(widget);
|
|
}
|
|
|
|
static void
|
|
launcher_activate(struct launcher *widget)
|
|
{
|
|
pid_t pid;
|
|
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
fprintf(stderr, "fork failed: %m\n");
|
|
return;
|
|
}
|
|
|
|
if (pid)
|
|
return;
|
|
|
|
if (execl(widget->path, widget->path, NULL) < 0) {
|
|
fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
launcher_button_handler(struct widget *widget,
|
|
struct input *input, uint32_t time,
|
|
uint32_t button,
|
|
enum wl_pointer_button_state state, void *data)
|
|
{
|
|
struct launcher *launcher;
|
|
|
|
launcher = widget_get_user_data(widget);
|
|
widget_schedule_redraw(widget);
|
|
if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
|
|
launcher_activate(launcher);
|
|
launcher->pressed = 0;
|
|
} else if (state == WL_POINTER_BUTTON_STATE_PRESSED)
|
|
launcher->pressed = 1;
|
|
}
|
|
|
|
static void
|
|
launcher_redraw_handler(struct widget *widget, void *data)
|
|
{
|
|
struct launcher *launcher = data;
|
|
cairo_surface_t *surface;
|
|
struct rectangle allocation;
|
|
cairo_t *cr;
|
|
|
|
surface = window_get_surface(launcher->homescreen->window);
|
|
cr = cairo_create(surface);
|
|
|
|
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 void
|
|
tablet_shell_add_launcher(struct tablet *tablet,
|
|
const char *icon, const char *path)
|
|
{
|
|
struct launcher *launcher;
|
|
struct homescreen *homescreen = tablet->homescreen;
|
|
|
|
launcher = malloc(sizeof *launcher);
|
|
launcher->path = strdup(path);
|
|
launcher->icon = load_cairo_surface(icon);
|
|
if ( !launcher->icon ||
|
|
cairo_surface_status (launcher->icon) != CAIRO_STATUS_SUCCESS) {
|
|
fprintf(stderr, "couldn't load %s\n", icon);
|
|
free(launcher);
|
|
return;
|
|
}
|
|
|
|
launcher->homescreen = homescreen;
|
|
launcher->widget = widget_add_widget(homescreen->widget, launcher);
|
|
widget_set_enter_handler(launcher->widget,
|
|
launcher_enter_handler);
|
|
widget_set_leave_handler(launcher->widget,
|
|
launcher_leave_handler);
|
|
widget_set_button_handler(launcher->widget,
|
|
launcher_button_handler);
|
|
widget_set_redraw_handler(launcher->widget,
|
|
launcher_redraw_handler);
|
|
|
|
wl_list_insert(&homescreen->launcher_list, &launcher->link);
|
|
}
|
|
|
|
static void
|
|
launcher_section_done(void *data)
|
|
{
|
|
struct tablet *tablet = data;
|
|
|
|
if (key_launcher_icon == NULL || key_launcher_path == NULL) {
|
|
fprintf(stderr, "invalid launcher section\n");
|
|
return;
|
|
}
|
|
|
|
tablet_shell_add_launcher(tablet, key_launcher_icon, key_launcher_path);
|
|
|
|
free(key_launcher_icon);
|
|
key_launcher_icon = NULL;
|
|
free(key_launcher_path);
|
|
key_launcher_path = NULL;
|
|
}
|
|
|
|
static void
|
|
global_handler(struct display *display, uint32_t name,
|
|
const char *interface, uint32_t version, void *data)
|
|
{
|
|
struct tablet *tablet = data;
|
|
|
|
if (!strcmp(interface, "tablet_shell")) {
|
|
tablet->tablet_shell =
|
|
display_bind(display, name,
|
|
&tablet_shell_interface, 1);
|
|
tablet_shell_add_listener(tablet->tablet_shell,
|
|
&tablet_shell_listener, tablet);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct tablet tablet = { 0 };
|
|
struct display *display;
|
|
int config_fd;
|
|
struct output *output;
|
|
|
|
display = display_create(&argc, argv);
|
|
if (display == NULL) {
|
|
fprintf(stderr, "failed to create display: %m\n");
|
|
return -1;
|
|
}
|
|
|
|
tablet.display = display;
|
|
|
|
display_set_user_data(tablet.display, &tablet);
|
|
display_set_global_handler(tablet.display, global_handler);
|
|
|
|
tablet.homescreen = homescreen_create(&tablet);
|
|
tablet_shell_set_homescreen(tablet.tablet_shell,
|
|
window_get_wl_surface(tablet.homescreen->window));
|
|
|
|
wl_display_roundtrip (display_get_display(tablet.display));
|
|
|
|
wl_list_init(&tablet.homescreen->launcher_list);
|
|
|
|
config_fd = open_config_file("weston.ini");
|
|
parse_config_file(config_fd,
|
|
config_sections, ARRAY_LENGTH(config_sections),
|
|
&tablet);
|
|
close(config_fd);
|
|
|
|
signal(SIGCHLD, sigchild_handler);
|
|
|
|
output = display_get_output(tablet.display);
|
|
output_get_allocation(output, &tablet.allocation);
|
|
widget_schedule_resize(tablet.homescreen->widget,
|
|
tablet.allocation.width,
|
|
tablet.allocation.height);
|
|
display_run(display);
|
|
|
|
return 0;
|
|
}
|