Rename src/ to libweston/

This clarifies what is supposed to be the libweston code.

v2: screen-share.c is already in compositor/ instead.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Yong Bakos <ybakos@humanoriented.com>
Acked-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Tested-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Tested-by: Benoit Gschwind <gschwind@gnu-log.net>
Acked-by: Benoit Gschwind <gschwind@gnu-log.net>
[Pekka: rebased]
This commit is contained in:
Pekka Paalanen
2016-06-03 17:12:10 +03:00
parent 58f98c99f5
commit b5e3ea218b
65 changed files with 101 additions and 101 deletions
+485
View File
@@ -0,0 +1,485 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include "compositor.h"
#include "shared/helpers.h"
WL_EXPORT void
weston_spring_init(struct weston_spring *spring,
double k, double current, double target)
{
spring->k = k;
spring->friction = 400.0;
spring->current = current;
spring->previous = current;
spring->target = target;
spring->clip = WESTON_SPRING_OVERSHOOT;
spring->min = 0.0;
spring->max = 1.0;
}
WL_EXPORT void
weston_spring_update(struct weston_spring *spring, uint32_t msec)
{
double force, v, current, step;
/* Limit the number of executions of the loop below by ensuring that
* the timestamp for last update of the spring is no more than 1s ago.
* This handles the case where time moves backwards or forwards in
* large jumps.
*/
if (msec - spring->timestamp > 1000) {
weston_log("unexpectedly large timestamp jump (from %u to %u)\n",
spring->timestamp, msec);
spring->timestamp = msec - 1000;
}
step = 0.01;
while (4 < msec - spring->timestamp) {
current = spring->current;
v = current - spring->previous;
force = spring->k * (spring->target - current) / 10.0 +
(spring->previous - current) - v * spring->friction;
spring->current =
current + (current - spring->previous) +
force * step * step;
spring->previous = current;
switch (spring->clip) {
case WESTON_SPRING_OVERSHOOT:
break;
case WESTON_SPRING_CLAMP:
if (spring->current > spring->max) {
spring->current = spring->max;
spring->previous = spring->max;
} else if (spring->current < 0.0) {
spring->current = spring->min;
spring->previous = spring->min;
}
break;
case WESTON_SPRING_BOUNCE:
if (spring->current > spring->max) {
spring->current =
2 * spring->max - spring->current;
spring->previous =
2 * spring->max - spring->previous;
} else if (spring->current < spring->min) {
spring->current =
2 * spring->min - spring->current;
spring->previous =
2 * spring->min - spring->previous;
}
break;
}
spring->timestamp += 4;
}
}
WL_EXPORT int
weston_spring_done(struct weston_spring *spring)
{
return fabs(spring->previous - spring->target) < 0.002 &&
fabs(spring->current - spring->target) < 0.002;
}
typedef void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
struct weston_view_animation {
struct weston_view *view;
struct weston_animation animation;
struct weston_spring spring;
struct weston_transform transform;
struct wl_listener listener;
float start, stop;
weston_view_animation_frame_func_t frame;
weston_view_animation_frame_func_t reset;
weston_view_animation_done_func_t done;
void *data;
void *private;
};
WL_EXPORT void
weston_view_animation_destroy(struct weston_view_animation *animation)
{
wl_list_remove(&animation->animation.link);
wl_list_remove(&animation->listener.link);
wl_list_remove(&animation->transform.link);
if (animation->reset)
animation->reset(animation);
weston_view_geometry_dirty(animation->view);
if (animation->done)
animation->done(animation, animation->data);
free(animation);
}
static void
handle_animation_view_destroy(struct wl_listener *listener, void *data)
{
struct weston_view_animation *animation =
container_of(listener,
struct weston_view_animation, listener);
weston_view_animation_destroy(animation);
}
static void
weston_view_animation_frame(struct weston_animation *base,
struct weston_output *output, uint32_t msecs)
{
struct weston_view_animation *animation =
container_of(base,
struct weston_view_animation, animation);
struct weston_compositor *compositor =
animation->view->surface->compositor;
if (base->frame_counter <= 1)
animation->spring.timestamp = msecs;
weston_spring_update(&animation->spring, msecs);
if (weston_spring_done(&animation->spring)) {
weston_view_schedule_repaint(animation->view);
weston_view_animation_destroy(animation);
return;
}
if (animation->frame)
animation->frame(animation);
weston_view_geometry_dirty(animation->view);
weston_view_schedule_repaint(animation->view);
/* The view's output_mask will be zero if its position is
* offscreen. Animations should always run but as they are also
* run off the repaint cycle, if there's nothing to repaint
* the animation stops running. Therefore if we catch this situation
* and schedule a repaint on all outputs it will be avoided.
*/
if (animation->view->output_mask == 0)
weston_compositor_schedule_repaint(compositor);
}
static struct weston_view_animation *
weston_view_animation_create(struct weston_view *view,
float start, float stop,
weston_view_animation_frame_func_t frame,
weston_view_animation_frame_func_t reset,
weston_view_animation_done_func_t done,
void *data,
void *private)
{
struct weston_view_animation *animation;
animation = malloc(sizeof *animation);
if (!animation)
return NULL;
animation->view = view;
animation->frame = frame;
animation->reset = reset;
animation->done = done;
animation->data = data;
animation->start = start;
animation->stop = stop;
animation->private = private;
weston_matrix_init(&animation->transform.matrix);
wl_list_insert(&view->geometry.transformation_list,
&animation->transform.link);
animation->animation.frame = weston_view_animation_frame;
animation->listener.notify = handle_animation_view_destroy;
wl_signal_add(&view->destroy_signal, &animation->listener);
wl_list_insert(&view->output->animation_list,
&animation->animation.link);
return animation;
}
static void
weston_view_animation_run(struct weston_view_animation *animation)
{
animation->animation.frame_counter = 0;
weston_view_animation_frame(&animation->animation, NULL, 0);
}
static void
reset_alpha(struct weston_view_animation *animation)
{
struct weston_view *view = animation->view;
view->alpha = animation->stop;
}
static void
zoom_frame(struct weston_view_animation *animation)
{
struct weston_view *es = animation->view;
float scale;
scale = animation->start +
(animation->stop - animation->start) *
animation->spring.current;
weston_matrix_init(&animation->transform.matrix);
weston_matrix_translate(&animation->transform.matrix,
-0.5f * es->surface->width,
-0.5f * es->surface->height, 0);
weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
weston_matrix_translate(&animation->transform.matrix,
0.5f * es->surface->width,
0.5f * es->surface->height, 0);
es->alpha = animation->spring.current;
if (es->alpha > 1.0)
es->alpha = 1.0;
}
WL_EXPORT struct weston_view_animation *
weston_zoom_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data)
{
struct weston_view_animation *zoom;
zoom = weston_view_animation_create(view, start, stop,
zoom_frame, reset_alpha,
done, data, NULL);
if (zoom == NULL)
return NULL;
weston_spring_init(&zoom->spring, 300.0, start, stop);
zoom->spring.friction = 1400;
zoom->spring.previous = start - (stop - start) * 0.03;
weston_view_animation_run(zoom);
return zoom;
}
static void
fade_frame(struct weston_view_animation *animation)
{
if (animation->spring.current > 0.999)
animation->view->alpha = 1;
else if (animation->spring.current < 0.001 )
animation->view->alpha = 0;
else
animation->view->alpha = animation->spring.current;
}
WL_EXPORT struct weston_view_animation *
weston_fade_run(struct weston_view *view,
float start, float end, float k,
weston_view_animation_done_func_t done, void *data)
{
struct weston_view_animation *fade;
fade = weston_view_animation_create(view, start, end,
fade_frame, reset_alpha,
done, data, NULL);
if (fade == NULL)
return NULL;
weston_spring_init(&fade->spring, 1000.0, start, end);
fade->spring.friction = 4000;
fade->spring.previous = start - (end - start) * 0.1;
view->alpha = start;
weston_view_animation_run(fade);
return fade;
}
WL_EXPORT void
weston_fade_update(struct weston_view_animation *fade, float target)
{
fade->spring.target = target;
fade->stop = target;
}
static void
stable_fade_frame(struct weston_view_animation *animation)
{
struct weston_view *back_view;
if (animation->spring.current > 0.999)
animation->view->alpha = 1;
else if (animation->spring.current < 0.001 )
animation->view->alpha = 0;
else
animation->view->alpha = animation->spring.current;
back_view = (struct weston_view *) animation->private;
back_view->alpha =
(animation->spring.target - animation->view->alpha) /
(1.0 - animation->view->alpha);
weston_view_geometry_dirty(back_view);
}
WL_EXPORT struct weston_view_animation *
weston_stable_fade_run(struct weston_view *front_view, float start,
struct weston_view *back_view, float end,
weston_view_animation_done_func_t done, void *data)
{
struct weston_view_animation *fade;
fade = weston_view_animation_create(front_view, 0, 0,
stable_fade_frame, NULL,
done, data, back_view);
if (fade == NULL)
return NULL;
weston_spring_init(&fade->spring, 400, start, end);
fade->spring.friction = 1150;
front_view->alpha = start;
back_view->alpha = end;
weston_view_animation_run(fade);
return fade;
}
static void
slide_frame(struct weston_view_animation *animation)
{
float scale;
scale = animation->start +
(animation->stop - animation->start) *
animation->spring.current;
weston_matrix_init(&animation->transform.matrix);
weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
}
WL_EXPORT struct weston_view_animation *
weston_slide_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data)
{
struct weston_view_animation *animation;
animation = weston_view_animation_create(view, start, stop,
slide_frame, NULL, done,
data, NULL);
if (!animation)
return NULL;
weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
animation->spring.friction = 600;
animation->spring.clip = WESTON_SPRING_BOUNCE;
weston_view_animation_run(animation);
return animation;
}
struct weston_move_animation {
int dx;
int dy;
int reverse;
weston_view_animation_done_func_t done;
};
static void
move_frame(struct weston_view_animation *animation)
{
struct weston_move_animation *move = animation->private;
float scale;
float progress = animation->spring.current;
if (move->reverse)
progress = 1.0 - progress;
scale = animation->start +
(animation->stop - animation->start) *
progress;
weston_matrix_init(&animation->transform.matrix);
weston_matrix_scale(&animation->transform.matrix, scale, scale, 1.0f);
weston_matrix_translate(&animation->transform.matrix,
move->dx * progress, move->dy * progress,
0);
}
static void
move_done(struct weston_view_animation *animation, void *data)
{
struct weston_move_animation *move = animation->private;
if (move->done)
move->done(animation, data);
free(move);
}
WL_EXPORT struct weston_view_animation *
weston_move_scale_run(struct weston_view *view, int dx, int dy,
float start, float end, int reverse,
weston_view_animation_done_func_t done, void *data)
{
struct weston_move_animation *move;
struct weston_view_animation *animation;
move = malloc(sizeof(*move));
if (!move)
return NULL;
move->dx = dx;
move->dy = dy;
move->reverse = reverse;
move->done = done;
animation = weston_view_animation_create(view, start, end, move_frame,
NULL, move_done, data, move);
if (animation == NULL){
free(move);
return NULL;
}
weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
animation->spring.friction = 1150;
weston_view_animation_run(animation);
return animation;
}
+579
View File
@@ -0,0 +1,579 @@
/*
* Copyright © 2011-2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <linux/input.h>
#include "compositor.h"
#include "shared/helpers.h"
struct weston_binding {
uint32_t key;
uint32_t button;
uint32_t axis;
uint32_t modifier;
void *handler;
void *data;
struct wl_list link;
};
static struct weston_binding *
weston_compositor_add_binding(struct weston_compositor *compositor,
uint32_t key, uint32_t button, uint32_t axis,
uint32_t modifier, void *handler, void *data)
{
struct weston_binding *binding;
binding = malloc(sizeof *binding);
if (binding == NULL)
return NULL;
binding->key = key;
binding->button = button;
binding->axis = axis;
binding->modifier = modifier;
binding->handler = handler;
binding->data = data;
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_key_binding(struct weston_compositor *compositor,
uint32_t key, uint32_t modifier,
weston_key_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, key, 0, 0,
modifier, handler, data);
if (binding == NULL)
return NULL;
wl_list_insert(compositor->key_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
uint32_t modifier,
weston_modifier_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, 0, 0, 0,
modifier, handler, data);
if (binding == NULL)
return NULL;
wl_list_insert(compositor->modifier_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_button_binding(struct weston_compositor *compositor,
uint32_t button, uint32_t modifier,
weston_button_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, 0, button, 0,
modifier, handler, data);
if (binding == NULL)
return NULL;
wl_list_insert(compositor->button_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_touch_binding(struct weston_compositor *compositor,
uint32_t modifier,
weston_touch_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, 0, 0, 0,
modifier, handler, data);
if (binding == NULL)
return NULL;
wl_list_insert(compositor->touch_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_axis_binding(struct weston_compositor *compositor,
uint32_t axis, uint32_t modifier,
weston_axis_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, 0, 0, axis,
modifier, handler, data);
if (binding == NULL)
return NULL;
wl_list_insert(compositor->axis_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT struct weston_binding *
weston_compositor_add_debug_binding(struct weston_compositor *compositor,
uint32_t key,
weston_key_binding_handler_t handler,
void *data)
{
struct weston_binding *binding;
binding = weston_compositor_add_binding(compositor, key, 0, 0, 0,
handler, data);
wl_list_insert(compositor->debug_binding_list.prev, &binding->link);
return binding;
}
WL_EXPORT void
weston_binding_destroy(struct weston_binding *binding)
{
wl_list_remove(&binding->link);
free(binding);
}
void
weston_binding_list_destroy_all(struct wl_list *list)
{
struct weston_binding *binding, *tmp;
wl_list_for_each_safe(binding, tmp, list, link)
weston_binding_destroy(binding);
}
struct binding_keyboard_grab {
uint32_t key;
struct weston_keyboard_grab grab;
};
static void
binding_key(struct weston_keyboard_grab *grab,
uint32_t time, uint32_t key, uint32_t state_w)
{
struct binding_keyboard_grab *b =
container_of(grab, struct binding_keyboard_grab, grab);
struct wl_resource *resource;
enum wl_keyboard_key_state state = state_w;
uint32_t serial;
struct weston_keyboard *keyboard = grab->keyboard;
struct wl_display *display = keyboard->seat->compositor->wl_display;
if (key == b->key) {
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
weston_keyboard_end_grab(grab->keyboard);
if (keyboard->input_method_resource)
keyboard->grab = &keyboard->input_method_grab;
free(b);
} else {
/* Don't send the key press event for the binding key */
return;
}
}
if (!wl_list_empty(&keyboard->focus_resource_list)) {
serial = wl_display_next_serial(display);
wl_resource_for_each(resource, &keyboard->focus_resource_list) {
wl_keyboard_send_key(resource,
serial,
time,
key,
state);
}
}
}
static void
binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
struct wl_resource *resource;
wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) {
wl_keyboard_send_modifiers(resource, serial, mods_depressed,
mods_latched, mods_locked, group);
}
}
static void
binding_cancel(struct weston_keyboard_grab *grab)
{
struct binding_keyboard_grab *binding_grab =
container_of(grab, struct binding_keyboard_grab, grab);
weston_keyboard_end_grab(grab->keyboard);
free(binding_grab);
}
static const struct weston_keyboard_grab_interface binding_grab = {
binding_key,
binding_modifiers,
binding_cancel,
};
static void
install_binding_grab(struct weston_keyboard *keyboard, uint32_t time,
uint32_t key, struct weston_surface *focus)
{
struct binding_keyboard_grab *grab;
grab = malloc(sizeof *grab);
grab->key = key;
grab->grab.interface = &binding_grab;
weston_keyboard_start_grab(keyboard, &grab->grab);
/* Notify the surface which had the focus before this binding
* triggered that we stole a keypress from under it, by forcing
* a wl_keyboard leave/enter pair. The enter event will contain
* the pressed key in the keys array, so the client will know
* the exact state of the keyboard.
* If the old focus surface is different than the new one it
* means it was changed in the binding handler, so it received
* the enter event already. */
if (focus && keyboard->focus == focus) {
weston_keyboard_set_focus(keyboard, NULL);
weston_keyboard_set_focus(keyboard, focus);
}
}
void
weston_compositor_run_key_binding(struct weston_compositor *compositor,
struct weston_keyboard *keyboard,
uint32_t time, uint32_t key,
enum wl_keyboard_key_state state)
{
struct weston_binding *b, *tmp;
struct weston_surface *focus;
struct weston_seat *seat = keyboard->seat;
if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
return;
/* Invalidate all active modifier bindings. */
wl_list_for_each(b, &compositor->modifier_binding_list, link)
b->key = key;
wl_list_for_each_safe(b, tmp, &compositor->key_binding_list, link) {
if (b->key == key && b->modifier == seat->modifier_state) {
weston_key_binding_handler_t handler = b->handler;
focus = keyboard->focus;
handler(keyboard, time, key, b->data);
/* If this was a key binding and it didn't
* install a keyboard grab, install one now to
* swallow the key press. */
if (keyboard->grab ==
&keyboard->default_grab)
install_binding_grab(keyboard,
time,
key,
focus);
}
}
}
void
weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
struct weston_keyboard *keyboard,
enum weston_keyboard_modifier modifier,
enum wl_keyboard_key_state state)
{
struct weston_binding *b, *tmp;
if (keyboard->grab != &keyboard->default_grab)
return;
wl_list_for_each_safe(b, tmp, &compositor->modifier_binding_list, link) {
weston_modifier_binding_handler_t handler = b->handler;
if (b->modifier != modifier)
continue;
/* Prime the modifier binding. */
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
b->key = 0;
continue;
}
/* Ignore the binding if a key was pressed in between. */
else if (b->key != 0) {
return;
}
handler(keyboard, modifier, b->data);
}
}
void
weston_compositor_run_button_binding(struct weston_compositor *compositor,
struct weston_pointer *pointer,
uint32_t time, uint32_t button,
enum wl_pointer_button_state state)
{
struct weston_binding *b, *tmp;
if (state == WL_POINTER_BUTTON_STATE_RELEASED)
return;
/* Invalidate all active modifier bindings. */
wl_list_for_each(b, &compositor->modifier_binding_list, link)
b->key = button;
wl_list_for_each_safe(b, tmp, &compositor->button_binding_list, link) {
if (b->button == button &&
b->modifier == pointer->seat->modifier_state) {
weston_button_binding_handler_t handler = b->handler;
handler(pointer, time, button, b->data);
}
}
}
void
weston_compositor_run_touch_binding(struct weston_compositor *compositor,
struct weston_touch *touch, uint32_t time,
int touch_type)
{
struct weston_binding *b, *tmp;
if (touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
return;
wl_list_for_each_safe(b, tmp, &compositor->touch_binding_list, link) {
if (b->modifier == touch->seat->modifier_state) {
weston_touch_binding_handler_t handler = b->handler;
handler(touch, time, b->data);
}
}
}
int
weston_compositor_run_axis_binding(struct weston_compositor *compositor,
struct weston_pointer *pointer,
uint32_t time,
struct weston_pointer_axis_event *event)
{
struct weston_binding *b, *tmp;
/* Invalidate all active modifier bindings. */
wl_list_for_each(b, &compositor->modifier_binding_list, link)
b->key = event->axis;
wl_list_for_each_safe(b, tmp, &compositor->axis_binding_list, link) {
if (b->axis == event->axis &&
b->modifier == pointer->seat->modifier_state) {
weston_axis_binding_handler_t handler = b->handler;
handler(pointer, time, event, b->data);
return 1;
}
}
return 0;
}
int
weston_compositor_run_debug_binding(struct weston_compositor *compositor,
struct weston_keyboard *keyboard,
uint32_t time, uint32_t key,
enum wl_keyboard_key_state state)
{
weston_key_binding_handler_t handler;
struct weston_binding *binding, *tmp;
int count = 0;
wl_list_for_each_safe(binding, tmp, &compositor->debug_binding_list, link) {
if (key != binding->key)
continue;
count++;
handler = binding->handler;
handler(keyboard, time, key, binding->data);
}
return count;
}
struct debug_binding_grab {
struct weston_keyboard_grab grab;
struct weston_seat *seat;
uint32_t key[2];
int key_released[2];
};
static void
debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
uint32_t key, uint32_t state)
{
struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
struct weston_compositor *ec = db->seat->compositor;
struct wl_display *display = ec->wl_display;
struct wl_resource *resource;
uint32_t serial;
int send = 0, terminate = 0;
int check_binding = 1;
int i;
struct wl_list *resource_list;
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
/* Do not run bindings on key releases */
check_binding = 0;
for (i = 0; i < 2; i++)
if (key == db->key[i])
db->key_released[i] = 1;
if (db->key_released[0] && db->key_released[1]) {
/* All key releases been swalled so end the grab */
terminate = 1;
} else if (key != db->key[0] && key != db->key[1]) {
/* Should not swallow release of other keys */
send = 1;
}
} else if (key == db->key[0] && !db->key_released[0]) {
/* Do not check bindings for the first press of the binding
* key. This allows it to be used as a debug shortcut.
* We still need to swallow this event. */
check_binding = 0;
} else if (db->key[1]) {
/* If we already ran a binding don't process another one since
* we can't keep track of all the binding keys that were
* pressed in order to swallow the release events. */
send = 1;
check_binding = 0;
}
if (check_binding) {
if (weston_compositor_run_debug_binding(ec, grab->keyboard,
time, key, state)) {
/* We ran a binding so swallow the press and keep the
* grab to swallow the released too. */
send = 0;
terminate = 0;
db->key[1] = key;
} else {
/* Terminate the grab since the key pressed is not a
* debug binding key. */
send = 1;
terminate = 1;
}
}
if (send) {
serial = wl_display_next_serial(display);
resource_list = &grab->keyboard->focus_resource_list;
wl_resource_for_each(resource, resource_list) {
wl_keyboard_send_key(resource, serial, time, key, state);
}
}
if (terminate) {
weston_keyboard_end_grab(grab->keyboard);
if (grab->keyboard->input_method_resource)
grab->keyboard->grab = &grab->keyboard->input_method_grab;
free(db);
}
}
static void
debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
struct wl_resource *resource;
struct wl_list *resource_list;
resource_list = &grab->keyboard->focus_resource_list;
wl_resource_for_each(resource, resource_list) {
wl_keyboard_send_modifiers(resource, serial, mods_depressed,
mods_latched, mods_locked, group);
}
}
static void
debug_binding_cancel(struct weston_keyboard_grab *grab)
{
struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
weston_keyboard_end_grab(grab->keyboard);
free(db);
}
struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
debug_binding_key,
debug_binding_modifiers,
debug_binding_cancel,
};
static void
debug_binding(struct weston_keyboard *keyboard, uint32_t time,
uint32_t key, void *data)
{
struct debug_binding_grab *grab;
grab = calloc(1, sizeof *grab);
if (!grab)
return;
grab->seat = keyboard->seat;
grab->key[0] = key;
grab->grab.interface = &debug_binding_keyboard_grab;
weston_keyboard_start_grab(keyboard, &grab->grab);
}
/** Install the trigger binding for debug bindings.
*
* \param compositor The compositor.
* \param mod The modifier.
*
* This will add a key binding for modifier+SHIFT+SPACE that will trigger
* debug key bindings.
*/
WL_EXPORT void
weston_install_debug_key_binding(struct weston_compositor *compositor,
uint32_t mod)
{
weston_compositor_add_key_binding(compositor, KEY_SPACE,
mod | MODIFIER_SHIFT,
debug_binding, NULL);
}
+306
View File
@@ -0,0 +1,306 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include "compositor.h"
#include "shared/helpers.h"
struct clipboard_source {
struct weston_data_source base;
struct wl_array contents;
struct clipboard *clipboard;
struct wl_event_source *event_source;
uint32_t serial;
int refcount;
int fd;
};
struct clipboard {
struct weston_seat *seat;
struct wl_listener selection_listener;
struct wl_listener destroy_listener;
struct clipboard_source *source;
};
static void clipboard_client_create(struct clipboard_source *source, int fd);
static void
clipboard_source_unref(struct clipboard_source *source)
{
char **s;
source->refcount--;
if (source->refcount > 0)
return;
if (source->event_source) {
wl_event_source_remove(source->event_source);
close(source->fd);
}
wl_signal_emit(&source->base.destroy_signal,
&source->base);
s = source->base.mime_types.data;
free(*s);
wl_array_release(&source->base.mime_types);
wl_array_release(&source->contents);
free(source);
}
static int
clipboard_source_data(int fd, uint32_t mask, void *data)
{
struct clipboard_source *source = data;
struct clipboard *clipboard = source->clipboard;
char *p;
int len, size;
if (source->contents.alloc - source->contents.size < 1024) {
wl_array_add(&source->contents, 1024);
source->contents.size -= 1024;
}
p = source->contents.data + source->contents.size;
size = source->contents.alloc - source->contents.size;
len = read(fd, p, size);
if (len == 0) {
wl_event_source_remove(source->event_source);
close(fd);
source->event_source = NULL;
} else if (len < 0) {
clipboard_source_unref(source);
clipboard->source = NULL;
} else {
source->contents.size += len;
}
return 1;
}
static void
clipboard_source_accept(struct weston_data_source *source,
uint32_t time, const char *mime_type)
{
}
static void
clipboard_source_send(struct weston_data_source *base,
const char *mime_type, int32_t fd)
{
struct clipboard_source *source =
container_of(base, struct clipboard_source, base);
char **s;
s = source->base.mime_types.data;
if (strcmp(mime_type, s[0]) == 0)
clipboard_client_create(source, fd);
else
close(fd);
}
static void
clipboard_source_cancel(struct weston_data_source *source)
{
}
static struct clipboard_source *
clipboard_source_create(struct clipboard *clipboard,
const char *mime_type, uint32_t serial, int fd)
{
struct wl_display *display = clipboard->seat->compositor->wl_display;
struct wl_event_loop *loop = wl_display_get_event_loop(display);
struct clipboard_source *source;
char **s;
source = zalloc(sizeof *source);
if (source == NULL)
return NULL;
wl_array_init(&source->contents);
wl_array_init(&source->base.mime_types);
source->base.resource = NULL;
source->base.accept = clipboard_source_accept;
source->base.send = clipboard_source_send;
source->base.cancel = clipboard_source_cancel;
wl_signal_init(&source->base.destroy_signal);
source->refcount = 1;
source->clipboard = clipboard;
source->serial = serial;
source->fd = fd;
s = wl_array_add(&source->base.mime_types, sizeof *s);
if (s == NULL)
goto err_add;
*s = strdup(mime_type);
if (*s == NULL)
goto err_strdup;
source->event_source =
wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
clipboard_source_data, source);
if (source->event_source == NULL)
goto err_source;
return source;
err_source:
free(*s);
err_strdup:
wl_array_release(&source->base.mime_types);
err_add:
free(source);
return NULL;
}
struct clipboard_client {
struct wl_event_source *event_source;
size_t offset;
struct clipboard_source *source;
};
static int
clipboard_client_data(int fd, uint32_t mask, void *data)
{
struct clipboard_client *client = data;
char *p;
size_t size;
int len;
size = client->source->contents.size;
p = client->source->contents.data;
len = write(fd, p + client->offset, size - client->offset);
if (len > 0)
client->offset += len;
if (client->offset == size || len <= 0) {
close(fd);
wl_event_source_remove(client->event_source);
clipboard_source_unref(client->source);
free(client);
}
return 1;
}
static void
clipboard_client_create(struct clipboard_source *source, int fd)
{
struct weston_seat *seat = source->clipboard->seat;
struct clipboard_client *client;
struct wl_event_loop *loop =
wl_display_get_event_loop(seat->compositor->wl_display);
client = zalloc(sizeof *client);
if (client == NULL)
return;
client->source = source;
source->refcount++;
client->event_source =
wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
clipboard_client_data, client);
}
static void
clipboard_set_selection(struct wl_listener *listener, void *data)
{
struct clipboard *clipboard =
container_of(listener, struct clipboard, selection_listener);
struct weston_seat *seat = data;
struct weston_data_source *source = seat->selection_data_source;
const char **mime_types;
int p[2];
if (source == NULL) {
if (clipboard->source)
weston_seat_set_selection(seat,
&clipboard->source->base,
clipboard->source->serial);
return;
} else if (source->accept == clipboard_source_accept) {
/* Callback for our data source. */
return;
}
if (clipboard->source)
clipboard_source_unref(clipboard->source);
clipboard->source = NULL;
mime_types = source->mime_types.data;
if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
return;
source->send(source, mime_types[0], p[1]);
clipboard->source =
clipboard_source_create(clipboard, mime_types[0],
seat->selection_serial, p[0]);
if (clipboard->source == NULL) {
close(p[0]);
return;
}
}
static void
clipboard_destroy(struct wl_listener *listener, void *data)
{
struct clipboard *clipboard =
container_of(listener, struct clipboard, destroy_listener);
wl_list_remove(&clipboard->selection_listener.link);
wl_list_remove(&clipboard->destroy_listener.link);
free(clipboard);
}
struct clipboard *
clipboard_create(struct weston_seat *seat)
{
struct clipboard *clipboard;
clipboard = zalloc(sizeof *clipboard);
if (clipboard == NULL)
return NULL;
clipboard->seat = seat;
clipboard->selection_listener.notify = clipboard_set_selection;
clipboard->destroy_listener.notify = clipboard_destroy;
wl_signal_add(&seat->selection_signal,
&clipboard->selection_listener);
wl_signal_add(&seat->destroy_signal,
&clipboard->destroy_listener);
return clipboard;
}
File diff suppressed because it is too large Load Diff
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2015 Giulio Camuffo
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_DRM_H
#define WESTON_COMPOSITOR_DRM_H
#include "compositor.h"
#ifdef __cplusplus
extern "C" {
#endif
#define WESTON_DRM_BACKEND_CONFIG_VERSION 1
struct libinput_device;
enum weston_drm_backend_output_mode {
/** The output is disabled */
WESTON_DRM_BACKEND_OUTPUT_OFF,
/** The output will use the current active mode */
WESTON_DRM_BACKEND_OUTPUT_CURRENT,
/** The output will use the preferred mode. A modeline can be provided
* by setting weston_backend_output_config::modeline in the form of
* "WIDTHxHEIGHT" or in the form of an explicit modeline calculated
* using e.g. the cvt tool. If a valid modeline is supplied it will be
* used, if invalid or NULL the preferred available mode will be used. */
WESTON_DRM_BACKEND_OUTPUT_PREFERRED,
};
struct weston_drm_backend_output_config {
struct weston_backend_output_config base;
/** The pixel format to be used by the output. Valid values are:
* - NULL - The format set at backend creation time will be used;
* - "xrgb8888";
* - "rgb565"
* - "xrgb2101010"
*/
char *gbm_format;
/** The seat to be used by the output. Set to NULL to use the
* default seat. */
char *seat;
/** The modeline to be used by the output. Refer to the documentation
* of WESTON_DRM_BACKEND_OUTPUT_PREFERRED for details. */
char *modeline;
};
/** The backend configuration struct.
*
* weston_drm_backend_config contains the configuration used by a DRM
* backend.
*/
struct weston_drm_backend_config {
struct weston_backend_config base;
/** The connector id of the output to be initialized.
*
* A value of 0 will enable all available outputs.
*/
int connector;
/** The tty to be used. Set to 0 to use the current tty. */
int tty;
/** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
bool use_pixman;
/** The seat to be used for input and output.
*
* If NULL the default "seat0" will be used. The backend will
* take ownership of the seat_id pointer and will free it on
* backend destruction.
*/
char *seat_id;
/** The pixel format of the framebuffer to be used.
*
* Valid values are:
* - NULL - The default format ("xrgb8888") will be used;
* - "xrgb8888";
* - "rgb565"
* - "xrgb2101010"
* The backend will take ownership of the format pointer and will free
* it on backend destruction.
*/
char *gbm_format;
/** Callback used to configure the outputs.
*
* This function will be called by the backend when a new DRM
* output needs to be configured.
*/
enum weston_drm_backend_output_mode
(*configure_output)(struct weston_compositor *compositor,
bool use_current_mode,
const char *name,
struct weston_drm_backend_output_config *output_config);
/** Callback used to configure input devices.
*
* This function will be called by the backend when a new input device
* needs to be configured.
* If NULL the device will use the default configuration.
*/
void (*configure_device)(struct weston_compositor *compositor,
struct libinput_device *device);
bool use_current_mode;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_DRM_H */
+783
View File
@@ -0,0 +1,783 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2012 Raspberry Pi Foundation
* Copyright © 2013 Philip Withnall
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <libudev.h>
#include "shared/helpers.h"
#include "compositor.h"
#include "compositor-fbdev.h"
#include "launcher-util.h"
#include "pixman-renderer.h"
#include "libinput-seat.h"
#include "presentation-time-server-protocol.h"
struct fbdev_backend {
struct weston_backend base;
struct weston_compositor *compositor;
uint32_t prev_state;
struct udev *udev;
struct udev_input input;
uint32_t output_transform;
struct wl_listener session_listener;
};
struct fbdev_screeninfo {
unsigned int x_resolution; /* pixels, visible area */
unsigned int y_resolution; /* pixels, visible area */
unsigned int width_mm; /* visible screen width in mm */
unsigned int height_mm; /* visible screen height in mm */
unsigned int bits_per_pixel;
size_t buffer_length; /* length of frame buffer memory in bytes */
size_t line_length; /* length of a line in bytes */
char id[16]; /* screen identifier */
pixman_format_code_t pixel_format; /* frame buffer pixel format */
unsigned int refresh_rate; /* Hertz */
};
struct fbdev_output {
struct fbdev_backend *backend;
struct weston_output base;
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
/* Frame buffer details. */
char *device;
struct fbdev_screeninfo fb_info;
void *fb; /* length is fb_info.buffer_length */
/* pixman details. */
pixman_image_t *hw_surface;
uint8_t depth;
};
static const char default_seat[] = "seat0";
static inline struct fbdev_output *
to_fbdev_output(struct weston_output *base)
{
return container_of(base, struct fbdev_output, base);
}
static inline struct fbdev_backend *
to_fbdev_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct fbdev_backend, base);
}
static void
fbdev_output_start_repaint_loop(struct weston_output *output)
{
struct timespec ts;
weston_compositor_read_presentation_clock(output->compositor, &ts);
weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
}
static int
fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
{
struct fbdev_output *output = to_fbdev_output(base);
struct weston_compositor *ec = output->base.compositor;
/* Repaint the damaged region onto the back buffer. */
pixman_renderer_output_set_buffer(base, output->hw_surface);
ec->renderer->repaint_output(base, damage);
/* Update the damage region. */
pixman_region32_subtract(&ec->primary_plane.damage,
&ec->primary_plane.damage, damage);
/* Schedule the end of the frame. We do not sync this to the frame
* buffer clock because users who want that should be using the DRM
* compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
* panning, which is broken in most kernel drivers.
*
* Finish the frame synchronised to the specified refresh rate. The
* refresh rate is given in mHz and the interval in ms. */
wl_event_source_timer_update(output->finish_frame_timer,
1000000 / output->mode.refresh);
return 0;
}
static int
finish_frame_handler(void *data)
{
struct fbdev_output *output = data;
struct timespec ts;
weston_compositor_read_presentation_clock(output->base.compositor, &ts);
weston_output_finish_frame(&output->base, &ts, 0);
return 1;
}
static pixman_format_code_t
calculate_pixman_format(struct fb_var_screeninfo *vinfo,
struct fb_fix_screeninfo *finfo)
{
/* Calculate the pixman format supported by the frame buffer from the
* buffer's metadata. Return 0 if no known pixman format is supported
* (since this has depth 0 it's guaranteed to not conflict with any
* actual pixman format).
*
* Documentation on the vinfo and finfo structures:
* http://www.mjmwired.net/kernel/Documentation/fb/api.txt
*
* TODO: Try a bit harder to support other formats, including setting
* the preferred format in the hardware. */
int type;
weston_log("Calculating pixman format from:\n"
STAMP_SPACE " - type: %i (aux: %i)\n"
STAMP_SPACE " - visual: %i\n"
STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
finfo->type, finfo->type_aux, finfo->visual,
vinfo->bits_per_pixel, vinfo->grayscale,
vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
vinfo->green.offset, vinfo->green.length,
vinfo->green.msb_right,
vinfo->blue.offset, vinfo->blue.length,
vinfo->blue.msb_right,
vinfo->transp.offset, vinfo->transp.length,
vinfo->transp.msb_right);
/* We only handle packed formats at the moment. */
if (finfo->type != FB_TYPE_PACKED_PIXELS)
return 0;
/* We only handle true-colour frame buffers at the moment. */
switch(finfo->visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_DIRECTCOLOR:
if (vinfo->grayscale != 0)
return 0;
break;
default:
return 0;
}
/* We only support formats with MSBs on the left. */
if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
vinfo->blue.msb_right != 0)
return 0;
/* Work out the format type from the offsets. We only support RGBA and
* ARGB at the moment. */
type = PIXMAN_TYPE_OTHER;
if ((vinfo->transp.offset >= vinfo->red.offset ||
vinfo->transp.length == 0) &&
vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset)
type = PIXMAN_TYPE_ARGB;
else if (vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset &&
vinfo->blue.offset >= vinfo->transp.offset)
type = PIXMAN_TYPE_RGBA;
if (type == PIXMAN_TYPE_OTHER)
return 0;
/* Build the format. */
return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
vinfo->transp.length,
vinfo->red.length,
vinfo->green.length,
vinfo->blue.length);
}
static int
calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
{
uint64_t quot;
/* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
quot *= vinfo->pixclock;
if (quot > 0) {
uint64_t refresh_rate;
refresh_rate = 1000000000000000LLU / quot;
if (refresh_rate > 200000)
refresh_rate = 200000; /* cap at 200 Hz */
return refresh_rate;
}
return 60 * 1000; /* default to 60 Hz */
}
static int
fbdev_query_screen_info(struct fbdev_output *output, int fd,
struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
struct fb_fix_screeninfo fixinfo;
/* Probe the device for screen information. */
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Store the pertinent data. */
info->x_resolution = varinfo.xres;
info->y_resolution = varinfo.yres;
info->width_mm = varinfo.width;
info->height_mm = varinfo.height;
info->bits_per_pixel = varinfo.bits_per_pixel;
info->buffer_length = fixinfo.smem_len;
info->line_length = fixinfo.line_length;
strncpy(info->id, fixinfo.id, sizeof(info->id));
info->id[sizeof(info->id)-1] = '\0';
info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
info->refresh_rate = calculate_refresh_rate(&varinfo);
if (info->pixel_format == 0) {
weston_log("Frame buffer uses an unsupported format.\n");
return -1;
}
return 1;
}
static int
fbdev_set_screen_info(struct fbdev_output *output, int fd,
struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
/* Grab the current screen information. */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Update the information. */
varinfo.xres = info->x_resolution;
varinfo.yres = info->y_resolution;
varinfo.width = info->width_mm;
varinfo.height = info->height_mm;
varinfo.bits_per_pixel = info->bits_per_pixel;
/* Try to set up an ARGB (x8r8g8b8) pixel format. */
varinfo.grayscale = 0;
varinfo.transp.offset = 24;
varinfo.transp.length = 0;
varinfo.transp.msb_right = 0;
varinfo.red.offset = 16;
varinfo.red.length = 8;
varinfo.red.msb_right = 0;
varinfo.green.offset = 8;
varinfo.green.length = 8;
varinfo.green.msb_right = 0;
varinfo.blue.offset = 0;
varinfo.blue.length = 8;
varinfo.blue.msb_right = 0;
/* Set the device's screen information. */
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
return -1;
}
return 1;
}
static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
/* Returns an FD for the frame buffer device. */
static int
fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
struct fbdev_screeninfo *screen_info)
{
int fd = -1;
weston_log("Opening fbdev frame buffer.\n");
/* Open the frame buffer device. */
fd = open(fb_dev, O_RDWR | O_CLOEXEC);
if (fd < 0) {
weston_log("Failed to open frame buffer device %s: %s\n",
fb_dev, strerror(errno));
return -1;
}
/* Grab the screen info. */
if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
weston_log("Failed to get frame buffer info: %s\n",
strerror(errno));
close(fd);
return -1;
}
return fd;
}
/* Closes the FD on success or failure. */
static int
fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
{
int retval = -1;
weston_log("Mapping fbdev frame buffer.\n");
/* Map the frame buffer. Write-only mode, since we don't want to read
* anything back (because it's slow). */
output->fb = mmap(NULL, output->fb_info.buffer_length,
PROT_WRITE, MAP_SHARED, fd, 0);
if (output->fb == MAP_FAILED) {
weston_log("Failed to mmap frame buffer: %s\n",
strerror(errno));
goto out_close;
}
/* Create a pixman image to wrap the memory mapped frame buffer. */
output->hw_surface =
pixman_image_create_bits(output->fb_info.pixel_format,
output->fb_info.x_resolution,
output->fb_info.y_resolution,
output->fb,
output->fb_info.line_length);
if (output->hw_surface == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
goto out_unmap;
}
/* Success! */
retval = 0;
out_unmap:
if (retval != 0 && output->fb != NULL)
fbdev_frame_buffer_destroy(output);
out_close:
if (fd >= 0)
close(fd);
return retval;
}
static void
fbdev_frame_buffer_destroy(struct fbdev_output *output)
{
weston_log("Destroying fbdev frame buffer.\n");
if (munmap(output->fb, output->fb_info.buffer_length) < 0)
weston_log("Failed to munmap frame buffer: %s\n",
strerror(errno));
output->fb = NULL;
}
static void fbdev_output_destroy(struct weston_output *base);
static void fbdev_output_disable(struct weston_output *base);
static int
fbdev_output_create(struct fbdev_backend *backend,
const char *device)
{
struct fbdev_output *output;
int fb_fd;
struct wl_event_loop *loop;
weston_log("Creating fbdev output.\n");
output = zalloc(sizeof *output);
if (output == NULL)
return -1;
output->backend = backend;
output->device = strdup(device);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
goto out_free;
}
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
goto out_free;
}
output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
output->base.repaint = fbdev_output_repaint;
output->base.destroy = fbdev_output_destroy;
/* only one static mode in list */
output->mode.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = output->fb_info.x_resolution;
output->mode.height = output->fb_info.y_resolution;
output->mode.refresh = output->fb_info.refresh_rate;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current_mode = &output->mode;
output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
output->base.make = "unknown";
output->base.model = output->fb_info.id;
output->base.name = strdup("fbdev");
weston_output_init(&output->base, backend->compositor,
0, 0, output->fb_info.width_mm,
output->fb_info.height_mm,
backend->output_transform,
1);
if (pixman_renderer_output_create(&output->base) < 0)
goto out_hw_surface;
loop = wl_display_get_event_loop(backend->compositor->wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
weston_compositor_add_output(backend->compositor, &output->base);
weston_log("fbdev output %d×%d px\n",
output->mode.width, output->mode.height);
weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
output->mode.refresh / 1000);
return 0;
out_hw_surface:
pixman_image_unref(output->hw_surface);
output->hw_surface = NULL;
weston_output_destroy(&output->base);
fbdev_frame_buffer_destroy(output);
out_free:
free(output->device);
free(output);
return -1;
}
static void
fbdev_output_destroy(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
weston_log("Destroying fbdev output.\n");
/* Close the frame buffer. */
fbdev_output_disable(base);
if (base->renderer_state != NULL)
pixman_renderer_output_destroy(base);
/* Remove the output. */
weston_output_destroy(&output->base);
free(output->device);
free(output);
}
/* strcmp()-style return values. */
static int
compare_screen_info (const struct fbdev_screeninfo *a,
const struct fbdev_screeninfo *b)
{
if (a->x_resolution == b->x_resolution &&
a->y_resolution == b->y_resolution &&
a->width_mm == b->width_mm &&
a->height_mm == b->height_mm &&
a->bits_per_pixel == b->bits_per_pixel &&
a->pixel_format == b->pixel_format &&
a->refresh_rate == b->refresh_rate)
return 0;
return 1;
}
static int
fbdev_output_reenable(struct fbdev_backend *backend,
struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
struct fbdev_screeninfo new_screen_info;
int fb_fd;
char *device;
weston_log("Re-enabling fbdev output.\n");
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(output, output->device,
&new_screen_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
goto err;
}
/* Check whether the frame buffer details have changed since we were
* disabled. */
if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
/* Perform a mode-set to restore the old mode. */
if (fbdev_set_screen_info(output, fb_fd,
&output->fb_info) < 0) {
weston_log("Failed to restore mode settings. "
"Attempting to re-open output anyway.\n");
}
close(fb_fd);
/* Remove and re-add the output so that resources depending on
* the frame buffer X/Y resolution (such as the shadow buffer)
* are re-initialised. */
device = strdup(output->device);
fbdev_output_destroy(&output->base);
fbdev_output_create(backend, device);
free(device);
return 0;
}
/* Map the device if it has the same details as before. */
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
goto err;
}
return 0;
err:
return -1;
}
/* NOTE: This leaves output->fb_info populated, caching data so that if
* fbdev_output_reenable() is called again, it can determine whether a mode-set
* is needed. */
static void
fbdev_output_disable(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
weston_log("Disabling fbdev output.\n");
if (output->hw_surface != NULL) {
pixman_image_unref(output->hw_surface);
output->hw_surface = NULL;
}
fbdev_frame_buffer_destroy(output);
}
static void
fbdev_backend_destroy(struct weston_compositor *base)
{
struct fbdev_backend *backend = to_fbdev_backend(base);
udev_input_destroy(&backend->input);
/* Destroy the output. */
weston_compositor_shutdown(base);
/* Chain up. */
weston_launcher_destroy(base->launcher);
free(backend);
}
static void
session_notify(struct wl_listener *listener, void *data)
{
struct weston_compositor *compositor = data;
struct fbdev_backend *backend = to_fbdev_backend(compositor);
struct weston_output *output;
if (compositor->session_active) {
weston_log("entering VT\n");
compositor->state = backend->prev_state;
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_output_reenable(backend, output);
}
weston_compositor_damage_all(compositor);
udev_input_enable(&backend->input);
} else {
weston_log("leaving VT\n");
udev_input_disable(&backend->input);
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_output_disable(output);
}
backend->prev_state = compositor->state;
weston_compositor_offscreen(compositor);
/* If we have a repaint scheduled (from the idle handler), make
* sure we cancel that so we don't try to pageflip when we're
* vt switched away. The OFFSCREEN state will prevent
* further attempts at repainting. When we switch
* back, we schedule a repaint, which will process
* pending frame callbacks. */
wl_list_for_each(output,
&compositor->output_list, link) {
output->repaint_needed = 0;
}
}
}
static void
fbdev_restore(struct weston_compositor *compositor)
{
weston_launcher_restore(compositor->launcher);
}
static struct fbdev_backend *
fbdev_backend_create(struct weston_compositor *compositor,
struct weston_fbdev_backend_config *param)
{
struct fbdev_backend *backend;
const char *seat_id = default_seat;
weston_log("initializing fbdev backend\n");
backend = zalloc(sizeof *backend);
if (backend == NULL)
return NULL;
backend->compositor = compositor;
if (weston_compositor_set_presentation_clock_software(
compositor) < 0)
goto out_compositor;
backend->udev = udev_new();
if (backend->udev == NULL) {
weston_log("Failed to initialize udev context.\n");
goto out_compositor;
}
/* Set up the TTY. */
backend->session_listener.notify = session_notify;
wl_signal_add(&compositor->session_signal,
&backend->session_listener);
compositor->launcher =
weston_launcher_connect(compositor, param->tty, "seat0", false);
if (!compositor->launcher) {
weston_log("fatal: fbdev backend should be run "
"using weston-launch binary or as root\n");
goto out_udev;
}
backend->base.destroy = fbdev_backend_destroy;
backend->base.restore = fbdev_restore;
backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
backend->output_transform = param->output_transform;
weston_setup_vt_switch_bindings(compositor);
if (pixman_renderer_init(compositor) < 0)
goto out_launcher;
if (fbdev_output_create(backend, param->device) < 0)
goto out_launcher;
udev_input_init(&backend->input, compositor, backend->udev,
seat_id, param->configure_device);
compositor->backend = &backend->base;
return backend;
out_launcher:
weston_launcher_destroy(compositor->launcher);
out_udev:
udev_unref(backend->udev);
out_compositor:
weston_compositor_shutdown(compositor);
free(backend);
return NULL;
}
static void
config_init_to_defaults(struct weston_fbdev_backend_config *config)
{
/* TODO: Ideally, available frame buffers should be enumerated using
* udev, rather than passing a device node in as a parameter. */
config->tty = 0; /* default to current tty */
config->device = "/dev/fb0"; /* default frame buffer */
config->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
}
WL_EXPORT int
backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct fbdev_backend *b;
struct weston_fbdev_backend_config config = {{ 0, }};
if (config_base == NULL ||
config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
weston_log("fbdev backend config structure is invalid\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
b = fbdev_backend_create(compositor, &config);
if (b == NULL)
return -1;
return 0;
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_FBDEV_H
#define WESTON_COMPOSITOR_FBDEV_H
#ifdef __cplusplus
extern "C" {
#endif
#include "compositor.h"
#define WESTON_FBDEV_BACKEND_CONFIG_VERSION 1
struct libinput_device;
struct weston_fbdev_backend_config {
struct weston_backend_config base;
int tty;
char *device;
uint32_t output_transform;
/** Callback used to configure input devices.
*
* This function will be called by the backend when a new input device
* needs to be configured.
* If NULL the device will use the default configuration.
*/
void (*configure_device)(struct weston_compositor *compositor,
struct libinput_device *device);
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_FBDEV_H */
+258
View File
@@ -0,0 +1,258 @@
/*
* Copyright © 2010-2011 Benjamin Franzke
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <stdbool.h>
#include "compositor.h"
#include "compositor-headless.h"
#include "shared/helpers.h"
#include "pixman-renderer.h"
#include "presentation-time-server-protocol.h"
struct headless_backend {
struct weston_backend base;
struct weston_compositor *compositor;
struct weston_seat fake_seat;
bool use_pixman;
};
struct headless_output {
struct weston_output base;
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
uint32_t *image_buf;
pixman_image_t *image;
};
static void
headless_output_start_repaint_loop(struct weston_output *output)
{
struct timespec ts;
weston_compositor_read_presentation_clock(output->compositor, &ts);
weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
}
static int
finish_frame_handler(void *data)
{
struct headless_output *output = data;
struct timespec ts;
weston_compositor_read_presentation_clock(output->base.compositor, &ts);
weston_output_finish_frame(&output->base, &ts, 0);
return 1;
}
static int
headless_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage)
{
struct headless_output *output = (struct headless_output *) output_base;
struct weston_compositor *ec = output->base.compositor;
ec->renderer->repaint_output(&output->base, damage);
pixman_region32_subtract(&ec->primary_plane.damage,
&ec->primary_plane.damage, damage);
wl_event_source_timer_update(output->finish_frame_timer, 16);
return 0;
}
static void
headless_output_destroy(struct weston_output *output_base)
{
struct headless_output *output = (struct headless_output *) output_base;
struct headless_backend *b =
(struct headless_backend *) output->base.compositor->backend;
wl_event_source_remove(output->finish_frame_timer);
if (b->use_pixman) {
pixman_renderer_output_destroy(&output->base);
pixman_image_unref(output->image);
free(output->image_buf);
}
weston_output_destroy(&output->base);
free(output);
return;
}
static int
headless_backend_create_output(struct headless_backend *b,
struct weston_headless_backend_config *config)
{
struct weston_compositor *c = b->compositor;
struct headless_output *output;
struct wl_event_loop *loop;
output = zalloc(sizeof *output);
if (output == NULL)
return -1;
output->mode.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = config->width;
output->mode.height = config->height;
output->mode.refresh = 60000;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current_mode = &output->mode;
weston_output_init(&output->base, c, 0, 0, config->width,
config->height, config->transform, 1);
output->base.make = "weston";
output->base.model = "headless";
loop = wl_display_get_event_loop(c->wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
output->base.start_repaint_loop = headless_output_start_repaint_loop;
output->base.repaint = headless_output_repaint;
output->base.destroy = headless_output_destroy;
output->base.assign_planes = NULL;
output->base.set_backlight = NULL;
output->base.set_dpms = NULL;
output->base.switch_mode = NULL;
if (b->use_pixman) {
output->image_buf = malloc(config->width * config->height * 4);
if (!output->image_buf)
return -1;
output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
config->width,
config->height,
output->image_buf,
config->width * 4);
if (pixman_renderer_output_create(&output->base) < 0)
return -1;
pixman_renderer_output_set_buffer(&output->base,
output->image);
}
weston_compositor_add_output(c, &output->base);
return 0;
}
static void
headless_restore(struct weston_compositor *ec)
{
}
static void
headless_destroy(struct weston_compositor *ec)
{
struct headless_backend *b = (struct headless_backend *) ec->backend;
weston_compositor_shutdown(ec);
free(b);
}
static struct headless_backend *
headless_backend_create(struct weston_compositor *compositor,
struct weston_headless_backend_config *config)
{
struct headless_backend *b;
b = zalloc(sizeof *b);
if (b == NULL)
return NULL;
b->compositor = compositor;
if (weston_compositor_set_presentation_clock_software(compositor) < 0)
goto err_free;
b->base.destroy = headless_destroy;
b->base.restore = headless_restore;
b->use_pixman = config->use_pixman;
if (b->use_pixman) {
pixman_renderer_init(compositor);
}
if (headless_backend_create_output(b, config) < 0)
goto err_input;
if (!b->use_pixman && noop_renderer_init(compositor) < 0)
goto err_input;
compositor->backend = &b->base;
return b;
err_input:
weston_compositor_shutdown(compositor);
err_free:
free(b);
return NULL;
}
static void
config_init_to_defaults(struct weston_headless_backend_config *config)
{
}
WL_EXPORT int
backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct headless_backend *b;
struct weston_headless_backend_config config = {{ 0, }};
if (config_base == NULL ||
config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
weston_log("headless backend config structure is invalid\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
b = headless_backend_create(compositor, &config);
if (b == NULL)
return -1;
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_HEADLESS_H
#define WESTON_COMPOSITOR_HEADLESS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "compositor.h"
#define WESTON_HEADLESS_BACKEND_CONFIG_VERSION 1
struct weston_headless_backend_config {
struct weston_backend_config base;
int width;
int height;
/** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
int use_pixman;
uint32_t transform;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_HEADLESS_H */
File diff suppressed because it is too large Load Diff
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_RDP_H
#define WESTON_COMPOSITOR_RDP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "compositor.h"
#define WESTON_RDP_BACKEND_CONFIG_VERSION 1
struct weston_rdp_backend_config {
struct weston_backend_config base;
int width;
int height;
char *bind_address;
int port;
char *rdp_key;
char *server_cert;
char *server_key;
int env_socket;
int no_clients_resize;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_RDP_H */
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_WAYLAND_H
#define WESTON_COMPOSITOR_WAYLAND_H
#include "compositor.h"
#ifdef __cplusplus
extern "C" {
#endif
#define WESTON_WAYLAND_BACKEND_CONFIG_VERSION 1
struct weston_wayland_backend_output_config {
int width;
int height;
char *name;
uint32_t transform;
int32_t scale;
};
struct weston_wayland_backend_config {
struct weston_backend_config base;
int use_pixman;
int sprawl;
char *display_name;
int fullscreen;
char *cursor_theme;
int cursor_size;
int num_outputs;
struct weston_wayland_backend_output_config *outputs;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_WAYLAND_H */
File diff suppressed because it is too large Load Diff
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_COMPOSITOR_X11_H
#define WESTON_COMPOSITOR_X11_H
#ifdef __cplusplus
extern "C" {
#endif
#include "compositor.h"
#define WESTON_X11_BACKEND_CONFIG_VERSION 1
struct weston_x11_backend_output_config {
int width;
int height;
char *name;
uint32_t transform;
int32_t scale;
};
struct weston_x11_backend_config {
struct weston_backend_config base;
bool fullscreen;
bool no_input;
/** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
bool use_pixman;
uint32_t num_outputs;
struct weston_x11_backend_output_config *outputs;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_X11_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+407
View File
@@ -0,0 +1,407 @@
/*
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* DBus Helpers
* This file contains the dbus mainloop integration and several helpers to
* make lowlevel libdbus access easier.
*/
#include "config.h"
#include <dbus/dbus.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <wayland-server.h>
#include "compositor.h"
#include "dbus.h"
/*
* DBus Mainloop Integration
* weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing
* DBusConnection to an existing wl_event_loop object. All dbus dispatching
* is then nicely integrated into the wayland event loop.
* Note that this only provides basic watch and timeout dispatching. No
* remote thread wakeup, signal handling or other dbus insanity is supported.
* This is fine as long as you don't use any of the deprecated libdbus
* interfaces (like waking up remote threads..). There is really no rational
* reason to support these.
*/
static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data)
{
DBusWatch *watch = data;
uint32_t flags = 0;
if (dbus_watch_get_enabled(watch)) {
if (mask & WL_EVENT_READABLE)
flags |= DBUS_WATCH_READABLE;
if (mask & WL_EVENT_WRITABLE)
flags |= DBUS_WATCH_WRITABLE;
if (mask & WL_EVENT_HANGUP)
flags |= DBUS_WATCH_HANGUP;
if (mask & WL_EVENT_ERROR)
flags |= DBUS_WATCH_ERROR;
dbus_watch_handle(watch, flags);
}
return 0;
}
static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data)
{
struct wl_event_loop *loop = data;
struct wl_event_source *s;
int fd;
uint32_t mask = 0, flags;
if (dbus_watch_get_enabled(watch)) {
flags = dbus_watch_get_flags(watch);
if (flags & DBUS_WATCH_READABLE)
mask |= WL_EVENT_READABLE;
if (flags & DBUS_WATCH_WRITABLE)
mask |= WL_EVENT_WRITABLE;
}
fd = dbus_watch_get_unix_fd(watch);
s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch,
watch);
if (!s)
return FALSE;
dbus_watch_set_data(watch, s, NULL);
return TRUE;
}
static void weston_dbus_remove_watch(DBusWatch *watch, void *data)
{
struct wl_event_source *s;
s = dbus_watch_get_data(watch);
if (!s)
return;
wl_event_source_remove(s);
}
static void weston_dbus_toggle_watch(DBusWatch *watch, void *data)
{
struct wl_event_source *s;
uint32_t mask = 0, flags;
s = dbus_watch_get_data(watch);
if (!s)
return;
if (dbus_watch_get_enabled(watch)) {
flags = dbus_watch_get_flags(watch);
if (flags & DBUS_WATCH_READABLE)
mask |= WL_EVENT_READABLE;
if (flags & DBUS_WATCH_WRITABLE)
mask |= WL_EVENT_WRITABLE;
}
wl_event_source_fd_update(s, mask);
}
static int weston_dbus_dispatch_timeout(void *data)
{
DBusTimeout *timeout = data;
if (dbus_timeout_get_enabled(timeout))
dbus_timeout_handle(timeout);
return 0;
}
static int weston_dbus_adjust_timeout(DBusTimeout *timeout,
struct wl_event_source *s)
{
int64_t t = 0;
if (dbus_timeout_get_enabled(timeout))
t = dbus_timeout_get_interval(timeout);
return wl_event_source_timer_update(s, t);
}
static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data)
{
struct wl_event_loop *loop = data;
struct wl_event_source *s;
int r;
s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout,
timeout);
if (!s)
return FALSE;
r = weston_dbus_adjust_timeout(timeout, s);
if (r < 0) {
wl_event_source_remove(s);
return FALSE;
}
dbus_timeout_set_data(timeout, s, NULL);
return TRUE;
}
static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data)
{
struct wl_event_source *s;
s = dbus_timeout_get_data(timeout);
if (!s)
return;
wl_event_source_remove(s);
}
static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data)
{
struct wl_event_source *s;
s = dbus_timeout_get_data(timeout);
if (!s)
return;
weston_dbus_adjust_timeout(timeout, s);
}
static int weston_dbus_dispatch(int fd, uint32_t mask, void *data)
{
DBusConnection *c = data;
int r;
do {
r = dbus_connection_dispatch(c);
if (r == DBUS_DISPATCH_COMPLETE)
r = 0;
else if (r == DBUS_DISPATCH_DATA_REMAINS)
r = -EAGAIN;
else if (r == DBUS_DISPATCH_NEED_MEMORY)
r = -ENOMEM;
else
r = -EIO;
} while (r == -EAGAIN);
if (r)
weston_log("cannot dispatch dbus events: %d\n", r);
return 0;
}
static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c,
struct wl_event_source **ctx_out)
{
bool b;
int r, fd;
/* Idle events cannot reschedule themselves, therefore we use a dummy
* event-fd and mark it for post-dispatch. Hence, the dbus
* dispatcher is called after every dispatch-round.
* This is required as dbus doesn't allow dispatching events from
* within its own event sources. */
fd = eventfd(0, EFD_CLOEXEC);
if (fd < 0)
return -errno;
*ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c);
close(fd);
if (!*ctx_out)
return -ENOMEM;
wl_event_source_check(*ctx_out);
b = dbus_connection_set_watch_functions(c,
weston_dbus_add_watch,
weston_dbus_remove_watch,
weston_dbus_toggle_watch,
loop,
NULL);
if (!b) {
r = -ENOMEM;
goto error;
}
b = dbus_connection_set_timeout_functions(c,
weston_dbus_add_timeout,
weston_dbus_remove_timeout,
weston_dbus_toggle_timeout,
loop,
NULL);
if (!b) {
r = -ENOMEM;
goto error;
}
dbus_connection_ref(c);
return 0;
error:
dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
NULL, NULL);
dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
NULL, NULL);
wl_event_source_remove(*ctx_out);
*ctx_out = NULL;
return r;
}
static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx)
{
dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
NULL, NULL);
dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
NULL, NULL);
dbus_connection_unref(c);
wl_event_source_remove(ctx);
}
/*
* Convenience Helpers
* Several convenience helpers are provided to make using dbus in weston
* easier. We don't use any of the gdbus or qdbus helpers as they pull in
* huge dependencies and actually are quite awful to use. Instead, we only
* use the basic low-level libdbus library.
*/
int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
DBusConnection **out, struct wl_event_source **ctx_out)
{
DBusConnection *c;
int r;
/* Ihhh, global state.. stupid dbus. */
dbus_connection_set_change_sigpipe(FALSE);
/* This is actually synchronous. It blocks for some authentication and
* setup. We just trust the dbus-server here and accept this blocking
* call. There is no real reason to complicate things further and make
* this asynchronous/non-blocking. A context should be created during
* thead/process/app setup, so blocking calls should be fine. */
c = dbus_bus_get_private(bus, NULL);
if (!c)
return -EIO;
dbus_connection_set_exit_on_disconnect(c, FALSE);
r = weston_dbus_bind(loop, c, ctx_out);
if (r < 0)
goto error;
*out = c;
return r;
error:
dbus_connection_close(c);
dbus_connection_unref(c);
return r;
}
void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx)
{
weston_dbus_unbind(c, ctx);
dbus_connection_close(c);
dbus_connection_unref(c);
}
int weston_dbus_add_match(DBusConnection *c, const char *format, ...)
{
DBusError err;
int r;
va_list list;
char *str;
va_start(list, format);
r = vasprintf(&str, format, list);
va_end(list);
if (r < 0)
return -ENOMEM;
dbus_error_init(&err);
dbus_bus_add_match(c, str, &err);
free(str);
if (dbus_error_is_set(&err)) {
dbus_error_free(&err);
return -EIO;
}
return 0;
}
int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
const char *iface, const char *member,
const char *path)
{
return weston_dbus_add_match(c,
"type='signal',"
"sender='%s',"
"interface='%s',"
"member='%s',"
"path='%s'",
sender, iface, member, path);
}
void weston_dbus_remove_match(DBusConnection *c, const char *format, ...)
{
int r;
va_list list;
char *str;
va_start(list, format);
r = vasprintf(&str, format, list);
va_end(list);
if (r < 0)
return;
dbus_bus_remove_match(c, str, NULL);
free(str);
}
void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
const char *iface, const char *member,
const char *path)
{
return weston_dbus_remove_match(c,
"type='signal',"
"sender='%s',"
"interface='%s',"
"member='%s',"
"path='%s'",
sender, iface, member, path);
}
+110
View File
@@ -0,0 +1,110 @@
/*
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _WESTON_DBUS_H_
#define _WESTON_DBUS_H_
#include "config.h"
#include <errno.h>
#include <wayland-server.h>
#include "compositor.h"
#ifdef HAVE_DBUS
#include <dbus/dbus.h>
/*
* weston_dbus_open() - Open new dbus connection
*
* Opens a new dbus connection to the bus given as @bus. It automatically
* integrates the new connection into the main-loop @loop. The connection
* itself is returned in @out.
* This also returns a context source used for dbus dispatching. It is
* returned on success in @ctx_out and must be passed to weston_dbus_close()
* unchanged. You must not access it from outside of a dbus helper!
*
* Returns 0 on success, negative error code on failure.
*/
int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
DBusConnection **out, struct wl_event_source **ctx_out);
/*
* weston_dbus_close() - Close dbus connection
*
* Closes a dbus connection that was previously opened via weston_dbus_open().
* It unbinds the connection from the main-loop it was previously bound to,
* closes the dbus connection and frees all resources. If you want to access
* @c after this call returns, you must hold a dbus-reference to it. But
* notice that the connection is closed after this returns so it cannot be
* used to spawn new dbus requests.
* You must pass the context source returns by weston_dbus_open() as @ctx.
*/
void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx);
/*
* weston_dbus_add_match() - Add dbus match
*
* Configure a dbus-match on the given dbus-connection. This match is saved
* on the dbus-server as long as the connection is open. See dbus-manual
* for information. Compared to the dbus_bus_add_match() this allows a
* var-arg formatted match-string.
*/
int weston_dbus_add_match(DBusConnection *c, const char *format, ...);
/*
* weston_dbus_add_match_signal() - Add dbus signal match
*
* Same as weston_dbus_add_match() but does the dbus-match formatting for
* signals internally.
*/
int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
const char *iface, const char *member,
const char *path);
/*
* weston_dbus_remove_match() - Remove dbus match
*
* Remove a previously configured dbus-match from the dbus server. There is
* no need to remove dbus-matches if you close the connection, anyway.
* Compared to dbus_bus_remove_match() this allows a var-arg formatted
* match string.
*/
void weston_dbus_remove_match(DBusConnection *c, const char *format, ...);
/*
* weston_dbus_remove_match_signal() - Remove dbus signal match
*
* Same as weston_dbus_remove_match() but does the dbus-match formatting for
* signals internally.
*/
void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
const char *iface, const char *member,
const char *path);
#endif /* HAVE_DBUS */
#endif // _WESTON_DBUS_H_
File diff suppressed because it is too large Load Diff
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright © 2012 John Kåre Alsaker
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "compositor.h"
#ifdef ENABLE_EGL
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
typedef int EGLint;
typedef int EGLenum;
typedef void *EGLDisplay;
typedef void *EGLSurface;
typedef void *EGLConfig;
typedef intptr_t EGLNativeDisplayType;
typedef intptr_t EGLNativeWindowType;
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
#endif /* ENABLE_EGL */
#ifndef EGL_EXT_platform_base
typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
#endif
#ifndef EGL_PLATFORM_GBM_KHR
#define EGL_PLATFORM_GBM_KHR 0x31D7
#endif
#ifndef EGL_PLATFORM_WAYLAND_KHR
#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
#endif
#ifndef EGL_PLATFORM_X11_KHR
#define EGL_PLATFORM_X11_KHR 0x31D5
#endif
#define NO_EGL_PLATFORM 0
enum gl_renderer_border_side {
GL_RENDERER_BORDER_TOP = 0,
GL_RENDERER_BORDER_LEFT = 1,
GL_RENDERER_BORDER_RIGHT = 2,
GL_RENDERER_BORDER_BOTTOM = 3,
};
struct gl_renderer_interface {
const EGLint *opaque_attribs;
const EGLint *alpha_attribs;
int (*create)(struct weston_compositor *ec,
EGLenum platform,
void *native_window,
const EGLint *attribs,
const EGLint *visual_id,
const int n_ids);
EGLDisplay (*display)(struct weston_compositor *ec);
int (*output_create)(struct weston_output *output,
EGLNativeWindowType window_for_legacy,
void *window_for_platform,
const EGLint *attribs,
const EGLint *visual_id,
const int n_ids);
void (*output_destroy)(struct weston_output *output);
EGLSurface (*output_surface)(struct weston_output *output);
/* Sets the output border.
*
* The side specifies the side for which we are setting the border.
* The width and height are the width and height of the border.
* The tex_width patemeter specifies the width of the actual
* texture; this may be larger than width if the data is not
* tightly packed.
*
* The top and bottom textures will extend over the sides to the
* full width of the bordered window. The right and left edges,
* however, will extend only to the top and bottom of the
* compositor surface. This is demonstrated by the picture below:
*
* +-----------------------+
* | TOP |
* +-+-------------------+-+
* | | | |
* |L| |R|
* |E| |I|
* |F| |G|
* |T| |H|
* | | |T|
* | | | |
* +-+-------------------+-+
* | BOTTOM |
* +-----------------------+
*/
void (*output_set_border)(struct weston_output *output,
enum gl_renderer_border_side side,
int32_t width, int32_t height,
int32_t tex_width, unsigned char *data);
void (*print_egl_error_state)(void);
};
+2765
View File
File diff suppressed because it is too large Load Diff
+315
View File
@@ -0,0 +1,315 @@
/*
* Copyright © 2012 Benjamin Franzke
* Copyright © 2013 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 "config.h"
#include "compositor.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/major.h>
#include "launcher-impl.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
static inline int
is_drm_master(int drm_fd)
{
drm_magic_t magic;
return drmGetMagic(drm_fd, &magic) == 0 &&
drmAuthMagic(drm_fd, magic) == 0;
}
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
static inline int
is_drm_master(int drm_fd)
{
return 0;
}
#endif
struct launcher_direct {
struct weston_launcher base;
struct weston_compositor *compositor;
int kb_mode, tty, drm_fd;
struct wl_event_source *vt_source;
};
static int
vt_handler(int signal_number, void *data)
{
struct launcher_direct *launcher = data;
struct weston_compositor *compositor = launcher->compositor;
if (compositor->session_active) {
compositor->session_active = 0;
wl_signal_emit(&compositor->session_signal, compositor);
drmDropMaster(launcher->drm_fd);
ioctl(launcher->tty, VT_RELDISP, 1);
} else {
ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
drmSetMaster(launcher->drm_fd);
compositor->session_active = 1;
wl_signal_emit(&compositor->session_signal, compositor);
}
return 1;
}
static int
setup_tty(struct launcher_direct *launcher, int tty)
{
struct wl_event_loop *loop;
struct vt_mode mode = { 0 };
struct stat buf;
char tty_device[32] ="<stdin>";
int ret, kd_mode;
if (tty == 0) {
launcher->tty = dup(tty);
if (launcher->tty == -1) {
weston_log("couldn't dup stdin: %m\n");
return -1;
}
} else {
snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
if (launcher->tty == -1) {
weston_log("couldn't open tty %s: %m\n", tty_device);
return -1;
}
}
if (fstat(launcher->tty, &buf) == -1 ||
major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
weston_log("%s not a vt\n", tty_device);
weston_log("if running weston from ssh, "
"use --tty to specify a tty\n");
goto err_close;
}
ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
if (ret) {
weston_log("failed to get VT mode: %m\n");
return -1;
}
if (kd_mode != KD_TEXT) {
weston_log("%s is already in graphics mode, "
"is another display server running?\n", tty_device);
goto err_close;
}
ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
weston_log("failed to read keyboard mode: %m\n");
goto err_close;
}
if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
weston_log("failed to set K_OFF keyboard mode: %m\n");
goto err_close;
}
ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
if (ret) {
weston_log("failed to set KD_GRAPHICS mode on tty: %m\n");
goto err_close;
}
/*
* SIGRTMIN is used as global VT-acquire+release signal. Note that
* SIGRT* must be tested on runtime, as their exact values are not
* known at compile-time. POSIX requires 32 of them to be available.
*/
if (SIGRTMIN > SIGRTMAX) {
weston_log("not enough RT signals available: %u-%u\n",
SIGRTMIN, SIGRTMAX);
ret = -EINVAL;
goto err_close;
}
mode.mode = VT_PROCESS;
mode.relsig = SIGRTMIN;
mode.acqsig = SIGRTMIN;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
weston_log("failed to take control of vt handling\n");
goto err_close;
}
loop = wl_display_get_event_loop(launcher->compositor->wl_display);
launcher->vt_source =
wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
if (!launcher->vt_source)
goto err_close;
return 0;
err_close:
close(launcher->tty);
return -1;
}
static int
launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
struct stat s;
int fd;
fd = open(path, flags | O_CLOEXEC);
if (fd == -1)
return -1;
if (fstat(fd, &s) == -1) {
close(fd);
return -1;
}
if (major(s.st_rdev) == DRM_MAJOR) {
launcher->drm_fd = fd;
if (!is_drm_master(fd)) {
weston_log("drm fd not master\n");
close(fd);
return -1;
}
}
return fd;
}
static void
launcher_direct_close(struct weston_launcher *launcher_base, int fd)
{
close(fd);
}
static void
launcher_direct_restore(struct weston_launcher *launcher_base)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
struct vt_mode mode = { 0 };
if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
weston_log("failed to restore kb mode: %m\n");
if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
weston_log("failed to set KD_TEXT mode on tty: %m\n");
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(launcher->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
weston_log("could not reset vt handling\n");
}
static int
launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
return ioctl(launcher->tty, VT_ACTIVATE, vt);
}
static int
launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
{
struct launcher_direct *launcher;
if (geteuid() != 0)
return -EINVAL;
launcher = zalloc(sizeof(*launcher));
if (launcher == NULL)
return -ENOMEM;
launcher->base.iface = &launcher_direct_iface;
launcher->compositor = compositor;
if (setup_tty(launcher, tty) == -1) {
free(launcher);
return -1;
}
* (struct launcher_direct **) out = launcher;
return 0;
}
static void
launcher_direct_destroy(struct weston_launcher *launcher_base)
{
struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
launcher_direct_restore(&launcher->base);
wl_event_source_remove(launcher->vt_source);
if (launcher->tty >= 0)
close(launcher->tty);
free(launcher);
}
struct launcher_interface launcher_direct_iface = {
launcher_direct_connect,
launcher_direct_destroy,
launcher_direct_open,
launcher_direct_close,
launcher_direct_activate_vt,
launcher_direct_restore,
};
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright © 2015 Jasper St. Pierre
*
* 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 "config.h"
#include "compositor.h"
struct weston_launcher;
struct launcher_interface {
int (* connect) (struct weston_launcher **launcher_out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm);
void (* destroy) (struct weston_launcher *launcher);
int (* open) (struct weston_launcher *launcher, const char *path, int flags);
void (* close) (struct weston_launcher *launcher, int fd);
int (* activate_vt) (struct weston_launcher *launcher, int vt);
void (* restore) (struct weston_launcher *launcher);
};
struct weston_launcher {
struct launcher_interface *iface;
};
extern struct launcher_interface launcher_logind_iface;
extern struct launcher_interface launcher_weston_launch_iface;
extern struct launcher_interface launcher_direct_iface;
+839
View File
@@ -0,0 +1,839 @@
/*
* Copyright © 2013 David Herrmann
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <systemd/sd-login.h>
#include <unistd.h>
#include "compositor.h"
#include "dbus.h"
#include "launcher-impl.h"
#define DRM_MAJOR 226
struct launcher_logind {
struct weston_launcher base;
struct weston_compositor *compositor;
bool sync_drm;
char *seat;
char *sid;
unsigned int vtnr;
int vt;
int kb_mode;
DBusConnection *dbus;
struct wl_event_source *dbus_ctx;
char *spath;
DBusPendingCall *pending_active;
};
static int
launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
uint32_t minor, bool *paused_out)
{
DBusMessage *m, *reply;
bool b;
int r, fd;
dbus_bool_t paused;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"TakeDevice");
if (!m)
return -ENOMEM;
b = dbus_message_append_args(m,
DBUS_TYPE_UINT32, &major,
DBUS_TYPE_UINT32, &minor,
DBUS_TYPE_INVALID);
if (!b) {
r = -ENOMEM;
goto err_unref;
}
reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
-1, NULL);
if (!reply) {
r = -ENODEV;
goto err_unref;
}
b = dbus_message_get_args(reply, NULL,
DBUS_TYPE_UNIX_FD, &fd,
DBUS_TYPE_BOOLEAN, &paused,
DBUS_TYPE_INVALID);
if (!b) {
r = -ENODEV;
goto err_reply;
}
r = fd;
if (paused_out)
*paused_out = paused;
err_reply:
dbus_message_unref(reply);
err_unref:
dbus_message_unref(m);
return r;
}
static void
launcher_logind_release_device(struct launcher_logind *wl, uint32_t major,
uint32_t minor)
{
DBusMessage *m;
bool b;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"ReleaseDevice");
if (m) {
b = dbus_message_append_args(m,
DBUS_TYPE_UINT32, &major,
DBUS_TYPE_UINT32, &minor,
DBUS_TYPE_INVALID);
if (b)
dbus_connection_send(wl->dbus, m, NULL);
dbus_message_unref(m);
}
}
static void
launcher_logind_pause_device_complete(struct launcher_logind *wl, uint32_t major,
uint32_t minor)
{
DBusMessage *m;
bool b;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"PauseDeviceComplete");
if (m) {
b = dbus_message_append_args(m,
DBUS_TYPE_UINT32, &major,
DBUS_TYPE_UINT32, &minor,
DBUS_TYPE_INVALID);
if (b)
dbus_connection_send(wl->dbus, m, NULL);
dbus_message_unref(m);
}
}
static int
launcher_logind_open(struct weston_launcher *launcher, const char *path, int flags)
{
struct launcher_logind *wl = wl_container_of(launcher, wl, base);
struct stat st;
int fl, r, fd;
r = stat(path, &st);
if (r < 0)
return -1;
if (!S_ISCHR(st.st_mode)) {
errno = ENODEV;
return -1;
}
fd = launcher_logind_take_device(wl, major(st.st_rdev),
minor(st.st_rdev), NULL);
if (fd < 0)
return fd;
/* Compared to weston_launcher_open() we cannot specify the open-mode
* directly. Instead, logind passes us an fd with sane default modes.
* For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
* something else, we need to change it afterwards. We currently
* only support setting O_NONBLOCK. Changing access-modes is not
* possible so accept whatever logind passes us. */
fl = fcntl(fd, F_GETFL);
if (fl < 0) {
r = -errno;
goto err_close;
}
if (flags & O_NONBLOCK)
fl |= O_NONBLOCK;
r = fcntl(fd, F_SETFL, fl);
if (r < 0) {
r = -errno;
goto err_close;
}
return fd;
err_close:
close(fd);
launcher_logind_release_device(wl, major(st.st_rdev),
minor(st.st_rdev));
errno = -r;
return -1;
}
static void
launcher_logind_close(struct weston_launcher *launcher, int fd)
{
struct launcher_logind *wl = wl_container_of(launcher, wl, base);
struct stat st;
int r;
r = fstat(fd, &st);
if (r < 0) {
weston_log("logind: cannot fstat fd: %m\n");
return;
}
if (!S_ISCHR(st.st_mode)) {
weston_log("logind: invalid device passed\n");
return;
}
launcher_logind_release_device(wl, major(st.st_rdev),
minor(st.st_rdev));
}
static void
launcher_logind_restore(struct weston_launcher *launcher)
{
}
static int
launcher_logind_activate_vt(struct weston_launcher *launcher, int vt)
{
struct launcher_logind *wl = wl_container_of(launcher, wl, base);
DBusMessage *m;
bool b;
int r;
m = dbus_message_new_method_call("org.freedesktop.login1",
"/org/freedesktop/login1/seat/self",
"org.freedesktop.login1.Seat",
"SwitchTo");
if (!m)
return -ENOMEM;
b = dbus_message_append_args(m,
DBUS_TYPE_UINT32, &vt,
DBUS_TYPE_INVALID);
if (!b) {
r = -ENOMEM;
goto err_unref;
}
dbus_connection_send(wl->dbus, m, NULL);
r = 0;
err_unref:
dbus_message_unref(m);
return r;
}
static void
launcher_logind_set_active(struct launcher_logind *wl, bool active)
{
if (!wl->compositor->session_active == !active)
return;
wl->compositor->session_active = active;
wl_signal_emit(&wl->compositor->session_signal,
wl->compositor);
}
static void
parse_active(struct launcher_logind *wl, DBusMessage *m, DBusMessageIter *iter)
{
DBusMessageIter sub;
dbus_bool_t b;
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
return;
dbus_message_iter_recurse(iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
return;
dbus_message_iter_get_basic(&sub, &b);
/* If the backend requested DRM master-device synchronization, we only
* wake-up the compositor once the master-device is up and running. For
* other backends, we immediately forward the Active-change event. */
if (!wl->sync_drm || !b)
launcher_logind_set_active(wl, b);
}
static void
get_active_cb(DBusPendingCall *pending, void *data)
{
struct launcher_logind *wl = data;
DBusMessageIter iter;
DBusMessage *m;
int type;
dbus_pending_call_unref(wl->pending_active);
wl->pending_active = NULL;
m = dbus_pending_call_steal_reply(pending);
if (!m)
return;
type = dbus_message_get_type(m);
if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
dbus_message_iter_init(m, &iter))
parse_active(wl, m, &iter);
dbus_message_unref(m);
}
static void
launcher_logind_get_active(struct launcher_logind *wl)
{
DBusPendingCall *pending;
DBusMessage *m;
bool b;
const char *iface, *name;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.DBus.Properties",
"Get");
if (!m)
return;
iface = "org.freedesktop.login1.Session";
name = "Active";
b = dbus_message_append_args(m,
DBUS_TYPE_STRING, &iface,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
if (!b)
goto err_unref;
b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
if (!b)
goto err_unref;
b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
if (!b) {
dbus_pending_call_cancel(pending);
dbus_pending_call_unref(pending);
goto err_unref;
}
if (wl->pending_active) {
dbus_pending_call_cancel(wl->pending_active);
dbus_pending_call_unref(wl->pending_active);
}
wl->pending_active = pending;
return;
err_unref:
dbus_message_unref(m);
}
static void
disconnected_dbus(struct launcher_logind *wl)
{
weston_log("logind: dbus connection lost, exiting..\n");
launcher_logind_restore(&wl->base);
exit(-1);
}
static void
session_removed(struct launcher_logind *wl, DBusMessage *m)
{
const char *name, *obj;
bool r;
r = dbus_message_get_args(m, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_OBJECT_PATH, &obj,
DBUS_TYPE_INVALID);
if (!r) {
weston_log("logind: cannot parse SessionRemoved dbus signal\n");
return;
}
if (!strcmp(name, wl->sid)) {
weston_log("logind: our session got closed, exiting..\n");
launcher_logind_restore(&wl->base);
exit(-1);
}
}
static void
property_changed(struct launcher_logind *wl, DBusMessage *m)
{
DBusMessageIter iter, sub, entry;
const char *interface, *name;
if (!dbus_message_iter_init(m, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
goto error;
dbus_message_iter_get_basic(&iter, &interface);
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
goto error;
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
dbus_message_iter_recurse(&sub, &entry);
if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
goto error;
dbus_message_iter_get_basic(&entry, &name);
if (!dbus_message_iter_next(&entry))
goto error;
if (!strcmp(name, "Active")) {
parse_active(wl, m, &entry);
return;
}
dbus_message_iter_next(&sub);
}
if (!dbus_message_iter_next(&iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
goto error;
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
dbus_message_iter_get_basic(&sub, &name);
if (!strcmp(name, "Active")) {
launcher_logind_get_active(wl);
return;
}
dbus_message_iter_next(&sub);
}
return;
error:
weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
}
static void
device_paused(struct launcher_logind *wl, DBusMessage *m)
{
bool r;
const char *type;
uint32_t major, minor;
r = dbus_message_get_args(m, NULL,
DBUS_TYPE_UINT32, &major,
DBUS_TYPE_UINT32, &minor,
DBUS_TYPE_STRING, &type,
DBUS_TYPE_INVALID);
if (!r) {
weston_log("logind: cannot parse PauseDevice dbus signal\n");
return;
}
/* "pause" means synchronous pausing. Acknowledge it unconditionally
* as we support asynchronous device shutdowns, anyway.
* "force" means asynchronous pausing.
* "gone" means the device is gone. We handle it the same as "force" as
* a following udev event will be caught, too.
*
* If it's our main DRM device, tell the compositor to go asleep. */
if (!strcmp(type, "pause"))
launcher_logind_pause_device_complete(wl, major, minor);
if (wl->sync_drm && major == DRM_MAJOR)
launcher_logind_set_active(wl, false);
}
static void
device_resumed(struct launcher_logind *wl, DBusMessage *m)
{
bool r;
uint32_t major;
r = dbus_message_get_args(m, NULL,
DBUS_TYPE_UINT32, &major,
/*DBUS_TYPE_UINT32, &minor,
DBUS_TYPE_UNIX_FD, &fd,*/
DBUS_TYPE_INVALID);
if (!r) {
weston_log("logind: cannot parse ResumeDevice dbus signal\n");
return;
}
/* DeviceResumed messages provide us a new file-descriptor for
* resumed devices. For DRM devices it's the same as before, for evdev
* devices it's a new open-file. As we reopen evdev devices, anyway,
* there is no need for us to handle this event for evdev. For DRM, we
* notify the compositor to wake up. */
if (wl->sync_drm && major == DRM_MAJOR)
launcher_logind_set_active(wl, true);
}
static DBusHandlerResult
filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
{
struct launcher_logind *wl = data;
if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
disconnected_dbus(wl);
} else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
"SessionRemoved")) {
session_removed(wl, m);
} else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
"PropertiesChanged")) {
property_changed(wl, m);
} else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
"PauseDevice")) {
device_paused(wl, m);
} else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
"ResumeDevice")) {
device_resumed(wl, m);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int
launcher_logind_setup_dbus(struct launcher_logind *wl)
{
bool b;
int r;
r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
wl->sid);
if (r < 0)
return -ENOMEM;
b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
if (!b) {
weston_log("logind: cannot add dbus filter\n");
r = -ENOMEM;
goto err_spath;
}
r = weston_dbus_add_match_signal(wl->dbus,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SessionRemoved",
"/org/freedesktop/login1");
if (r < 0) {
weston_log("logind: cannot add dbus match\n");
goto err_spath;
}
r = weston_dbus_add_match_signal(wl->dbus,
"org.freedesktop.login1",
"org.freedesktop.login1.Session",
"PauseDevice",
wl->spath);
if (r < 0) {
weston_log("logind: cannot add dbus match\n");
goto err_spath;
}
r = weston_dbus_add_match_signal(wl->dbus,
"org.freedesktop.login1",
"org.freedesktop.login1.Session",
"ResumeDevice",
wl->spath);
if (r < 0) {
weston_log("logind: cannot add dbus match\n");
goto err_spath;
}
r = weston_dbus_add_match_signal(wl->dbus,
"org.freedesktop.login1",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
wl->spath);
if (r < 0) {
weston_log("logind: cannot add dbus match\n");
goto err_spath;
}
return 0;
err_spath:
/* don't remove any dbus-match as the connection is closed, anyway */
free(wl->spath);
return r;
}
static void
launcher_logind_destroy_dbus(struct launcher_logind *wl)
{
/* don't remove any dbus-match as the connection is closed, anyway */
free(wl->spath);
}
static int
launcher_logind_take_control(struct launcher_logind *wl)
{
DBusError err;
DBusMessage *m, *reply;
dbus_bool_t force;
bool b;
int r;
dbus_error_init(&err);
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"TakeControl");
if (!m)
return -ENOMEM;
force = false;
b = dbus_message_append_args(m,
DBUS_TYPE_BOOLEAN, &force,
DBUS_TYPE_INVALID);
if (!b) {
r = -ENOMEM;
goto err_unref;
}
reply = dbus_connection_send_with_reply_and_block(wl->dbus,
m, -1, &err);
if (!reply) {
if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
weston_log("logind: old systemd version detected\n");
else
weston_log("logind: cannot take control over session %s\n", wl->sid);
dbus_error_free(&err);
r = -EIO;
goto err_unref;
}
dbus_message_unref(reply);
dbus_message_unref(m);
return 0;
err_unref:
dbus_message_unref(m);
return r;
}
static void
launcher_logind_release_control(struct launcher_logind *wl)
{
DBusMessage *m;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"ReleaseControl");
if (m) {
dbus_connection_send(wl->dbus, m, NULL);
dbus_message_unref(m);
}
}
static int
weston_sd_session_get_vt(const char *sid, unsigned int *out)
{
#ifdef HAVE_SYSTEMD_LOGIN_209
return sd_session_get_vt(sid, out);
#else
int r;
char *tty;
r = sd_session_get_tty(sid, &tty);
if (r < 0)
return r;
r = sscanf(tty, "tty%u", out);
free(tty);
if (r != 1)
return -EINVAL;
return 0;
#endif
}
static int
launcher_logind_activate(struct launcher_logind *wl)
{
DBusMessage *m;
m = dbus_message_new_method_call("org.freedesktop.login1",
wl->spath,
"org.freedesktop.login1.Session",
"Activate");
if (!m)
return -ENOMEM;
dbus_connection_send(wl->dbus, m, NULL);
return 0;
}
static int
launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
{
struct launcher_logind *wl;
struct wl_event_loop *loop;
char *t;
int r;
wl = zalloc(sizeof(*wl));
if (wl == NULL) {
r = -ENOMEM;
goto err_out;
}
wl->base.iface = &launcher_logind_iface;
wl->compositor = compositor;
wl->sync_drm = sync_drm;
wl->seat = strdup(seat_id);
if (!wl->seat) {
r = -ENOMEM;
goto err_wl;
}
r = sd_pid_get_session(getpid(), &wl->sid);
if (r < 0) {
weston_log("logind: not running in a systemd session\n");
goto err_seat;
}
t = NULL;
r = sd_session_get_seat(wl->sid, &t);
if (r < 0) {
weston_log("logind: failed to get session seat\n");
free(t);
goto err_session;
} else if (strcmp(seat_id, t)) {
weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
seat_id, t);
r = -EINVAL;
free(t);
goto err_session;
}
free(t);
r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
if (r < 0) {
weston_log("logind: session not running on a VT\n");
goto err_session;
} else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
tty, wl->vtnr);
r = -EINVAL;
goto err_session;
}
loop = wl_display_get_event_loop(compositor->wl_display);
r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
if (r < 0) {
weston_log("logind: cannot connect to system dbus\n");
goto err_session;
}
r = launcher_logind_setup_dbus(wl);
if (r < 0)
goto err_dbus;
r = launcher_logind_take_control(wl);
if (r < 0)
goto err_dbus_cleanup;
r = launcher_logind_activate(wl);
if (r < 0)
goto err_dbus_cleanup;
weston_log("logind: session control granted\n");
* (struct launcher_logind **) out = wl;
return 0;
err_dbus_cleanup:
launcher_logind_destroy_dbus(wl);
err_dbus:
weston_dbus_close(wl->dbus, wl->dbus_ctx);
err_session:
free(wl->sid);
err_seat:
free(wl->seat);
err_wl:
free(wl);
err_out:
weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
errno = -r;
return -1;
}
static void
launcher_logind_destroy(struct weston_launcher *launcher)
{
struct launcher_logind *wl = wl_container_of(launcher, wl, base);
if (wl->pending_active) {
dbus_pending_call_cancel(wl->pending_active);
dbus_pending_call_unref(wl->pending_active);
}
launcher_logind_release_control(wl);
launcher_logind_destroy_dbus(wl);
weston_dbus_close(wl->dbus, wl->dbus_ctx);
free(wl->sid);
free(wl->seat);
free(wl);
}
struct launcher_interface launcher_logind_iface = {
launcher_logind_connect,
launcher_logind_destroy,
launcher_logind_open,
launcher_logind_close,
launcher_logind_activate_vt,
launcher_logind_restore,
};
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright © 2012 Benjamin Franzke
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "compositor.h"
#include "launcher-util.h"
#include "launcher-impl.h"
#include <unistd.h>
#include <linux/input.h>
static struct launcher_interface *ifaces[] = {
#ifdef HAVE_SYSTEMD_LOGIN
&launcher_logind_iface,
#endif
&launcher_weston_launch_iface,
&launcher_direct_iface,
NULL,
};
WL_EXPORT struct weston_launcher *
weston_launcher_connect(struct weston_compositor *compositor, int tty,
const char *seat_id, bool sync_drm)
{
struct launcher_interface **it;
for (it = ifaces; *it != NULL; it++) {
struct launcher_interface *iface = *it;
struct weston_launcher *launcher;
if (iface->connect(&launcher, compositor, tty, seat_id, sync_drm) == 0)
return launcher;
}
return NULL;
}
WL_EXPORT void
weston_launcher_destroy(struct weston_launcher *launcher)
{
launcher->iface->destroy(launcher);
}
WL_EXPORT int
weston_launcher_open(struct weston_launcher *launcher,
const char *path, int flags)
{
return launcher->iface->open(launcher, path, flags);
}
WL_EXPORT void
weston_launcher_close(struct weston_launcher *launcher, int fd)
{
launcher->iface->close(launcher, fd);
}
WL_EXPORT int
weston_launcher_activate_vt(struct weston_launcher *launcher, int vt)
{
return launcher->iface->activate_vt(launcher, vt);
}
WL_EXPORT void
weston_launcher_restore(struct weston_launcher *launcher)
{
launcher->iface->restore(launcher);
}
static void
switch_vt_binding(struct weston_keyboard *keyboard,
uint32_t time, uint32_t key, void *data)
{
struct weston_compositor *compositor = data;
weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
}
WL_EXPORT void
weston_setup_vt_switch_bindings(struct weston_compositor *compositor)
{
uint32_t key;
if (compositor->vt_switching == false)
return;
for (key = KEY_F1; key < KEY_F9; key++)
weston_compositor_add_key_binding(compositor, key,
MODIFIER_CTRL | MODIFIER_ALT,
switch_vt_binding,
compositor);
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _WESTON_LAUNCHER_UTIL_H_
#define _WESTON_LAUNCHER_UTIL_H_
#include "config.h"
#include "compositor.h"
struct weston_launcher;
struct weston_launcher *
weston_launcher_connect(struct weston_compositor *compositor, int tty,
const char *seat_id, bool sync_drm);
void
weston_launcher_destroy(struct weston_launcher *launcher);
int
weston_launcher_open(struct weston_launcher *launcher,
const char *path, int flags);
void
weston_launcher_close(struct weston_launcher *launcher, int fd);
int
weston_launcher_activate_vt(struct weston_launcher *launcher, int vt);
void
weston_launcher_restore(struct weston_launcher *launcher);
void
weston_setup_vt_switch_bindings(struct weston_compositor *compositor);
#endif
+300
View File
@@ -0,0 +1,300 @@
/*
* Copyright © 2012 Benjamin Franzke
* Copyright © 2013 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/major.h>
#include "compositor.h"
#include "weston-launch.h"
#include "launcher-impl.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
static inline int
is_drm_master(int drm_fd)
{
drm_magic_t magic;
return drmGetMagic(drm_fd, &magic) == 0 &&
drmAuthMagic(drm_fd, magic) == 0;
}
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
static inline int
is_drm_master(int drm_fd)
{
return 0;
}
#endif
union cmsg_data { unsigned char b[4]; int fd; };
struct launcher_weston_launch {
struct weston_launcher base;
struct weston_compositor *compositor;
struct wl_event_loop *loop;
int fd;
struct wl_event_source *source;
int kb_mode, tty, drm_fd;
};
static int
launcher_weston_launch_open(struct weston_launcher *launcher_base,
const char *path, int flags)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
int n, ret;
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
union cmsg_data *data;
char control[CMSG_SPACE(sizeof data->fd)];
ssize_t len;
struct weston_launcher_open *message;
n = sizeof(*message) + strlen(path) + 1;
message = malloc(n);
if (!message)
return -1;
message->header.opcode = WESTON_LAUNCHER_OPEN;
message->flags = flags;
strcpy(message->path, path);
do {
len = send(launcher->fd, message, n, 0);
} while (len < 0 && errno == EINTR);
free(message);
memset(&msg, 0, sizeof msg);
iov.iov_base = &ret;
iov.iov_len = sizeof ret;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof control;
do {
len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
} while (len < 0 && errno == EINTR);
if (len != sizeof ret ||
ret < 0)
return -1;
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "invalid control message\n");
return -1;
}
data = (union cmsg_data *) CMSG_DATA(cmsg);
if (data->fd == -1) {
fprintf(stderr, "missing drm fd in socket request\n");
return -1;
}
return data->fd;
}
static void
launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
{
close(fd);
}
static void
launcher_weston_launch_restore(struct weston_launcher *launcher_base)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
struct vt_mode mode = { 0 };
if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
weston_log("failed to restore kb mode: %m\n");
if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
weston_log("failed to set KD_TEXT mode on tty: %m\n");
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(launcher->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
weston_log("could not reset vt handling\n");
}
static int
launcher_weston_launch_data(int fd, uint32_t mask, void *data)
{
struct launcher_weston_launch *launcher = data;
int len, ret;
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
weston_log("launcher socket closed, exiting\n");
/* Normally the weston-launch will reset the tty, but
* in this case it died or something, so do it here so
* we don't end up with a stuck vt. */
launcher_weston_launch_restore(&launcher->base);
exit(-1);
}
do {
len = recv(launcher->fd, &ret, sizeof ret, 0);
} while (len < 0 && errno == EINTR);
switch (ret) {
case WESTON_LAUNCHER_ACTIVATE:
launcher->compositor->session_active = 1;
wl_signal_emit(&launcher->compositor->session_signal,
launcher->compositor);
break;
case WESTON_LAUNCHER_DEACTIVATE:
launcher->compositor->session_active = 0;
wl_signal_emit(&launcher->compositor->session_signal,
launcher->compositor);
break;
default:
weston_log("unexpected event from weston-launch\n");
break;
}
return 1;
}
static int
launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
return ioctl(launcher->tty, VT_ACTIVATE, vt);
}
static int
launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
int tty, const char *seat_id, bool sync_drm)
{
struct launcher_weston_launch *launcher;
struct wl_event_loop *loop;
launcher = malloc(sizeof *launcher);
if (launcher == NULL)
return -ENOMEM;
launcher->base.iface = &launcher_weston_launch_iface;
* (struct launcher_weston_launch **) out = launcher;
launcher->compositor = compositor;
launcher->drm_fd = -1;
launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
if (launcher->fd != -1) {
launcher->tty = weston_environment_get_fd("WESTON_TTY_FD");
/* We don't get a chance to read out the original kb
* mode for the tty, so just hard code K_UNICODE here
* in case we have to clean if weston-launch dies. */
launcher->kb_mode = K_UNICODE;
loop = wl_display_get_event_loop(compositor->wl_display);
launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
WL_EVENT_READABLE,
launcher_weston_launch_data,
launcher);
if (launcher->source == NULL) {
free(launcher);
return -ENOMEM;
}
return 0;
} else {
return -1;
}
}
static void
launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
{
struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
if (launcher->fd != -1) {
close(launcher->fd);
wl_event_source_remove(launcher->source);
} else {
launcher_weston_launch_restore(&launcher->base);
}
if (launcher->tty >= 0)
close(launcher->tty);
free(launcher);
}
struct launcher_interface launcher_weston_launch_iface = {
launcher_weston_launch_connect,
launcher_weston_launch_destroy,
launcher_weston_launch_open,
launcher_weston_launch_close,
launcher_weston_launch_activate_vt,
launcher_weston_launch_restore,
};
+310
View File
@@ -0,0 +1,310 @@
/*
* libbacklight - userspace interface to Linux backlight control
*
* Copyright © 2012 Intel Corporation
* Copyright 2010 Red Hat <mjg@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Matthew Garrett <mjg@redhat.com>
* Tiago Vignatti <vignatti@freedesktop.org>
*/
#include "config.h"
#include "libbacklight.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/types.h>
#include <dirent.h>
#include <drm.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
static long backlight_get(struct backlight *backlight, char *node)
{
char buffer[100];
char *path;
int fd;
long value, ret;
if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
return -ENOMEM;
fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -1;
goto out;
}
ret = read(fd, &buffer, sizeof(buffer));
if (ret < 1) {
ret = -1;
goto out;
}
value = strtol(buffer, NULL, 10);
ret = value;
out:
if (fd >= 0)
close(fd);
free(path);
return ret;
}
long backlight_get_brightness(struct backlight *backlight)
{
return backlight_get(backlight, "brightness");
}
long backlight_get_max_brightness(struct backlight *backlight)
{
return backlight_get(backlight, "max_brightness");
}
long backlight_get_actual_brightness(struct backlight *backlight)
{
return backlight_get(backlight, "actual_brightness");
}
long backlight_set_brightness(struct backlight *backlight, long brightness)
{
char *path;
char *buffer = NULL;
int fd;
long ret;
if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
return -ENOMEM;
fd = open(path, O_RDWR);
if (fd < 0) {
ret = -1;
goto out;
}
ret = read(fd, &buffer, sizeof(buffer));
if (ret < 1) {
ret = -1;
goto out;
}
if (asprintf(&buffer, "%ld", brightness) < 0) {
ret = -1;
goto out;
}
ret = write(fd, buffer, strlen(buffer));
if (ret < 0) {
ret = -1;
goto out;
}
ret = backlight_get_brightness(backlight);
backlight->brightness = ret;
out:
free(buffer);
free(path);
if (fd >= 0)
close(fd);
return ret;
}
void backlight_destroy(struct backlight *backlight)
{
if (!backlight)
return;
if (backlight->path)
free(backlight->path);
free(backlight);
}
struct backlight *backlight_init(struct udev_device *drm_device,
uint32_t connector_type)
{
const char *syspath = NULL;
char *pci_name = NULL;
char *chosen_path = NULL;
char *path = NULL;
DIR *backlights = NULL;
struct dirent *entry;
enum backlight_type type = 0;
char buffer[100];
struct backlight *backlight = NULL;
int ret;
if (!drm_device)
return NULL;
syspath = udev_device_get_syspath(drm_device);
if (!syspath)
return NULL;
if (asprintf(&path, "%s/%s", syspath, "device") < 0)
return NULL;
ret = readlink(path, buffer, sizeof(buffer) - 1);
free(path);
if (ret < 0)
return NULL;
buffer[ret] = '\0';
pci_name = basename(buffer);
if (connector_type <= 0)
return NULL;
backlights = opendir("/sys/class/backlight");
if (!backlights)
return NULL;
/* Find the "best" backlight for the device. Firmware
interfaces are preferred over platform interfaces are
preferred over raw interfaces. For raw interfaces we'll
check if the device ID in the form of pci match, while
for firmware interfaces we require the pci ID to
match. It's assumed that platform interfaces always match,
since we can't actually associate them with IDs.
A further awkwardness is that, while it's theoretically
possible for an ACPI interface to include support for
changing the backlight of external devices, it's unlikely
to ever be done. It's effectively impossible for a platform
interface to do so. So if we get asked about anything that
isn't LVDS or eDP, we pretty much have to require that the
control be supplied via a raw interface */
while ((entry = readdir(backlights))) {
char *backlight_path;
char *parent;
enum backlight_type entry_type;
int fd;
if (entry->d_name[0] == '.')
continue;
if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
entry->d_name) < 0)
goto err;
if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
free(backlight_path);
goto err;
}
fd = open(path, O_RDONLY);
if (fd < 0)
goto out;
ret = read (fd, &buffer, sizeof(buffer));
close (fd);
if (ret < 1)
goto out;
buffer[ret] = '\0';
if (!strncmp(buffer, "raw\n", sizeof(buffer)))
entry_type = BACKLIGHT_RAW;
else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
entry_type = BACKLIGHT_PLATFORM;
else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
entry_type = BACKLIGHT_FIRMWARE;
else
goto out;
if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
connector_type != DRM_MODE_CONNECTOR_eDP) {
/* External displays are assumed to require
gpu control at the moment */
if (entry_type != BACKLIGHT_RAW)
goto out;
}
free (path);
if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
goto err;
ret = readlink(path, buffer, sizeof(buffer) - 1);
if (ret < 0)
goto out;
buffer[ret] = '\0';
parent = basename(buffer);
/* Perform matching for raw and firmware backlights -
platform backlights have to be assumed to match */
if (entry_type == BACKLIGHT_RAW ||
entry_type == BACKLIGHT_FIRMWARE) {
if (!(pci_name && !strcmp(pci_name, parent)))
goto out;
}
if (entry_type < type)
goto out;
type = entry_type;
if (chosen_path)
free(chosen_path);
chosen_path = strdup(backlight_path);
out:
free(backlight_path);
free(path);
}
if (!chosen_path)
goto err;
backlight = malloc(sizeof(struct backlight));
if (!backlight)
goto err;
backlight->path = chosen_path;
backlight->type = type;
backlight->max_brightness = backlight_get_max_brightness(backlight);
if (backlight->max_brightness < 0)
goto err;
backlight->brightness = backlight_get_actual_brightness(backlight);
if (backlight->brightness < 0)
goto err;
closedir(backlights);
return backlight;
err:
closedir(backlights);
free (chosen_path);
free (backlight);
return NULL;
}
+79
View File
@@ -0,0 +1,79 @@
/*
* libbacklight - userspace interface to Linux backlight control
*
* Copyright © 2012 Intel Corporation
* Copyright 2010 Red Hat <mjg@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Matthew Garrett <mjg@redhat.com>
* Tiago Vignatti <vignatti@freedesktop.org>
*/
#ifndef LIBBACKLIGHT_H
#define LIBBACKLIGHT_H
#include <libudev.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
enum backlight_type {
BACKLIGHT_RAW,
BACKLIGHT_PLATFORM,
BACKLIGHT_FIRMWARE
};
struct backlight {
char *path;
int max_brightness;
int brightness;
enum backlight_type type;
};
/*
* Find and set up a backlight for a valid udev connector device, i.e. one
* matching drm subsytem and with status of connected.
*/
struct backlight *backlight_init(struct udev_device *drm_device,
uint32_t connector_type);
/* Free backlight resources */
void backlight_destroy(struct backlight *backlight);
/* Provide the maximum backlight value */
long backlight_get_max_brightness(struct backlight *backlight);
/* Provide the cached backlight value */
long backlight_get_brightness(struct backlight *backlight);
/* Provide the hardware backlight value */
long backlight_get_actual_brightness(struct backlight *backlight);
/* Set the backlight to a value between 0 and max */
long backlight_set_brightness(struct backlight *backlight, long brightness);
#ifdef __cplusplus
}
#endif
#endif /* LIBBACKLIGHT_H */
+593
View File
@@ -0,0 +1,593 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2013 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <mtdev.h>
#include <assert.h>
#include <libinput.h>
#include "compositor.h"
#include "libinput-device.h"
#include "shared/helpers.h"
void
evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
{
enum libinput_led leds = 0;
if (weston_leds & LED_NUM_LOCK)
leds |= LIBINPUT_LED_NUM_LOCK;
if (weston_leds & LED_CAPS_LOCK)
leds |= LIBINPUT_LED_CAPS_LOCK;
if (weston_leds & LED_SCROLL_LOCK)
leds |= LIBINPUT_LED_SCROLL_LOCK;
libinput_device_led_update(device->device, leds);
}
static void
handle_keyboard_key(struct libinput_device *libinput_device,
struct libinput_event_keyboard *keyboard_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
int key_state =
libinput_event_keyboard_get_key_state(keyboard_event);
int seat_key_count =
libinput_event_keyboard_get_seat_key_count(keyboard_event);
/* Ignore key events that are not seat wide state changes. */
if ((key_state == LIBINPUT_KEY_STATE_PRESSED &&
seat_key_count != 1) ||
(key_state == LIBINPUT_KEY_STATE_RELEASED &&
seat_key_count != 0))
return;
notify_key(device->seat,
libinput_event_keyboard_get_time(keyboard_event),
libinput_event_keyboard_get_key(keyboard_event),
key_state, STATE_UPDATE_AUTOMATIC);
}
static bool
handle_pointer_motion(struct libinput_device *libinput_device,
struct libinput_event_pointer *pointer_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
struct weston_pointer_motion_event event = { 0 };
event = (struct weston_pointer_motion_event) {
.mask = WESTON_POINTER_MOTION_REL,
.dx = libinput_event_pointer_get_dx(pointer_event),
.dy = libinput_event_pointer_get_dy(pointer_event),
};
notify_motion(device->seat,
libinput_event_pointer_get_time(pointer_event),
&event);
return true;
}
static bool
handle_pointer_motion_absolute(
struct libinput_device *libinput_device,
struct libinput_event_pointer *pointer_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
struct weston_output *output = device->output;
uint32_t time;
double x, y;
uint32_t width, height;
if (!output)
return false;
time = libinput_event_pointer_get_time(pointer_event);
width = device->output->current_mode->width;
height = device->output->current_mode->height;
x = libinput_event_pointer_get_absolute_x_transformed(pointer_event,
width);
y = libinput_event_pointer_get_absolute_y_transformed(pointer_event,
height);
weston_output_transform_coordinate(device->output, x, y, &x, &y);
notify_motion_absolute(device->seat, time, x, y);
return true;
}
static bool
handle_pointer_button(struct libinput_device *libinput_device,
struct libinput_event_pointer *pointer_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
int button_state =
libinput_event_pointer_get_button_state(pointer_event);
int seat_button_count =
libinput_event_pointer_get_seat_button_count(pointer_event);
/* Ignore button events that are not seat wide state changes. */
if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED &&
seat_button_count != 1) ||
(button_state == LIBINPUT_BUTTON_STATE_RELEASED &&
seat_button_count != 0))
return false;
notify_button(device->seat,
libinput_event_pointer_get_time(pointer_event),
libinput_event_pointer_get_button(pointer_event),
button_state);
return true;
}
static double
normalize_scroll(struct libinput_event_pointer *pointer_event,
enum libinput_pointer_axis axis)
{
enum libinput_pointer_axis_source source;
double value = 0.0;
source = libinput_event_pointer_get_axis_source(pointer_event);
/* libinput < 0.8 sent wheel click events with value 10. Since 0.8
the value is the angle of the click in degrees. To keep
backwards-compat with existing clients, we just send multiples of
the click count.
*/
switch (source) {
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
value = 10 * libinput_event_pointer_get_axis_value_discrete(
pointer_event,
axis);
break;
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
value = libinput_event_pointer_get_axis_value(pointer_event,
axis);
break;
}
return value;
}
static int32_t
get_axis_discrete(struct libinput_event_pointer *pointer_event,
enum libinput_pointer_axis axis)
{
enum libinput_pointer_axis_source source;
source = libinput_event_pointer_get_axis_source(pointer_event);
if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
return 0;
return libinput_event_pointer_get_axis_value_discrete(pointer_event,
axis);
}
static bool
handle_pointer_axis(struct libinput_device *libinput_device,
struct libinput_event_pointer *pointer_event)
{
static int warned;
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
double vert, horiz;
int32_t vert_discrete, horiz_discrete;
enum libinput_pointer_axis axis;
struct weston_pointer_axis_event weston_event;
enum libinput_pointer_axis_source source;
uint32_t wl_axis_source;
bool has_vert, has_horiz;
has_vert = libinput_event_pointer_has_axis(pointer_event,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
has_horiz = libinput_event_pointer_has_axis(pointer_event,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
if (!has_vert && !has_horiz)
return false;
source = libinput_event_pointer_get_axis_source(pointer_event);
switch (source) {
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
wl_axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
break;
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
wl_axis_source = WL_POINTER_AXIS_SOURCE_FINGER;
break;
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
wl_axis_source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
break;
default:
if (warned < 5) {
weston_log("Unknown scroll source %d.\n", source);
warned++;
}
return false;
}
notify_axis_source(device->seat, wl_axis_source);
if (has_vert) {
axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
vert_discrete = get_axis_discrete(pointer_event, axis);
vert = normalize_scroll(pointer_event, axis);
weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
weston_event.value = vert;
weston_event.discrete = vert_discrete;
weston_event.has_discrete = (vert_discrete != 0);
notify_axis(device->seat,
libinput_event_pointer_get_time(pointer_event),
&weston_event);
}
if (has_horiz) {
axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
horiz_discrete = get_axis_discrete(pointer_event, axis);
horiz = normalize_scroll(pointer_event, axis);
weston_event.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
weston_event.value = horiz;
weston_event.discrete = horiz_discrete;
weston_event.has_discrete = (horiz_discrete != 0);
notify_axis(device->seat,
libinput_event_pointer_get_time(pointer_event),
&weston_event);
}
return true;
}
static void
handle_touch_with_coords(struct libinput_device *libinput_device,
struct libinput_event_touch *touch_event,
int touch_type)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
double x;
double y;
uint32_t width, height;
uint32_t time;
int32_t slot;
if (!device->output)
return;
time = libinput_event_touch_get_time(touch_event);
slot = libinput_event_touch_get_seat_slot(touch_event);
width = device->output->current_mode->width;
height = device->output->current_mode->height;
x = libinput_event_touch_get_x_transformed(touch_event, width);
y = libinput_event_touch_get_y_transformed(touch_event, height);
weston_output_transform_coordinate(device->output,
x, y, &x, &y);
notify_touch(device->seat, time, slot, x, y, touch_type);
}
static void
handle_touch_down(struct libinput_device *device,
struct libinput_event_touch *touch_event)
{
handle_touch_with_coords(device, touch_event, WL_TOUCH_DOWN);
}
static void
handle_touch_motion(struct libinput_device *device,
struct libinput_event_touch *touch_event)
{
handle_touch_with_coords(device, touch_event, WL_TOUCH_MOTION);
}
static void
handle_touch_up(struct libinput_device *libinput_device,
struct libinput_event_touch *touch_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
uint32_t time = libinput_event_touch_get_time(touch_event);
int32_t slot = libinput_event_touch_get_seat_slot(touch_event);
notify_touch(device->seat, time, slot, 0, 0, WL_TOUCH_UP);
}
static void
handle_touch_frame(struct libinput_device *libinput_device,
struct libinput_event_touch *touch_event)
{
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
struct weston_seat *seat = device->seat;
notify_touch_frame(seat);
}
int
evdev_device_process_event(struct libinput_event *event)
{
struct libinput_device *libinput_device =
libinput_event_get_device(event);
struct evdev_device *device =
libinput_device_get_user_data(libinput_device);
int handled = 1;
bool need_frame = false;
switch (libinput_event_get_type(event)) {
case LIBINPUT_EVENT_KEYBOARD_KEY:
handle_keyboard_key(libinput_device,
libinput_event_get_keyboard_event(event));
break;
case LIBINPUT_EVENT_POINTER_MOTION:
need_frame = handle_pointer_motion(libinput_device,
libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
need_frame = handle_pointer_motion_absolute(
libinput_device,
libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_BUTTON:
need_frame = handle_pointer_button(libinput_device,
libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_AXIS:
need_frame = handle_pointer_axis(
libinput_device,
libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_TOUCH_DOWN:
handle_touch_down(libinput_device,
libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_MOTION:
handle_touch_motion(libinput_device,
libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_UP:
handle_touch_up(libinput_device,
libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_FRAME:
handle_touch_frame(libinput_device,
libinput_event_get_touch_event(event));
break;
default:
handled = 0;
weston_log("unknown libinput event %d\n",
libinput_event_get_type(event));
}
if (need_frame)
notify_pointer_frame(device->seat);
return handled;
}
static void
notify_output_destroy(struct wl_listener *listener, void *data)
{
struct evdev_device *device =
container_of(listener,
struct evdev_device, output_destroy_listener);
struct weston_compositor *c = device->seat->compositor;
struct weston_output *output;
if (!device->output_name && !wl_list_empty(&c->output_list)) {
output = container_of(c->output_list.next,
struct weston_output, link);
evdev_device_set_output(device, output);
} else {
device->output = NULL;
}
}
/**
* The WL_CALIBRATION property requires a pixel-specific matrix to be
* applied after scaling device coordinates to screen coordinates. libinput
* can't do that, so we need to convert the calibration to the normalized
* format libinput expects.
*/
void
evdev_device_set_calibration(struct evdev_device *device)
{
struct udev *udev;
struct udev_device *udev_device = NULL;
const char *sysname = libinput_device_get_sysname(device->device);
const char *calibration_values;
uint32_t width, height;
float calibration[6];
enum libinput_config_status status;
if (!device->output)
return;
width = device->output->width;
height = device->output->height;
if (width == 0 || height == 0)
return;
/* If libinput has a pre-set calibration matrix, don't override it */
if (!libinput_device_config_calibration_has_matrix(device->device) ||
libinput_device_config_calibration_get_default_matrix(
device->device,
calibration) != 0)
return;
udev = udev_new();
if (!udev)
return;
udev_device = udev_device_new_from_subsystem_sysname(udev,
"input",
sysname);
if (!udev_device)
goto out;
calibration_values =
udev_device_get_property_value(udev_device,
"WL_CALIBRATION");
if (!calibration_values || sscanf(calibration_values,
"%f %f %f %f %f %f",
&calibration[0],
&calibration[1],
&calibration[2],
&calibration[3],
&calibration[4],
&calibration[5]) != 6)
goto out;
weston_log("Applying calibration: %f %f %f %f %f %f "
"(normalized %f %f)\n",
calibration[0],
calibration[1],
calibration[2],
calibration[3],
calibration[4],
calibration[5],
calibration[2] / width,
calibration[5] / height);
/* normalize to a format libinput can use. There is a chance of
this being wrong if the width/height don't match the device
width/height but I'm not sure how to fix that */
calibration[2] /= width;
calibration[5] /= height;
status = libinput_device_config_calibration_set_matrix(device->device,
calibration);
if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
weston_log("Failed to apply calibration.\n");
out:
if (udev_device)
udev_device_unref(udev_device);
udev_unref(udev);
}
void
evdev_device_set_output(struct evdev_device *device,
struct weston_output *output)
{
if (device->output_destroy_listener.notify) {
wl_list_remove(&device->output_destroy_listener.link);
device->output_destroy_listener.notify = NULL;
}
device->output = output;
device->output_destroy_listener.notify = notify_output_destroy;
wl_signal_add(&output->destroy_signal,
&device->output_destroy_listener);
evdev_device_set_calibration(device);
}
struct evdev_device *
evdev_device_create(struct libinput_device *libinput_device,
struct weston_seat *seat)
{
struct evdev_device *device;
device = zalloc(sizeof *device);
if (device == NULL)
return NULL;
device->seat = seat;
wl_list_init(&device->link);
device->device = libinput_device;
if (libinput_device_has_capability(libinput_device,
LIBINPUT_DEVICE_CAP_KEYBOARD)) {
weston_seat_init_keyboard(seat, NULL);
device->seat_caps |= EVDEV_SEAT_KEYBOARD;
}
if (libinput_device_has_capability(libinput_device,
LIBINPUT_DEVICE_CAP_POINTER)) {
weston_seat_init_pointer(seat);
device->seat_caps |= EVDEV_SEAT_POINTER;
}
if (libinput_device_has_capability(libinput_device,
LIBINPUT_DEVICE_CAP_TOUCH)) {
weston_seat_init_touch(seat);
device->seat_caps |= EVDEV_SEAT_TOUCH;
}
libinput_device_set_user_data(libinput_device, device);
libinput_device_ref(libinput_device);
return device;
}
void
evdev_device_destroy(struct evdev_device *device)
{
if (device->seat_caps & EVDEV_SEAT_POINTER)
weston_seat_release_pointer(device->seat);
if (device->seat_caps & EVDEV_SEAT_KEYBOARD)
weston_seat_release_keyboard(device->seat);
if (device->seat_caps & EVDEV_SEAT_TOUCH)
weston_seat_release_touch(device->seat);
if (device->output)
wl_list_remove(&device->output_destroy_listener.link);
wl_list_remove(&device->link);
libinput_device_unref(device->device);
free(device->devnode);
free(device->output_name);
free(device);
}
void
evdev_notify_keyboard_focus(struct weston_seat *seat,
struct wl_list *evdev_devices)
{
struct wl_array keys;
if (seat->keyboard_device_count == 0)
return;
wl_array_init(&keys);
notify_keyboard_focus_in(seat, &keys, STATE_UPDATE_AUTOMATIC);
wl_array_release(&keys);
}
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright © 2011, 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _LIBINPUT_DEVICE_H_
#define _LIBINPUT_DEVICE_H_
#include "config.h"
#include <linux/input.h>
#include <wayland-util.h>
#include <libinput.h>
#include "compositor.h"
enum evdev_device_seat_capability {
EVDEV_SEAT_POINTER = (1 << 0),
EVDEV_SEAT_KEYBOARD = (1 << 1),
EVDEV_SEAT_TOUCH = (1 << 2)
};
struct evdev_device {
struct weston_seat *seat;
enum evdev_device_seat_capability seat_caps;
struct libinput_device *device;
struct wl_list link;
struct weston_output *output;
struct wl_listener output_destroy_listener;
char *devnode;
char *output_name;
int fd;
};
void
evdev_led_update(struct evdev_device *device, enum weston_led leds);
struct evdev_device *
evdev_device_create(struct libinput_device *libinput_device,
struct weston_seat *seat);
int
evdev_device_process_event(struct libinput_event *event);
void
evdev_device_set_output(struct evdev_device *device,
struct weston_output *output);
void
evdev_device_destroy(struct evdev_device *device);
void
evdev_notify_keyboard_focus(struct weston_seat *seat,
struct wl_list *evdev_devices);
void
evdev_device_set_calibration(struct evdev_device *device);
int
dispatch_libinput(struct libinput *libinput);
#endif /* _LIBINPUT_DEVICE_H_ */
+416
View File
@@ -0,0 +1,416 @@
/*
* Copyright © 2013 Intel Corporation
* Copyright © 2013 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <libinput.h>
#include <libudev.h>
#include "compositor.h"
#include "launcher-util.h"
#include "libinput-seat.h"
#include "libinput-device.h"
#include "shared/helpers.h"
static void
process_events(struct udev_input *input);
static struct udev_seat *
udev_seat_create(struct udev_input *input, const char *seat_name);
static void
udev_seat_destroy(struct udev_seat *seat);
static struct udev_seat *
get_udev_seat(struct udev_input *input, struct libinput_device *device)
{
struct libinput_seat *libinput_seat;
const char *seat_name;
libinput_seat = libinput_device_get_seat(device);
seat_name = libinput_seat_get_logical_name(libinput_seat);
return udev_seat_get_named(input, seat_name);
}
static void
device_added(struct udev_input *input, struct libinput_device *libinput_device)
{
struct weston_compositor *c;
struct evdev_device *device;
struct weston_output *output;
const char *output_name;
struct weston_seat *seat;
struct udev_seat *udev_seat;
struct weston_pointer *pointer;
c = input->compositor;
udev_seat = get_udev_seat(input, libinput_device);
if (!udev_seat)
return;
seat = &udev_seat->base;
device = evdev_device_create(libinput_device, seat);
if (device == NULL)
return;
if (input->configure_device != NULL)
input->configure_device(c, device->device);
evdev_device_set_calibration(device);
udev_seat = (struct udev_seat *) seat;
wl_list_insert(udev_seat->devices_list.prev, &device->link);
pointer = weston_seat_get_pointer(seat);
if (seat->output && pointer)
weston_pointer_clamp(pointer,
&pointer->x,
&pointer->y);
output_name = libinput_device_get_output_name(libinput_device);
if (output_name) {
device->output_name = strdup(output_name);
wl_list_for_each(output, &c->output_list, link)
if (output->name &&
strcmp(output->name, device->output_name) == 0)
evdev_device_set_output(device, output);
} else if (device->output == NULL && !wl_list_empty(&c->output_list)) {
output = container_of(c->output_list.next,
struct weston_output, link);
evdev_device_set_output(device, output);
}
if (!input->suspended)
weston_seat_repick(seat);
}
static void
device_removed(struct udev_input *input, struct libinput_device *libinput_device)
{
struct evdev_device *device;
device = libinput_device_get_user_data(libinput_device);
evdev_device_destroy(device);
}
static void
udev_seat_remove_devices(struct udev_seat *seat)
{
struct evdev_device *device, *next;
wl_list_for_each_safe(device, next, &seat->devices_list, link) {
evdev_device_destroy(device);
}
}
void
udev_input_disable(struct udev_input *input)
{
if (input->suspended)
return;
libinput_suspend(input->libinput);
process_events(input);
input->suspended = 1;
}
static int
udev_input_process_event(struct libinput_event *event)
{
struct libinput *libinput = libinput_event_get_context(event);
struct libinput_device *libinput_device =
libinput_event_get_device(event);
struct udev_input *input = libinput_get_user_data(libinput);
int handled = 1;
switch (libinput_event_get_type(event)) {
case LIBINPUT_EVENT_DEVICE_ADDED:
device_added(input, libinput_device);
break;
case LIBINPUT_EVENT_DEVICE_REMOVED:
device_removed(input, libinput_device);
break;
default:
handled = 0;
}
return handled;
}
static void
process_event(struct libinput_event *event)
{
if (udev_input_process_event(event))
return;
if (evdev_device_process_event(event))
return;
}
static void
process_events(struct udev_input *input)
{
struct libinput_event *event;
while ((event = libinput_get_event(input->libinput))) {
process_event(event);
libinput_event_destroy(event);
}
}
static int
udev_input_dispatch(struct udev_input *input)
{
if (libinput_dispatch(input->libinput) != 0)
weston_log("libinput: Failed to dispatch libinput\n");
process_events(input);
return 0;
}
static int
libinput_source_dispatch(int fd, uint32_t mask, void *data)
{
struct udev_input *input = data;
return udev_input_dispatch(input) != 0;
}
static int
open_restricted(const char *path, int flags, void *user_data)
{
struct udev_input *input = user_data;
struct weston_launcher *launcher = input->compositor->launcher;
return weston_launcher_open(launcher, path, flags);
}
static void
close_restricted(int fd, void *user_data)
{
struct udev_input *input = user_data;
struct weston_launcher *launcher = input->compositor->launcher;
weston_launcher_close(launcher, fd);
}
const struct libinput_interface libinput_interface = {
open_restricted,
close_restricted,
};
int
udev_input_enable(struct udev_input *input)
{
struct wl_event_loop *loop;
struct weston_compositor *c = input->compositor;
int fd;
struct udev_seat *seat;
int devices_found = 0;
loop = wl_display_get_event_loop(c->wl_display);
fd = libinput_get_fd(input->libinput);
input->libinput_source =
wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
libinput_source_dispatch, input);
if (!input->libinput_source) {
return -1;
}
if (input->suspended) {
if (libinput_resume(input->libinput) != 0) {
wl_event_source_remove(input->libinput_source);
input->libinput_source = NULL;
return -1;
}
input->suspended = 0;
process_events(input);
}
wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
if (!wl_list_empty(&seat->devices_list))
devices_found = 1;
}
if (devices_found == 0) {
weston_log(
"warning: no input devices on entering Weston. "
"Possible causes:\n"
"\t- no permissions to read /dev/input/event*\n"
"\t- seats misconfigured "
"(Weston backend option 'seat', "
"udev device property ID_SEAT)\n");
return -1;
}
return 0;
}
static void
libinput_log_func(struct libinput *libinput,
enum libinput_log_priority priority,
const char *format, va_list args)
{
weston_vlog(format, args);
}
int
udev_input_init(struct udev_input *input, struct weston_compositor *c,
struct udev *udev, const char *seat_id,
udev_configure_device_t configure_device)
{
enum libinput_log_priority priority = LIBINPUT_LOG_PRIORITY_INFO;
const char *log_priority = NULL;
memset(input, 0, sizeof *input);
input->compositor = c;
input->configure_device = configure_device;
log_priority = getenv("WESTON_LIBINPUT_LOG_PRIORITY");
input->libinput = libinput_udev_create_context(&libinput_interface,
input, udev);
if (!input->libinput) {
return -1;
}
libinput_log_set_handler(input->libinput, &libinput_log_func);
if (log_priority) {
if (strcmp(log_priority, "debug") == 0) {
priority = LIBINPUT_LOG_PRIORITY_DEBUG;
} else if (strcmp(log_priority, "info") == 0) {
priority = LIBINPUT_LOG_PRIORITY_INFO;
} else if (strcmp(log_priority, "error") == 0) {
priority = LIBINPUT_LOG_PRIORITY_ERROR;
}
}
libinput_log_set_priority(input->libinput, priority);
if (libinput_udev_assign_seat(input->libinput, seat_id) != 0) {
libinput_unref(input->libinput);
return -1;
}
process_events(input);
return udev_input_enable(input);
}
void
udev_input_destroy(struct udev_input *input)
{
struct udev_seat *seat, *next;
wl_event_source_remove(input->libinput_source);
wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link)
udev_seat_destroy(seat);
libinput_unref(input->libinput);
}
static void
udev_seat_led_update(struct weston_seat *seat_base, enum weston_led leds)
{
struct udev_seat *seat = (struct udev_seat *) seat_base;
struct evdev_device *device;
wl_list_for_each(device, &seat->devices_list, link)
evdev_led_update(device, leds);
}
static void
notify_output_create(struct wl_listener *listener, void *data)
{
struct udev_seat *seat = container_of(listener, struct udev_seat,
output_create_listener);
struct evdev_device *device;
struct weston_output *output = data;
wl_list_for_each(device, &seat->devices_list, link) {
if (device->output_name &&
strcmp(output->name, device->output_name) == 0) {
evdev_device_set_output(device, output);
}
if (device->output_name == NULL && device->output == NULL)
evdev_device_set_output(device, output);
}
}
static struct udev_seat *
udev_seat_create(struct udev_input *input, const char *seat_name)
{
struct weston_compositor *c = input->compositor;
struct udev_seat *seat;
seat = zalloc(sizeof *seat);
if (!seat)
return NULL;
weston_seat_init(&seat->base, c, seat_name);
seat->base.led_update = udev_seat_led_update;
seat->output_create_listener.notify = notify_output_create;
wl_signal_add(&c->output_created_signal,
&seat->output_create_listener);
wl_list_init(&seat->devices_list);
return seat;
}
static void
udev_seat_destroy(struct udev_seat *seat)
{
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(&seat->base);
if (keyboard)
notify_keyboard_focus_out(&seat->base);
udev_seat_remove_devices(seat);
weston_seat_release(&seat->base);
wl_list_remove(&seat->output_create_listener.link);
free(seat);
}
struct udev_seat *
udev_seat_get_named(struct udev_input *input, const char *seat_name)
{
struct udev_seat *seat;
wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
if (strcmp(seat->base.seat_name, seat_name) == 0)
return seat;
}
return udev_seat_create(input, seat_name);
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright © 2013 Intel Corporation
* Copyright © 2013 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _LIBINPUT_SEAT_H_
#define _LIBINPUT_SEAT_H_
#include "config.h"
#include <libudev.h>
#include "compositor.h"
struct libinput_device;
struct udev_seat {
struct weston_seat base;
struct wl_list devices_list;
struct wl_listener output_create_listener;
};
typedef void (*udev_configure_device_t)(struct weston_compositor *compositor,
struct libinput_device *device);
struct udev_input {
struct libinput *libinput;
struct wl_event_source *libinput_source;
struct weston_compositor *compositor;
int suspended;
udev_configure_device_t configure_device;
};
int
udev_input_enable(struct udev_input *input);
void
udev_input_disable(struct udev_input *input);
int
udev_input_init(struct udev_input *input,
struct weston_compositor *c,
struct udev *udev,
const char *seat_id,
udev_configure_device_t configure_device);
void
udev_input_destroy(struct udev_input *input);
struct udev_seat *
udev_seat_get_named(struct udev_input *u,
const char *seat_name);
#endif
+12
View File
@@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
pkgincludedir=${includedir}/libweston-@LIBWESTON_ABI_VERSION@
Name: libweston API
Description: Header files for libweston compositors development
Version: @WESTON_VERSION@
Requires.private: wayland-server pixman-1 xkbcommon
Cflags: -I${pkgincludedir}
Libs: -L${libdir} -lweston-@LIBWESTON_ABI_VERSION@
+497
View File
@@ -0,0 +1,497 @@
/*
* Copyright © 2014, 2015 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 "config.h"
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include "compositor.h"
#include "linux-dmabuf.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
static void
linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
{
int i;
for (i = 0; i < buffer->attributes.n_planes; i++) {
close(buffer->attributes.fd[i]);
buffer->attributes.fd[i] = -1;
}
buffer->attributes.n_planes = 0;
free(buffer);
}
static void
destroy_params(struct wl_resource *params_resource)
{
struct linux_dmabuf_buffer *buffer;
buffer = wl_resource_get_user_data(params_resource);
if (!buffer)
return;
linux_dmabuf_buffer_destroy(buffer);
}
static void
params_destroy(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
params_add(struct wl_client *client,
struct wl_resource *params_resource,
int32_t name_fd,
uint32_t plane_idx,
uint32_t offset,
uint32_t stride,
uint32_t modifier_hi,
uint32_t modifier_lo)
{
struct linux_dmabuf_buffer *buffer;
buffer = wl_resource_get_user_data(params_resource);
if (!buffer) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
"params was already used to create a wl_buffer");
close(name_fd);
return;
}
assert(buffer->params_resource == params_resource);
assert(!buffer->buffer_resource);
if (plane_idx >= MAX_DMABUF_PLANES) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
"plane index %u is too high", plane_idx);
close(name_fd);
return;
}
if (buffer->attributes.fd[plane_idx] != -1) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
"a dmabuf has already been added for plane %u",
plane_idx);
close(name_fd);
return;
}
buffer->attributes.fd[plane_idx] = name_fd;
buffer->attributes.offset[plane_idx] = offset;
buffer->attributes.stride[plane_idx] = stride;
buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
modifier_lo;
buffer->attributes.n_planes++;
}
static void
linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
linux_dmabuf_wl_buffer_destroy
};
static void
destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
{
struct linux_dmabuf_buffer *buffer;
buffer = wl_resource_get_user_data(resource);
assert(buffer->buffer_resource == resource);
assert(!buffer->params_resource);
if (buffer->user_data_destroy_func)
buffer->user_data_destroy_func(buffer);
linux_dmabuf_buffer_destroy(buffer);
}
static void
params_create(struct wl_client *client,
struct wl_resource *params_resource,
int32_t width,
int32_t height,
uint32_t format,
uint32_t flags)
{
struct linux_dmabuf_buffer *buffer;
int i;
buffer = wl_resource_get_user_data(params_resource);
if (!buffer) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
"params was already used to create a wl_buffer");
return;
}
assert(buffer->params_resource == params_resource);
assert(!buffer->buffer_resource);
/* Switch the linux_dmabuf_buffer object from params resource to
* eventually wl_buffer resource.
*/
wl_resource_set_user_data(buffer->params_resource, NULL);
buffer->params_resource = NULL;
if (!buffer->attributes.n_planes) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"no dmabuf has been added to the params");
goto err_out;
}
/* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
for (i = 0; i < buffer->attributes.n_planes; i++) {
if (buffer->attributes.fd[i] == -1) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"no dmabuf has been added for plane %i", i);
goto err_out;
}
}
buffer->attributes.width = width;
buffer->attributes.height = height;
buffer->attributes.format = format;
buffer->attributes.flags = flags;
if (width < 1 || height < 1) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
"invalid width %d or height %d", width, height);
goto err_out;
}
for (i = 0; i < buffer->attributes.n_planes; i++) {
off_t size;
if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"size overflow for plane %i", i);
goto err_out;
}
if (i == 0 &&
(uint64_t) buffer->attributes.offset[i] +
(uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"size overflow for plane %i", i);
goto err_out;
}
/* Don't report an error as it might be caused
* by the kernel not supporting seeking on dmabuf */
size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
if (size == -1)
continue;
if (buffer->attributes.offset[i] >= size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid offset %i for plane %i",
buffer->attributes.offset[i], i);
goto err_out;
}
if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid stride %i for plane %i",
buffer->attributes.stride[i], i);
goto err_out;
}
/* Only valid for first plane as other planes might be
* sub-sampled according to fourcc format */
if (i == 0 &&
buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid buffer stride or height for plane %i", i);
goto err_out;
}
}
/* XXX: Some additional sanity checks could be done with respect
* to the fourcc format. A centralized collection (kernel or
* libdrm) would be useful to avoid code duplication for these
* checks (e.g. drm_format_num_planes).
*/
if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
goto err_failed;
buffer->buffer_resource = wl_resource_create(client,
&wl_buffer_interface,
1, 0);
if (!buffer->buffer_resource) {
wl_resource_post_no_memory(params_resource);
goto err_buffer;
}
wl_resource_set_implementation(buffer->buffer_resource,
&linux_dmabuf_buffer_implementation,
buffer, destroy_linux_dmabuf_wl_buffer);
zwp_linux_buffer_params_v1_send_created(params_resource,
buffer->buffer_resource);
return;
err_buffer:
if (buffer->user_data_destroy_func)
buffer->user_data_destroy_func(buffer);
err_failed:
zwp_linux_buffer_params_v1_send_failed(params_resource);
err_out:
linux_dmabuf_buffer_destroy(buffer);
}
static const struct zwp_linux_buffer_params_v1_interface
zwp_linux_buffer_params_implementation = {
params_destroy,
params_add,
params_create
};
static void
linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
linux_dmabuf_create_params(struct wl_client *client,
struct wl_resource *linux_dmabuf_resource,
uint32_t params_id)
{
struct weston_compositor *compositor;
struct linux_dmabuf_buffer *buffer;
uint32_t version;
int i;
version = wl_resource_get_version(linux_dmabuf_resource);
compositor = wl_resource_get_user_data(linux_dmabuf_resource);
buffer = zalloc(sizeof *buffer);
if (!buffer)
goto err_out;
for (i = 0; i < MAX_DMABUF_PLANES; i++)
buffer->attributes.fd[i] = -1;
buffer->compositor = compositor;
buffer->params_resource =
wl_resource_create(client,
&zwp_linux_buffer_params_v1_interface,
version, params_id);
if (!buffer->params_resource)
goto err_dealloc;
wl_resource_set_implementation(buffer->params_resource,
&zwp_linux_buffer_params_implementation,
buffer, destroy_params);
return;
err_dealloc:
free(buffer);
err_out:
wl_resource_post_no_memory(linux_dmabuf_resource);
}
/** Get the linux_dmabuf_buffer from a wl_buffer resource
*
* If the given wl_buffer resource was created through the linux_dmabuf
* protocol interface, returns the linux_dmabuf_buffer object. This can
* be used as a type check for a wl_buffer.
*
* \param resource A wl_buffer resource.
* \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
*/
WL_EXPORT struct linux_dmabuf_buffer *
linux_dmabuf_buffer_get(struct wl_resource *resource)
{
struct linux_dmabuf_buffer *buffer;
if (!resource)
return NULL;
if (!wl_resource_instance_of(resource, &wl_buffer_interface,
&linux_dmabuf_buffer_implementation))
return NULL;
buffer = wl_resource_get_user_data(resource);
assert(buffer);
assert(!buffer->params_resource);
assert(buffer->buffer_resource == resource);
return buffer;
}
/** Set renderer-private data
*
* Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
* a non-NULL user data with a new non-NULL pointer. This is meant to
* protect against renderers fighting over linux_dmabuf_buffer user data
* ownership.
*
* The renderer-private data is usually set from the
* weston_renderer::import_dmabuf hook.
*
* \param buffer The linux_dmabuf_buffer object to set for.
* \param data The new renderer-private data pointer.
* \param func Destructor function to be called for the renderer-private
* data when the linux_dmabuf_buffer gets destroyed.
*
* \sa weston_compositor_import_dmabuf
*/
WL_EXPORT void
linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
void *data,
dmabuf_user_data_destroy_func func)
{
assert(data == NULL || buffer->user_data == NULL);
buffer->user_data = data;
buffer->user_data_destroy_func = func;
}
/** Get renderer-private data
*
* Get the user data from the linux_dmabuf_buffer.
*
* \param buffer The linux_dmabuf_buffer to query.
* \return Renderer-private data pointer.
*
* \sa linux_dmabuf_buffer_set_user_data
*/
WL_EXPORT void *
linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
{
return buffer->user_data;
}
static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
linux_dmabuf_destroy,
linux_dmabuf_create_params
};
static void
bind_linux_dmabuf(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
struct weston_compositor *compositor = data;
struct wl_resource *resource;
resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
version, id);
if (resource == NULL) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
compositor, NULL);
/* EGL_EXT_image_dma_buf_import does not provide a way to query the
* supported pixel formats. */
/* XXX: send formats */
}
/** Advertise linux_dmabuf support
*
* Calling this initializes the zwp_linux_dmabuf protocol support, so that
* the interface will be advertised to clients. Essentially it creates a
* global. Do not call this function multiple times in the compositor's
* lifetime. There is no way to deinit explicitly, globals will be reaped
* when the wl_display gets destroyed.
*
* \param compositor The compositor to init for.
* \return Zero on success, -1 on failure.
*/
WL_EXPORT int
linux_dmabuf_setup(struct weston_compositor *compositor)
{
if (!wl_global_create(compositor->wl_display,
&zwp_linux_dmabuf_v1_interface, 1,
compositor, bind_linux_dmabuf))
return -1;
return 0;
}
/** Resolve an internal compositor error by disconnecting the client.
*
* This function is used in cases when the dmabuf-based wl_buffer
* turns out unusable and there is no fallback path. This is used by
* renderers which are the fallback path in the first place.
*
* It is possible the fault is caused by a compositor bug, the underlying
* graphics stack bug or normal behaviour, or perhaps a client mistake.
* In any case, the options are to either composite garbage or nothing,
* or disconnect the client. This is a helper function for the latter.
*
* The error is sent as a INVALID_OBJECT error on the client's wl_display.
*
* \param buffer The linux_dmabuf_buffer that is unusable.
* \param msg A custom error message attached to the protocol error.
*/
WL_EXPORT void
linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
const char *msg)
{
struct wl_client *client;
struct wl_resource *display_resource;
uint32_t id;
assert(buffer->buffer_resource);
id = wl_resource_get_id(buffer->buffer_resource);
client = wl_resource_get_client(buffer->buffer_resource);
display_resource = wl_client_get_object(client, 1);
assert(display_resource);
wl_resource_post_error(display_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"linux_dmabuf server error with "
"wl_buffer@%u: %s", id, msg);
}
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright © 2014, 2015 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.
*/
#ifndef WESTON_LINUX_DMABUF_H
#define WESTON_LINUX_DMABUF_H
#include <stdint.h>
#define MAX_DMABUF_PLANES 4
struct linux_dmabuf_buffer;
typedef void (*dmabuf_user_data_destroy_func)(
struct linux_dmabuf_buffer *buffer);
struct dmabuf_attributes {
int32_t width;
int32_t height;
uint32_t format;
uint32_t flags; /* enum zlinux_buffer_params_flags */
int n_planes;
int fd[MAX_DMABUF_PLANES];
uint32_t offset[MAX_DMABUF_PLANES];
uint32_t stride[MAX_DMABUF_PLANES];
uint64_t modifier[MAX_DMABUF_PLANES];
};
struct linux_dmabuf_buffer {
struct wl_resource *buffer_resource;
struct wl_resource *params_resource;
struct weston_compositor *compositor;
struct dmabuf_attributes attributes;
void *user_data;
dmabuf_user_data_destroy_func user_data_destroy_func;
/* XXX:
*
* Add backend private data. This would be for the backend
* to do all additional imports it might ever use in advance.
* The basic principle, even if not implemented in drivers today,
* is that dmabufs are first attached, but the actual allocation
* is deferred to first use. This would allow the exporter and all
* attachers to agree on how to allocate.
*
* The DRM backend would use this to create drmFBs for each
* dmabuf_buffer, just in case at some point it would become
* feasible to scan it out directly. This would improve the
* possibilities to successfully scan out, avoiding compositing.
*/
};
int
linux_dmabuf_setup(struct weston_compositor *compositor);
struct linux_dmabuf_buffer *
linux_dmabuf_buffer_get(struct wl_resource *resource);
void
linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
void *data,
dmabuf_user_data_destroy_func func);
void *
linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer);
void
linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
const char *msg);
#endif /* WESTON_LINUX_DMABUF_H */
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright © 2012 Martin Minarik
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <wayland-util.h>
#include "compositor.h"
static log_func_t log_handler = 0;
static log_func_t log_continue_handler = 0;
/** Install the log handler
*
* The given functions will be called to output text as passed to the
* \a weston_log and \a weston_log_continue functions.
*
* \param log The log function. This function will be called when
* \a weston_log is called, and should begin a new line,
* with user defined line headers, if any.
* \param cont The continue log function. This function will be called
* when \a weston_log_continue is called, and should append
* its output to the current line, without any header or
* other content in between.
*/
WL_EXPORT void
weston_log_set_handler(log_func_t log, log_func_t cont)
{
log_handler = log;
log_continue_handler = cont;
}
WL_EXPORT int
weston_vlog(const char *fmt, va_list ap)
{
return log_handler(fmt, ap);
}
WL_EXPORT int
weston_log(const char *fmt, ...)
{
int l;
va_list argp;
va_start(argp, fmt);
l = weston_vlog(fmt, argp);
va_end(argp);
return l;
}
WL_EXPORT int
weston_vlog_continue(const char *fmt, va_list argp)
{
return log_continue_handler(fmt, argp);
}
WL_EXPORT int
weston_log_continue(const char *fmt, ...)
{
int l;
va_list argp;
va_start(argp, fmt);
l = weston_vlog_continue(fmt, argp);
va_end(argp);
return l;
}
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include "compositor.h"
static int
noop_renderer_read_pixels(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
{
return 0;
}
static void
noop_renderer_repaint_output(struct weston_output *output,
pixman_region32_t *output_damage)
{
}
static void
noop_renderer_flush_damage(struct weston_surface *surface)
{
}
static void
noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct wl_shm_buffer *shm_buffer;
uint8_t *data;
uint32_t size, i, width, height, stride;
volatile unsigned char unused = 0; /* volatile so it's not optimized out */
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (!shm_buffer) {
weston_log("No-op renderer supports only SHM buffers\n");
return;
}
data = wl_shm_buffer_get_data(shm_buffer);
stride = wl_shm_buffer_get_stride(shm_buffer);
width = wl_shm_buffer_get_width(shm_buffer);
height = wl_shm_buffer_get_height(shm_buffer);
size = stride * height;
/* Access the buffer data to make sure the buffer's client gets killed
* if the buffer size is invalid. This makes the bad_buffer test pass.
* This can be removed if we start reading the buffer contents
* somewhere else, e.g. in repaint_output(). */
wl_shm_buffer_begin_access(shm_buffer);
for (i = 0; i < size; i++)
unused ^= data[i];
wl_shm_buffer_end_access(shm_buffer);
buffer->shm_buffer = shm_buffer;
buffer->width = width;
buffer->height = height;
}
static void
noop_renderer_surface_set_color(struct weston_surface *surface,
float red, float green, float blue, float alpha)
{
}
static void
noop_renderer_destroy(struct weston_compositor *ec)
{
free(ec->renderer);
ec->renderer = NULL;
}
WL_EXPORT int
noop_renderer_init(struct weston_compositor *ec)
{
struct weston_renderer *renderer;
renderer = malloc(sizeof *renderer);
if (renderer == NULL)
return -1;
renderer->read_pixels = noop_renderer_read_pixels;
renderer->repaint_output = noop_renderer_repaint_output;
renderer->flush_damage = noop_renderer_flush_damage;
renderer->attach = noop_renderer_attach;
renderer->surface_set_color = noop_renderer_surface_set_color;
renderer->destroy = noop_renderer_destroy;
ec->renderer = renderer;
return 0;
}
+931
View File
@@ -0,0 +1,931 @@
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
* Copyright © 2015 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include "pixman-renderer.h"
#include "shared/helpers.h"
#include <linux/input.h>
struct pixman_output_state {
void *shadow_buffer;
pixman_image_t *shadow_image;
pixman_image_t *hw_buffer;
};
struct pixman_surface_state {
struct weston_surface *surface;
pixman_image_t *image;
struct weston_buffer_reference buffer_ref;
struct wl_listener buffer_destroy_listener;
struct wl_listener surface_destroy_listener;
struct wl_listener renderer_destroy_listener;
};
struct pixman_renderer {
struct weston_renderer base;
int repaint_debug;
pixman_image_t *debug_color;
struct weston_binding *debug_binding;
struct wl_signal destroy_signal;
};
static inline struct pixman_output_state *
get_output_state(struct weston_output *output)
{
return (struct pixman_output_state *)output->renderer_state;
}
static int
pixman_renderer_create_surface(struct weston_surface *surface);
static inline struct pixman_surface_state *
get_surface_state(struct weston_surface *surface)
{
if (!surface->renderer_state)
pixman_renderer_create_surface(surface);
return (struct pixman_surface_state *)surface->renderer_state;
}
static inline struct pixman_renderer *
get_renderer(struct weston_compositor *ec)
{
return (struct pixman_renderer *)ec->renderer;
}
static int
pixman_renderer_read_pixels(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height)
{
struct pixman_output_state *po = get_output_state(output);
pixman_transform_t transform;
pixman_image_t *out_buf;
if (!po->hw_buffer) {
errno = ENODEV;
return -1;
}
out_buf = pixman_image_create_bits(format,
width,
height,
pixels,
(PIXMAN_FORMAT_BPP(format) / 8) * width);
/* Caller expects vflipped source image */
pixman_transform_init_translate(&transform,
pixman_int_to_fixed (x),
pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
pixman_transform_scale(&transform, NULL,
pixman_fixed_1,
pixman_fixed_minus_1);
pixman_image_set_transform(po->hw_buffer, &transform);
pixman_image_composite32(PIXMAN_OP_SRC,
po->hw_buffer, /* src */
NULL /* mask */,
out_buf, /* dest */
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
pixman_image_get_width (po->hw_buffer), /* width */
pixman_image_get_height (po->hw_buffer) /* height */);
pixman_image_set_transform(po->hw_buffer, NULL);
pixman_image_unref(out_buf);
return 0;
}
static void
region_global_to_output(struct weston_output *output, pixman_region32_t *region)
{
if (output->zoom.active) {
weston_matrix_transform_region(region, &output->matrix, region);
} else {
pixman_region32_translate(region, -output->x, -output->y);
weston_transformed_region(output->width, output->height,
output->transform,
output->current_scale,
region, region);
}
}
#define D2F(v) pixman_double_to_fixed((double)v)
static void
weston_matrix_to_pixman_transform(pixman_transform_t *pt,
const struct weston_matrix *wm)
{
/* Pixman supports only 2D transform matrix, but Weston uses 3D, *
* so we're omitting Z coordinate here. */
pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
}
static void
pixman_renderer_compute_transform(pixman_transform_t *transform_out,
struct weston_view *ev,
struct weston_output *output)
{
struct weston_matrix matrix;
/* Set up the source transformation based on the surface
position, the output position/transform/scale and the client
specified buffer transform/scale */
matrix = output->inverse_matrix;
if (ev->transform.enabled) {
weston_matrix_multiply(&matrix, &ev->transform.inverse);
} else {
weston_matrix_translate(&matrix,
-ev->geometry.x, -ev->geometry.y, 0);
}
weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
weston_matrix_to_pixman_transform(transform_out, &matrix);
}
static bool
view_transformation_is_translation(struct weston_view *view)
{
if (!view->transform.enabled)
return true;
if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
return true;
return false;
}
static void
region_intersect_only_translation(pixman_region32_t *result_global,
pixman_region32_t *global,
pixman_region32_t *surf,
struct weston_view *view)
{
float view_x, view_y;
assert(view_transformation_is_translation(view));
/* Convert from surface to global coordinates */
pixman_region32_copy(result_global, surf);
weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
pixman_region32_translate(result_global, (int)view_x, (int)view_y);
pixman_region32_intersect(result_global, result_global, global);
}
static void
composite_whole(pixman_op_t op,
pixman_image_t *src,
pixman_image_t *mask,
pixman_image_t *dest,
const pixman_transform_t *transform,
pixman_filter_t filter)
{
int32_t dest_width;
int32_t dest_height;
dest_width = pixman_image_get_width(dest);
dest_height = pixman_image_get_height(dest);
pixman_image_set_transform(src, transform);
pixman_image_set_filter(src, filter, NULL, 0);
pixman_image_composite32(op, src, mask, dest,
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
dest_width, dest_height);
}
static void
composite_clipped(pixman_image_t *src,
pixman_image_t *mask,
pixman_image_t *dest,
const pixman_transform_t *transform,
pixman_filter_t filter,
pixman_region32_t *src_clip)
{
int n_box;
pixman_box32_t *boxes;
int32_t dest_width;
int32_t dest_height;
int src_stride;
int bitspp;
pixman_format_code_t src_format;
void *src_data;
int i;
/* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
* a Pixman image produces (0,0,0,0) instead of discarding the
* fragment.
*/
dest_width = pixman_image_get_width(dest);
dest_height = pixman_image_get_height(dest);
src_format = pixman_image_get_format(src);
src_stride = pixman_image_get_stride(src);
bitspp = PIXMAN_FORMAT_BPP(src_format);
src_data = pixman_image_get_data(src);
assert(src_format);
/* This would be massive overdraw, except when n_box is 1. */
boxes = pixman_region32_rectangles(src_clip, &n_box);
for (i = 0; i < n_box; i++) {
uint8_t *ptr = src_data;
pixman_image_t *boximg;
pixman_transform_t adj = *transform;
ptr += boxes[i].y1 * src_stride;
ptr += boxes[i].x1 * bitspp / 8;
boximg = pixman_image_create_bits_no_clear(src_format,
boxes[i].x2 - boxes[i].x1,
boxes[i].y2 - boxes[i].y1,
(uint32_t *)ptr, src_stride);
pixman_transform_translate(&adj, NULL,
pixman_int_to_fixed(-boxes[i].x1),
pixman_int_to_fixed(-boxes[i].y1));
pixman_image_set_transform(boximg, &adj);
pixman_image_set_filter(boximg, filter, NULL, 0);
pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
dest_width, dest_height);
pixman_image_unref(boximg);
}
if (n_box > 1) {
static bool warned = false;
if (!warned)
weston_log("Pixman-renderer warning: %dx overdraw\n",
n_box);
warned = true;
}
}
/** Paint an intersected region
*
* \param ev The view to be painted.
* \param output The output being painted.
* \param repaint_output The region to be painted in output coordinates.
* \param source_clip The region of the source image to use, in source image
* coordinates. If NULL, use the whole source image.
* \param pixman_op Compositing operator, either SRC or OVER.
*/
static void
repaint_region(struct weston_view *ev, struct weston_output *output,
pixman_region32_t *repaint_output,
pixman_region32_t *source_clip,
pixman_op_t pixman_op)
{
struct pixman_renderer *pr =
(struct pixman_renderer *) output->compositor->renderer;
struct pixman_surface_state *ps = get_surface_state(ev->surface);
struct pixman_output_state *po = get_output_state(output);
struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
pixman_transform_t transform;
pixman_filter_t filter;
pixman_image_t *mask_image;
pixman_color_t mask = { 0, };
/* Clip rendering to the damaged output region */
pixman_image_set_clip_region32(po->shadow_image, repaint_output);
pixman_renderer_compute_transform(&transform, ev, output);
if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
filter = PIXMAN_FILTER_BILINEAR;
else
filter = PIXMAN_FILTER_NEAREST;
if (ps->buffer_ref.buffer)
wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
if (ev->alpha < 1.0) {
mask.alpha = 0xffff * ev->alpha;
mask_image = pixman_image_create_solid_fill(&mask);
} else {
mask_image = NULL;
}
if (source_clip)
composite_clipped(ps->image, mask_image, po->shadow_image,
&transform, filter, source_clip);
else
composite_whole(pixman_op, ps->image, mask_image,
po->shadow_image, &transform, filter);
if (mask_image)
pixman_image_unref(mask_image);
if (ps->buffer_ref.buffer)
wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
if (pr->repaint_debug)
pixman_image_composite32(PIXMAN_OP_OVER,
pr->debug_color, /* src */
NULL /* mask */,
po->shadow_image, /* dest */
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
pixman_image_get_width (po->shadow_image), /* width */
pixman_image_get_height (po->shadow_image) /* height */);
pixman_image_set_clip_region32 (po->shadow_image, NULL);
}
static void
draw_view_translated(struct weston_view *view, struct weston_output *output,
pixman_region32_t *repaint_global)
{
struct weston_surface *surface = view->surface;
/* non-opaque region in surface coordinates: */
pixman_region32_t surface_blend;
/* region to be painted in output coordinates: */
pixman_region32_t repaint_output;
pixman_region32_init(&repaint_output);
/* Blended region is whole surface minus opaque region,
* unless surface alpha forces us to blend all.
*/
pixman_region32_init_rect(&surface_blend, 0, 0,
surface->width, surface->height);
if (!(view->alpha < 1.0)) {
pixman_region32_subtract(&surface_blend, &surface_blend,
&surface->opaque);
if (pixman_region32_not_empty(&surface->opaque)) {
region_intersect_only_translation(&repaint_output,
repaint_global,
&surface->opaque,
view);
region_global_to_output(output, &repaint_output);
repaint_region(view, output, &repaint_output, NULL,
PIXMAN_OP_SRC);
}
}
if (pixman_region32_not_empty(&surface_blend)) {
region_intersect_only_translation(&repaint_output,
repaint_global,
&surface_blend, view);
region_global_to_output(output, &repaint_output);
repaint_region(view, output, &repaint_output, NULL,
PIXMAN_OP_OVER);
}
pixman_region32_fini(&surface_blend);
pixman_region32_fini(&repaint_output);
}
static void
draw_view_source_clipped(struct weston_view *view,
struct weston_output *output,
pixman_region32_t *repaint_global)
{
struct weston_surface *surface = view->surface;
pixman_region32_t surf_region;
pixman_region32_t buffer_region;
pixman_region32_t repaint_output;
/* Do not bother separating the opaque region from non-opaque.
* Source clipping requires PIXMAN_OP_OVER in all cases, so painting
* opaque separately has no benefit.
*/
pixman_region32_init_rect(&surf_region, 0, 0,
surface->width, surface->height);
if (view->geometry.scissor_enabled)
pixman_region32_intersect(&surf_region, &surf_region,
&view->geometry.scissor);
pixman_region32_init(&buffer_region);
weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
pixman_region32_init(&repaint_output);
pixman_region32_copy(&repaint_output, repaint_global);
region_global_to_output(output, &repaint_output);
repaint_region(view, output, &repaint_output, &buffer_region,
PIXMAN_OP_OVER);
pixman_region32_fini(&repaint_output);
pixman_region32_fini(&buffer_region);
pixman_region32_fini(&surf_region);
}
static void
draw_view(struct weston_view *ev, struct weston_output *output,
pixman_region32_t *damage) /* in global coordinates */
{
struct pixman_surface_state *ps = get_surface_state(ev->surface);
/* repaint bounding region in global coordinates: */
pixman_region32_t repaint;
/* No buffer attached */
if (!ps->image)
return;
pixman_region32_init(&repaint);
pixman_region32_intersect(&repaint,
&ev->transform.boundingbox, damage);
pixman_region32_subtract(&repaint, &repaint, &ev->clip);
if (!pixman_region32_not_empty(&repaint))
goto out;
if (view_transformation_is_translation(ev)) {
/* The simple case: The surface regions opaque, non-opaque,
* etc. are convertible to global coordinate space.
* There is no need to use a source clip region.
* It is possible to paint opaque region as PIXMAN_OP_SRC.
* Also the boundingbox is accurate rather than an
* approximation.
*/
draw_view_translated(ev, output, &repaint);
} else {
/* The complex case: the view transformation does not allow
* converting opaque etc. regions into global coordinate space.
* Therefore we need source clipping to avoid sampling from
* unwanted source image areas, unless the source image is
* to be used whole. Source clipping does not work with
* PIXMAN_OP_SRC.
*/
draw_view_source_clipped(ev, output, &repaint);
}
out:
pixman_region32_fini(&repaint);
}
static void
repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
{
struct weston_compositor *compositor = output->compositor;
struct weston_view *view;
wl_list_for_each_reverse(view, &compositor->view_list, link)
if (view->plane == &compositor->primary_plane)
draw_view(view, output, damage);
}
static void
copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
{
struct pixman_output_state *po = get_output_state(output);
pixman_region32_t output_region;
pixman_region32_init(&output_region);
pixman_region32_copy(&output_region, region);
region_global_to_output(output, &output_region);
pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
pixman_region32_fini(&output_region);
pixman_image_composite32(PIXMAN_OP_SRC,
po->shadow_image, /* src */
NULL /* mask */,
po->hw_buffer, /* dest */
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
pixman_image_get_width (po->hw_buffer), /* width */
pixman_image_get_height (po->hw_buffer) /* height */);
pixman_image_set_clip_region32 (po->hw_buffer, NULL);
}
static void
pixman_renderer_repaint_output(struct weston_output *output,
pixman_region32_t *output_damage)
{
struct pixman_output_state *po = get_output_state(output);
if (!po->hw_buffer)
return;
repaint_surfaces(output, output_damage);
copy_to_hw_buffer(output, output_damage);
pixman_region32_copy(&output->previous_damage, output_damage);
wl_signal_emit(&output->frame_signal, output);
/* Actual flip should be done by caller */
}
static void
pixman_renderer_flush_damage(struct weston_surface *surface)
{
/* No-op for pixman renderer */
}
static void
buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
{
struct pixman_surface_state *ps;
ps = container_of(listener, struct pixman_surface_state,
buffer_destroy_listener);
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->buffer_destroy_listener.notify = NULL;
}
static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
struct pixman_surface_state *ps = get_surface_state(es);
struct wl_shm_buffer *shm_buffer;
pixman_format_code_t pixman_format;
weston_buffer_reference(&ps->buffer_ref, buffer);
if (ps->buffer_destroy_listener.notify) {
wl_list_remove(&ps->buffer_destroy_listener.link);
ps->buffer_destroy_listener.notify = NULL;
}
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
if (!buffer)
return;
shm_buffer = wl_shm_buffer_get(buffer->resource);
if (! shm_buffer) {
weston_log("Pixman renderer supports only SHM buffers\n");
weston_buffer_reference(&ps->buffer_ref, NULL);
return;
}
switch (wl_shm_buffer_get_format(shm_buffer)) {
case WL_SHM_FORMAT_XRGB8888:
pixman_format = PIXMAN_x8r8g8b8;
break;
case WL_SHM_FORMAT_ARGB8888:
pixman_format = PIXMAN_a8r8g8b8;
break;
case WL_SHM_FORMAT_RGB565:
pixman_format = PIXMAN_r5g6b5;
break;
default:
weston_log("Unsupported SHM buffer format\n");
weston_buffer_reference(&ps->buffer_ref, NULL);
return;
break;
}
buffer->shm_buffer = shm_buffer;
buffer->width = wl_shm_buffer_get_width(shm_buffer);
buffer->height = wl_shm_buffer_get_height(shm_buffer);
ps->image = pixman_image_create_bits(pixman_format,
buffer->width, buffer->height,
wl_shm_buffer_get_data(shm_buffer),
wl_shm_buffer_get_stride(shm_buffer));
ps->buffer_destroy_listener.notify =
buffer_state_handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal,
&ps->buffer_destroy_listener);
}
static void
pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
{
wl_list_remove(&ps->surface_destroy_listener.link);
wl_list_remove(&ps->renderer_destroy_listener.link);
if (ps->buffer_destroy_listener.notify) {
wl_list_remove(&ps->buffer_destroy_listener.link);
ps->buffer_destroy_listener.notify = NULL;
}
ps->surface->renderer_state = NULL;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
weston_buffer_reference(&ps->buffer_ref, NULL);
free(ps);
}
static void
surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
{
struct pixman_surface_state *ps;
ps = container_of(listener, struct pixman_surface_state,
surface_destroy_listener);
pixman_renderer_surface_state_destroy(ps);
}
static void
surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
{
struct pixman_surface_state *ps;
ps = container_of(listener, struct pixman_surface_state,
renderer_destroy_listener);
pixman_renderer_surface_state_destroy(ps);
}
static int
pixman_renderer_create_surface(struct weston_surface *surface)
{
struct pixman_surface_state *ps;
struct pixman_renderer *pr = get_renderer(surface->compositor);
ps = zalloc(sizeof *ps);
if (ps == NULL)
return -1;
surface->renderer_state = ps;
ps->surface = surface;
ps->surface_destroy_listener.notify =
surface_state_handle_surface_destroy;
wl_signal_add(&surface->destroy_signal,
&ps->surface_destroy_listener);
ps->renderer_destroy_listener.notify =
surface_state_handle_renderer_destroy;
wl_signal_add(&pr->destroy_signal,
&ps->renderer_destroy_listener);
return 0;
}
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
float red, float green, float blue, float alpha)
{
struct pixman_surface_state *ps = get_surface_state(es);
pixman_color_t color;
color.red = red * 0xffff;
color.green = green * 0xffff;
color.blue = blue * 0xffff;
color.alpha = alpha * 0xffff;
if (ps->image) {
pixman_image_unref(ps->image);
ps->image = NULL;
}
ps->image = pixman_image_create_solid_fill(&color);
}
static void
pixman_renderer_destroy(struct weston_compositor *ec)
{
struct pixman_renderer *pr = get_renderer(ec);
wl_signal_emit(&pr->destroy_signal, pr);
weston_binding_destroy(pr->debug_binding);
free(pr);
ec->renderer = NULL;
}
static void
pixman_renderer_surface_get_content_size(struct weston_surface *surface,
int *width, int *height)
{
struct pixman_surface_state *ps = get_surface_state(surface);
if (ps->image) {
*width = pixman_image_get_width(ps->image);
*height = pixman_image_get_height(ps->image);
} else {
*width = 0;
*height = 0;
}
}
static int
pixman_renderer_surface_copy_content(struct weston_surface *surface,
void *target, size_t size,
int src_x, int src_y,
int width, int height)
{
const pixman_format_code_t format = PIXMAN_a8b8g8r8;
const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
struct pixman_surface_state *ps = get_surface_state(surface);
pixman_image_t *out_buf;
if (!ps->image)
return -1;
out_buf = pixman_image_create_bits(format, width, height,
target, width * bytespp);
pixman_image_set_transform(ps->image, NULL);
pixman_image_composite32(PIXMAN_OP_SRC,
ps->image, /* src */
NULL, /* mask */
out_buf, /* dest */
src_x, src_y, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
0, 0, /* dest_x, dest_y */
width, height);
pixman_image_unref(out_buf);
return 0;
}
static void
debug_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
void *data)
{
struct weston_compositor *ec = data;
struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
pr->repaint_debug ^= 1;
if (pr->repaint_debug) {
pixman_color_t red = {
0x3fff, 0x0000, 0x0000, 0x3fff
};
pr->debug_color = pixman_image_create_solid_fill(&red);
} else {
pixman_image_unref(pr->debug_color);
weston_compositor_damage_all(ec);
}
}
WL_EXPORT int
pixman_renderer_init(struct weston_compositor *ec)
{
struct pixman_renderer *renderer;
renderer = zalloc(sizeof *renderer);
if (renderer == NULL)
return -1;
renderer->repaint_debug = 0;
renderer->debug_color = NULL;
renderer->base.read_pixels = pixman_renderer_read_pixels;
renderer->base.repaint_output = pixman_renderer_repaint_output;
renderer->base.flush_damage = pixman_renderer_flush_damage;
renderer->base.attach = pixman_renderer_attach;
renderer->base.surface_set_color = pixman_renderer_surface_set_color;
renderer->base.destroy = pixman_renderer_destroy;
renderer->base.surface_get_content_size =
pixman_renderer_surface_get_content_size;
renderer->base.surface_copy_content =
pixman_renderer_surface_copy_content;
ec->renderer = &renderer->base;
ec->capabilities |= WESTON_CAP_ROTATION_ANY;
ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
renderer->debug_binding =
weston_compositor_add_debug_binding(ec, KEY_R,
debug_binding, ec);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
wl_signal_init(&renderer->destroy_signal);
return 0;
}
WL_EXPORT void
pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
{
struct pixman_output_state *po = get_output_state(output);
if (po->hw_buffer)
pixman_image_unref(po->hw_buffer);
po->hw_buffer = buffer;
if (po->hw_buffer) {
output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
pixman_image_ref(po->hw_buffer);
}
}
WL_EXPORT int
pixman_renderer_output_create(struct weston_output *output)
{
struct pixman_output_state *po;
int w, h;
po = zalloc(sizeof *po);
if (po == NULL)
return -1;
/* set shadow image transformation */
w = output->current_mode->width;
h = output->current_mode->height;
po->shadow_buffer = malloc(w * h * 4);
if (!po->shadow_buffer) {
free(po);
return -1;
}
po->shadow_image =
pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
po->shadow_buffer, w * 4);
if (!po->shadow_image) {
free(po->shadow_buffer);
free(po);
return -1;
}
output->renderer_state = po;
return 0;
}
WL_EXPORT void
pixman_renderer_output_destroy(struct weston_output *output)
{
struct pixman_output_state *po = get_output_state(output);
pixman_image_unref(po->shadow_image);
if (po->hw_buffer)
pixman_image_unref(po->hw_buffer);
free(po->shadow_buffer);
po->shadow_buffer = NULL;
po->shadow_image = NULL;
po->hw_buffer = NULL;
free(po);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "compositor.h"
int
pixman_renderer_init(struct weston_compositor *ec);
int
pixman_renderer_output_create(struct weston_output *output);
void
pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer);
void
pixman_renderer_output_destroy(struct weston_output *output);
+487
View File
@@ -0,0 +1,487 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include "compositor.h"
#include "shared/helpers.h"
#include "wcap/wcap-decode.h"
struct screenshooter_frame_listener {
struct wl_listener listener;
struct weston_buffer *buffer;
weston_screenshooter_done_func_t done;
void *data;
};
static void
copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
{
uint8_t *end;
end = dst + height * stride;
while (dst < end) {
memcpy(dst, src, stride);
dst += stride;
src -= stride;
}
}
static void
copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride)
{
/* TODO: optimize this out */
memcpy(dst, src, height * stride);
}
static void
copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
{
uint32_t *dst = vdst;
uint32_t *src = vsrc;
uint32_t *end = dst + bytes / 4;
while (dst < end) {
uint32_t v = *src++;
/* A R G B */
uint32_t tmp = v & 0xff00ff00;
tmp |= (v >> 16) & 0x000000ff;
tmp |= (v << 16) & 0x00ff0000;
*dst++ = tmp;
}
}
static void
copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
{
uint8_t *end;
end = dst + height * stride;
while (dst < end) {
copy_row_swap_RB(dst, src, stride);
dst += stride;
src -= stride;
}
}
static void
copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride)
{
uint8_t *end;
end = dst + height * stride;
while (dst < end) {
copy_row_swap_RB(dst, src, stride);
dst += stride;
src += stride;
}
}
static void
screenshooter_frame_notify(struct wl_listener *listener, void *data)
{
struct screenshooter_frame_listener *l =
container_of(listener,
struct screenshooter_frame_listener, listener);
struct weston_output *output = data;
struct weston_compositor *compositor = output->compositor;
int32_t stride;
uint8_t *pixels, *d, *s;
output->disable_planes--;
wl_list_remove(&listener->link);
stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
pixels = malloc(stride * l->buffer->height);
if (pixels == NULL) {
l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
free(l);
return;
}
compositor->renderer->read_pixels(output,
compositor->read_format, pixels,
0, 0, output->current_mode->width,
output->current_mode->height);
stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
s = pixels + stride * (l->buffer->height - 1);
wl_shm_buffer_begin_access(l->buffer->shm_buffer);
switch (compositor->read_format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
copy_bgra_yflip(d, s, output->current_mode->height, stride);
else
copy_bgra(d, pixels, output->current_mode->height, stride);
break;
case PIXMAN_x8b8g8r8:
case PIXMAN_a8b8g8r8:
if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
copy_rgba_yflip(d, s, output->current_mode->height, stride);
else
copy_rgba(d, pixels, output->current_mode->height, stride);
break;
default:
break;
}
wl_shm_buffer_end_access(l->buffer->shm_buffer);
l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
free(pixels);
free(l);
}
WL_EXPORT int
weston_screenshooter_shoot(struct weston_output *output,
struct weston_buffer *buffer,
weston_screenshooter_done_func_t done, void *data)
{
struct screenshooter_frame_listener *l;
if (!wl_shm_buffer_get(buffer->resource)) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
return -1;
}
buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
if (buffer->width < output->current_mode->width ||
buffer->height < output->current_mode->height) {
done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
return -1;
}
l = malloc(sizeof *l);
if (l == NULL) {
done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
return -1;
}
l->buffer = buffer;
l->done = done;
l->data = data;
l->listener.notify = screenshooter_frame_notify;
wl_signal_add(&output->frame_signal, &l->listener);
output->disable_planes++;
weston_output_schedule_repaint(output);
return 0;
}
struct weston_recorder {
struct weston_output *output;
uint32_t *frame, *rect;
uint32_t *tmpbuf;
uint32_t total;
int fd;
struct wl_listener frame_listener;
int count, destroying;
};
static uint32_t *
output_run(uint32_t *p, uint32_t delta, int run)
{
int i;
while (run > 0) {
if (run <= 0xe0) {
*p++ = delta | ((run - 1) << 24);
break;
}
i = 24 - __builtin_clz(run);
*p++ = delta | ((i + 0xe0) << 24);
run -= 1 << (7 + i);
}
return p;
}
static uint32_t
component_delta(uint32_t next, uint32_t prev)
{
unsigned char dr, dg, db;
dr = (next >> 16) - (prev >> 16);
dg = (next >> 8) - (prev >> 8);
db = (next >> 0) - (prev >> 0);
return (dr << 16) | (dg << 8) | (db << 0);
}
static void
weston_recorder_destroy(struct weston_recorder *recorder);
static void
weston_recorder_frame_notify(struct wl_listener *listener, void *data)
{
struct weston_recorder *recorder =
container_of(listener, struct weston_recorder, frame_listener);
struct weston_output *output = data;
struct weston_compositor *compositor = output->compositor;
uint32_t msecs = output->frame_time;
pixman_box32_t *r;
pixman_region32_t damage, transformed_damage;
int i, j, k, n, width, height, run, stride;
uint32_t delta, prev, *d, *s, *p, next;
struct {
uint32_t msecs;
uint32_t nrects;
} header;
struct iovec v[2];
int do_yflip;
int y_orig;
uint32_t *outbuf;
do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
if (do_yflip)
outbuf = recorder->rect;
else
outbuf = recorder->tmpbuf;
pixman_region32_init(&damage);
pixman_region32_init(&transformed_damage);
pixman_region32_intersect(&damage, &output->region,
&output->previous_damage);
pixman_region32_translate(&damage, -output->x, -output->y);
weston_transformed_region(output->width, output->height,
output->transform, output->current_scale,
&damage, &transformed_damage);
pixman_region32_fini(&damage);
r = pixman_region32_rectangles(&transformed_damage, &n);
if (n == 0) {
pixman_region32_fini(&transformed_damage);
return;
}
header.msecs = msecs;
header.nrects = n;
v[0].iov_base = &header;
v[0].iov_len = sizeof header;
v[1].iov_base = r;
v[1].iov_len = n * sizeof *r;
recorder->total += writev(recorder->fd, v, 2);
stride = output->current_mode->width;
for (i = 0; i < n; i++) {
width = r[i].x2 - r[i].x1;
height = r[i].y2 - r[i].y1;
if (do_yflip)
y_orig = output->current_mode->height - r[i].y2;
else
y_orig = r[i].y1;
compositor->renderer->read_pixels(output,
compositor->read_format, recorder->rect,
r[i].x1, y_orig, width, height);
p = outbuf;
run = prev = 0; /* quiet gcc */
for (j = 0; j < height; j++) {
if (do_yflip)
s = recorder->rect + width * j;
else
s = recorder->rect + width * (height - j - 1);
y_orig = r[i].y2 - j - 1;
d = recorder->frame + stride * y_orig + r[i].x1;
for (k = 0; k < width; k++) {
next = *s++;
delta = component_delta(next, *d);
*d++ = next;
if (run == 0 || delta == prev) {
run++;
} else {
p = output_run(p, prev, run);
run = 1;
}
prev = delta;
}
}
p = output_run(p, prev, run);
recorder->total += write(recorder->fd,
outbuf, (p - outbuf) * 4);
#if 0
fprintf(stderr,
"%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n",
width, height, r[i].x1, r[i].y1,
width * height * 4, (int) (p - outbuf) * 4,
(float) (p - outbuf) / (width * height),
recorder->total / 1024 / 1024);
#endif
}
pixman_region32_fini(&transformed_damage);
recorder->count++;
if (recorder->destroying)
weston_recorder_destroy(recorder);
}
static void
weston_recorder_free(struct weston_recorder *recorder)
{
if (recorder == NULL)
return;
free(recorder->tmpbuf);
free(recorder->rect);
free(recorder->frame);
free(recorder);
}
static struct weston_recorder *
weston_recorder_create(struct weston_output *output, const char *filename)
{
struct weston_compositor *compositor = output->compositor;
struct weston_recorder *recorder;
int stride, size;
struct { uint32_t magic, format, width, height; } header;
int do_yflip;
do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
recorder = zalloc(sizeof *recorder);
if (recorder == NULL) {
weston_log("%s: out of memory\n", __func__);
return NULL;
}
stride = output->current_mode->width;
size = stride * 4 * output->current_mode->height;
recorder->frame = zalloc(size);
recorder->rect = malloc(size);
recorder->output = output;
if ((recorder->frame == NULL) || (recorder->rect == NULL)) {
weston_log("%s: out of memory\n", __func__);
goto err_recorder;
}
if (!do_yflip) {
recorder->tmpbuf = malloc(size);
if (recorder->tmpbuf == NULL) {
weston_log("%s: out of memory\n", __func__);
goto err_recorder;
}
}
header.magic = WCAP_HEADER_MAGIC;
switch (compositor->read_format) {
case PIXMAN_x8r8g8b8:
case PIXMAN_a8r8g8b8:
header.format = WCAP_FORMAT_XRGB8888;
break;
case PIXMAN_a8b8g8r8:
header.format = WCAP_FORMAT_XBGR8888;
break;
default:
weston_log("unknown recorder format\n");
goto err_recorder;
}
recorder->fd = open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (recorder->fd < 0) {
weston_log("problem opening output file %s: %m\n", filename);
goto err_recorder;
}
header.width = output->current_mode->width;
header.height = output->current_mode->height;
recorder->total += write(recorder->fd, &header, sizeof header);
recorder->frame_listener.notify = weston_recorder_frame_notify;
wl_signal_add(&output->frame_signal, &recorder->frame_listener);
output->disable_planes++;
weston_output_damage(output);
return recorder;
err_recorder:
weston_recorder_free(recorder);
return NULL;
}
static void
weston_recorder_destroy(struct weston_recorder *recorder)
{
wl_list_remove(&recorder->frame_listener.link);
close(recorder->fd);
recorder->output->disable_planes--;
weston_recorder_free(recorder);
}
WL_EXPORT struct weston_recorder *
weston_recorder_start(struct weston_output *output, const char *filename)
{
struct wl_listener *listener;
listener = wl_signal_get(&output->frame_signal,
weston_recorder_frame_notify);
if (listener) {
weston_log("a recorder on output %s is already running\n",
output->name);
return NULL;
}
weston_log("starting recorder for output %s, file %s\n",
output->name, filename);
return weston_recorder_create(output, filename);
}
WL_EXPORT void
weston_recorder_stop(struct weston_recorder *recorder)
{
weston_log("stopping recorder, total file size %dM, %d frames\n",
recorder->total / (1024 * 1024), recorder->count);
recorder->destroying = 1;
weston_output_schedule_repaint(recorder->output);
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright © 2011 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "compositor.h"
WL_EXPORT void
weston_view_geometry_dirty(struct weston_view *view)
{
}
WL_EXPORT int
weston_log(const char *fmt, ...)
{
return 0;
}
WL_EXPORT void
weston_view_schedule_repaint(struct weston_view *view)
{
}
WL_EXPORT void
weston_compositor_schedule_repaint(struct weston_compositor *compositor)
{
}
int
main(int argc, char *argv[])
{
const double k = 300.0;
const double current = 0.5;
const double target = 1.0;
const double friction = 1400;
struct weston_spring spring;
uint32_t time = 0;
weston_spring_init(&spring, k, current, target);
spring.friction = friction;
spring.previous = 0.48;
spring.timestamp = 0;
while (!weston_spring_done(&spring)) {
printf("\t%d\t%f\n", time, spring.current);
weston_spring_update(&spring, time);
time += 16;
}
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright © 2014 Pekka Paalanen <pq@iki.fi>
* Copyright © 2014 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_TIMELINE_OBJECT_H
#define WESTON_TIMELINE_OBJECT_H
/*
* This struct can be embedded in objects related to timeline output.
* It must be initialized to all-zero. Afterwards, the timeline code
* will handle it alone. No clean-up is necessary.
*/
struct weston_timeline_object {
/*
* Timeline series gets bumped every time a new log is opened.
* This triggers id allocation and object info emission.
* 0 is an invalid series value.
*/
unsigned series;
/* Object id in the timeline JSON output. 0 is invalid. */
unsigned id;
/*
* If non-zero, forces a re-emission of object description.
* Should be set to non-zero, when changing long-lived
* object state that is not emitted on normal timeline
* events.
*/
unsigned force_refresh;
};
#endif /* WESTON_TIMELINE_OBJECT_H */
+292
View File
@@ -0,0 +1,292 @@
/*
* Copyright © 2014 Pekka Paalanen <pq@iki.fi>
* Copyright © 2014 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "timeline.h"
#include "compositor.h"
#include "file-util.h"
struct timeline_log {
clock_t clk_id;
FILE *file;
unsigned series;
struct wl_listener compositor_destroy_listener;
};
WL_EXPORT int weston_timeline_enabled_;
static struct timeline_log timeline_ = { CLOCK_MONOTONIC, NULL, 0 };
static int
weston_timeline_do_open(void)
{
const char *prefix = "weston-timeline-";
const char *suffix = ".log";
char fname[1000];
timeline_.file = file_create_dated(prefix, suffix,
fname, sizeof(fname));
if (!timeline_.file) {
const char *msg;
switch (errno) {
case ETIME:
msg = "failure in datetime formatting";
break;
default:
msg = strerror(errno);
}
weston_log("Cannot open '%s*%s' for writing: %s\n",
prefix, suffix, msg);
return -1;
}
weston_log("Opened timeline file '%s'\n", fname);
return 0;
}
static void
timeline_notify_destroy(struct wl_listener *listener, void *data)
{
weston_timeline_close();
}
void
weston_timeline_open(struct weston_compositor *compositor)
{
if (weston_timeline_enabled_)
return;
if (weston_timeline_do_open() < 0)
return;
timeline_.compositor_destroy_listener.notify = timeline_notify_destroy;
wl_signal_add(&compositor->destroy_signal,
&timeline_.compositor_destroy_listener);
if (++timeline_.series == 0)
++timeline_.series;
weston_timeline_enabled_ = 1;
}
void
weston_timeline_close(void)
{
if (!weston_timeline_enabled_)
return;
weston_timeline_enabled_ = 0;
wl_list_remove(&timeline_.compositor_destroy_listener.link);
fclose(timeline_.file);
timeline_.file = NULL;
weston_log("Timeline log file closed.\n");
}
struct timeline_emit_context {
FILE *cur;
FILE *out;
unsigned series;
};
static unsigned
timeline_new_id(void)
{
static unsigned idc;
if (++idc == 0)
++idc;
return idc;
}
static int
check_series(struct timeline_emit_context *ctx,
struct weston_timeline_object *to)
{
if (to->series == 0 || to->series != ctx->series) {
to->series = ctx->series;
to->id = timeline_new_id();
return 1;
}
if (to->force_refresh) {
to->force_refresh = 0;
return 1;
}
return 0;
}
static void
fprint_quoted_string(FILE *fp, const char *str)
{
if (!str) {
fprintf(fp, "null");
return;
}
fprintf(fp, "\"%s\"", str);
}
static int
emit_weston_output(struct timeline_emit_context *ctx, void *obj)
{
struct weston_output *o = obj;
if (check_series(ctx, &o->timeline)) {
fprintf(ctx->out, "{ \"id\":%u, "
"\"type\":\"weston_output\", \"name\":",
o->timeline.id);
fprint_quoted_string(ctx->out, o->name);
fprintf(ctx->out, " }\n");
}
fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
return 1;
}
static void
check_weston_surface_description(struct timeline_emit_context *ctx,
struct weston_surface *s)
{
struct weston_surface *mains;
char d[512];
char mainstr[32];
if (!check_series(ctx, &s->timeline))
return;
mains = weston_surface_get_main_surface(s);
if (mains != s) {
check_weston_surface_description(ctx, mains);
if (snprintf(mainstr, sizeof(mainstr),
", \"main_surface\":%u", mains->timeline.id) < 0)
mainstr[0] = '\0';
} else {
mainstr[0] = '\0';
}
if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
d[0] = '\0';
fprintf(ctx->out, "{ \"id\":%u, "
"\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
fprint_quoted_string(ctx->out, d[0] ? d : NULL);
fprintf(ctx->out, "%s }\n", mainstr);
}
static int
emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
{
struct weston_surface *s = obj;
check_weston_surface_description(ctx, s);
fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
return 1;
}
static int
emit_vblank_timestamp(struct timeline_emit_context *ctx, void *obj)
{
struct timespec *ts = obj;
fprintf(ctx->cur, "\"vblank\":[%" PRId64 ", %ld]",
(int64_t)ts->tv_sec, ts->tv_nsec);
return 1;
}
typedef int (*type_func)(struct timeline_emit_context *ctx, void *obj);
static const type_func type_dispatch[] = {
[TLT_OUTPUT] = emit_weston_output,
[TLT_SURFACE] = emit_weston_surface,
[TLT_VBLANK] = emit_vblank_timestamp,
};
WL_EXPORT void
weston_timeline_point(const char *name, ...)
{
va_list argp;
struct timespec ts;
enum timeline_type otype;
void *obj;
char buf[512];
struct timeline_emit_context ctx;
clock_gettime(timeline_.clk_id, &ts);
ctx.out = timeline_.file;
ctx.cur = fmemopen(buf, sizeof(buf), "w");
ctx.series = timeline_.series;
if (!ctx.cur) {
weston_log("Timeline error in fmemopen, closing.\n");
weston_timeline_close();
return;
}
fprintf(ctx.cur, "{ \"T\":[%" PRId64 ", %ld], \"N\":\"%s\"",
(int64_t)ts.tv_sec, ts.tv_nsec, name);
va_start(argp, name);
while (1) {
otype = va_arg(argp, enum timeline_type);
if (otype == TLT_END)
break;
obj = va_arg(argp, void *);
if (type_dispatch[otype]) {
fprintf(ctx.cur, ", ");
type_dispatch[otype](&ctx, obj);
}
}
va_end(argp);
fprintf(ctx.cur, " }\n");
fflush(ctx.cur);
if (ferror(ctx.cur)) {
weston_log("Timeline error in constructing entry, closing.\n");
weston_timeline_close();
} else {
fprintf(ctx.out, "%s", buf);
}
fclose(ctx.cur);
}
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright © 2014 Pekka Paalanen <pq@iki.fi>
* Copyright © 2014 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_TIMELINE_H
#define WESTON_TIMELINE_H
extern int weston_timeline_enabled_;
struct weston_compositor;
void
weston_timeline_open(struct weston_compositor *compositor);
void
weston_timeline_close(void);
enum timeline_type {
TLT_END = 0,
TLT_OUTPUT,
TLT_SURFACE,
TLT_VBLANK,
};
#define TYPEVERIFY(type, arg) ({ \
typeof(arg) tmp___ = (arg); \
(void)((type)0 == tmp___); \
tmp___; })
#define TLP_END TLT_END, NULL
#define TLP_OUTPUT(o) TLT_OUTPUT, TYPEVERIFY(struct weston_output *, (o))
#define TLP_SURFACE(s) TLT_SURFACE, TYPEVERIFY(struct weston_surface *, (s))
#define TLP_VBLANK(t) TLT_VBLANK, TYPEVERIFY(const struct timespec *, (t))
#define TL_POINT(...) do { \
if (weston_timeline_enabled_) \
weston_timeline_point(__VA_ARGS__); \
} while (0)
void
weston_timeline_point(const char *name, ...);
#endif /* WESTON_TIMELINE_H */
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _VAAPI_RECORDER_H_
#define _VAAPI_RECORDER_H_
struct vaapi_recorder;
struct vaapi_recorder *
vaapi_recorder_create(int drm_fd, int width, int height, const char *filename);
void
vaapi_recorder_destroy(struct vaapi_recorder *r);
int
vaapi_recorder_frame(struct vaapi_recorder *r, int fd, int stride);
#endif /* _VAAPI_RECORDER_H_ */
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_VERSION_H
#define WESTON_VERSION_H
#define WESTON_VERSION_MAJOR @WESTON_VERSION_MAJOR@
#define WESTON_VERSION_MINOR @WESTON_VERSION_MINOR@
#define WESTON_VERSION_MICRO @WESTON_VERSION_MICRO@
#define WESTON_VERSION "@WESTON_VERSION@"
/* This macro may not do what you expect. Weston doesn't guarantee
* a stable API between 1.X and 1.Y, and thus this macro will return
* FALSE on any WESTON_VERSION_AT_LEAST(1,X,0) if the actual version
* is 1.Y.0 and X != Y). In particular, it fails if X < Y, that is,
* 1.3.0 is considered to not be "at least" 1.4.0.
*
* If you want to test for the version number being 1.3.0 or above or
* maybe in a range (eg 1.2.0 to 1.4.0), just use the WESTON_VERSION_*
* defines above directly.
*/
#define WESTON_VERSION_AT_LEAST(major, minor, micro) \
(WESTON_VERSION_MAJOR == (major) && \
WESTON_VERSION_MINOR == (minor) && \
WESTON_VERSION_MICRO >= (micro))
#endif
+330
View File
@@ -0,0 +1,330 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <assert.h>
#include <float.h>
#include <math.h>
#include "vertex-clipping.h"
float
float_difference(float a, float b)
{
/* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
static const float max_diff = 4.0f * FLT_MIN;
static const float max_rel_diff = 4.0e-5;
float diff = a - b;
float adiff = fabsf(diff);
if (adiff <= max_diff)
return 0.0f;
a = fabsf(a);
b = fabsf(b);
if (adiff <= (a > b ? a : b) * max_rel_diff)
return 0.0f;
return diff;
}
/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
* Compute the y coordinate of the intersection.
*/
static float
clip_intersect_y(float p1x, float p1y, float p2x, float p2y,
float x_arg)
{
float a;
float diff = float_difference(p1x, p2x);
/* Practically vertical line segment, yet the end points have already
* been determined to be on different sides of the line. Therefore
* the line segment is part of the line and intersects everywhere.
* Return the end point, so we use the whole line segment.
*/
if (diff == 0.0f)
return p2y;
a = (x_arg - p2x) / diff;
return p2y + (p1y - p2y) * a;
}
/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
* Compute the x coordinate of the intersection.
*/
static float
clip_intersect_x(float p1x, float p1y, float p2x, float p2y,
float y_arg)
{
float a;
float diff = float_difference(p1y, p2y);
/* Practically horizontal line segment, yet the end points have already
* been determined to be on different sides of the line. Therefore
* the line segment is part of the line and intersects everywhere.
* Return the end point, so we use the whole line segment.
*/
if (diff == 0.0f)
return p2x;
a = (y_arg - p2y) / diff;
return p2x + (p1x - p2x) * a;
}
enum path_transition {
PATH_TRANSITION_OUT_TO_OUT = 0,
PATH_TRANSITION_OUT_TO_IN = 1,
PATH_TRANSITION_IN_TO_OUT = 2,
PATH_TRANSITION_IN_TO_IN = 3,
};
static void
clip_append_vertex(struct clip_context *ctx, float x, float y)
{
*ctx->vertices.x++ = x;
*ctx->vertices.y++ = y;
}
static enum path_transition
path_transition_left_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
}
static enum path_transition
path_transition_right_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
}
static enum path_transition
path_transition_top_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
}
static enum path_transition
path_transition_bottom_edge(struct clip_context *ctx, float x, float y)
{
return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
}
static void
clip_polygon_leftright(struct clip_context *ctx,
enum path_transition transition,
float x, float y, float clip_x)
{
float yi;
switch (transition) {
case PATH_TRANSITION_IN_TO_IN:
clip_append_vertex(ctx, x, y);
break;
case PATH_TRANSITION_IN_TO_OUT:
yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
clip_append_vertex(ctx, clip_x, yi);
break;
case PATH_TRANSITION_OUT_TO_IN:
yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
clip_append_vertex(ctx, clip_x, yi);
clip_append_vertex(ctx, x, y);
break;
case PATH_TRANSITION_OUT_TO_OUT:
/* nothing */
break;
default:
assert(0 && "bad enum path_transition");
}
ctx->prev.x = x;
ctx->prev.y = y;
}
static void
clip_polygon_topbottom(struct clip_context *ctx,
enum path_transition transition,
float x, float y, float clip_y)
{
float xi;
switch (transition) {
case PATH_TRANSITION_IN_TO_IN:
clip_append_vertex(ctx, x, y);
break;
case PATH_TRANSITION_IN_TO_OUT:
xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
clip_append_vertex(ctx, xi, clip_y);
break;
case PATH_TRANSITION_OUT_TO_IN:
xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
clip_append_vertex(ctx, xi, clip_y);
clip_append_vertex(ctx, x, y);
break;
case PATH_TRANSITION_OUT_TO_OUT:
/* nothing */
break;
default:
assert(0 && "bad enum path_transition");
}
ctx->prev.x = x;
ctx->prev.y = y;
}
static void
clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
float *dst_x, float *dst_y)
{
ctx->prev.x = src->x[src->n - 1];
ctx->prev.y = src->y[src->n - 1];
ctx->vertices.x = dst_x;
ctx->vertices.y = dst_y;
}
static int
clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
if (src->n < 2)
return 0;
clip_context_prepare(ctx, src, dst_x, dst_y);
for (i = 0; i < src->n; i++) {
trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
ctx->clip.x1);
}
return ctx->vertices.x - dst_x;
}
static int
clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
if (src->n < 2)
return 0;
clip_context_prepare(ctx, src, dst_x, dst_y);
for (i = 0; i < src->n; i++) {
trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
ctx->clip.x2);
}
return ctx->vertices.x - dst_x;
}
static int
clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
if (src->n < 2)
return 0;
clip_context_prepare(ctx, src, dst_x, dst_y);
for (i = 0; i < src->n; i++) {
trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
ctx->clip.y1);
}
return ctx->vertices.x - dst_x;
}
static int
clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
float *dst_x, float *dst_y)
{
enum path_transition trans;
int i;
if (src->n < 2)
return 0;
clip_context_prepare(ctx, src, dst_x, dst_y);
for (i = 0; i < src->n; i++) {
trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
ctx->clip.y2);
}
return ctx->vertices.x - dst_x;
}
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) > (b)) ? (b) : (a))
#define clip(x, a, b) min(max(x, a), b)
int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
float *ey)
{
int i;
for (i = 0; i < surf->n; i++) {
ex[i] = clip(surf->x[i], ctx->clip.x1, ctx->clip.x2);
ey[i] = clip(surf->y[i], ctx->clip.y1, ctx->clip.y2);
}
return surf->n;
}
int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
float *ey)
{
struct polygon8 polygon;
int i, n;
polygon.n = clip_polygon_left(ctx, surf, polygon.x, polygon.y);
surf->n = clip_polygon_right(ctx, &polygon, surf->x, surf->y);
polygon.n = clip_polygon_top(ctx, surf, polygon.x, polygon.y);
surf->n = clip_polygon_bottom(ctx, &polygon, surf->x, surf->y);
/* Get rid of duplicate vertices */
ex[0] = surf->x[0];
ey[0] = surf->y[0];
n = 1;
for (i = 1; i < surf->n; i++) {
if (float_difference(ex[n - 1], surf->x[i]) == 0.0f &&
float_difference(ey[n - 1], surf->y[i]) == 0.0f)
continue;
ex[n] = surf->x[i];
ey[n] = surf->y[i];
n++;
}
if (float_difference(ex[n - 1], surf->x[0]) == 0.0f &&
float_difference(ey[n - 1], surf->y[0]) == 0.0f)
n--;
return n;
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _WESTON_VERTEX_CLIPPING_H
#define _WESTON_VERTEX_CLIPPING_H
struct polygon8 {
float x[8];
float y[8];
int n;
};
struct clip_context {
struct {
float x;
float y;
} prev;
struct {
float x1, y1;
float x2, y2;
} clip;
struct {
float *x;
float *y;
} vertices;
};
float
float_difference(float a, float b);
int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
float *ey);
int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
float *ex,
float *ey);\
#endif
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Extensions used by Weston, copied from Mesa's eglmesaext.h, */
#ifndef WESTON_EGL_EXT_H
#define WESTON_EGL_EXT_H
#ifndef EGL_WL_bind_wayland_display
#define EGL_WL_bind_wayland_display 1
struct wl_display;
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
#endif
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
#endif
/*
* This is a little different to the tests shipped with EGL implementations,
* which wrap the entire thing in #ifndef EGL_WL_bind_wayland_display, then go
* on to define both BindWaylandDisplay and QueryWaylandBuffer.
*
* Unfortunately, some implementations (particularly the version of Mesa shipped
* in Ubuntu 12.04) define EGL_WL_bind_wayland_display, but then only provide
* prototypes for (Un)BindWaylandDisplay, completely omitting
* QueryWaylandBuffer.
*
* Detect this, and provide our own definitions if necessary.
*/
#ifndef EGL_WAYLAND_BUFFER_WL
#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */
#define EGL_WAYLAND_PLANE_WL 0x31D6 /* eglCreateImageKHR target */
#define EGL_TEXTURE_Y_U_V_WL 0x31D7
#define EGL_TEXTURE_Y_UV_WL 0x31D8
#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
struct wl_resource;
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
#endif
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
#endif
#ifndef EGL_WL_create_wayland_buffer_from_image
#define EGL_WL_create_wayland_buffer_from_image 1
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
#endif
typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
#endif
#ifndef EGL_TEXTURE_EXTERNAL_WL
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
#endif
#ifndef EGL_BUFFER_AGE_EXT
#define EGL_BUFFER_AGE_EXT 0x313D
#endif
#ifndef EGL_WAYLAND_Y_INVERTED_WL
#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB /* eglQueryWaylandBufferWL attribute */
#endif
/* Mesas gl2ext.h and probably Khronos upstream defined
* GL_EXT_unpack_subimage with non _EXT suffixed GL_UNPACK_* tokens.
* In case we're using that mess, manually define the _EXT versions
* of the tokens here.*/
#if defined(GL_EXT_unpack_subimage) && !defined(GL_UNPACK_ROW_LENGTH_EXT)
#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
#endif
/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
* here to avoid having to add ifdefs everywhere.*/
#ifndef EGL_EXT_image_dma_buf_import
#define EGL_LINUX_DMA_BUF_EXT 0x3270
#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
#endif
#endif
+772
View File
@@ -0,0 +1,772 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <error.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <linux/kd.h>
#include <pwd.h>
#include <grp.h>
#include <security/pam_appl.h>
#ifdef HAVE_SYSTEMD_LOGIN
#include <systemd/sd-login.h>
#endif
#include "weston-launch.h"
#define DRM_MAJOR 226
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifndef EVIOCREVOKE
#define EVIOCREVOKE _IOW('E', 0x91, int)
#endif
#define MAX_ARGV_SIZE 256
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#else
static inline int
drmDropMaster(int drm_fd)
{
return 0;
}
static inline int
drmSetMaster(int drm_fd)
{
return 0;
}
#endif
struct weston_launch {
struct pam_conv pc;
pam_handle_t *ph;
int tty;
int ttynr;
int sock[2];
int drm_fd;
int last_input_fd;
int kb_mode;
struct passwd *pw;
int signalfd;
pid_t child;
int verbose;
char *new_user;
};
union cmsg_data { unsigned char b[4]; int fd; };
static gid_t *
read_groups(void)
{
int n;
gid_t *groups;
n = getgroups(0, NULL);
if (n < 0) {
fprintf(stderr, "Unable to retrieve groups: %m\n");
return NULL;
}
groups = malloc(n * sizeof(gid_t));
if (!groups)
return NULL;
if (getgroups(n, groups) < 0) {
fprintf(stderr, "Unable to retrieve groups: %m\n");
free(groups);
return NULL;
}
return groups;
}
static bool
weston_launch_allowed(struct weston_launch *wl)
{
struct group *gr;
gid_t *groups;
int i;
#ifdef HAVE_SYSTEMD_LOGIN
char *session, *seat;
int err;
#endif
if (getuid() == 0)
return true;
gr = getgrnam("weston-launch");
if (gr) {
groups = read_groups();
if (groups) {
for (i = 0; groups[i]; ++i) {
if (groups[i] == gr->gr_gid) {
free(groups);
return true;
}
}
free(groups);
}
}
#ifdef HAVE_SYSTEMD_LOGIN
err = sd_pid_get_session(getpid(), &session);
if (err == 0 && session) {
if (sd_session_is_active(session) &&
sd_session_get_seat(session, &seat) == 0) {
free(seat);
free(session);
return true;
}
free(session);
}
#endif
return false;
}
static int
pam_conversation_fn(int msg_count,
const struct pam_message **messages,
struct pam_response **responses,
void *user_data)
{
return PAM_SUCCESS;
}
static int
setup_pam(struct weston_launch *wl)
{
int err;
wl->pc.conv = pam_conversation_fn;
wl->pc.appdata_ptr = wl;
err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to start pam transaction: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_open_session(wl->ph, 0);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to open pam session: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
return 0;
}
static int
setup_launcher_socket(struct weston_launch *wl)
{
if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
error(1, errno, "socketpair failed");
if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
error(1, errno, "fcntl failed");
return 0;
}
static int
setup_signals(struct weston_launch *wl)
{
int ret;
sigset_t mask;
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
ret = sigaction(SIGCHLD, &sa, NULL);
assert(ret == 0);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction(SIGHUP, &sa, NULL);
ret = sigemptyset(&mask);
assert(ret == 0);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(ret == 0);
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (wl->signalfd < 0)
return -errno;
return 0;
}
static void
setenv_fd(const char *env, int fd)
{
char buf[32];
snprintf(buf, sizeof buf, "%d", fd);
setenv(env, buf, 1);
}
static int
send_reply(struct weston_launch *wl, int reply)
{
int len;
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
return len;
}
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
int fd = -1, ret = -1;
char control[CMSG_SPACE(sizeof(fd))];
struct cmsghdr *cmsg;
struct stat s;
struct msghdr nmsg;
struct iovec iov;
struct weston_launcher_open *message;
union cmsg_data *data;
message = msg->msg_iov->iov_base;
if ((size_t)len < sizeof(*message))
goto err0;
/* Ensure path is null-terminated */
((char *) message)[len-1] = '\0';
fd = open(message->path, message->flags);
if (fd < 0) {
fprintf(stderr, "Error opening device %s: %m\n",
message->path);
goto err0;
}
if (fstat(fd, &s) < 0) {
close(fd);
fd = -1;
fprintf(stderr, "Failed to stat %s\n", message->path);
goto err0;
}
if (major(s.st_rdev) != INPUT_MAJOR &&
major(s.st_rdev) != DRM_MAJOR) {
close(fd);
fd = -1;
fprintf(stderr, "Device %s is not an input or drm device\n",
message->path);
goto err0;
}
err0:
memset(&nmsg, 0, sizeof nmsg);
nmsg.msg_iov = &iov;
nmsg.msg_iovlen = 1;
if (fd != -1) {
nmsg.msg_control = control;
nmsg.msg_controllen = sizeof control;
cmsg = CMSG_FIRSTHDR(&nmsg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
data = (union cmsg_data *) CMSG_DATA(cmsg);
data->fd = fd;
nmsg.msg_controllen = cmsg->cmsg_len;
ret = 0;
}
iov.iov_base = &ret;
iov.iov_len = sizeof ret;
if (wl->verbose)
fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
message->path, ret, fd);
do {
len = sendmsg(wl->sock[0], &nmsg, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
wl->drm_fd = fd;
if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
wl->last_input_fd < fd)
wl->last_input_fd = fd;
return 0;
}
static int
handle_socket_msg(struct weston_launch *wl)
{
char control[CMSG_SPACE(sizeof(int))];
char buf[BUFSIZ];
struct msghdr msg;
struct iovec iov;
int ret = -1;
ssize_t len;
struct weston_launcher_message *message;
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf;
iov.iov_len = sizeof buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof control;
do {
len = recvmsg(wl->sock[0], &msg, 0);
} while (len < 0 && errno == EINTR);
if (len < 1)
return -1;
message = (void *) buf;
switch (message->opcode) {
case WESTON_LAUNCHER_OPEN:
ret = handle_open(wl, &msg, len);
break;
}
return ret;
}
static void
quit(struct weston_launch *wl, int status)
{
struct vt_mode mode = { 0 };
int err;
close(wl->signalfd);
close(wl->sock[0]);
if (wl->new_user) {
err = pam_close_session(wl->ph, 0);
if (err)
fprintf(stderr, "pam_close_session failed: %d: %s\n",
err, pam_strerror(wl->ph, err));
pam_end(wl->ph, err);
}
if (ioctl(wl->tty, KDSKBMUTE, 0) &&
ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
fprintf(stderr, "failed to restore keyboard mode: %m\n");
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
/* We have to drop master before we switch the VT back in
* VT_AUTO, so we don't risk switching to a VT with another
* display server, that will then fail to set drm master. */
drmDropMaster(wl->drm_fd);
mode.mode = VT_AUTO;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
fprintf(stderr, "could not reset vt handling\n");
exit(status);
}
static void
close_input_fds(struct weston_launch *wl)
{
struct stat s;
int fd;
for (fd = 3; fd <= wl->last_input_fd; fd++) {
if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
/* EVIOCREVOKE may fail if the kernel doesn't
* support it, but all we can do is ignore it. */
ioctl(fd, EVIOCREVOKE, 0);
close(fd);
}
}
}
static int
handle_signal(struct weston_launch *wl)
{
struct signalfd_siginfo sig;
int pid, status, ret;
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
error(0, errno, "reading signalfd failed");
return -1;
}
switch (sig.ssi_signo) {
case SIGCHLD:
pid = waitpid(-1, &status, 0);
if (pid == wl->child) {
wl->child = 0;
if (WIFEXITED(status))
ret = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
/*
* If weston dies because of signal N, we
* return 10+N. This is distinct from
* weston-launch dying because of a signal
* (128+N).
*/
ret = 10 + WTERMSIG(status);
else
ret = 0;
quit(wl, ret);
}
break;
case SIGTERM:
case SIGINT:
if (wl->child)
kill(wl->child, sig.ssi_signo);
break;
case SIGUSR1:
send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
close_input_fds(wl);
drmDropMaster(wl->drm_fd);
ioctl(wl->tty, VT_RELDISP, 1);
break;
case SIGUSR2:
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
drmSetMaster(wl->drm_fd);
send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
break;
default:
return -1;
}
return 0;
}
static int
setup_tty(struct weston_launch *wl, const char *tty)
{
struct stat buf;
struct vt_mode mode = { 0 };
char *t;
if (!wl->new_user) {
wl->tty = STDIN_FILENO;
} else if (tty) {
t = ttyname(STDIN_FILENO);
if (t && strcmp(t, tty) == 0)
wl->tty = STDIN_FILENO;
else
wl->tty = open(tty, O_RDWR | O_NOCTTY);
} else {
int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
char filename[16];
if (tty0 < 0)
error(1, errno, "could not open tty0");
if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
error(1, errno, "failed to find non-opened console");
snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
wl->tty = open(filename, O_RDWR | O_NOCTTY);
close(tty0);
}
if (wl->tty < 0)
error(1, errno, "failed to open tty");
if (fstat(wl->tty, &buf) == -1 ||
major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
error(1, 0, "weston-launch must be run from a virtual terminal");
if (tty) {
if (fstat(wl->tty, &buf) < 0)
error(1, errno, "stat %s failed", tty);
if (major(buf.st_rdev) != TTY_MAJOR)
error(1, 0, "invalid tty device: %s", tty);
wl->ttynr = minor(buf.st_rdev);
}
if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
error(1, errno, "failed to get current keyboard mode: %m\n");
if (ioctl(wl->tty, KDSKBMUTE, 1) &&
ioctl(wl->tty, KDSKBMODE, K_OFF))
error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR2;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
error(1, errno, "failed to take control of vt handling\n");
return 0;
}
static void
setup_session(struct weston_launch *wl)
{
char **env;
char *term;
int i;
if (wl->tty != STDIN_FILENO) {
if (setsid() < 0)
error(1, errno, "setsid failed");
if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
error(1, errno, "TIOCSCTTY failed - tty is in use");
}
term = getenv("TERM");
clearenv();
if (term)
setenv("TERM", term, 1);
setenv("USER", wl->pw->pw_name, 1);
setenv("LOGNAME", wl->pw->pw_name, 1);
setenv("HOME", wl->pw->pw_dir, 1);
setenv("SHELL", wl->pw->pw_shell, 1);
env = pam_getenvlist(wl->ph);
if (env) {
for (i = 0; env[i]; ++i) {
if (putenv(env[i]) != 0)
error(0, 0, "putenv %s failed", env[i]);
}
free(env);
}
}
static void
drop_privileges(struct weston_launch *wl)
{
if (setgid(wl->pw->pw_gid) < 0 ||
#ifdef HAVE_INITGROUPS
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
#endif
setuid(wl->pw->pw_uid) < 0)
error(1, errno, "dropping privileges failed");
}
static void
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
{
char *child_argv[MAX_ARGV_SIZE];
sigset_t mask;
int i;
if (wl->verbose)
printf("weston-launch: spawned weston with pid: %d\n", getpid());
if (wl->new_user)
setup_session(wl);
if (geteuid() == 0)
drop_privileges(wl);
setenv_fd("WESTON_TTY_FD", wl->tty);
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
unsetenv("DISPLAY");
/* Do not give our signal mask to the new process. */
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
child_argv[0] = "/bin/sh";
child_argv[1] = "-l";
child_argv[2] = "-c";
child_argv[3] = BINDIR "/weston \"$@\"";
child_argv[4] = "weston";
for (i = 0; i < argc; ++i)
child_argv[5 + i] = argv[i];
child_argv[5 + i] = NULL;
execv(child_argv[0], child_argv);
error(1, errno, "exec failed");
}
static void
help(const char *name)
{
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
fprintf(stderr, " -u, --user Start session as specified username\n");
fprintf(stderr, " -t, --tty Start session on alternative tty\n");
fprintf(stderr, " -v, --verbose Be verbose\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
int
main(int argc, char *argv[])
{
struct weston_launch wl;
int i, c;
char *tty = NULL;
struct option opts[] = {
{ "user", required_argument, NULL, 'u' },
{ "tty", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
memset(&wl, 0, sizeof wl);
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
switch (c) {
case 'u':
wl.new_user = optarg;
if (getuid() != 0)
error(1, 0, "Permission denied. -u allowed for root only");
break;
case 't':
tty = optarg;
break;
case 'v':
wl.verbose = 1;
break;
case 'h':
help("weston-launch");
exit(EXIT_FAILURE);
default:
exit(EXIT_FAILURE);
}
}
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
error(1, E2BIG, "Too many arguments to pass to weston");
if (wl.new_user)
wl.pw = getpwnam(wl.new_user);
else
wl.pw = getpwuid(getuid());
if (wl.pw == NULL)
error(1, errno, "failed to get username");
if (!weston_launch_allowed(&wl))
error(1, 0, "Permission denied. You should either:\n"
#ifdef HAVE_SYSTEMD_LOGIN
" - run from an active and local (systemd) session.\n"
#else
" - enable systemd session support for weston-launch.\n"
#endif
" - or add yourself to the 'weston-launch' group.");
if (setup_tty(&wl, tty) < 0)
exit(EXIT_FAILURE);
if (wl.new_user && setup_pam(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_launcher_socket(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_signals(&wl) < 0)
exit(EXIT_FAILURE);
wl.child = fork();
if (wl.child == -1)
error(EXIT_FAILURE, errno, "fork failed");
if (wl.child == 0)
launch_compositor(&wl, argc - optind, argv + optind);
close(wl.sock[1]);
if (wl.tty != STDIN_FILENO)
close(wl.tty);
while (1) {
struct pollfd fds[2];
int n;
fds[0].fd = wl.sock[0];
fds[0].events = POLLIN;
fds[1].fd = wl.signalfd;
fds[1].events = POLLIN;
n = poll(fds, 2, -1);
if (n < 0)
error(0, errno, "poll failed");
if (fds[0].revents & POLLIN)
handle_socket_msg(&wl);
if (fds[1].revents)
handle_signal(&wl);
}
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _WESTON_LAUNCH_H_
#define _WESTON_LAUNCH_H_
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN,
};
enum weston_launcher_event {
WESTON_LAUNCHER_SUCCESS,
WESTON_LAUNCHER_ACTIVATE,
WESTON_LAUNCHER_DEACTIVATE
};
struct weston_launcher_message {
int opcode;
};
struct weston_launcher_open {
struct weston_launcher_message header;
int flags;
char path[0];
};
#endif
+177
View File
@@ -0,0 +1,177 @@
/*
* Copyright © 2012 Scott Moreau
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include "compositor.h"
#include "text-cursor-position-server-protocol.h"
#include "shared/helpers.h"
static void
weston_zoom_frame_z(struct weston_animation *animation,
struct weston_output *output, uint32_t msecs)
{
if (animation->frame_counter <= 1)
output->zoom.spring_z.timestamp = msecs;
weston_spring_update(&output->zoom.spring_z, msecs);
if (output->zoom.spring_z.current > output->zoom.max_level)
output->zoom.spring_z.current = output->zoom.max_level;
else if (output->zoom.spring_z.current < 0.0)
output->zoom.spring_z.current = 0.0;
if (weston_spring_done(&output->zoom.spring_z)) {
if (output->zoom.active && output->zoom.level <= 0.0) {
output->zoom.active = false;
output->zoom.seat = NULL;
output->disable_planes--;
wl_list_remove(&output->zoom.motion_listener.link);
}
output->zoom.spring_z.current = output->zoom.level;
wl_list_remove(&animation->link);
wl_list_init(&animation->link);
}
output->dirty = 1;
weston_output_damage(output);
}
static void
zoom_area_center_from_point(struct weston_output *output,
double *x, double *y)
{
float level = output->zoom.spring_z.current;
*x = (*x - output->x) * level + output->width / 2.;
*y = (*y - output->y) * level + output->height / 2.;
}
static void
weston_output_update_zoom_transform(struct weston_output *output)
{
double x = output->zoom.current.x; /* global pointer coords */
double y = output->zoom.current.y;
float level;
level = output->zoom.spring_z.current;
if (!output->zoom.active || level > output->zoom.max_level ||
level == 0.0f)
return;
zoom_area_center_from_point(output, &x, &y);
output->zoom.trans_x = x - output->width / 2;
output->zoom.trans_y = y - output->height / 2;
if (output->zoom.trans_x < 0)
output->zoom.trans_x = 0;
if (output->zoom.trans_y < 0)
output->zoom.trans_y = 0;
if (output->zoom.trans_x > level * output->width)
output->zoom.trans_x = level * output->width;
if (output->zoom.trans_y > level * output->height)
output->zoom.trans_y = level * output->height;
}
static void
weston_zoom_transition(struct weston_output *output)
{
if (output->zoom.level != output->zoom.spring_z.current) {
output->zoom.spring_z.target = output->zoom.level;
if (wl_list_empty(&output->zoom.animation_z.link)) {
output->zoom.animation_z.frame_counter = 0;
wl_list_insert(output->animation_list.prev,
&output->zoom.animation_z.link);
}
}
output->dirty = 1;
weston_output_damage(output);
}
WL_EXPORT void
weston_output_update_zoom(struct weston_output *output)
{
struct weston_seat *seat = output->zoom.seat;
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
assert(output->zoom.active);
output->zoom.current.x = wl_fixed_to_double(pointer->x);
output->zoom.current.y = wl_fixed_to_double(pointer->y);
weston_zoom_transition(output);
weston_output_update_zoom_transform(output);
}
static void
motion(struct wl_listener *listener, void *data)
{
struct weston_output_zoom *zoom =
container_of(listener, struct weston_output_zoom, motion_listener);
struct weston_output *output =
container_of(zoom, struct weston_output, zoom);
weston_output_update_zoom(output);
}
WL_EXPORT void
weston_output_activate_zoom(struct weston_output *output,
struct weston_seat *seat)
{
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
if (output->zoom.active)
return;
output->zoom.active = true;
output->zoom.seat = seat;
output->disable_planes++;
wl_signal_add(&pointer->motion_signal,
&output->zoom.motion_listener);
}
WL_EXPORT void
weston_output_init_zoom(struct weston_output *output)
{
output->zoom.active = false;
output->zoom.seat = NULL;
output->zoom.increment = 0.07;
output->zoom.max_level = 0.95;
output->zoom.level = 0.0;
output->zoom.trans_x = 0.0;
output->zoom.trans_y = 0.0;
weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
output->zoom.spring_z.friction = 1000;
output->zoom.animation_z.frame = weston_zoom_frame_z;
wl_list_init(&output->zoom.animation_z.link);
output->zoom.motion_listener.notify = motion;
}