Merge branch 'dragsurface-resize' into 'main'
Fix drag surfaces ignoring size updates on Wayland and X11 See merge request GNOME/gtk!5597
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
#include <gdk/gdkdisplaymanager.h>
|
||||
#include <gdk/gdkdrag.h>
|
||||
#include <gdk/gdkdragsurface.h>
|
||||
#include <gdk/gdkdragsurfacesize.h>
|
||||
#include <gdk/gdkdrawcontext.h>
|
||||
#include <gdk/gdkdrop.h>
|
||||
#include <gdk/gdkenums.h>
|
||||
|
||||
@@ -37,6 +37,22 @@
|
||||
|
||||
G_DEFINE_INTERFACE (GdkDragSurface, gdk_drag_surface, GDK_TYPE_SURFACE)
|
||||
|
||||
enum
|
||||
{
|
||||
COMPUTE_SIZE,
|
||||
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
void
|
||||
gdk_drag_surface_notify_compute_size (GdkDragSurface *surface,
|
||||
GdkDragSurfaceSize *size)
|
||||
{
|
||||
g_signal_emit (surface, signals[COMPUTE_SIZE], 0, size);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_drag_surface_default_present (GdkDragSurface *drag_surface,
|
||||
int width,
|
||||
@@ -49,6 +65,35 @@ static void
|
||||
gdk_drag_surface_default_init (GdkDragSurfaceInterface *iface)
|
||||
{
|
||||
iface->present = gdk_drag_surface_default_present;
|
||||
|
||||
/**
|
||||
* GdkDragSurface::compute-size:
|
||||
* @surface: a `GdkDragSurface`
|
||||
* @size: (type Gdk.DragSurfaceSize) (out caller-allocates): a
|
||||
* `GdkDragSurfaceSize`
|
||||
*
|
||||
* Emitted when the size for the surface needs to be computed, when it is
|
||||
* present.
|
||||
*
|
||||
* It will normally be emitted during the native surface layout cycle when the
|
||||
* surface size needs to be recomputed.
|
||||
*
|
||||
* It is the responsibility of the drag surface user to handle this signal and
|
||||
* compute the desired size of the surface, storing the computed size in the
|
||||
* [struct@Gdk.DragSurfaceSize] object. Failing to do so will result in an
|
||||
* arbitrary size being used as a result.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
signals[COMPUTE_SIZE] =
|
||||
g_signal_new (I_("compute-size"),
|
||||
GDK_TYPE_DRAG_SURFACE,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DRAG_SURFACE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __GDK_DRAG_SURFACE_PRIVATE_H__
|
||||
|
||||
#include "gdkdragsurface.h"
|
||||
#include "gdkdragsurfacesize.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -15,6 +16,9 @@ struct _GdkDragSurfaceInterface
|
||||
int height);
|
||||
};
|
||||
|
||||
void gdk_drag_surface_notify_compute_size (GdkDragSurface *surface,
|
||||
GdkDragSurfaceSize *size);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_DRAG_SURFACE_PRIVATE_H__ */
|
||||
|
||||
53
gdk/gdkdragsurfacesize.c
Normal file
53
gdk/gdkdragsurfacesize.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2023 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkdragsurfacesizeprivate.h"
|
||||
|
||||
/**
|
||||
* GdkDragSurfaceSize:
|
||||
*
|
||||
* The `GdkDragSurfaceSize` struct contains information that is useful
|
||||
* to compute the size of a drag surface.
|
||||
*/
|
||||
|
||||
G_DEFINE_POINTER_TYPE (GdkDragSurfaceSize, gdk_drag_surface_size)
|
||||
|
||||
void
|
||||
gdk_drag_surface_size_init (GdkDragSurfaceSize *size)
|
||||
{
|
||||
*size = (GdkDragSurfaceSize) { 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_drag_surface_size_set_size:
|
||||
* @size: a `GdkDragSurfaceSize`
|
||||
* @width: the width
|
||||
* @height: the height
|
||||
*
|
||||
* Sets the size the drag surface prefers to be resized to.
|
||||
*/
|
||||
void
|
||||
gdk_drag_surface_size_set_size (GdkDragSurfaceSize *size,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
size->width = width;
|
||||
size->height = height;
|
||||
}
|
||||
42
gdk/gdkdragsurfacesize.h
Normal file
42
gdk/gdkdragsurfacesize.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2023 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(__GDK_H_INSIDE__) && !defined(GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GdkDragSurfaceSize GdkDragSurfaceSize;
|
||||
|
||||
#define GDK_TYPE_DRAG_SURFACE_SIZE (gdk_drag_surface_size_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_4_12
|
||||
GType gdk_drag_surface_size_get_type (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_12
|
||||
void gdk_drag_surface_size_set_size (GdkDragSurfaceSize *size,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
G_END_DECLS
|
||||
29
gdk/gdkdragsurfacesizeprivate.h
Normal file
29
gdk/gdkdragsurfacesizeprivate.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2023 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gdkdragsurfacesize.h"
|
||||
|
||||
struct _GdkDragSurfaceSize
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
void gdk_drag_surface_size_init (GdkDragSurfaceSize *size);
|
||||
@@ -16,6 +16,8 @@ gdk_public_sources = files([
|
||||
'gdkdisplay.c',
|
||||
'gdkdisplaymanager.c',
|
||||
'gdkdrag.c',
|
||||
'gdkdragsurface.c',
|
||||
'gdkdragsurfacesize.c',
|
||||
'gdkdrawcontext.c',
|
||||
'gdkdrop.c',
|
||||
'gdkevents.c',
|
||||
@@ -52,7 +54,6 @@ gdk_public_sources = files([
|
||||
'gdktoplevellayout.c',
|
||||
'gdktoplevelsize.c',
|
||||
'gdktoplevel.c',
|
||||
'gdkdragsurface.c',
|
||||
'loaders/gdkpng.c',
|
||||
'loaders/gdktiff.c',
|
||||
'loaders/gdkjpeg.c',
|
||||
@@ -76,6 +77,7 @@ gdk_public_headers = files([
|
||||
'gdkdisplay.h',
|
||||
'gdkdisplaymanager.h',
|
||||
'gdkdrag.h',
|
||||
'gdkdragsurfacesize.h',
|
||||
'gdkdrawcontext.h',
|
||||
'gdkdrop.h',
|
||||
'gdkenums.h',
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gdksurfaceprivate.h"
|
||||
#include "gdktoplevelprivate.h"
|
||||
#include "gdkdevice-wayland-private.h"
|
||||
#include "gdkdragsurfacesizeprivate.h"
|
||||
|
||||
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
@@ -78,6 +79,17 @@ gdk_wayland_drag_surface_compute_size (GdkSurface *surface)
|
||||
|
||||
if (impl->next_layout.surface_geometry_dirty)
|
||||
{
|
||||
GdkDragSurfaceSize size;
|
||||
|
||||
gdk_drag_surface_size_init (&size);
|
||||
size.width = impl->next_layout.configured_width;
|
||||
size.height = impl->next_layout.configured_height;
|
||||
|
||||
gdk_drag_surface_notify_compute_size (GDK_DRAG_SURFACE (surface), &size);
|
||||
|
||||
impl->next_layout.configured_width = size.width;
|
||||
impl->next_layout.configured_height = size.height;
|
||||
|
||||
gdk_wayland_surface_update_size (surface,
|
||||
impl->next_layout.configured_width,
|
||||
impl->next_layout.configured_height,
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "gdkglcontext-x11.h"
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gdkdragsurfacesizeprivate.h"
|
||||
|
||||
#include "gdkseatprivate.h"
|
||||
#include "gdkprivate.h"
|
||||
@@ -345,6 +346,36 @@ compute_toplevel_size (GdkSurface *surface,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
compute_drag_surface_size (GdkSurface *surface,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
GdkX11Surface *impl = GDK_X11_SURFACE (surface);
|
||||
GdkDragSurfaceSize size;
|
||||
|
||||
gdk_drag_surface_size_init (&size);
|
||||
size.width = impl->next_layout.configured_width;
|
||||
size.height = impl->next_layout.configured_height;
|
||||
|
||||
gdk_drag_surface_notify_compute_size (GDK_DRAG_SURFACE (surface), &size);
|
||||
|
||||
if ((impl->last_computed_width != size.width ||
|
||||
impl->last_computed_height != size.height) &&
|
||||
(impl->next_layout.configured_width != size.width ||
|
||||
impl->next_layout.configured_height != size.height))
|
||||
{
|
||||
*width = size.width;
|
||||
*height = size.height;
|
||||
impl->last_computed_width = size.width;
|
||||
impl->last_computed_height = size.height;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
compute_size_idle (gpointer user_data)
|
||||
{
|
||||
@@ -394,6 +425,24 @@ gdk_x11_surface_compute_size (GdkSurface *surface)
|
||||
impl->surface_scale);
|
||||
}
|
||||
|
||||
impl->next_layout.surface_geometry_dirty = FALSE;
|
||||
impl->next_layout.configure_pending = FALSE;
|
||||
}
|
||||
else if (GDK_IS_DRAG_SURFACE (surface))
|
||||
{
|
||||
int width, height;
|
||||
|
||||
if (compute_drag_surface_size (surface, &width, &height))
|
||||
gdk_x11_surface_toplevel_resize (surface, width, height);
|
||||
|
||||
if (surface->resize_count == 0)
|
||||
{
|
||||
gdk_x11_surface_update_size (impl,
|
||||
impl->next_layout.configured_width,
|
||||
impl->next_layout.configured_height,
|
||||
impl->surface_scale);
|
||||
}
|
||||
|
||||
impl->next_layout.surface_geometry_dirty = FALSE;
|
||||
impl->next_layout.configure_pending = FALSE;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
|
||||
#include "gdk/gdksurfaceprivate.h"
|
||||
#include "gdk/gdkdragsurfacesize.h"
|
||||
|
||||
/* for the drag icons */
|
||||
#include "gtkcolorswatchprivate.h"
|
||||
@@ -183,6 +184,16 @@ surface_render (GdkSurface *surface,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_compute_size (GdkDragSurface *surface,
|
||||
GdkDragSurfaceSize *size,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkRequisition nat_size;
|
||||
gtk_widget_get_preferred_size (widget, NULL, &nat_size);
|
||||
gdk_drag_surface_size_set_size (size, nat_size.width, nat_size.height);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_icon_realize (GtkWidget *widget)
|
||||
{
|
||||
@@ -193,6 +204,7 @@ gtk_drag_icon_realize (GtkWidget *widget)
|
||||
gdk_surface_set_widget (icon->surface, widget);
|
||||
|
||||
g_signal_connect (icon->surface, "render", G_CALLBACK (surface_render), widget);
|
||||
g_signal_connect (icon->surface, "compute-size", G_CALLBACK (surface_compute_size), widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->realize (widget);
|
||||
|
||||
@@ -216,6 +228,7 @@ gtk_drag_icon_unrealize (GtkWidget *widget)
|
||||
if (icon->surface)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (icon->surface, surface_render, widget);
|
||||
g_signal_handlers_disconnect_by_func (icon->surface, surface_compute_size, widget);
|
||||
gdk_surface_set_widget (icon->surface, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ gtk_tests = [
|
||||
['testdialog'],
|
||||
['testdnd'],
|
||||
['testdnd2'],
|
||||
['testdndresize'],
|
||||
['testellipsise'],
|
||||
['testentrycompletion'],
|
||||
['testentryicons'],
|
||||
|
||||
123
tests/testdndresize.c
Normal file
123
tests/testdndresize.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "gtkcssprovider.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkRequisition size;
|
||||
static gint64 start_time;
|
||||
static gboolean stop_update_size;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
GtkWidget *label;
|
||||
GtkDragSource *source;
|
||||
GdkContentProvider *content;
|
||||
gboolean done = FALSE;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider,
|
||||
".dnd {"
|
||||
"background-color: red;"
|
||||
"border-top: 10px solid rebeccapurple;"
|
||||
"}",
|
||||
-1);
|
||||
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);
|
||||
|
||||
label = gtk_label_new ("Drag Me");
|
||||
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));
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), label);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user