commit ba0d051

Michael Forney  ·  2013-07-01 11:37:34 +0000 UTC
parent 7c074d1
Implement copy and paste (data_{device{,_manager},source,offer})
9 files changed,  +502, -10
A data.c
A data.h
M seat.c
M seat.h
+1, -0
1@@ -19,6 +19,7 @@ libswc_la_SOURCES = \
2 	seat.c seat.h \
3 	data_device_manager.c data_device_manager.h \
4 	data_device.c data_device.h \
5+	data.c data.h \
6 	mode.c mode.h \
7 	tty.c tty.h \
8 	evdev_device.c evdev_device.h \
A data.c
+174, -0
  1@@ -0,0 +1,174 @@
  2+/* swc: data.c
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25+#include "data.h"
 26+#include "util.h"
 27+
 28+#include <stdlib.h>
 29+#include <string.h>
 30+
 31+struct data
 32+{
 33+    struct wl_array mime_types;
 34+    struct wl_resource * source;
 35+    struct wl_list offers;
 36+};
 37+
 38+static void offer_accept(struct wl_client * client,
 39+                         struct wl_resource * offer,
 40+                         uint32_t serial, const char * mime_type)
 41+{
 42+    struct data * data = wl_resource_get_user_data(offer);
 43+
 44+    /* Protect against expired data_offers being used. */
 45+    if (data)
 46+        wl_data_source_send_target(data->source, mime_type);
 47+}
 48+
 49+static void offer_receive(struct wl_client * client,
 50+                          struct wl_resource * offer,
 51+                          const char * mime_type, int fd)
 52+{
 53+    struct data * data = wl_resource_get_user_data(offer);
 54+
 55+    /* Protect against expired data_offers being used. */
 56+    if (data)
 57+        wl_data_source_send_send(data->source, mime_type, fd);
 58+}
 59+
 60+static void offer_destroy(struct wl_client * client,
 61+                          struct wl_resource * offer)
 62+{
 63+    wl_resource_destroy(offer);
 64+}
 65+
 66+struct wl_data_offer_interface data_offer_implementation = {
 67+    .accept = &offer_accept,
 68+    .receive = &offer_receive,
 69+    .destroy = &offer_destroy
 70+};
 71+
 72+static void source_offer(struct wl_client * client,
 73+                         struct wl_resource * source,
 74+                         const char * mime_type)
 75+{
 76+    struct data * data = wl_resource_get_user_data(source);
 77+    char ** destination;
 78+
 79+    destination = wl_array_add(&data->mime_types, sizeof *destination);
 80+    *destination = strdup(mime_type);
 81+}
 82+
 83+static void source_destroy(struct wl_client * client,
 84+                           struct wl_resource * source)
 85+{
 86+    wl_resource_destroy(source);
 87+}
 88+
 89+struct wl_data_source_interface data_source_implementation = {
 90+    .offer = &source_offer,
 91+    .destroy = &source_destroy
 92+};
 93+
 94+static void data_destroy(struct wl_resource * source)
 95+{
 96+    struct data * data = wl_resource_get_user_data(source);
 97+    struct wl_resource * offer;
 98+    char ** mime_type;
 99+
100+    wl_array_for_each(mime_type, &data->mime_types)
101+        free(*mime_type);
102+    wl_array_release(&data->mime_types);
103+
104+    /* After this data_source is destroyed, each of the data_offer objects
105+     * associated with the data_source has a pointer to a free'd struct. We
106+     * can't destroy the resources because this results in a segfault on the
107+     * client when it correctly tries to call data_source.destroy. However, a
108+     * misbehaving client could still attempt to call accept or receive on the
109+     * data_offer, which would crash the server.
110+     *
111+     * So, we clear the user data on each of the offers to protect us. */
112+    wl_list_for_each(offer, &data->offers, link)
113+        wl_resource_set_user_data(offer, NULL);
114+
115+    free(data);
116+}
117+
118+static struct data * data_new()
119+{
120+    struct data * data;
121+
122+    data = malloc(sizeof *data);
123+
124+    if (!data)
125+        return NULL;
126+
127+    wl_array_init(&data->mime_types);
128+    wl_list_init(&data->offers);
129+
130+    return data;
131+}
132+
133+struct wl_resource * swc_data_source_new(struct wl_client * client, uint32_t id)
134+{
135+    struct data * data;
136+
137+    data = data_new();
138+
139+    if (!data)
140+        return NULL;
141+
142+    /* Add the data source to the client. */
143+    data->source = wl_client_add_object(client, &wl_data_source_interface,
144+                                        &data_source_implementation, id, data);
145+
146+    /* Destroy the data object when the source disappears. */
147+    wl_resource_set_destructor(data->source, &data_destroy);
148+
149+    return data->source;
150+}
151+
152+struct wl_resource * swc_data_offer_new(struct wl_client * client,
153+                                        struct wl_resource * source)
154+{
155+    struct data * data = wl_resource_get_user_data(source);
156+    struct wl_resource * offer;
157+
158+    offer = wl_client_new_object(client, &wl_data_offer_interface,
159+                                 &data_offer_implementation, data);
160+    wl_list_insert(&data->offers, wl_resource_get_link(offer));
161+    wl_resource_set_destructor(offer, &swc_remove_resource);
162+
163+    return offer;
164+}
165+
166+void swc_data_send_mime_types(struct wl_resource * source,
167+                              struct wl_resource * offer)
168+{
169+    struct data * data = wl_resource_get_user_data(source);
170+    char ** mime_type;
171+
172+    wl_array_for_each(mime_type, &data->mime_types)
173+        wl_data_offer_send_offer(offer, *mime_type);
174+}
175+
A data.h
+39, -0
 1@@ -0,0 +1,39 @@
 2+/* swc: data.h
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef SWC_DATA_H
26+#define SWC_DATA_H 1
27+
28+#include <wayland-server.h>
29+
30+struct wl_resource * swc_data_source_new(struct wl_client * client,
31+                                         uint32_t id);
32+
33+struct wl_resource * swc_data_offer_new(struct wl_client * client,
34+                                        struct wl_resource * source);
35+
36+void swc_data_send_mime_types(struct wl_resource * source,
37+                              struct wl_resource * offer);
38+
39+#endif
40+
+121, -4
  1@@ -1,16 +1,66 @@
  2+/* swc: data_device.c
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25 #include "data_device.h"
 26+#include "data.h"
 27+#include "util.h"
 28 
 29 static void start_drag(struct wl_client * client, struct wl_resource * resource,
 30                        struct wl_resource * source_resource,
 31                        struct wl_resource * origin_resource,
 32                        struct wl_resource * icon_resource, uint32_t serial)
 33 {
 34+    /* XXX: Implement */
 35 }
 36 
 37 static void set_selection(struct wl_client * client,
 38                           struct wl_resource * resource,
 39-                          struct wl_resource * source_resource, uint32_t serial)
 40+                          struct wl_resource * data_source, uint32_t serial)
 41 {
 42+    struct swc_data_device * data_device = wl_resource_get_user_data(resource);
 43+    struct swc_event event;
 44+
 45+    /* Check if this data source is already the current selection. */
 46+    if (data_source == data_device->selection)
 47+        return;
 48+
 49+    event.type = SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED;
 50+
 51+    if (data_device->selection)
 52+    {
 53+        wl_data_source_send_cancelled(data_device->selection);
 54+        wl_list_remove(&data_device->selection_destroy_listener.link);
 55+    }
 56+
 57+    data_device->selection = data_source;
 58+
 59+    if (data_source)
 60+    {
 61+        wl_resource_add_destroy_listener
 62+            (data_source, &data_device->selection_destroy_listener);
 63+    }
 64+
 65+    wl_signal_emit(&data_device->event_signal, &event);
 66 }
 67 
 68 struct wl_data_device_interface data_device_implementation = {
 69@@ -18,9 +68,76 @@ struct wl_data_device_interface data_device_implementation = {
 70     .set_selection = &set_selection
 71 };
 72 
 73-void swc_data_device_new(struct wl_client * client, uint32_t id)
 74+static void handle_selection_destroy(struct wl_listener * listener, void * data)
 75+{
 76+    struct swc_data_device * data_device
 77+        = wl_container_of(listener, data_device, selection_destroy_listener);
 78+    struct swc_event event;
 79+
 80+    event.type = SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED;
 81+    data_device->selection = NULL;
 82+    wl_signal_emit(&data_device->event_signal, &event);
 83+}
 84+
 85+bool swc_data_device_initialize(struct swc_data_device * data_device)
 86+{
 87+    data_device->selection_destroy_listener.notify = &handle_selection_destroy;
 88+    wl_signal_init(&data_device->event_signal);
 89+    wl_list_init(&data_device->resources);
 90+
 91+    return true;
 92+}
 93+
 94+void swc_data_device_finish(struct swc_data_device * data_device)
 95+{
 96+    struct wl_resource * resource, * tmp;
 97+
 98+    wl_list_for_each_safe(resource, tmp, &data_device->resources, link)
 99+        wl_resource_destroy(resource);
100+}
101+
102+void swc_data_device_bind(struct swc_data_device * data_device,
103+                          struct wl_client * client, uint32_t id)
104+{
105+    struct wl_resource * resource;
106+
107+    resource = wl_client_add_object(client, &wl_data_device_interface,
108+                                    &data_device_implementation, id,
109+                                    data_device);
110+    wl_list_insert(&data_device->resources, &resource->link);
111+    wl_resource_set_destructor(resource, &swc_remove_resource);
112+}
113+
114+static struct wl_resource * new_offer(struct wl_resource * resource,
115+                                      struct wl_client * client,
116+                                      struct wl_resource * source)
117+{
118+    struct wl_resource * offer;
119+
120+    offer = swc_data_offer_new(client, source);
121+    wl_data_device_send_data_offer(resource, offer);
122+    swc_data_send_mime_types(source, offer);
123+
124+    return offer;
125+}
126+
127+void swc_data_device_offer_selection(struct swc_data_device * data_device,
128+                                     struct wl_client * client)
129 {
130-    wl_client_add_object(client, &wl_data_device_interface,
131-                         &data_device_implementation, id, NULL);
132+    struct wl_resource * resource;
133+    struct wl_resource * offer;
134+
135+    /* Look for the client's data_device resource. */
136+    resource = wl_resource_find_for_client(&data_device->resources, client);
137+
138+    /* If the client does not have a data device, there is nothing to do. */
139+    if (!resource)
140+        return;
141+
142+    /* If we don't have a selection, send NULL to the client. */
143+    offer = data_device->selection
144+        ? new_offer(resource, client, data_device->selection) : NULL;
145+
146+    wl_data_device_send_selection(resource, offer);
147 }
148 
+49, -1
 1@@ -1,9 +1,57 @@
 2+/* swc: data_device.h
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25 #ifndef SWC_DATA_DEVICE_H
26 #define SWC_DATA_DEVICE_H 1
27 
28+#include "event.h"
29+
30+#include <stdbool.h>
31 #include <wayland-server.h>
32 
33-void swc_data_device_new(struct wl_client * client, uint32_t id);
34+enum swc_data_device_event_type
35+{
36+    SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED
37+};
38+
39+struct swc_data_device
40+{
41+    /* The data source corresponding to the current selection. */
42+    struct wl_resource * selection;
43+    struct wl_listener selection_destroy_listener;
44+
45+    struct wl_signal event_signal;
46+    struct wl_list resources;
47+};
48+
49+bool swc_data_device_initialize(struct swc_data_device * data_device);
50+void swc_data_device_finish(struct swc_data_device * data_device);
51+
52+void swc_data_device_bind(struct swc_data_device * data_device,
53+                          struct wl_client * client, uint32_t id);
54+
55+void swc_data_device_offer_selection(struct swc_data_device * data_device,
56+                                     struct wl_client * client);
57 
58 #endif
59 
+33, -5
 1@@ -1,11 +1,40 @@
 2+/* swc: data_device_manager.c
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25 #include "data_device_manager.h"
26 #include "data_device.h"
27-
28-#include <stdio.h>
29+#include "data.h"
30+#include "seat.h"
31 
32 static void create_data_source(struct wl_client * client,
33                                struct wl_resource * resource, uint32_t id)
34 {
35+    struct wl_resource * data_source;
36+
37+    data_source = swc_data_source_new(client, id);
38+
39+    if (!data_source)
40+        wl_resource_post_no_memory(resource);
41 }
42 
43 static void get_data_device(struct wl_client * client,
44@@ -14,10 +43,9 @@ static void get_data_device(struct wl_client * client,
45 {
46     struct swc_seat * seat = wl_resource_get_user_data(seat_resource);
47 
48-    printf("get_data_device\n");
49+    printf("data_device_manager.get_data_device\n");
50 
51-    // TODO: keep track of resource?
52-    swc_data_device_new(client, id);
53+    swc_data_device_bind(&seat->data_device, client, id);
54 }
55 
56 static struct wl_data_device_manager_interface
+23, -0
 1@@ -1,3 +1,26 @@
 2+/* swc: data_device_manager.h
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25 #ifndef SWC_DATA_DEVICE_MANAGER_H
26 #define SWC_DATA_DEVICE_MANAGER_H 1
27 
M seat.c
+56, -0
 1@@ -156,6 +156,48 @@ static void handle_evdev_event(struct wl_listener * listener, void * data)
 2     }
 3 }
 4 
 5+static void handle_keyboard_focus_event(struct wl_listener * listener,
 6+                                        void * data)
 7+{
 8+    struct swc_seat * seat
 9+        = wl_container_of(listener, seat, keyboard_focus_listener);
10+    struct swc_event * event = data;
11+    struct swc_input_focus_event_data * event_data = event->data;
12+
13+    switch (event->type)
14+    {
15+        case SWC_INPUT_FOCUS_EVENT_CHANGED:
16+            if (event_data->new)
17+            {
18+                struct wl_client * client
19+                    = wl_resource_get_client(event_data->new->resource);
20+
21+                /* Offer the selection to the new focus. */
22+                swc_data_device_offer_selection(&seat->data_device, client);
23+            }
24+            break;
25+    }
26+}
27+
28+static void handle_data_device_event(struct wl_listener * listener, void * data)
29+{
30+    struct swc_seat * seat
31+        = wl_container_of(listener, seat, data_device_listener);
32+    struct swc_event * event = data;
33+
34+    switch (event->type)
35+    {
36+        case SWC_DATA_DEVICE_EVENT_SELECTION_CHANGED:
37+            if (seat->keyboard.focus.resource)
38+            {
39+                struct wl_client * client
40+                    = wl_resource_get_client(seat->keyboard.focus.resource);
41+                swc_data_device_offer_selection(&seat->data_device, client);
42+            }
43+            break;
44+    }
45+}
46+
47 /* Wayland Seat Interface */
48 static void get_pointer(struct wl_client * client, struct wl_resource * resource,
49                         uint32_t id)
50@@ -260,6 +302,8 @@ static void add_device(struct swc_seat * seat, struct udev_device * udev_device)
51     {
52         printf("initializing keyboard\n");
53         swc_keyboard_initialize(&seat->keyboard);
54+        wl_signal_add(&seat->keyboard.focus.event_signal,
55+                      &seat->keyboard_focus_listener);
56         seat->capabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
57         update_capabilities(seat);
58     }
59@@ -274,6 +318,8 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev,
60 {
61     seat->name = strdup(seat_name);
62     seat->capabilities = 0;
63+    seat->keyboard_focus_listener.notify = &handle_keyboard_focus_event;
64+    seat->data_device_listener.notify = &handle_data_device_event;
65 
66     if (!swc_xkb_initialize(&seat->xkb))
67     {
68@@ -281,6 +327,14 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev,
69         goto error_name;
70     }
71 
72+    if (!swc_data_device_initialize(&seat->data_device))
73+    {
74+        printf("could not initialize data device\n");
75+        goto error_xkb;
76+    }
77+
78+    wl_signal_add(&seat->data_device.event_signal, &seat->data_device_listener);
79+
80     wl_list_init(&seat->resources);
81     wl_signal_init(&seat->destroy_signal);
82     wl_list_init(&seat->devices);
83@@ -288,6 +342,8 @@ bool swc_seat_initialize(struct swc_seat * seat, struct udev * udev,
84 
85     return true;
86 
87+  error_xkb:
88+    swc_xkb_finish(&seat->xkb);
89   error_name:
90     free(seat->name);
91   error_base:
M seat.h
+6, -0
 1@@ -2,6 +2,7 @@
 2 #define SWC_SEAT_H 1
 3 
 4 #include "xkb.h"
 5+#include "data_device.h"
 6 #include "keyboard.h"
 7 #include "pointer.h"
 8 
 9@@ -20,7 +21,12 @@ struct swc_seat
10     struct wl_list resources;
11     struct wl_signal destroy_signal;
12 
13+    struct swc_data_device data_device;
14+    struct wl_listener data_device_listener;
15+
16     struct swc_keyboard keyboard;
17+    struct wl_listener keyboard_focus_listener;
18+
19     struct swc_pointer pointer;
20 
21     struct wl_list devices;