diff --git a/tests/subsurface.c b/tests/subsurface.c index 8daf0ee433..ef12812fbf 100644 --- a/tests/subsurface.c +++ b/tests/subsurface.c @@ -76,20 +76,28 @@ create_subsurface (struct wl_surface *parent, struct wl_surface **child, struct wl_subsurface **subsurface) { + struct wl_region *region; + *child = wl_compositor_create_surface (wl_compositor); *subsurface = wl_subcompositor_get_subsurface (wl_subcompositor, *child, parent); wl_subsurface_set_desync (*subsurface); + + region = wl_compositor_create_region (wl_compositor); + wl_surface_set_input_region (*child, region); + wl_region_destroy (region); } static void surface_fill (struct wl_surface *surface, int width, - int height) + int height, + const GdkRGBA *c) { size_t size; const char *xdg_runtime_dir; int fd; guint32 *data; + guint32 pixel; struct wl_shm_pool *pool; struct wl_buffer *buffer; @@ -99,9 +107,11 @@ surface_fill (struct wl_surface *surface, ftruncate (fd, size); data = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + pixel = 0xff000000 | ((int)(c->red * 255) << 16) | ((int)(c->green * 255) << 8) | ((int)c->blue * 255); + for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) - data[i * width + j] = 0xff00ff00; + data[i * width + j] = pixel; pool = wl_shm_create_pool (wl_shm, fd, size); buffer = wl_shm_pool_create_buffer (pool, 0, width, height, width * 4, WL_SHM_FORMAT_XRGB8888); @@ -113,33 +123,227 @@ surface_fill (struct wl_surface *surface, wl_surface_commit (surface); } -int -main (int argc, char *argv[]) +#define DEMO_TYPE_WIDGET (demo_widget_get_type ()) +G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget) + +GtkWidget * demo_widget_new (void); + +void demo_widget_add_child (DemoWidget *self, + GtkWidget *child); + +struct _DemoWidget { - GtkWidget *window; - GdkSurface *surface; + GtkWidget parent_instance; + struct wl_display *wl_display; struct wl_surface *parent; struct wl_surface *child; struct wl_subsurface *subsurface; + GdkRGBA color1; + GdkRGBA color2; + guint64 time2; + float t; + + guint tick_cb; + + GtkPopover *popover; +}; + +struct _DemoWidgetClass +{ + GtkWidgetClass parent_class; +}; + +G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET) + +#define TIME_SPAN (3.0 * G_TIME_SPAN_SECOND) + +static gboolean +change_color (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer data) +{ + DemoWidget *demo = DEMO_WIDGET (widget); + gint64 time; + + time = gdk_frame_clock_get_frame_time (frame_clock); + + if (time >= demo->time2) + { + demo->time2 = time + TIME_SPAN; + + demo->color1 = demo->color2; + demo->color2.red = g_random_double_range (0, 1); + demo->color2.green = g_random_double_range (0, 1); + demo->color2.blue = g_random_double_range (0, 1); + demo->color2.alpha = 1; + } + + demo->t = 1 - (demo->time2 - time) / TIME_SPAN; + + gtk_widget_queue_draw (widget); + + return G_SOURCE_CONTINUE; +} + +static void +pressed_cb (GtkGesture *gesture, + int n_press, + double x, + double y, + gpointer data) +{ + DemoWidget *demo = data; + + gtk_popover_set_pointing_to (demo->popover, &(GdkRectangle){ x, y, 1, 1 }); + gtk_popover_popup (demo->popover); +} + +static void +clicked_cb (GtkButton *button, + gpointer data) +{ + DemoWidget *demo = data; + + gtk_popover_popdown (demo->popover); +} + +static void +demo_widget_init (DemoWidget *demo) +{ + GtkWidget *button; + GtkGesture *controller; + + gtk_widget_add_tick_callback (GTK_WIDGET (demo), change_color, NULL, NULL); + + demo->popover = GTK_POPOVER (gtk_popover_new ()); + gtk_widget_set_parent (GTK_WIDGET (demo->popover), GTK_WIDGET (demo)); + button = gtk_button_new_with_label ("OK"); + g_signal_connect (button, "clicked", G_CALLBACK (clicked_cb), demo); + gtk_popover_set_child (demo->popover, button); + + controller = gtk_gesture_click_new (); + g_signal_connect (controller, "pressed", G_CALLBACK (pressed_cb), demo); + gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (controller)); +} + +static void +demo_widget_dispose (GObject *object) +{ + //DemoWidget *demo = DEMO_WIDGET (object); + + G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object); +} + +static void +demo_widget_realize (GtkWidget *widget) +{ + DemoWidget *demo = DEMO_WIDGET (widget); + GdkSurface *surface; + + GTK_WIDGET_CLASS (demo_widget_parent_class)->realize (widget); + + demo->wl_display = gdk_wayland_display_get_wl_display (gtk_widget_get_display (widget)); + surface = gtk_native_get_surface (gtk_widget_get_native (widget)); + demo->parent = gdk_wayland_surface_get_wl_surface (surface); + + set_up_registry (demo->wl_display); + create_subsurface (demo->parent, &demo->child, &demo->subsurface); +} + +static void +demo_widget_unrealize (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (demo_widget_parent_class)->unrealize (widget); + + /* FIXME */ +} + +static void +demo_widget_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum_size, + int *natural_size, + int *minimum_baseline, + int *natural_baseline) +{ + *minimum_size = 100; + *natural_size = 200; +} + +static void +demo_widget_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + DemoWidget *demo = DEMO_WIDGET (widget); + GtkNative *native; + double x0, y0, x, y; + + native = gtk_widget_get_native (widget); + gtk_native_get_surface_transform (native, &x0, &y0); + gtk_widget_translate_coordinates (widget, + GTK_WIDGET (native), + 0, 0, + &x, &y); + wl_subsurface_set_position (demo->subsurface, x0 + x + 40, y0 + y + 40); + + gtk_popover_present (demo->popover); +} + +static void +demo_widget_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + DemoWidget *demo = DEMO_WIDGET (widget); + int width, height; + GdkRGBA c; + + width = gtk_widget_get_width (widget); + height = gtk_widget_get_height (widget); + + c.red = (1 - demo->t) * demo->color1.red + demo->t * demo->color2.red; + c.green = (1 - demo->t) * demo->color1.green + demo->t * demo->color2.green; + c.blue = (1 - demo->t) * demo->color1.blue + demo->t * demo->color2.blue; + c.alpha = 1; + + surface_fill (demo->child, width - 80, height - 80, &c); +} + +static void +demo_widget_class_init (DemoWidgetClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->dispose = demo_widget_dispose; + + widget_class->realize = demo_widget_realize; + widget_class->unrealize = demo_widget_unrealize; + widget_class->measure = demo_widget_measure; + widget_class->size_allocate = demo_widget_size_allocate; + widget_class->snapshot = demo_widget_snapshot; +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *child; + gtk_init (); window = gtk_window_new (); - gtk_window_set_title (GTK_WINDOW (window), "hello world"); + gtk_window_set_title (GTK_WINDOW (window), "hello subsurface"); + + child = g_object_new (demo_widget_get_type (), NULL); + gtk_window_set_child (GTK_WINDOW (window), child); gtk_widget_show (window); - surface = gtk_native_get_surface (GTK_NATIVE (window)); - - wl_display = gdk_wayland_display_get_wl_display (gdk_display_get_default ()); - parent = gdk_wayland_surface_get_wl_surface (surface); - - set_up_registry (wl_display); - create_subsurface (parent, &child, &subsurface); - wl_subsurface_set_position (subsurface, 100, 100); - surface_fill (child, 100, 100); - while (TRUE) g_main_context_iteration (NULL, TRUE);