2023-03-07 04:19:31 +00:00
|
|
|
#include "gtkcssprovider.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
static GtkRequisition size;
|
|
|
|
static gint64 start_time;
|
|
|
|
static gboolean stop_update_size;
|
|
|
|
|
2023-03-15 23:09:51 +00:00
|
|
|
// Animated paintable for testing content-invalidating drag surfaces.
|
|
|
|
#define GTK_TYPE_ANIMATED_ICON (gtk_animated_icon_get_type ())
|
|
|
|
G_DECLARE_FINAL_TYPE (GtkAnimatedIcon, gtk_animated_icon, GTK, ANIMATED_ICON, GObject)
|
|
|
|
|
|
|
|
struct _GtkAnimatedIcon
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GtkAnimatedIconClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_animated_icon_snapshot (GdkPaintable *paintable,
|
|
|
|
GdkSnapshot *snapshot,
|
|
|
|
double width,
|
|
|
|
double height)
|
|
|
|
{
|
|
|
|
gint64 now = g_get_monotonic_time ();
|
|
|
|
float t;
|
|
|
|
|
|
|
|
t = fmodf ((now - start_time) / (float) G_TIME_SPAN_SECOND, 1);
|
|
|
|
if (t >= 0.5)
|
|
|
|
t = 1 - t;
|
|
|
|
|
|
|
|
gtk_snapshot_append_color (snapshot,
|
|
|
|
&(GdkRGBA) { 0, t + 0.5, 0, 1 },
|
|
|
|
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_animated_icon_paintable_init (GdkPaintableInterface *iface)
|
|
|
|
{
|
|
|
|
iface->snapshot = gtk_animated_icon_snapshot;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GtkAnimatedIcon, gtk_animated_icon, G_TYPE_OBJECT,
|
|
|
|
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
|
|
|
gtk_animated_icon_paintable_init))
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_animated_icon_class_init (GtkAnimatedIconClass *klass)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_animated_icon_init (GtkAnimatedIcon *nuclear)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-03-07 04:19:31 +00:00
|
|
|
static gboolean
|
|
|
|
update_size (GtkWidget *widget, GdkFrameClock *clock, gpointer data)
|
|
|
|
{
|
|
|
|
GdkDrag *drag = data;
|
|
|
|
gint64 now = g_get_monotonic_time ();
|
|
|
|
float t;
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
if (stop_update_size)
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
|
|
|
t = fmodf ((now - start_time) / (float) G_TIME_SPAN_SECOND, 1);
|
|
|
|
if (t >= 0.5)
|
|
|
|
t = 1 - t;
|
|
|
|
|
|
|
|
width = size.width + t * 300;
|
|
|
|
height = size.height + t * 150;
|
|
|
|
|
|
|
|
gtk_widget_set_size_request (widget, width, height);
|
|
|
|
gdk_drag_set_hotspot (drag, width / 2, height / 2);
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drag_begin (GtkDragSource *source,
|
|
|
|
GdkDrag *drag)
|
|
|
|
{
|
|
|
|
GtkWidget *widget;
|
|
|
|
GtkWidget *icon;
|
|
|
|
|
|
|
|
icon = gtk_drag_icon_get_for_drag (drag);
|
|
|
|
|
|
|
|
widget = gtk_label_new ("This Should Resize\n\nAnd Stay Centered");
|
|
|
|
gtk_widget_add_css_class (widget, "dnd");
|
|
|
|
gtk_widget_get_preferred_size (widget, NULL, &size);
|
|
|
|
|
|
|
|
gtk_drag_icon_set_child (GTK_DRAG_ICON (icon), widget);
|
|
|
|
gtk_widget_set_size_request (widget, size.width, size.height);
|
|
|
|
gdk_drag_set_hotspot (drag, size.width / 2, size.height / 2);
|
|
|
|
|
|
|
|
start_time = g_get_monotonic_time ();
|
|
|
|
stop_update_size = FALSE;
|
|
|
|
gtk_widget_add_tick_callback (widget, update_size, drag, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drag_end (GtkDragSource *source,
|
|
|
|
GdkDrag *drag,
|
|
|
|
gboolean delete_data,
|
|
|
|
gboolean data)
|
|
|
|
{
|
|
|
|
stop_update_size = TRUE;
|
|
|
|
}
|
|
|
|
|
2023-03-15 23:09:51 +00:00
|
|
|
static gboolean
|
|
|
|
invalidate_contents (GtkWidget *widget, GdkFrameClock *clock, gpointer data)
|
|
|
|
{
|
|
|
|
GdkPaintable *paintable = data;
|
|
|
|
gdk_paintable_invalidate_contents (paintable);
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drag_begin_non_resizing (GtkDragSource *source,
|
|
|
|
GdkDrag *drag)
|
|
|
|
{
|
|
|
|
GdkPaintable *paintable;
|
|
|
|
GtkWidget *widget;
|
|
|
|
int width = 64, height = 32;
|
|
|
|
|
|
|
|
paintable = GDK_PAINTABLE (g_object_new (GTK_TYPE_ANIMATED_ICON, NULL));
|
|
|
|
gtk_drag_icon_set_from_paintable (drag, paintable, width / 2, height / 2);
|
|
|
|
|
|
|
|
widget = gtk_drag_icon_get_child (GTK_DRAG_ICON (gtk_drag_icon_get_for_drag (drag)));
|
|
|
|
gtk_widget_set_size_request (widget, width, height);
|
|
|
|
gtk_widget_add_tick_callback (widget, invalidate_contents, paintable, NULL);
|
|
|
|
}
|
|
|
|
|
2023-03-07 04:19:31 +00:00
|
|
|
static void
|
|
|
|
quit_cb (GtkWidget *widget,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
gboolean *done = data;
|
|
|
|
|
|
|
|
*done = TRUE;
|
|
|
|
|
|
|
|
g_main_context_wakeup (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
GtkCssProvider *provider;
|
|
|
|
GtkWidget *window;
|
2023-03-15 23:09:51 +00:00
|
|
|
GtkWidget *box;
|
2023-03-07 04:19:31 +00:00
|
|
|
GtkWidget *label;
|
|
|
|
GtkDragSource *source;
|
|
|
|
GdkContentProvider *content;
|
|
|
|
gboolean done = FALSE;
|
|
|
|
|
|
|
|
gtk_init ();
|
|
|
|
|
|
|
|
provider = gtk_css_provider_new ();
|
2023-05-16 20:22:01 +00:00
|
|
|
gtk_css_provider_load_from_string (provider,
|
|
|
|
".dnd {"
|
|
|
|
"background-color: red;"
|
|
|
|
"border-top: 10px solid rebeccapurple;"
|
|
|
|
"}");
|
2023-03-07 04:19:31 +00:00
|
|
|
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
|
|
|
GTK_STYLE_PROVIDER(provider),
|
|
|
|
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
|
|
|
|
|
|
|
window = gtk_window_new ();
|
|
|
|
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
|
|
|
|
2023-03-15 23:09:51 +00:00
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
|
|
|
|
|
|
// The resizing icon label.
|
|
|
|
label = gtk_label_new ("Drag Me (Resizing)");
|
2023-03-07 04:19:31 +00:00
|
|
|
g_object_set (label,
|
|
|
|
"margin-start", 64,
|
|
|
|
"margin-end", 64,
|
|
|
|
"margin-top", 64,
|
|
|
|
"margin-bottom", 64,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
source = gtk_drag_source_new ();
|
|
|
|
content = gdk_content_provider_new_typed (G_TYPE_STRING, "I'm data!");
|
|
|
|
gtk_drag_source_set_content (source, content);
|
|
|
|
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
|
|
|
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
|
|
|
|
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (source));
|
|
|
|
|
2023-03-15 23:09:51 +00:00
|
|
|
gtk_box_append (GTK_BOX (box), label);
|
|
|
|
|
|
|
|
// The non-resizing icon label.
|
|
|
|
label = gtk_label_new ("Drag Me (Non-Resizing)");
|
|
|
|
g_object_set (label,
|
|
|
|
"margin-start", 64,
|
|
|
|
"margin-end", 64,
|
|
|
|
"margin-top", 64,
|
|
|
|
"margin-bottom", 64,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
source = gtk_drag_source_new ();
|
|
|
|
content = gdk_content_provider_new_typed (G_TYPE_STRING, "I'm data!");
|
|
|
|
gtk_drag_source_set_content (source, content);
|
|
|
|
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin_non_resizing), NULL);
|
|
|
|
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (source));
|
|
|
|
|
|
|
|
gtk_box_append (GTK_BOX (box), label);
|
|
|
|
|
|
|
|
gtk_window_set_child (GTK_WINDOW (window), box);
|
2023-03-07 04:19:31 +00:00
|
|
|
|
|
|
|
gtk_window_present (GTK_WINDOW (window));
|
|
|
|
|
|
|
|
while (!done)
|
|
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|