First attempt at selection support
authorKristian Høgsberg <krh@bitplanet.net>
Tue, 18 Jan 2011 14:08:53 +0000 (09:08 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 19 Jan 2011 19:25:12 +0000 (14:25 -0500)
compositor/compositor.c
compositor/compositor.h
compositor/shell.c
protocol/wayland.xml
wayland/wayland-server.h

index 31f70cf..72a3878 100644 (file)
@@ -682,6 +682,10 @@ notify_button(struct wl_input_device *device,
        if (state && device->grab == NULL) {
                wlsc_surface_raise(surface);
 
+               if (wd->selection)
+                       wlsc_selection_set_focus(wd->selection,
+                                                &surface->surface, time);
+
                wl_input_device_start_grab(device,
                                           &device->motion_grab,
                                           button, time);
index 6ca7242..ac826ed 100644 (file)
@@ -69,6 +69,7 @@ struct wlsc_input_device {
        int32_t hotspot_x, hotspot_y;
        struct wl_list link;
        uint32_t modifier_state;
+       struct wl_selection *selection;
 };
 
 struct wlsc_drm {
@@ -165,6 +166,10 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device,
 struct wlsc_surface *
 pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy);
 
+void
+wlsc_selection_set_focus(struct wl_selection *selection,
+                        struct wl_surface *surface, uint32_t time);
+
 uint32_t
 get_time(void);
 
index a0331e2..d50a3d6 100644 (file)
@@ -207,11 +207,6 @@ shell_resize(struct wl_client *client, struct wl_shell *shell,
 }
 
 static void
-wl_drag_set_pointer_focus(struct wl_drag *drag,
-                         struct wl_surface *surface, uint32_t time,
-                         int32_t x, int32_t y, int32_t sx, int32_t sy);
-
-static void
 destroy_drag(struct wl_resource *resource, struct wl_client *client)
 {
        struct wl_drag *drag =
@@ -458,10 +453,176 @@ shell_create_drag(struct wl_client *client,
        wl_client_add_resource(client, &drag->resource);
 }
 
+void
+wlsc_selection_set_focus(struct wl_selection *selection,
+                        struct wl_surface *surface, uint32_t time)
+{
+       char **p, **end;
+
+       if (selection->selection_focus == surface)
+               return;
+
+       if (selection->selection_focus != NULL)
+               wl_client_post_event(selection->selection_focus->client,
+                                    &selection->selection_offer.object,
+                                    WL_SELECTION_OFFER_KEYBOARD_FOCUS,
+                                    NULL);
+
+       if (surface) {
+               wl_client_post_global(surface->client,
+                                     &selection->selection_offer.object);
+
+               end = selection->types.data + selection->types.size;
+               for (p = selection->types.data; p < end; p++)
+                       wl_client_post_event(surface->client,
+                                            &selection->selection_offer.object,
+                                            WL_SELECTION_OFFER_OFFER, *p);
+
+               wl_list_remove(&selection->selection_focus_listener.link);
+               wl_list_insert(surface->destroy_listener_list.prev,
+                              &selection->selection_focus_listener.link);
+
+               wl_client_post_event(surface->client,
+                                    &selection->selection_offer.object,
+                                    WL_SELECTION_OFFER_KEYBOARD_FOCUS,
+                                    selection->input_device);
+       }
+
+       selection->selection_focus = surface;
+
+       wl_list_remove(&selection->selection_focus_listener.link);
+       if (surface)
+               wl_list_insert(surface->destroy_listener_list.prev,
+                              &selection->selection_focus_listener.link);
+}
+
+static void
+selection_offer_receive(struct wl_client *client,
+                       struct wl_selection_offer *offer,
+                       const char *mime_type, int fd)
+{
+       struct wl_selection *selection =
+               container_of(offer, struct wl_selection, selection_offer);
+
+       wl_client_post_event(selection->client,
+                            &selection->resource.object,
+                            WL_SELECTION_SEND, mime_type, fd);
+       close(fd);
+}
+
+static const struct wl_selection_offer_interface selection_offer_interface = {
+       selection_offer_receive
+};
+
+static void
+selection_offer(struct wl_client *client,
+               struct wl_selection *selection, const char *type)
+{
+       char **p;
+
+       p = wl_array_add(&selection->types, sizeof *p);
+       if (p)
+               *p = strdup(type);
+       if (!p || !*p)
+               wl_client_post_no_memory(client);
+}
+
+static void
+selection_activate(struct wl_client *client,
+                  struct wl_selection *selection,
+                  struct wl_input_device *device, uint32_t time)
+{
+       struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
+       struct wl_display *display = wl_client_get_display (client);
+
+       selection->input_device = device;
+
+       selection->selection_offer.object.interface =
+               &wl_selection_offer_interface;
+       selection->selection_offer.object.implementation =
+               (void (**)(void)) &selection_offer_interface;
+
+       wl_display_add_object(display, &selection->selection_offer.object);
+
+       if (wd->selection) {
+               wl_client_post_event(wd->selection->client,
+                                    &wd->selection->resource.object,
+                                    WL_SELECTION_CANCELLED);
+       }
+       wd->selection = selection;
+
+       wlsc_selection_set_focus(selection, device->keyboard_focus, time);
+}
+
+static void
+selection_destroy(struct wl_client *client, struct wl_selection *selection)
+{
+       wl_resource_destroy(&selection->resource, client);
+}
+
+static const struct wl_selection_interface selection_interface = {
+       selection_offer,
+       selection_activate,
+       selection_destroy
+};
+
+static void
+destroy_selection(struct wl_resource *resource, struct wl_client *client)
+{
+       struct wl_selection *selection =
+               container_of(resource, struct wl_selection, resource);
+       struct wlsc_input_device *wd =
+               (struct wlsc_input_device *) selection->input_device;
+
+       if (wd && wd->selection == selection) {
+               wd->selection = NULL;
+               wlsc_selection_set_focus(selection, NULL, get_time());
+       }
+
+       wl_list_remove(&selection->selection_focus_listener.link);
+       free(selection);
+}
+
+static void
+selection_handle_surface_destroy(struct wl_listener *listener,
+                                struct wl_surface *surface, uint32_t time)
+{
+}
+
+static void
+shell_create_selection(struct wl_client *client,
+                      struct wl_shell *shell, uint32_t id)
+{
+       struct wl_selection *selection;
+
+       selection = malloc(sizeof *selection);
+       if (selection == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       memset(selection, 0, sizeof *selection);
+       selection->resource.object.id = id;
+       selection->resource.object.interface = &wl_selection_interface;
+       selection->resource.object.implementation =
+               (void (**)(void)) &selection_interface;
+
+       selection->client = client;
+       selection->resource.destroy = destroy_selection;
+       selection->selection_focus = NULL;
+
+       selection->selection_focus_listener.func =
+               selection_handle_surface_destroy;
+       wl_list_init(&selection->selection_focus_listener.link);
+
+       wl_client_add_resource(client, &selection->resource);
+}
+
 const static struct wl_shell_interface shell_interface = {
        shell_move,
        shell_resize,
-       shell_create_drag
+       shell_create_drag,
+       shell_create_selection
 };
 
 int
index 8799a64..75ccb5b 100644 (file)
       <arg name="id" type="new_id" interface="drag"/>
     </request>
 
+    <request name="create_selection">
+      <arg name="id" type="new_id" interface="selection"/>
+    </request>
+
     <!-- The configure event asks the client to resize its surface.
          The size is a hint, in the sense that the client is free to
          ignore it if it doesn't resize, pick a smaller size (to
     </event>
   </interface>
 
+  <interface name="selection" version="1">
+    <!-- Add an offered mime type.  Can be called several times to
+         offer multiple types, but must be called before 'activate'. -->
+    <request name="offer">
+      <arg name="type" type="string"/>
+    </request>
+
+    <!-- Can the selection be activated for multiple devices? -->
+    <request name="activate">
+      <arg name="input_device" type="object" interface="input_device"/>
+      <arg name="time" type="uint"/>
+    </request>
+
+    <!-- Destroy the selection. -->
+    <request name="destroy" type="destructor"/>
+
+    <!-- Another client pasted the selection, send the mime-type over
+         the passed fd. -->
+    <event name="send">
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </event>
+
+    <!-- Another selection became active. -->
+    <event name="cancelled"/>
+  </interface>
+
+  <interface name="selection_offer" version="1">
+    <!-- Called to receive the selection data as the specified type.
+         Sends the pipe fd to the compositor, which forwards it to the
+         source in the 'send' event -->
+    <request name="receive">
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </request>
+
+    <!-- Sent before the keyboard_focus event to announce the types
+         offered.  One event per offered mime type.  A mime type of
+         NULL means the selection offer is going away.  -->
+    <event name="offer">
+      <arg name="type" type="string"/>
+    </event>
+
+    <event name="keyboard_focus">
+      <arg name="input_device" type="object" interface="input_device"/>
+    </event>
+  </interface>
 
   <interface name="drag" version="1">
     <!-- Add an offered mime type.  Can be called several times to
index 9666158..f74cbae 100644 (file)
@@ -188,6 +188,21 @@ struct wl_drag {
        struct wl_listener drag_focus_listener;
 };
 
+struct wl_selection_offer {
+       struct wl_object object;
+};
+
+struct wl_selection {
+       struct wl_resource resource;
+       struct wl_client *client;
+       struct wl_input_device *input_device;
+       struct wl_selection_offer selection_offer;
+       struct wl_surface *selection_focus;
+       struct wl_client *target;
+       struct wl_array types;
+       struct wl_listener selection_focus_listener;
+};
+
 void
 wl_client_post_event(struct wl_client *client,
                      struct wl_object *sender,