The new confine client will be used to demonstrate pointer confinement. It is so far identical to clickdot except that it doesn't respond to clicks. Signed-off-by: Jonas Ådahl <jadahl@gmail.com> Reviewed-by: Derek Foreman <derekf@osg.samsung.com> Acked-by: Daniel Stone <daniels@collabora.com>dev
parent
9f8c8942ba
commit
61831f42c6
@ -0,0 +1,331 @@ |
|||||||
|
/*
|
||||||
|
* Copyright © 2010 Intel Corporation |
||||||
|
* Copyright © 2012 Collabora, Ltd. |
||||||
|
* Copyright © 2012 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 <stdint.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <cairo.h> |
||||||
|
#include <math.h> |
||||||
|
#include <assert.h> |
||||||
|
#include <sys/timerfd.h> |
||||||
|
#include <sys/epoll.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <linux/input.h> |
||||||
|
#include <wayland-client.h> |
||||||
|
|
||||||
|
#include "window.h" |
||||||
|
#include "shared/helpers.h" |
||||||
|
#include "shared/xalloc.h" |
||||||
|
|
||||||
|
struct confine { |
||||||
|
struct display *display; |
||||||
|
struct window *window; |
||||||
|
struct widget *widget; |
||||||
|
|
||||||
|
cairo_surface_t *buffer; |
||||||
|
|
||||||
|
struct { |
||||||
|
int32_t x, y; |
||||||
|
int32_t old_x, old_y; |
||||||
|
} line; |
||||||
|
|
||||||
|
int reset; |
||||||
|
|
||||||
|
struct input *cursor_timeout_input; |
||||||
|
int cursor_timeout_fd; |
||||||
|
struct task cursor_timeout_task; |
||||||
|
}; |
||||||
|
|
||||||
|
static void |
||||||
|
draw_line(struct confine *confine, cairo_t *cr, |
||||||
|
struct rectangle *allocation) |
||||||
|
{ |
||||||
|
cairo_t *bcr; |
||||||
|
cairo_surface_t *tmp_buffer = NULL; |
||||||
|
|
||||||
|
if (confine->reset) { |
||||||
|
tmp_buffer = confine->buffer; |
||||||
|
confine->buffer = NULL; |
||||||
|
confine->line.x = -1; |
||||||
|
confine->line.y = -1; |
||||||
|
confine->line.old_x = -1; |
||||||
|
confine->line.old_y = -1; |
||||||
|
confine->reset = 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (confine->buffer == NULL) { |
||||||
|
confine->buffer = |
||||||
|
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, |
||||||
|
allocation->width, |
||||||
|
allocation->height); |
||||||
|
bcr = cairo_create(confine->buffer); |
||||||
|
cairo_set_source_rgba(bcr, 0, 0, 0, 0); |
||||||
|
cairo_rectangle(bcr, |
||||||
|
0, 0, |
||||||
|
allocation->width, allocation->height); |
||||||
|
cairo_fill(bcr); |
||||||
|
} |
||||||
|
else |
||||||
|
bcr = cairo_create(confine->buffer); |
||||||
|
|
||||||
|
if (tmp_buffer) { |
||||||
|
cairo_set_source_surface(bcr, tmp_buffer, 0, 0); |
||||||
|
cairo_rectangle(bcr, 0, 0, |
||||||
|
allocation->width, allocation->height); |
||||||
|
cairo_clip(bcr); |
||||||
|
cairo_paint(bcr); |
||||||
|
|
||||||
|
cairo_surface_destroy(tmp_buffer); |
||||||
|
} |
||||||
|
|
||||||
|
if (confine->line.x != -1 && confine->line.y != -1) { |
||||||
|
if (confine->line.old_x != -1 && |
||||||
|
confine->line.old_y != -1) { |
||||||
|
cairo_set_line_width(bcr, 2.0); |
||||||
|
cairo_set_source_rgb(bcr, 1, 1, 1); |
||||||
|
cairo_translate(bcr, |
||||||
|
-allocation->x, -allocation->y); |
||||||
|
|
||||||
|
cairo_move_to(bcr, |
||||||
|
confine->line.old_x, |
||||||
|
confine->line.old_y); |
||||||
|
cairo_line_to(bcr, |
||||||
|
confine->line.x, |
||||||
|
confine->line.y); |
||||||
|
|
||||||
|
cairo_stroke(bcr); |
||||||
|
} |
||||||
|
|
||||||
|
confine->line.old_x = confine->line.x; |
||||||
|
confine->line.old_y = confine->line.y; |
||||||
|
} |
||||||
|
cairo_destroy(bcr); |
||||||
|
|
||||||
|
cairo_set_source_surface(cr, confine->buffer, |
||||||
|
allocation->x, allocation->y); |
||||||
|
cairo_set_operator(cr, CAIRO_OPERATOR_ADD); |
||||||
|
cairo_rectangle(cr, |
||||||
|
allocation->x, allocation->y, |
||||||
|
allocation->width, allocation->height); |
||||||
|
cairo_clip(cr); |
||||||
|
cairo_paint(cr); |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
redraw_handler(struct widget *widget, void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
cairo_surface_t *surface; |
||||||
|
cairo_t *cr; |
||||||
|
struct rectangle allocation; |
||||||
|
|
||||||
|
widget_get_allocation(confine->widget, &allocation); |
||||||
|
|
||||||
|
surface = window_get_surface(confine->window); |
||||||
|
|
||||||
|
cr = cairo_create(surface); |
||||||
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); |
||||||
|
cairo_rectangle(cr, |
||||||
|
allocation.x, |
||||||
|
allocation.y, |
||||||
|
allocation.width, |
||||||
|
allocation.height); |
||||||
|
cairo_set_source_rgba(cr, 0, 0, 0, 0.8); |
||||||
|
cairo_fill(cr); |
||||||
|
|
||||||
|
draw_line(confine, cr, &allocation); |
||||||
|
|
||||||
|
cairo_destroy(cr); |
||||||
|
|
||||||
|
cairo_surface_destroy(surface); |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
keyboard_focus_handler(struct window *window, |
||||||
|
struct input *device, void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
|
||||||
|
window_schedule_redraw(confine->window); |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
key_handler(struct window *window, struct input *input, uint32_t time, |
||||||
|
uint32_t key, uint32_t sym, |
||||||
|
enum wl_keyboard_key_state state, void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
|
||||||
|
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) |
||||||
|
return; |
||||||
|
|
||||||
|
switch (sym) { |
||||||
|
case XKB_KEY_Escape: |
||||||
|
display_exit(confine->display); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
cursor_timeout_reset(struct confine *confine) |
||||||
|
{ |
||||||
|
const long cursor_timeout = 500; |
||||||
|
struct itimerspec its; |
||||||
|
|
||||||
|
its.it_interval.tv_sec = 0; |
||||||
|
its.it_interval.tv_nsec = 0; |
||||||
|
its.it_value.tv_sec = cursor_timeout / 1000; |
||||||
|
its.it_value.tv_nsec = (cursor_timeout % 1000) * 1000 * 1000; |
||||||
|
timerfd_settime(confine->cursor_timeout_fd, 0, &its, NULL); |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
motion_handler(struct widget *widget, |
||||||
|
struct input *input, uint32_t time, |
||||||
|
float x, float y, void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
confine->line.x = x; |
||||||
|
confine->line.y = y; |
||||||
|
|
||||||
|
window_schedule_redraw(confine->window); |
||||||
|
|
||||||
|
cursor_timeout_reset(confine); |
||||||
|
confine->cursor_timeout_input = input; |
||||||
|
|
||||||
|
return CURSOR_BLANK; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
resize_handler(struct widget *widget, |
||||||
|
int32_t width, int32_t height, |
||||||
|
void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
|
||||||
|
confine->reset = 1; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
leave_handler(struct widget *widget, |
||||||
|
struct input *input, void *data) |
||||||
|
{ |
||||||
|
struct confine *confine = data; |
||||||
|
|
||||||
|
confine->reset = 1; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
cursor_timeout_func(struct task *task, uint32_t events) |
||||||
|
{ |
||||||
|
struct confine *confine = |
||||||
|
container_of(task, struct confine, cursor_timeout_task); |
||||||
|
uint64_t exp; |
||||||
|
|
||||||
|
if (read(confine->cursor_timeout_fd, &exp, sizeof (uint64_t)) != |
||||||
|
sizeof(uint64_t)) |
||||||
|
abort(); |
||||||
|
|
||||||
|
input_set_pointer_image(confine->cursor_timeout_input, |
||||||
|
CURSOR_LEFT_PTR); |
||||||
|
} |
||||||
|
|
||||||
|
static struct confine * |
||||||
|
confine_create(struct display *display) |
||||||
|
{ |
||||||
|
struct confine *confine; |
||||||
|
|
||||||
|
confine = xzalloc(sizeof *confine); |
||||||
|
confine->window = window_create(display); |
||||||
|
confine->widget = window_frame_create(confine->window, confine); |
||||||
|
window_set_title(confine->window, "Wayland Confine"); |
||||||
|
confine->display = display; |
||||||
|
confine->buffer = NULL; |
||||||
|
|
||||||
|
window_set_key_handler(confine->window, key_handler); |
||||||
|
window_set_user_data(confine->window, confine); |
||||||
|
window_set_keyboard_focus_handler(confine->window, |
||||||
|
keyboard_focus_handler); |
||||||
|
|
||||||
|
widget_set_redraw_handler(confine->widget, redraw_handler); |
||||||
|
widget_set_motion_handler(confine->widget, motion_handler); |
||||||
|
widget_set_resize_handler(confine->widget, resize_handler); |
||||||
|
widget_set_leave_handler(confine->widget, leave_handler); |
||||||
|
|
||||||
|
widget_schedule_resize(confine->widget, 500, 400); |
||||||
|
confine->line.x = -1; |
||||||
|
confine->line.y = -1; |
||||||
|
confine->line.old_x = -1; |
||||||
|
confine->line.old_y = -1; |
||||||
|
confine->reset = 0; |
||||||
|
|
||||||
|
confine->cursor_timeout_fd = |
||||||
|
timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); |
||||||
|
confine->cursor_timeout_task.run = cursor_timeout_func; |
||||||
|
display_watch_fd(window_get_display(confine->window), |
||||||
|
confine->cursor_timeout_fd, |
||||||
|
EPOLLIN, &confine->cursor_timeout_task); |
||||||
|
|
||||||
|
return confine; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
confine_destroy(struct confine *confine) |
||||||
|
{ |
||||||
|
display_unwatch_fd(window_get_display(confine->window), |
||||||
|
confine->cursor_timeout_fd); |
||||||
|
close(confine->cursor_timeout_fd); |
||||||
|
if (confine->buffer) |
||||||
|
cairo_surface_destroy(confine->buffer); |
||||||
|
widget_destroy(confine->widget); |
||||||
|
window_destroy(confine->window); |
||||||
|
free(confine); |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
struct display *display; |
||||||
|
struct confine *confine; |
||||||
|
|
||||||
|
display = display_create(&argc, argv); |
||||||
|
if (display == NULL) { |
||||||
|
fprintf(stderr, "failed to create display: %m\n"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
confine = confine_create(display); |
||||||
|
|
||||||
|
display_run(display); |
||||||
|
|
||||||
|
confine_destroy(confine); |
||||||
|
display_destroy(display); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Loading…
Reference in new issue