swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit ba0d051b9c19f0c8a382f7854add1b6cb9ce6ede
parent 7c074d1a4ce3e8205f0adb337a3ca1fd061e193b
Author: Michael Forney <mforney@mforney.org>
Date:   Mon,  1 Jul 2013 04:37:34 -0700

Implement copy and paste (data_{device{,_manager},source,offer})

Diffstat:
MMakefile.am | 1+
Adata.c | 174+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adata.h | 39+++++++++++++++++++++++++++++++++++++++
Mdata_device.c | 125++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdata_device.h | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
Mdata_device_manager.c | 38+++++++++++++++++++++++++++++++++-----
Mdata_device_manager.h | 23+++++++++++++++++++++++
Mseat.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mseat.h | 6++++++
9 files changed, 502 insertions(+), 10 deletions(-)

diff --git a/Makefile.am b/Makefile.am @@ -19,6 +19,7 @@ libswc_la_SOURCES = \ seat.c seat.h \ data_device_manager.c data_device_manager.h \ data_device.c data_device.h \ + data.c data.h \ mode.c mode.h \ tty.c tty.h \ evdev_device.c evdev_device.h \ diff --git a/data.c b/data.c @@ -0,0 +1,174 @@ +/* swc: data.c + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 "data.h" +#include "util.h" + +#include <stdlib.h> +#include <string.h> + +struct data +{ + struct wl_array mime_types; + struct wl_resource * source; + struct wl_list offers; +}; + +static void offer_accept(struct wl_client * client, + struct wl_resource * offer, + uint32_t serial, const char * mime_type) +{ + struct data * data = wl_resource_get_user_data(offer); + + /* Protect against expired data_offers being used. */ + if (data) + wl_data_source_send_target(data->source, mime_type); +} + +static void offer_receive(struct wl_client * client, + struct wl_resource * offer, + const char * mime_type, int fd) +{ + struct data * data = wl_resource_get_user_data(offer); + + /* Protect against expired data_offers being used. */ + if (data) + wl_data_source_send_send(data->source, mime_type, fd); +} + +static void offer_destroy(struct wl_client * client, + struct wl_resource * offer) +{ + wl_resource_destroy(offer); +} + +struct wl_data_offer_interface data_offer_implementation = { + .accept = &offer_accept, + .receive = &offer_receive, + .destroy = &offer_destroy +}; + +static void source_offer(struct wl_client * client, + struct wl_resource * source, + const char * mime_type) +{ + struct data * data = wl_resource_get_user_data(source); + char ** destination; + + destination = wl_array_add(&data->mime_types, sizeof *destination); + *destination = strdup(mime_type); +} + +static void source_destroy(struct wl_client * client, + struct wl_resource * source) +{ + wl_resource_destroy(source); +} + +struct wl_data_source_interface data_source_implementation = { + .offer = &source_offer, + .destroy = &source_destroy +}; + +static void data_destroy(struct wl_resource * source) +{ + struct data * data = wl_resource_get_user_data(source); + struct wl_resource * offer; + char ** mime_type; + + wl_array_for_each(mime_type, &data->mime_types) + free(*mime_type); + wl_array_release(&data->mime_types); + + /* After this data_source is destroyed, each of the data_offer objects + * associated with the data_source has a pointer to a free'd struct. We + * can't destroy the resources because this results in a segfault on the + * client when it correctly tries to call data_source.destroy. However, a + * misbehaving client could still attempt to call accept or receive on the + * data_offer, which would crash the server. + * + * So, we clear the user data on each of the offers to protect us. */ + wl_list_for_each(offer, &data->offers, link) + wl_resource_set_user_data(offer, NULL); + + free(data); +} + +static struct data * data_new() +{ + struct data * data; + + data = malloc(sizeof *data); + + if (!data) + return NULL; + + wl_array_init(&data->mime_types); + wl_list_init(&data->offers); + + return data; +} + +struct wl_resource * swc_data_source_new(struct wl_client * client, uint32_t id) +{ + struct data * data; + + data = data_new(); + + if (!data) + return NULL; + + /* Add the data source to the client. */ + data->source = wl_client_add_object(client, &wl_data_source_interface, + &data_source_implementation, id, data); + + /* Destroy the data object when the source disappears. */ + wl_resource_set_destructor(data->source, &data_destroy); + + return data->source; +} + +struct wl_resource * swc_data_offer_new(struct wl_client * client, + struct wl_resource * source) +{ + struct data * data = wl_resource_get_user_data(source); + struct wl_resource * offer; + + offer = wl_client_new_object(client, &wl_data_offer_interface, + &data_offer_implementation, data); + wl_list_insert(&data->offers, wl_resource_get_link(offer)); + wl_resource_set_destructor(offer, &swc_remove_resource); + + return offer; +} + +void swc_data_send_mime_types(struct wl_resource * source, + struct wl_resource * offer) +{ + struct data * data = wl_resource_get_user_data(source); + char ** mime_type; + + wl_array_for_each(mime_type, &data->mime_types) + wl_data_offer_send_offer(offer, *mime_type); +} + diff --git a/data.h b/data.h @@ -0,0 +1,39 @@ +/* swc: data.h + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 SWC_DATA_H +#define SWC_DATA_H 1 + +#include <wayland-server.h> + +struct wl_resource * swc_data_source_new(struct wl_client * client, + uint32_t id); + +struct wl_resource * swc_data_offer_new(struct wl_client * client, + struct wl_resource * source); + +void swc_data_send_mime_types(struct wl_resource * source, + struct wl_resource * offer); + +#endif + diff --git a/data_device.c b/data_device.c @@ -1,16 +1,66 @@ +/* swc: data_device.c + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 "data_device.h" +#include "data.h" +#include "util.h" static void start_drag(struct wl_client * client, struct wl_resource * resource, struct wl_resource * source_resource, struct wl_resource * origin_resource, struct wl_resource * icon_resource, uint32_t serial) { + /* XXX: Implement */ } static void set_selection(struct wl_client * client, struct wl_resource * resource, - struct wl_resource * source_resource, uint32_t serial) + struct wl_resource * data_source, uint32_t serial) { + struct swc_data_device * data_device = wl_resource_get_user_data(resource); + struct swc_event event; + + /* Check if this data source is already the current selection. */ + if (data_source == data_device->selection) + return; + + event.type = SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED; + + if (data_device->selection) + { + wl_data_source_send_cancelled(data_device->selection); + wl_list_remove(&data_device->selection_destroy_listener.link); + } + + data_device->selection = data_source; + + if (data_source) + { + wl_resource_add_destroy_listener + (data_source, &data_device->selection_destroy_listener); + } + + wl_signal_emit(&data_device->event_signal, &event); } struct wl_data_device_interface data_device_implementation = { @@ -18,9 +68,76 @@ struct wl_data_device_interface data_device_implementation = { .set_selection = &set_selection }; -void swc_data_device_new(struct wl_client * client, uint32_t id) +static void handle_selection_destroy(struct wl_listener * listener, void * data) +{ + struct swc_data_device * data_device + = wl_container_of(listener, data_device, selection_destroy_listener); + struct swc_event event; + + event.type = SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED; + data_device->selection = NULL; + wl_signal_emit(&data_device->event_signal, &event); +} + +bool swc_data_device_initialize(struct swc_data_device * data_device) +{ + data_device->selection_destroy_listener.notify = &handle_selection_destroy; + wl_signal_init(&data_device->event_signal); + wl_list_init(&data_device->resources); + + return true; +} + +void swc_data_device_finish(struct swc_data_device * data_device) +{ + struct wl_resource * resource, * tmp; + + wl_list_for_each_safe(resource, tmp, &data_device->resources, link) + wl_resource_destroy(resource); +} + +void swc_data_device_bind(struct swc_data_device * data_device, + struct wl_client * client, uint32_t id) +{ + struct wl_resource * resource; + + resource = wl_client_add_object(client, &wl_data_device_interface, + &data_device_implementation, id, + data_device); + wl_list_insert(&data_device->resources, &resource->link); + wl_resource_set_destructor(resource, &swc_remove_resource); +} + +static struct wl_resource * new_offer(struct wl_resource * resource, + struct wl_client * client, + struct wl_resource * source) +{ + struct wl_resource * offer; + + offer = swc_data_offer_new(client, source); + wl_data_device_send_data_offer(resource, offer); + swc_data_send_mime_types(source, offer); + + return offer; +} + +void swc_data_device_offer_selection(struct swc_data_device * data_device, + struct wl_client * client) { - wl_client_add_object(client, &wl_data_device_interface, - &data_device_implementation, id, NULL); + struct wl_resource * resource; + struct wl_resource * offer; + + /* Look for the client's data_device resource. */ + resource = wl_resource_find_for_client(&data_device->resources, client); + + /* If the client does not have a data device, there is nothing to do. */ + if (!resource) + return; + + /* If we don't have a selection, send NULL to the client. */ + offer = data_device->selection + ? new_offer(resource, client, data_device->selection) : NULL; + + wl_data_device_send_selection(resource, offer); } diff --git a/data_device.h b/data_device.h @@ -1,9 +1,57 @@ +/* swc: data_device.h + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 SWC_DATA_DEVICE_H #define SWC_DATA_DEVICE_H 1 +#include "event.h" + +#include <stdbool.h> #include <wayland-server.h> -void swc_data_device_new(struct wl_client * client, uint32_t id); +enum swc_data_device_event_type +{ + SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED +}; + +struct swc_data_device +{ + /* The data source corresponding to the current selection. */ + struct wl_resource * selection; + struct wl_listener selection_destroy_listener; + + struct wl_signal event_signal; + struct wl_list resources; +}; + +bool swc_data_device_initialize(struct swc_data_device * data_device); +void swc_data_device_finish(struct swc_data_device * data_device); + +void swc_data_device_bind(struct swc_data_device * data_device, + struct wl_client * client, uint32_t id); + +void swc_data_device_offer_selection(struct swc_data_device * data_device, + struct wl_client * client); #endif diff --git a/data_device_manager.c b/data_device_manager.c @@ -1,11 +1,40 @@ +/* swc: data_device_manager.c + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 "data_device_manager.h" #include "data_device.h" - -#include <stdio.h> +#include "data.h" +#include "seat.h" static void create_data_source(struct wl_client * client, struct wl_resource * resource, uint32_t id) { + struct wl_resource * data_source; + + data_source = swc_data_source_new(client, id); + + if (!data_source) + wl_resource_post_no_memory(resource); } static void get_data_device(struct wl_client * client, @@ -14,10 +43,9 @@ static void get_data_device(struct wl_client * client, { struct swc_seat * seat = wl_resource_get_user_data(seat_resource); - printf("get_data_device\n"); + printf("data_device_manager.get_data_device\n"); - // TODO: keep track of resource? - swc_data_device_new(client, id); + swc_data_device_bind(&seat->data_device, client, id); } static struct wl_data_device_manager_interface diff --git a/data_device_manager.h b/data_device_manager.h @@ -1,3 +1,26 @@ +/* swc: data_device_manager.h + * + * Copyright (c) 2013 Michael Forney + * + * 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 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 SWC_DATA_DEVICE_MANAGER_H #define SWC_DATA_DEVICE_MANAGER_H 1 diff --git a/seat.c b/seat.c @@ -156,6 +156,48 @@ static void handle_evdev_event(struct wl_listener * listener, void * data) } } +static void handle_keyboard_focus_event(struct wl_listener * listener, + void * data) +{ + struct swc_seat * seat + = wl_container_of(listener, seat, keyboard_focus_listener); + struct swc_event * event = data; + struct swc_input_focus_event_data * event_data = event->data; + + switch (event->type) + { + case SWC_INPUT_FOCUS_EVENT_CHANGED: + if (event_data->new) + { + struct wl_client * client + = wl_resource_get_client(event_data->new->resource); + + /* Offer the selection to the new focus. */ + swc_data_device_offer_selection(&seat->data_device, client); + } + break; + } +} + +static void handle_data_device_event(struct wl_listener * listener, void * data) +{ + struct swc_seat * seat + = wl_container_of(listener, seat, data_device_listener); + struct swc_event * event = data; + + switch (event->type) + { + case SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED: + if (seat->keyboard.focus.resource) + { + struct wl_client * client + = wl_resource_get_client(seat->keyboard.focus.resource); + swc_data_device_offer_selection(&seat->data_device, client); + } + break; + } +} + /* Wayland Seat Interface */ static void get_pointer(struct wl_client * client, struct wl_resource * resource, uint32_t id) @@ -260,6 +302,8 @@ static void add_device(struct swc_seat * seat, struct udev_device * udev_device) { printf("initializing keyboard\n"); swc_keyboard_initialize(&seat->keyboard); + wl_signal_add(&seat->keyboard.focus.event_signal, + &seat->keyboard_focus_listener); seat->capabilities |= WL_SEAT_CAPABILITY_KEYBOARD; update_capabilities(seat); } @@ -274,6 +318,8 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev, { seat->name = strdup(seat_name); seat->capabilities = 0; + seat->keyboard_focus_listener.notify = &handle_keyboard_focus_event; + seat->data_device_listener.notify = &handle_data_device_event; if (!swc_xkb_initialize(&seat->xkb)) { @@ -281,6 +327,14 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev, goto error_name; } + if (!swc_data_device_initialize(&seat->data_device)) + { + printf("could not initialize data device\n"); + goto error_xkb; + } + + wl_signal_add(&seat->data_device.event_signal, &seat->data_device_listener); + wl_list_init(&seat->resources); wl_signal_init(&seat->destroy_signal); wl_list_init(&seat->devices); @@ -288,6 +342,8 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev, return true; + error_xkb: + swc_xkb_finish(&seat->xkb); error_name: free(seat->name); error_base: diff --git a/seat.h b/seat.h @@ -2,6 +2,7 @@ #define SWC_SEAT_H 1 #include "xkb.h" +#include "data_device.h" #include "keyboard.h" #include "pointer.h" @@ -20,7 +21,12 @@ struct swc_seat struct wl_list resources; struct wl_signal destroy_signal; + struct swc_data_device data_device; + struct wl_listener data_device_listener; + struct swc_keyboard keyboard; + struct wl_listener keyboard_focus_listener; + struct swc_pointer pointer; struct wl_list devices;