Actually add dnd client
authorKristian Høgsberg <krh@bitplanet.net>
Thu, 19 Aug 2010 00:31:06 +0000 (20:31 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 19 Aug 2010 00:31:06 +0000 (20:31 -0400)
clients/dnd.c [new file with mode: 0644]

diff --git a/clients/dnd.c b/clients/dnd.c
new file mode 100644 (file)
index 0000000..5772e8e
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright © 2010 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <sys/time.h>
+#include <cairo.h>
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "wayland-client.h"
+#include "wayland-glib.h"
+
+#include "window.h"
+
+static const char socket_name[] = "\0wayland";
+
+struct dnd {
+       struct window *window;
+       struct display *display;
+       uint32_t key;
+       struct item *items[16];
+};
+
+struct item {
+       cairo_surface_t *surface;
+       int x, y;
+};
+
+static const int item_width = 64;
+static const int item_height = 64;
+static const int item_padding = 16;
+
+static struct item *
+item_create(struct display *display, int x, int y)
+{
+       const int petal_count = 3 + random() % 5;
+       const double r1 = 20 + random() % 10;
+       const double r2 = 5 + random() % 12;
+       const double u = (10 + random() % 90) / 100.0;
+       const double v = (random() % 90) / 100.0;
+
+       cairo_t *cr;
+       int i;
+       double t, dt = 2 * M_PI / (petal_count * 2);
+       double x1, y1, x2, y2, x3, y3;
+       struct rectangle rect;
+       struct item *item;
+
+       item = malloc(sizeof *item);
+       if (item == NULL)
+               return NULL;
+
+       rect.width = item_width;
+       rect.height = item_height;
+       item->surface = display_create_surface(display, &rect);
+
+       item->x = x;
+       item->y = y;
+
+       cr = cairo_create(item->surface);
+       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+       cairo_set_source_rgba(cr, 0, 0, 0, 0);
+       cairo_paint(cr);
+
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       cairo_translate(cr, item_width / 2, item_height / 2);
+       t = random();
+       cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
+       for (i = 0; i < petal_count; i++, t += dt * 2) {
+               x1 = cos(t) * r1;
+               y1 = sin(t) * r1;
+               x2 = cos(t + dt) * r2;
+               y2 = sin(t + dt) * r2;
+               x3 = cos(t + 2 * dt) * r1;
+               y3 = sin(t + 2 * dt) * r1;
+
+               cairo_curve_to(cr,
+                              x1 - y1 * u, y1 + x1 * u,
+                              x2 + y2 * v, y2 - x2 * v,
+                              x2, y2);                        
+
+               cairo_curve_to(cr,
+                              x2 - y2 * v, y2 + x2 * v,
+                              x3 + y3 * u, y3 - x3 * u,
+                              x3, y3);
+       }
+
+       cairo_close_path(cr);
+
+       cairo_set_source_rgba(cr,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 100) / 99.0);
+
+       cairo_fill_preserve(cr);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgba(cr,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 50) / 49.0,
+                             0.5 + (random() % 100) / 99.0);
+       cairo_stroke(cr);
+
+       cairo_destroy(cr);
+
+       return item;
+}
+
+static void
+dnd_draw(struct dnd *dnd)
+{
+       struct rectangle rectangle;
+       cairo_t *cr;
+       cairo_surface_t *wsurface, *surface;
+       int i;
+
+       window_draw(dnd->window);
+
+       window_get_child_rectangle(dnd->window, &rectangle);
+
+       wsurface = window_get_surface(dnd->window);
+       surface = cairo_surface_create_similar(wsurface,
+                                              CAIRO_CONTENT_COLOR_ALPHA,
+                                              rectangle.width,
+                                              rectangle.height);
+
+       cr = cairo_create(surface);
+       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+       cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
+       cairo_paint(cr);
+
+       cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+       for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+               if (!dnd->items[i])
+                       continue;
+               cairo_set_source_surface(cr, dnd->items[i]->surface,
+                                        dnd->items[i]->x, dnd->items[i]->y);
+               cairo_paint(cr);
+       }
+
+       cairo_destroy(cr);
+
+       window_copy_surface(dnd->window, &rectangle, surface);
+       window_commit(dnd->window, dnd->key);
+       cairo_surface_destroy(surface);
+}
+
+static void
+redraw_handler(struct window *window, void *data)
+{
+       struct dnd *dnd = data;
+
+       dnd_draw(dnd);
+}
+
+static void
+keyboard_focus_handler(struct window *window,
+                      struct input *device, void *data)
+{
+       struct dnd *dnd = data;
+
+       window_schedule_redraw(dnd->window);
+}
+
+static struct item *
+dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
+{
+       struct item *item;
+       int i;
+
+       for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+               item = dnd->items[i];
+               if (item &&
+                   item->x <= x && x < item->x + item_width &&
+                   item->y <= y && y < item->y + item_height)
+                       return item;
+       }
+
+       return NULL;
+}
+
+static void
+dnd_button_handler(struct window *window,
+                  struct input *input, uint32_t time,
+                  int button, int state, void *data)
+{
+       struct dnd *dnd = data;
+       int32_t x, y, hotspot_x, hotspot_y, pointer_width, pointer_height;
+       struct rectangle rectangle;
+       struct item *item;
+       struct wl_buffer *buffer;
+       cairo_surface_t *surface, *pointer;
+       cairo_t *cr;
+
+       input_get_position(input, &x, &y);
+       window_get_child_rectangle(dnd->window, &rectangle);
+
+       x -= rectangle.x;
+       y -= rectangle.y;
+       item = dnd_get_item(dnd, x, y);
+
+       if (item && state == 1) {
+               fprintf(stderr, "start drag, item %p\n", item);
+
+               pointer = display_get_pointer_surface(dnd->display,
+                                                     POINTER_DRAGGING,
+                                                     &pointer_width,
+                                                     &pointer_height,
+                                                     &hotspot_x,
+                                                     &hotspot_y);
+
+               rectangle.width = item_width + 2 * pointer_width;
+               rectangle.height = item_height + 2 * pointer_height;
+               surface = display_create_surface(dnd->display, &rectangle);
+
+               cr = cairo_create(surface);
+               cairo_translate(cr, pointer_width, pointer_height);
+
+               cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+               cairo_set_source_rgba(cr, 0, 0, 0, 0);
+               cairo_paint(cr);
+
+               cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+               cairo_set_source_surface(cr, item->surface, 0, 0);
+               cairo_paint(cr);
+
+               cairo_set_source_surface(cr, pointer,
+                                        x - item->x - hotspot_x,
+                                        y - item->y - hotspot_y);
+               cairo_surface_destroy(pointer);
+               cairo_paint(cr);
+               cairo_destroy(cr);
+
+               buffer = display_get_buffer_for_surface(dnd->display,
+                                                       surface);
+               window_start_drag(window, input, time,
+                                 buffer,
+                                 pointer_width + x - item->x,
+                                 pointer_height + y - item->y);
+
+               /* FIXME: We leak the surface because we can't free it
+                * until the server has referenced it. */
+       }
+}
+
+static int
+dnd_motion_handler(struct window *window,
+                  struct input *input, uint32_t time,
+                  int32_t x, int32_t y,
+                  int32_t sx, int32_t sy, void *data)
+{
+       struct dnd *dnd = data;
+       struct item *item;
+       struct rectangle rectangle;
+
+       window_get_child_rectangle(dnd->window, &rectangle);
+       item = dnd_get_item(dnd, sx - rectangle.x, sy - rectangle.y);
+
+       if (item)
+               return POINTER_HAND1;
+       else
+               return POINTER_LEFT_PTR;
+}
+
+static struct dnd *
+dnd_create(struct display *display)
+{
+       struct dnd *dnd;
+       gchar *title;
+       int i, x, y;
+       struct rectangle rectangle;
+
+       dnd = malloc(sizeof *dnd);
+       if (dnd == NULL)
+               return dnd;
+       memset(dnd, 0, sizeof *dnd);
+
+       title = g_strdup_printf("Wayland Drag and Drop Demo");
+
+       dnd->window = window_create(display, title, 100, 100, 500, 400);
+       dnd->display = display;
+       dnd->key = 100;
+
+       for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+               x = (i % 4) * (item_width + item_padding) + item_padding;
+               y = (i / 4) * (item_height + item_padding) + item_padding;
+               if ((i ^ (i >> 2)) & 1)
+                       dnd->items[i] = item_create(display, x, y);
+               else
+                       dnd->items[i] = NULL;
+       }
+
+       window_set_user_data(dnd->window, dnd);
+       window_set_redraw_handler(dnd->window, redraw_handler);
+       window_set_keyboard_focus_handler(dnd->window,
+                                         keyboard_focus_handler);
+       window_set_button_handler(dnd->window,
+                                 dnd_button_handler);
+
+       window_set_motion_handler(dnd->window,
+                                 dnd_motion_handler);
+
+       rectangle.width = 4 * (item_width + item_padding) + item_padding;
+       rectangle.height = 4 * (item_height + item_padding) + item_padding;
+       window_set_child_size(dnd->window, &rectangle);
+
+       dnd_draw(dnd);
+
+       return dnd;
+}
+
+static const GOptionEntry option_entries[] = {
+       { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+       struct display *d;
+       struct dnd *dnd;
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       srandom(tv.tv_usec);
+
+       d = display_create(&argc, &argv, option_entries);
+
+       dnd = dnd_create (d);
+
+       display_run(d);
+
+       return 0;
+}