Add proof-of-concept selection support to terminal
authorKristian Høgsberg <krh@bitplanet.net>
Wed, 19 Jan 2011 19:27:42 +0000 (14:27 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 19 Jan 2011 19:27:42 +0000 (14:27 -0500)
Next will be to support mouse selections so we can copy and paste
something more interesting than just 'selection data'.

clients/terminal.c
clients/window.c
clients/window.h

index a89a5bf..ab9bdb3 100644 (file)
@@ -390,6 +390,11 @@ struct terminal {
        struct terminal_color color_table[256];
        cairo_font_extents_t extents;
        cairo_scaled_font_t *font_normal, *font_bold;
+
+       uint32_t tag;
+       struct wl_selection *selection;
+       struct wl_selection_offer *selection_offer;
+       uint32_t selection_offer_has_text;
 };
 
 /* Create default tab stops, every 8 characters */
@@ -1872,6 +1877,88 @@ terminal_data(struct terminal *terminal, const char *data, size_t length)
 }
 
 static void
+selection_listener_send(void *data, struct wl_selection *selection,
+                       const char *mime_type, int fd)
+{
+       struct terminal *terminal = data;
+       static const char msg[] = "selection data";
+
+       fprintf(stderr, "selection send, fd is %d\n", fd);
+       write(fd, msg, sizeof msg);
+       close(fd);
+}
+
+static void
+selection_listener_cancelled(void *data, struct wl_selection *selection)
+{
+       struct terminal *terminal = data;
+
+       fprintf(stderr, "selection cancelled\n");
+       wl_selection_destroy(selection);
+}
+
+static const struct wl_selection_listener selection_listener = {
+       selection_listener_send,
+       selection_listener_cancelled
+};
+
+static gboolean
+selection_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+       struct terminal *terminal = data;
+       char buffer[256];
+       unsigned int len;
+       int fd;
+
+       fd = g_io_channel_unix_get_fd(source);
+       len = read(fd, buffer, sizeof buffer);
+       fprintf(stderr, "read %d bytes: %.*s\n", len, len, buffer);
+
+       close(fd);
+       g_source_remove(terminal->tag);
+
+       g_io_channel_unref(source);
+
+       return TRUE;
+}
+
+static int
+handle_bound_key(struct terminal *terminal,
+                struct input *input, uint32_t sym, uint32_t time)
+{
+       struct wl_shell *shell;
+       GIOChannel *channel;
+       int fd;
+
+       switch (sym) {
+       case XK_C:
+               shell = display_get_shell(terminal->display);
+               terminal->selection = wl_shell_create_selection(shell);
+               wl_selection_add_listener(terminal->selection,
+                                         &selection_listener, terminal);
+               wl_selection_offer(terminal->selection, "text/plain");
+               wl_selection_activate(terminal->selection,
+                                     input_get_input_device(input), time);
+
+               return 1;
+       case XK_V:
+               if (input_offers_mime_type(input, "text/plain")) {
+                       fd = input_receive_mime_type(input, "text/plain");
+                       channel = g_io_channel_unix_new(fd);
+                       terminal->tag = g_io_add_watch(channel, G_IO_IN,
+                                                      selection_io_func,
+                                                      terminal);
+               }
+
+               return 1;
+       case XK_X:
+               /* cut selection; terminal doesn't do cut */
+               return 0;
+       default:
+               return 0;
+       }
+}
+
 static void
 key_handler(struct window *window, struct input *input, uint32_t time,
            uint32_t key, uint32_t sym, uint32_t state, void *data)
index f05405e..bd7d392 100644 (file)
@@ -118,6 +118,7 @@ struct input {
        struct wl_input_device *input_device;
        struct window *pointer_focus;
        struct window *keyboard_focus;
+       struct selection_offer *offer;
        uint32_t current_pointer_image;
        uint32_t modifiers;
        int32_t x, y, sx, sy;
@@ -1317,6 +1318,117 @@ display_add_input(struct display *d, uint32_t id)
        wl_input_device_set_user_data(input->input_device, input);
 }
 
+struct selection_offer {
+       struct display *display;
+       struct wl_selection_offer *offer;
+       struct wl_array types;
+       struct input *input;
+};
+
+int
+input_offers_mime_type(struct input *input, const char *type)
+{
+       struct selection_offer *offer = input->offer;
+       char **p, **end;
+
+       if (offer == NULL)
+               return 0;
+
+       end = offer->types.data + offer->types.size;
+       for (p = offer->types.data; p < end; p++)
+               if (strcmp(*p, type) == 0)
+                       return 1;
+
+       return 0;
+}
+
+int
+input_receive_mime_type(struct input *input, const char *type)
+{
+       struct selection_offer *offer = input->offer;
+       int p[2];
+
+       pipe(p);
+       /* FIXME: A number of things can go wrong here: the object may
+        * not be the current selection offer any more (which could
+        * still work, but the source may have gone away or just
+        * destroyed its wl_selection) or the offer may not have the
+        * requested type after all (programmer/client error,
+        * typically) */
+       wl_selection_offer_receive(offer->offer, type, p[1]);
+       close(p[1]);
+
+       return p[0];
+}
+
+static void
+selection_offer_offer(void *data,
+                     struct wl_selection_offer *selection_offer,
+                     const char *type)
+{
+       struct selection_offer *offer = data;
+
+       char **p;
+
+       p = wl_array_add(&offer->types, sizeof *p);
+       if (p)
+               *p = strdup(type);
+};
+
+static void
+selection_offer_keyboard_focus(void *data,
+                              struct wl_selection_offer *selection_offer,
+                              struct wl_input_device *input_device)
+{
+       struct selection_offer *offer = data;
+       struct input *input;
+       char **p, **end;
+
+       if (input_device == NULL) {
+               printf("selection offer retracted %p\n", selection_offer);
+               input = offer->input;
+               input->offer = NULL;
+               wl_selection_offer_destroy(selection_offer);
+               wl_array_release(&offer->types);
+               free(offer);
+               return;
+       }
+
+       input = wl_input_device_get_user_data(input_device);
+       printf("new selection offer %p:", selection_offer);
+
+       offer->input = input;
+       input->offer = offer;
+       end = offer->types.data + offer->types.size;
+       for (p = offer->types.data; p < end; p++)
+               printf(" %s", *p);
+
+       printf("\n");
+}
+
+struct wl_selection_offer_listener selection_offer_listener = {
+       selection_offer_offer,
+       selection_offer_keyboard_focus
+};
+
+static void
+add_selection_offer(struct display *d, uint32_t id)
+{
+       struct selection_offer *offer;
+
+       offer = malloc(sizeof *offer);
+       if (offer == NULL)
+               return;
+
+       offer->offer = wl_selection_offer_create(d->display, id);
+       offer->display = d;
+       wl_array_init(&offer->types);
+       offer->input = NULL;
+
+       wl_selection_offer_add_listener(offer->offer,
+                                       &selection_offer_listener, offer);
+}
+
 static void
 display_handle_global(struct wl_display *display, uint32_t id,
                      const char *interface, uint32_t version, void *data)
@@ -1338,6 +1450,8 @@ display_handle_global(struct wl_display *display, uint32_t id,
                wl_drm_add_listener(d->drm, &drm_listener, d);
        } else if (strcmp(interface, "shm") == 0) {
                d->shm = wl_shm_create(display, id);
+       } else if (strcmp(interface, "selection_offer") == 0) {
+               add_selection_offer(d, id);
        } else if (d->global_handler) {
                d->global_handler(d, interface, id, version);
        }
@@ -1534,6 +1648,12 @@ display_get_egl_display(struct display *d)
        return d->dpy;
 }
 
+struct wl_shell *
+display_get_shell(struct display *display)
+{
+       return display->shell;
+}
+
 void
 display_run(struct display *d)
 {
index 9d6a22a..d67aeda 100644 (file)
@@ -47,6 +47,9 @@ display_get_display(struct display *display);
 struct wl_compositor *
 display_get_compositor(struct display *display);
 
+struct wl_shell *
+display_get_shell(struct display *display);
+
 #ifdef EGL_NO_DISPLAY
 EGLDisplay
 display_get_egl_display(struct display *d);
@@ -243,4 +246,10 @@ input_get_modifiers(struct input *input);
 struct wl_input_device *
 input_get_input_device(struct input *input);
 
+int
+input_offers_mime_type(struct input *input, const char *type);
+int
+input_receive_mime_type(struct input *input, const char *type);
+
+
 #endif