Bug 540674: [GTK4] Adapt to new drawing model changes

This patch furthers the work on the drawing model changes in GTK4.

1) Remove instances of GdkEventExpose as this has been gone in GTK3
already.

2) Replace GDK drawing API with purely Cairo sourced drawing contexts
provided by draw/snapshot handlers or other such callbacks. This include
methods like Canvas.scroll().

3) Fixes the snapshot handling in SWT-GTK4 and propagates all snapshots
down the hierarchy to ensure things like Canvases drawing properly.

Change-Id: If96d1e0d33c97aeb5eed7bb6e5f478ee1785f30a
Signed-off-by: Eric Williams <ericwill@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/cairo_rectangle_int_t.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/cairo_rectangle_int_t.java
index 6b0c20d..e158f1c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/cairo_rectangle_int_t.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cairo/org/eclipse/swt/internal/cairo/cairo_rectangle_int_t.java
@@ -42,4 +42,15 @@
 		}
 		return;
 	}
+
+	/**
+	 * Returns a string containing a concise, human-readable
+	 * description of the receiver.
+	 *
+	 * @return a string representation of the <code>cairo_rectangle_int_t</code>
+	 */
+	@Override
+	public String toString() {
+		return "cairo_rectangle_int_t {" + x + ", " + y + ", " + width + ", " + height + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+	}
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
index 3bdf639..7048fab 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -96,18 +96,6 @@
 }
 #endif
 
-#ifndef NO_GdkEventExpose_1sizeof
-JNIEXPORT jint JNICALL GDK_NATIVE(GdkEventExpose_1sizeof)
-	(JNIEnv *env, jclass that)
-{
-	jint rc = 0;
-	GDK_NATIVE_ENTER(env, that, GdkEventExpose_1sizeof_FUNC);
-	rc = (jint)GdkEventExpose_sizeof();
-	GDK_NATIVE_EXIT(env, that, GdkEventExpose_1sizeof_FUNC);
-	return rc;
-}
-#endif
-
 #ifndef NO_GdkEventFocus_1sizeof
 JNIEXPORT jint JNICALL GDK_NATIVE(GdkEventFocus_1sizeof)
 	(JNIEnv *env, jclass that)
@@ -2587,26 +2575,6 @@
 }
 #endif
 
-#ifndef NO__1gdk_1window_1begin_1draw_1frame
-JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1window_1begin_1draw_1frame)
-	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
-{
-	jintLong rc = 0;
-	GDK_NATIVE_ENTER(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
-/*
-	rc = (jintLong)gdk_window_begin_draw_frame((GdkWindow *)arg0, (cairo_region_t *)arg1);
-*/
-	{
-		GDK_LOAD_FUNCTION(fp, gdk_window_begin_draw_frame)
-		if (fp) {
-			rc = (jintLong)((jintLong (CALLING_CONVENTION*)(GdkWindow *, cairo_region_t *))fp)((GdkWindow *)arg0, (cairo_region_t *)arg1);
-		}
-	}
-	GDK_NATIVE_EXIT(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
-	return rc;
-}
-#endif
-
 #ifndef NO__1gdk_1window_1create_1similar_1surface
 JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1window_1create_1similar_1surface)
 	(JNIEnv *env, jclass that, jintLong arg0, jint arg1, jint arg2, jint arg3)
@@ -2629,26 +2597,6 @@
 }
 #endif
 
-#ifndef NO__1gdk_1window_1end_1draw_1frame
-JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1window_1end_1draw_1frame)
-	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
-{
-	jintLong rc = 0;
-	GDK_NATIVE_ENTER(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
-/*
-	rc = (jintLong)gdk_window_end_draw_frame((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
-*/
-	{
-		GDK_LOAD_FUNCTION(fp, gdk_window_end_draw_frame)
-		if (fp) {
-			rc = (jintLong)((jintLong (CALLING_CONVENTION*)(GdkWindow *, GdkDrawingContext *))fp)((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
-		}
-	}
-	GDK_NATIVE_EXIT(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
-	return rc;
-}
-#endif
-
 #ifndef NO__1gdk_1window_1focus
 JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1window_1focus)
 	(JNIEnv *env, jclass that, jintLong arg0, jint arg1)
@@ -12377,6 +12325,18 @@
 }
 #endif
 
+#ifndef NO__1gtk_1widget_1get_1next_1sibling
+JNIEXPORT jintLong JNICALL GTK_NATIVE(_1gtk_1widget_1get_1next_1sibling)
+	(JNIEnv *env, jclass that, jintLong arg0)
+{
+	jintLong rc = 0;
+	GTK_NATIVE_ENTER(env, that, _1gtk_1widget_1get_1next_1sibling_FUNC);
+	rc = (jintLong)gtk_widget_get_next_sibling((GtkWidget *)arg0);
+	GTK_NATIVE_EXIT(env, that, _1gtk_1widget_1get_1next_1sibling_FUNC);
+	return rc;
+}
+#endif
+
 #ifndef NO__1gtk_1widget_1get_1opacity
 JNIEXPORT jdouble JNICALL GTK_NATIVE(_1gtk_1widget_1get_1opacity)
 	(JNIEnv *env, jclass that, jintLong arg0)
@@ -18895,32 +18855,6 @@
 }
 #endif
 
-#if (!defined(NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II) && !defined(JNI64)) || (!defined(NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ) && defined(JNI64))
-#ifndef JNI64
-JNIEXPORT void JNICALL OS_NATIVE(memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II)(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jintLong arg2)
-#else
-JNIEXPORT void JNICALL OS_NATIVE(memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ)(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jintLong arg2)
-#endif
-{
-	GdkEventExpose _arg0, *lparg0=NULL;
-#ifndef JNI64
-	OS_NATIVE_ENTER(env, that, memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II_FUNC);
-#else
-	OS_NATIVE_ENTER(env, that, memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ_FUNC);
-#endif
-	if (!arg0) goto fail;
-	if ((lparg0 = &_arg0) == NULL) goto fail;
-	memmove((void *)lparg0, (const void *)arg1, (size_t)arg2);
-fail:
-	if (arg0 && lparg0) setGdkEventExposeFields(env, arg0, lparg0);
-#ifndef JNI64
-	OS_NATIVE_EXIT(env, that, memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II_FUNC);
-#else
-	OS_NATIVE_EXIT(env, that, memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ_FUNC);
-#endif
-}
-#endif
-
 #if (!defined(NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2II) && !defined(JNI64)) || (!defined(NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2JJ) && defined(JNI64))
 #ifndef JNI64
 JNIEXPORT void JNICALL OS_NATIVE(memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2II)(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jintLong arg2)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
index 9a9a962..9eaee50 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
@@ -182,7 +182,6 @@
 #define NO_GdkEventAny
 #define NO_GdkEventButton
 #define NO_GdkEventCrossing
-#define NO_GdkEventExpose
 #define NO_GdkEventFocus
 #define NO_GdkEventKey
 #define NO_GdkEventMotion
@@ -205,8 +204,6 @@
 #define NO_memmove__Jorg_eclipse_swt_internal_gtk_GdkEventCrossing_2J
 #define NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventCrossing_2II
 #define NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventCrossing_2JJ
-#define NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II
-#define NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ
 #define NO_memmove__Iorg_eclipse_swt_internal_gtk_GdkEventFocus_2I
 #define NO_memmove__Jorg_eclipse_swt_internal_gtk_GdkEventFocus_2J
 #define NO_memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2II
@@ -442,6 +439,7 @@
 #define NO__1gtk_1widget_1measure
 #define NO__1gtk_1style_1context_1add_1provider_1for_1display
 #define NO__1gtk_1widget_1get_1first_1child
+#define NO__1gtk_1widget_1get_1next_1sibling
 #define NO__1gtk_1css_1provider_1load_1from_1data__I_3BI
 #define NO__1gtk_1css_1provider_1load_1from_1data__J_3BJ
 #define NO__1gdk_1display_1is_1composited
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
index 8d7c009..2beb0ce 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
@@ -28,7 +28,6 @@
 	"GdkEventAny_1sizeof",
 	"GdkEventButton_1sizeof",
 	"GdkEventCrossing_1sizeof",
-	"GdkEventExpose_1sizeof",
 	"GdkEventFocus_1sizeof",
 	"GdkEventKey_1sizeof",
 	"GdkEventMotion_1sizeof",
@@ -211,10 +210,8 @@
 	"_1gdk_1unicode_1to_1keyval",
 	"_1gdk_1utf8_1to_1string_1target",
 	"_1gdk_1visual_1get_1depth",
-	"_1gdk_1window_1begin_1draw_1frame",
 	"_1gdk_1window_1create_1similar_1surface",
 	"_1gdk_1window_1destroy",
-	"_1gdk_1window_1end_1draw_1frame",
 	"_1gdk_1window_1focus",
 	"_1gdk_1window_1get_1children",
 	"_1gdk_1window_1get_1device_1position",
@@ -1131,6 +1128,7 @@
 	"_1gtk_1widget_1get_1margin_1start",
 	"_1gtk_1widget_1get_1margin_1top",
 	"_1gtk_1widget_1get_1name",
+	"_1gtk_1widget_1get_1next_1sibling",
 	"_1gtk_1widget_1get_1opacity",
 	"_1gtk_1widget_1get_1pango_1context",
 	"_1gtk_1widget_1get_1parent",
@@ -1822,11 +1820,6 @@
 	"memmove__Lorg_eclipse_swt_internal_gtk_GdkEventCrossing_2JJ",
 #endif
 #ifndef JNI64
-	"memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II",
-#else
-	"memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ",
-#endif
-#ifndef JNI64
 	"memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2II",
 #else
 	"memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2JJ",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
index 810be76..5dd2f7a 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
@@ -38,7 +38,6 @@
 	GdkEventAny_1sizeof_FUNC,
 	GdkEventButton_1sizeof_FUNC,
 	GdkEventCrossing_1sizeof_FUNC,
-	GdkEventExpose_1sizeof_FUNC,
 	GdkEventFocus_1sizeof_FUNC,
 	GdkEventKey_1sizeof_FUNC,
 	GdkEventMotion_1sizeof_FUNC,
@@ -221,10 +220,8 @@
 	_1gdk_1unicode_1to_1keyval_FUNC,
 	_1gdk_1utf8_1to_1string_1target_FUNC,
 	_1gdk_1visual_1get_1depth_FUNC,
-	_1gdk_1window_1begin_1draw_1frame_FUNC,
 	_1gdk_1window_1create_1similar_1surface_FUNC,
 	_1gdk_1window_1destroy_FUNC,
-	_1gdk_1window_1end_1draw_1frame_FUNC,
 	_1gdk_1window_1focus_FUNC,
 	_1gdk_1window_1get_1children_FUNC,
 	_1gdk_1window_1get_1device_1position_FUNC,
@@ -1129,6 +1126,7 @@
 	_1gtk_1widget_1get_1margin_1start_FUNC,
 	_1gtk_1widget_1get_1margin_1top_FUNC,
 	_1gtk_1widget_1get_1name_FUNC,
+	_1gtk_1widget_1get_1next_1sibling_FUNC,
 	_1gtk_1widget_1get_1opacity_FUNC,
 	_1gtk_1widget_1get_1pango_1context_FUNC,
 	_1gtk_1widget_1get_1parent_FUNC,
@@ -1796,11 +1794,6 @@
 	memmove__Lorg_eclipse_swt_internal_gtk_GdkEventCrossing_2JJ_FUNC,
 #endif
 #ifndef JNI64
-	memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2II_FUNC,
-#else
-	memmove__Lorg_eclipse_swt_internal_gtk_GdkEventExpose_2JJ_FUNC,
-#endif
-#ifndef JNI64
 	memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2II_FUNC,
 #else
 	memmove__Lorg_eclipse_swt_internal_gtk_GdkEventFocus_2JJ_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.c
index ed4049d..06b16ba 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.c
@@ -402,61 +402,6 @@
 }
 #endif
 
-#ifndef NO_GdkEventExpose
-typedef struct GdkEventExpose_FID_CACHE {
-	int cached;
-	jclass clazz;
-	jfieldID window, send_event, area_x, area_y, area_width, area_height, region, count;
-} GdkEventExpose_FID_CACHE;
-
-GdkEventExpose_FID_CACHE GdkEventExposeFc;
-
-void cacheGdkEventExposeFields(JNIEnv *env, jobject lpObject)
-{
-	if (GdkEventExposeFc.cached) return;
-	cacheGdkEventFields(env, lpObject);
-	GdkEventExposeFc.clazz = (*env)->GetObjectClass(env, lpObject);
-	GdkEventExposeFc.window = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "window", I_J);
-	GdkEventExposeFc.send_event = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "send_event", "B");
-	GdkEventExposeFc.area_x = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "area_x", "I");
-	GdkEventExposeFc.area_y = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "area_y", "I");
-	GdkEventExposeFc.area_width = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "area_width", "I");
-	GdkEventExposeFc.area_height = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "area_height", "I");
-	GdkEventExposeFc.region = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "region", I_J);
-	GdkEventExposeFc.count = (*env)->GetFieldID(env, GdkEventExposeFc.clazz, "count", "I");
-	GdkEventExposeFc.cached = 1;
-}
-
-GdkEventExpose *getGdkEventExposeFields(JNIEnv *env, jobject lpObject, GdkEventExpose *lpStruct)
-{
-	if (!GdkEventExposeFc.cached) cacheGdkEventExposeFields(env, lpObject);
-	getGdkEventFields(env, lpObject, (GdkEvent *)lpStruct);
-	lpStruct->window = (GdkWindow *)(*env)->GetIntLongField(env, lpObject, GdkEventExposeFc.window);
-	lpStruct->send_event = (gint8)(*env)->GetByteField(env, lpObject, GdkEventExposeFc.send_event);
-	lpStruct->area.x = (*env)->GetIntField(env, lpObject, GdkEventExposeFc.area_x);
-	lpStruct->area.y = (*env)->GetIntField(env, lpObject, GdkEventExposeFc.area_y);
-	lpStruct->area.width = (*env)->GetIntField(env, lpObject, GdkEventExposeFc.area_width);
-	lpStruct->area.height = (*env)->GetIntField(env, lpObject, GdkEventExposeFc.area_height);
-	lpStruct->region = (void *)(*env)->GetIntLongField(env, lpObject, GdkEventExposeFc.region);
-	lpStruct->count = (gint)(*env)->GetIntField(env, lpObject, GdkEventExposeFc.count);
-	return lpStruct;
-}
-
-void setGdkEventExposeFields(JNIEnv *env, jobject lpObject, GdkEventExpose *lpStruct)
-{
-	if (!GdkEventExposeFc.cached) cacheGdkEventExposeFields(env, lpObject);
-	setGdkEventFields(env, lpObject, (GdkEvent *)lpStruct);
-	(*env)->SetIntLongField(env, lpObject, GdkEventExposeFc.window, (jintLong)lpStruct->window);
-	(*env)->SetByteField(env, lpObject, GdkEventExposeFc.send_event, (jbyte)lpStruct->send_event);
-	(*env)->SetIntField(env, lpObject, GdkEventExposeFc.area_x, (jint)lpStruct->area.x);
-	(*env)->SetIntField(env, lpObject, GdkEventExposeFc.area_y, (jint)lpStruct->area.y);
-	(*env)->SetIntField(env, lpObject, GdkEventExposeFc.area_width, (jint)lpStruct->area.width);
-	(*env)->SetIntField(env, lpObject, GdkEventExposeFc.area_height, (jint)lpStruct->area.height);
-	(*env)->SetIntLongField(env, lpObject, GdkEventExposeFc.region, (jintLong)lpStruct->region);
-	(*env)->SetIntField(env, lpObject, GdkEventExposeFc.count, (jint)lpStruct->count);
-}
-#endif
-
 #ifndef NO_GdkEventFocus
 typedef struct GdkEventFocus_FID_CACHE {
 	int cached;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.h
index a208b73..7d66133 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_structs.h
@@ -114,18 +114,6 @@
 #define GdkEventCrossing_sizeof() 0
 #endif
 
-#ifndef NO_GdkEventExpose
-void cacheGdkEventExposeFields(JNIEnv *env, jobject lpObject);
-GdkEventExpose *getGdkEventExposeFields(JNIEnv *env, jobject lpObject, GdkEventExpose *lpStruct);
-void setGdkEventExposeFields(JNIEnv *env, jobject lpObject, GdkEventExpose *lpStruct);
-#define GdkEventExpose_sizeof() sizeof(GdkEventExpose)
-#else
-#define cacheGdkEventExposeFields(a,b)
-#define getGdkEventExposeFields(a,b,c) NULL
-#define setGdkEventExposeFields(a,b,c)
-#define GdkEventExpose_sizeof() 0
-#endif
-
 #ifndef NO_GdkEventFocus
 void cacheGdkEventFocusFields(JNIEnv *env, jobject lpObject);
 GdkEventFocus *getGdkEventFocusFields(JNIEnv *env, jobject lpObject, GdkEventFocus *lpStruct);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
index 7fcdd86..fbc6670 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
@@ -278,7 +278,6 @@
 	public static final native int GdkEventAny_sizeof();
 	public static final native int GdkEventButton_sizeof();
 	public static final native int GdkEventCrossing_sizeof();
-	public static final native int GdkEventExpose_sizeof();
 	public static final native int GdkEventFocus_sizeof();
 	public static final native int GdkEventKey_sizeof();
 	public static final native int GdkEventMotion_sizeof();
@@ -431,36 +430,6 @@
 		}
 	}
 	/**
-	 * @param window cast=(GdkWindow *)
-	 * @param region cast=(cairo_region_t *)
-	 * @method flags=dynamic
-	 */
-	public static final native long /*int*/ _gdk_window_begin_draw_frame(long /*int*/ window, long /*int*/ region);
-	/** [GTK3 only, if-def'd in os.h] */
-	public static final long /*int*/ gdk_window_begin_draw_frame(long /*int*/ window, long /*int*/ region) {
-		lock.lock();
-		try {
-			return _gdk_window_begin_draw_frame(window, region);
-		} finally {
-			lock.unlock();
-		}
-	}
-	/**
-	 * @param window cast=(GdkWindow *)
-	 * @param context cast=(GdkDrawingContext *)
-	 * @method flags=dynamic
-	 */
-	public static final native long /*int*/ _gdk_window_end_draw_frame(long /*int*/ window, long /*int*/ context);
-	/** [GTK3 only, if-def'd in os.h] */
-	public static final long /*int*/ gdk_window_end_draw_frame(long /*int*/ window, long /*int*/ context) {
-		lock.lock();
-		try {
-			return _gdk_window_end_draw_frame(window, context);
-		} finally {
-			lock.unlock();
-		}
-	}
-	/**
 	 * @method flags=dynamic
 	 * @param atom_name cast=(const gchar *),flags=no_out critical
 	 */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
index a684afd..a54a970 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
@@ -475,6 +475,18 @@
 		}
 	}
 
+	/** @param widget cast=(GtkWidget *) */
+	public static final native long /*int*/ _gtk_widget_get_next_sibling(long /*int*/ widget);
+	/** [GTK4 only, if-def'd in os.h] */
+	public static final long /*int*/ gtk_widget_get_next_sibling(long /*int*/ widget) {
+		lock.lock();
+		try {
+			return _gtk_widget_get_next_sibling(widget);
+		} finally {
+			lock.unlock();
+		}
+	}
+
 	/**
 	 * @param widget cast=(GtkWidget *)
 	 */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GdkEventExpose.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GdkEventExpose.java
deleted file mode 100644
index 209d0fa..0000000
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GdkEventExpose.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others. All rights reserved.
- * The contents of this file are made available under the terms
- * of the GNU Lesser General Public License (LGPL) Version 2.1 that
- * accompanies this distribution (lgpl-v21.txt).  The LGPL is also
- * available at http://www.gnu.org/licenses/lgpl.html.  If the version
- * of the LGPL at http://www.gnu.org is different to the version of
- * the LGPL accompanying this distribution and there is any conflict
- * between the two license versions, the terms of the LGPL accompanying
- * this distribution shall govern.
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.swt.internal.gtk;
-
-
-public class GdkEventExpose extends GdkEvent {
-	/** @field cast=(GdkWindow *) */
-	public long /*int*/ window;
-	/** @field cast=(gint8) */
-	public byte send_event;
-	/** @field accessor=area.x */
-	public int area_x;
-	/** @field accessor=area.y */
-	public int area_y;
-	/** @field accessor=area.width */
-	public int area_width;
-	/** @field accessor=area.height */
-	public int area_height;
-	/** @field cast=(void *) */
-	public long /*int*/ region;
-	/** @field cast=(gint) */
-	public int count;
-	public static final int sizeof = GDK.GdkEventExpose_sizeof();
-}
-
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index 5c6963f..5a6db5e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -2936,12 +2936,6 @@
  * @param src cast=(const void *)
  * @param size cast=(size_t)
  */
-public static final native void memmove(GdkEventExpose dest, long /*int*/ src, long /*int*/ size);
-/**
- * @param dest cast=(void *),flags=no_in
- * @param src cast=(const void *)
- * @param size cast=(size_t)
- */
 public static final native void memmove(GdkEventFocus dest, long /*int*/ src, long /*int*/ size);
 /**
  * @param dest cast=(void *),flags=no_in
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
index 38733a5..1df0c59 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
@@ -464,7 +464,7 @@
 	if (data.image != null) {
 		Cairo.cairo_set_source_surface(cairo, data.image.surface, 0, 0);
 	} else if (data.drawable != 0) {
-		GDK.gdk_cairo_set_source_window(cairo, data.drawable, 0, 0);
+		if (!GTK.GTK4) GDK.gdk_cairo_set_source_window(cairo, data.drawable, 0, 0);
 	} else {
 		Cairo.cairo_destroy(cairo);
 		return;
@@ -542,7 +542,7 @@
 		Cairo.cairo_translate(handle, deltaX, deltaY);
 		Cairo.cairo_set_operator(handle, Cairo.CAIRO_OPERATOR_SOURCE);
 		Cairo.cairo_push_group(handle);
-		GDK.gdk_cairo_set_source_window(handle, drawable, 0, 0);
+		if (!GTK.GTK4) GDK.gdk_cairo_set_source_window(handle, drawable, 0, 0);
 		Cairo.cairo_paint(handle);
 		Cairo.cairo_pop_group_to_source(handle);
 		Cairo.cairo_rectangle(handle, destX - deltaX, destY - deltaY, width, height);
@@ -550,24 +550,24 @@
 		Cairo.cairo_paint(handle);
 		Cairo.cairo_restore(handle);
 		if (paint) {
-			long /*int*/ visibleRegion = GDK.gdk_window_get_visible_region (drawable);
 			cairo_rectangle_int_t srcRect = new cairo_rectangle_int_t ();
 			srcRect.x = srcX;
 			srcRect.y = srcY;
 			srcRect.width = width;
 			srcRect.height = height;
-			long /*int*/ copyRegion = Cairo.cairo_region_create_rectangle (srcRect);
-			Cairo.cairo_region_intersect(copyRegion, visibleRegion);
 			long /*int*/ invalidateRegion = Cairo.cairo_region_create_rectangle (srcRect);
-			Cairo.cairo_region_subtract (invalidateRegion, visibleRegion);
-			Cairo.cairo_region_translate (invalidateRegion, deltaX, deltaY);
 			if (GTK.GTK4) {
 				GDK.gdk_surface_invalidate_region(drawable, invalidateRegion);
 			} else {
+				long /*int*/ visibleRegion = GDK.gdk_window_get_visible_region (drawable);
+				long /*int*/ copyRegion = Cairo.cairo_region_create_rectangle (srcRect);
+				Cairo.cairo_region_intersect(copyRegion, visibleRegion);
+				Cairo.cairo_region_subtract (invalidateRegion, visibleRegion);
+				Cairo.cairo_region_translate (invalidateRegion, deltaX, deltaY);
 				GDK.gdk_window_invalidate_region(drawable, invalidateRegion, false);
+				Cairo.cairo_region_destroy (visibleRegion);
+				Cairo.cairo_region_destroy (copyRegion);
 			}
-			Cairo.cairo_region_destroy (visibleRegion);
-			Cairo.cairo_region_destroy (copyRegion);
 			Cairo.cairo_region_destroy (invalidateRegion);
 		}
 	}
@@ -579,8 +579,11 @@
 			rect.y = srcY;
 			rect.width = Math.max (0, width);
 			rect.height = Math.max (0, height);
-			GDK.gdk_window_invalidate_rect (drawable, rect, false);
-//			OS.gdk_window_clear_area_e(drawable, srcX, srcY, width, height);
+			if (GTK.GTK4) {
+				GDK.gdk_surface_invalidate_rect (drawable, rect);
+			} else {
+				GDK.gdk_window_invalidate_rect (drawable, rect, false);
+			}
 		} else {
 			if (deltaX != 0) {
 				int newX = destX - deltaX;
@@ -589,8 +592,11 @@
 				rect.y = srcY;
 				rect.width = Math.abs(deltaX);
 				rect.height = Math.max (0, height);
-				GDK.gdk_window_invalidate_rect (drawable, rect, false);
-//				OS.gdk_window_clear_area_e(drawable, newX, srcY, Math.abs(deltaX), height);
+				if (GTK.GTK4) {
+					GDK.gdk_surface_invalidate_rect (drawable, rect);
+				} else {
+					GDK.gdk_window_invalidate_rect (drawable, rect, false);
+				}
 			}
 			if (deltaY != 0) {
 				int newY = destY - deltaY;
@@ -599,8 +605,11 @@
 				rect.y = newY;
 				rect.width = Math.max (0, width);
 				rect.height = Math.abs(deltaY);
-				GDK.gdk_window_invalidate_rect (drawable, rect, false);
-//				OS.gdk_window_clear_area_e(drawable, srcX, newY, width, Math.abs(deltaY));
+				if (GTK.GTK4) {
+					GDK.gdk_surface_invalidate_rect (drawable, rect);
+				} else {
+					GDK.gdk_window_invalidate_rect (drawable, rect, false);
+				}
 			}
 		}
 	}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
index 6a7ca9a..03ad58e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
@@ -45,6 +45,7 @@
 public class Canvas extends Composite {
 	Caret caret;
 	IME ime;
+	long /*int*/ cachedCairo;
 	boolean blink, drawFlag;
 
 Canvas () {}
@@ -178,6 +179,7 @@
 		 result = super.gtk_draw (widget, cairo);
 		if (isFocus) caret.setFocus ();
 	} else {
+		this.cachedCairo = cairo;
 		result = super.gtk_draw (widget, cairo);
 		/*
 		 *  blink is needed to be checked as gtk_draw() signals sent from other parts of the canvas
@@ -317,6 +319,8 @@
 }
 
 void scrollInPixels (int destX, int destY, int x, int y, int width, int height, boolean all) {
+	long /*int*/ cairo = this.cachedCairo;
+	if (cairo == 0) return;
 	if ((style & SWT.MIRRORED) != 0) {
 		int clientWidth = getClientWidth ();
 		x = clientWidth - width - x;
@@ -327,9 +331,12 @@
 	if (!isVisible ()) return;
 	boolean isFocus = caret != null && caret.isFocusCaret ();
 	if (isFocus) caret.killFocus ();
-	long /*int*/ window = paintWindow ();
-	long /*int*/ visibleRegion = GDK.gdk_window_get_visible_region (window);
+	GdkRectangle clipRect = new GdkRectangle ();
+	GDK.gdk_cairo_get_clip_rectangle (cairo, clipRect);
 	cairo_rectangle_int_t srcRect = new cairo_rectangle_int_t ();
+	srcRect.convertFromGdkRectangle(clipRect);
+	long /*int*/ gdkResource = GTK.GTK4? paintSurface () : paintWindow ();
+	long /*int*/ visibleRegion = Cairo.cairo_region_create_rectangle(srcRect);
 	srcRect.x = x;
 	srcRect.y = y;
 	/*
@@ -377,63 +384,48 @@
 		redrawWidget (x, y, width, height, false, false, false);
 		redrawWidget (destX, destY, width, height, false, false, false);
 	} else {
-		long /*int*/ cairo = 0;
-		long /*int*/ context = 0;
-		if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-			long /*int*/ cairo_region = GDK.gdk_window_get_visible_region(window);
-			context = GDK.gdk_window_begin_draw_frame(window, cairo_region);
-			cairo = GDK.gdk_drawing_context_get_cairo_context(context);
-		} else {
-			cairo = GDK.gdk_cairo_create(window);
-		}
-		if (Cairo.cairo_version() < Cairo.CAIRO_VERSION_ENCODE(1, 12, 0)) {
-			GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
-		} else {
-			Cairo.cairo_push_group(cairo);
-			GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
-			Cairo.cairo_paint(cairo);
-			Cairo.cairo_pop_group_to_source(cairo);
-		}
+		Cairo.cairo_push_group(cairo);
+		Cairo.cairo_paint(cairo);
+		Cairo.cairo_pop_group_to_source(cairo);
 		double[] matrix = {1, 0, 0, 1, -deltaX, -deltaY};
 		Cairo.cairo_pattern_set_matrix(Cairo.cairo_get_source(cairo), matrix);
 		Cairo.cairo_rectangle(cairo, copyRect.x + deltaX, copyRect.y + deltaY, copyRect.width, copyRect.height);
 		Cairo.cairo_clip(cairo);
 		Cairo.cairo_paint(cairo);
-		if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-			if (context != 0) GDK.gdk_window_end_draw_frame(window, context);
-		} else {
-			Cairo.cairo_destroy(cairo);
-		}
 		boolean disjoint = (destX + width < x) || (x + width < destX) || (destY + height < y) || (y + height < destY);
 		if (disjoint) {
-			cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
-			rect.x = x;
-			rect.y = y;
-			rect.width = width;
-			rect.height = height;
-			Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
+			cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
+			cairoRect.x = x;
+			cairoRect.y = y;
+			cairoRect.width = width;
+			cairoRect.height = height;
+			Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
 		} else {
-			cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
+			cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
 			if (deltaX != 0) {
 				int newX = destX - deltaX;
 				if (deltaX < 0) newX = destX + width;
-				rect.x = newX;
-				rect.y = y;
-				rect.width = Math.abs(deltaX);
-				rect.height = height;
-				Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
+				cairoRect.x = newX;
+				cairoRect.y = y;
+				cairoRect.width = Math.abs(deltaX);
+				cairoRect.height = height;
+				Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
 			}
 			if (deltaY != 0) {
 				int newY = destY - deltaY;
 				if (deltaY < 0) newY = destY + height;
-				rect.x = x;
-				rect.y = newY;
-				rect.width = width;
-				rect.height = Math.abs(deltaY);
-				Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
+				cairoRect.x = x;
+				cairoRect.y = newY;
+				cairoRect.width = width;
+				cairoRect.height = Math.abs(deltaY);
+				Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
 			}
 		}
-		GDK.gdk_window_invalidate_region(window, invalidateRegion, all);
+		if (GTK.GTK4) {
+			GDK.gdk_surface_invalidate_region(gdkResource, invalidateRegion);
+		} else {
+			GDK.gdk_window_invalidate_region(gdkResource, invalidateRegion, all);
+		}
 	}
 	Cairo.cairo_region_destroy (visibleRegion);
 	Cairo.cairo_region_destroy (copyRegion);
@@ -442,10 +434,10 @@
 		Control [] children = _getChildren ();
 		for (int i=0; i<children.length; i++) {
 			Control child = children [i];
-			Rectangle rect = child.getBoundsInPixels ();
-			if (Math.min(x + width, rect.x + rect.width) >= Math.max (x, rect.x) &&
-				Math.min(y + height, rect.y + rect.height) >= Math.max (y, rect.y)) {
-					child.setLocationInPixels (rect.x + deltaX, rect.y + deltaY);
+			Rectangle childBounds = child.getBoundsInPixels ();
+			if (Math.min(x + width, childBounds.x + childBounds.width) >= Math.max (x, childBounds.x) &&
+				Math.min(y + height, childBounds.y + childBounds.height) >= Math.max (y, childBounds.y)) {
+					child.setLocationInPixels (childBounds.x + deltaX, childBounds.y + deltaY);
 			}
 		}
 	}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index ee2c76a1..9d202ec 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -191,23 +191,22 @@
 	if (imHandle != 0) display.removeWidget (imHandle);
 }
 
-void drawBackground (Control control, long /*int*/ window, long /*int*/ region, int x, int y, int width, int height) {
-	drawBackground(control, window, 0, region, x, y, width, height);
-}
-
-void drawBackground (Control control, long /*int*/ window, long /*int*/ cr, long /*int*/ region, int x, int y, int width, int height) {
-	long /*int*/ cairo = 0;
-	long /*int*/ context = 0;
-	if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-		if (cr == 0) {
-			long /*int*/ cairo_region = region != 0 ? region: GDK.gdk_window_get_visible_region(window);
-			context = GDK.gdk_window_begin_draw_frame(window, cairo_region);
-			cairo = GDK.gdk_drawing_context_get_cairo_context(context);
+void drawBackground (Control control, long /*int*/ gdkResource, long /*int*/ cr, long /*int*/ region, int x, int y, int width, int height) {
+	long /*int*/ cairo = cr;
+	if (region == 0 && gdkResource != 0) {
+		cairo_rectangle_int_t regionRect = new cairo_rectangle_int_t ();
+		int [] fetchedHeight = new int [1];
+		int [] fetchedWidth = new int [1];
+		if (GTK.GTK4) {
+			gdk_surface_get_size(gdkResource, fetchedWidth, fetchedHeight);
 		} else {
-			cairo = cr;
+			gdk_window_get_size(gdkResource, fetchedWidth, fetchedHeight);
 		}
-	} else {
-		cairo = cr != 0 ? cr : GDK.gdk_cairo_create(window);
+		regionRect.x = 0;
+		regionRect.y = 0;
+		regionRect.width = fetchedWidth[0];
+		regionRect.height = fetchedHeight[0];
+		region = Cairo.cairo_region_create_rectangle(regionRect);
 	}
 	/*
 	 * It's possible that a client is using an SWT.NO_BACKGROUND Composite with custom painting
@@ -245,11 +244,6 @@
 	}
 	Cairo.cairo_rectangle (cairo, x, y, width, height);
 	Cairo.cairo_fill (cairo);
-	if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-		if (cairo != cr && context != 0) GDK.gdk_window_end_draw_frame(window, context);
-	} else {
-		if (cairo != cr) Cairo.cairo_destroy(cairo);
-	}
 }
 
 boolean drawGripper (GC gc, int x, int y, int width, int height, boolean vertical) {
@@ -6763,12 +6757,9 @@
 				GdkRectangle rect = new GdkRectangle ();
 				GDK.gdk_cairo_get_clip_rectangle (cairo, rect);
 				if (control == null) control = this;
-				long /*int*/ window = GTK.gtk_widget_get_window (handle);
-				if (window != 0) {
-					drawBackground (control, window, 0, 0, rect.x, rect.y, rect.width, rect.height);
-				} else {
-					drawBackground (control, 0, cairo, 0, rect.x, rect.y, rect.width, rect.height);
-				}
+				long /*int*/ gdkResource = GTK.GTK4 ? GTK.gtk_widget_get_surface(handle) :
+					GTK.gtk_widget_get_window(handle);
+				drawBackground (control, gdkResource, cairo, 0, rect.x, rect.y, rect.width, rect.height);
 			}
 			break;
 		}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
index f1f9a00..46dcfe5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
@@ -1504,6 +1504,12 @@
 	Display display = getCurrent ();
 	Widget widget = display.getWidget (handle);
 	if (widget != null) widget.snapshotToDraw(handle, snapshot);
+	long /*int*/ child = GTK.gtk_widget_get_first_child(handle);
+	// Propagate the snapshot down the widget tree
+	while (child != 0) {
+		GTK.gtk_widget_snapshot_child(handle, child, snapshot);
+		child = GTK.gtk_widget_get_next_sibling(child);
+	}
 	return 0;
 }
 
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
index 1d10480..a8850a2 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
@@ -2233,20 +2233,19 @@
 	return 0;
 }
 
-void drawInheritedBackground (long /*int*/ eventPtr, long /*int*/ cairo) {
+void drawInheritedBackground (long /*int*/ cairo) {
 	if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
 		Control control = findBackgroundControl ();
 		if (control != null) {
-			long /*int*/ window = GTK.gtk_tree_view_get_bin_window (handle);
-			long /*int*/ rgn = 0;
-			if (eventPtr != 0) {
-				GdkEventExpose gdkEvent = new GdkEventExpose ();
-				OS.memmove (gdkEvent, eventPtr, GdkEventExpose.sizeof);
-				if (window != gdkEvent.window) return;
-				rgn = gdkEvent.region;
-			}
 			int [] width = new int [1], height = new int [1];
-			gdk_window_get_size (window, width, height);
+			long /*int*/ gdkResource;
+			if (GTK.GTK4) {
+				gdkResource = gtk_widget_get_surface(handle);
+				gdk_surface_get_size (gdkResource, width, height);
+			} else {
+				gdkResource = GTK.gtk_tree_view_get_bin_window (handle);
+				gdk_window_get_size (gdkResource, width, height);
+			}
 			int bottom = 0;
 			if (itemCount != 0) {
 				long /*int*/ iter = OS.g_malloc (GTK.GtkTreeIter_sizeof ());
@@ -2259,7 +2258,7 @@
 				OS.g_free (iter);
 			}
 			if (height [0] > bottom) {
-				drawBackground (control, window, cairo, rgn, 0, bottom, width [0], height [0] - bottom);
+				drawBackground (control, gdkResource, cairo, 0, 0, bottom, width [0], height [0] - bottom);
 			}
 		}
 	}
@@ -2283,7 +2282,7 @@
 		GTK.gtk_widget_queue_draw(handle);
 		return 0;
 	}
-	drawInheritedBackground (0, cairo);
+	drawInheritedBackground (cairo);
 	return super.gtk_draw (widget, cairo);
 }
 
@@ -4180,15 +4179,15 @@
 			 * expose events. The fix is to fill the background in the inverse expose
 			 * event.
 			 */
-			if (itemCount == 0 && (state & OBSCURED) == 0) {
+			if (itemCount == 0 && (state & OBSCURED) == 0 && !GTK.GTK4) {
 				if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
 					Control control = findBackgroundControl ();
 					if (control != null) {
-						GdkEventExpose gdkEvent = new GdkEventExpose ();
-						OS.memmove (gdkEvent, arg0, GdkEventExpose.sizeof);
 						long /*int*/ window = GTK.gtk_tree_view_get_bin_window (handle);
-						if (window == gdkEvent.window) {
-							drawBackground (control, window, gdkEvent.region, gdkEvent.area_x, gdkEvent.area_y, gdkEvent.area_width, gdkEvent.area_height);
+						if (window == GTK.gtk_widget_get_window(handle)) {
+							GdkRectangle rect = new GdkRectangle ();
+							GDK.gdk_cairo_get_clip_rectangle (arg0, rect);
+							drawBackground (control, window, arg0, 0, rect.x, rect.y, rect.width, rect.height);
 						}
 					}
 				}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolTip.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolTip.java
index 620f019..a89d321 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolTip.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ToolTip.java
@@ -505,23 +505,9 @@
 	return 0;
 }
 
-void drawTooltip (long /*int*/ cr) {
-	long /*int*/ gdkResource = GTK.GTK4 ? gtk_widget_get_surface(handle) : gtk_widget_get_window (handle);
+void drawTooltip (long /*int*/ cairo) {
 	int x = BORDER + PADDING;
 	int y = BORDER + PADDING;
-	long /*int*/ cairo = 0;
-	long /*int*/ context = 0;
-	if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-		if (cr == 0) {
-			long /*int*/ cairo_region = GDK.gdk_window_get_visible_region(gdkResource);
-			context = GDK.gdk_window_begin_draw_frame(gdkResource, cairo_region);
-			cairo = GDK.gdk_drawing_context_get_cairo_context(context);
-		} else {
-			cairo = cr;
-		}
-	} else {
-		cairo = cr != 0 ? cr : GDK.gdk_cairo_create(gdkResource);
-	}
 	if (cairo == 0) error (SWT.ERROR_NO_HANDLES);
 	int count = borderPolygon.length / 2;
 	if (count != 0) {
@@ -565,11 +551,6 @@
 		Cairo.cairo_move_to(cairo, x, y);
 		OS.pango_cairo_show_layout(cairo, layoutMessage);
 	}
-	if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
-		if (cairo != cr && context != 0) GDK.gdk_window_end_draw_frame(gdkResource, context);
-	} else {
-		if (cairo != cr) Cairo.cairo_destroy(cairo);
-	}
 }
 
 @Override
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
index 495b1d5..5f41ce8 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
@@ -2305,20 +2305,19 @@
 	return 0;
 }
 
-void drawInheritedBackground (long /*int*/ eventPtr, long /*int*/ cairo) {
+void drawInheritedBackground (long /*int*/ cairo) {
 	if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
 		Control control = findBackgroundControl ();
 		if (control != null) {
-			long /*int*/ window = GTK.gtk_tree_view_get_bin_window (handle);
-			long /*int*/ rgn = 0;
-			if (eventPtr != 0) {
-				GdkEventExpose gdkEvent = new GdkEventExpose ();
-				OS.memmove (gdkEvent, eventPtr, GdkEventExpose.sizeof);
-				if (window != gdkEvent.window) return;
-				rgn = gdkEvent.region;
-			}
 			int [] width = new int [1], height = new int [1];
-			gdk_window_get_size (window, width, height);
+			long /*int*/ gdkResource;
+			if (GTK.GTK4) {
+				gdkResource = gtk_widget_get_surface(handle);
+				gdk_surface_get_size (gdkResource, width, height);
+			} else {
+				gdkResource = GTK.gtk_tree_view_get_bin_window (handle);
+				gdk_window_get_size (gdkResource, width, height);
+			}
 			long /*int*/ parent = 0;
 			int itemCount = GTK.gtk_tree_model_iter_n_children (modelHandle, parent);
 			GdkRectangle rect = new GdkRectangle ();
@@ -2336,7 +2335,7 @@
 			}
 			if (parent != 0) OS.g_free (parent);
 			if (height [0] > (rect.y + rect.height)) {
-				drawBackground (control, window, cairo, rgn, 0, rect.y + rect.height, width [0], height [0] - (rect.y + rect.height));
+				drawBackground (control, gdkResource, cairo, 0, 0, rect.y + rect.height, width [0], height [0] - (rect.y + rect.height));
 			}
 		}
 	}
@@ -2360,7 +2359,7 @@
 		GTK.gtk_widget_queue_draw(handle);
 		return 0;
 	}
-	drawInheritedBackground	(0, cairo);
+	drawInheritedBackground	(cairo);
 	return super.gtk_draw (widget, cairo);
 }
 
@@ -4134,11 +4133,11 @@
 				if ((state & PARENT_BACKGROUND) != 0 || backgroundImage != null) {
 					Control control = findBackgroundControl ();
 					if (control != null) {
-						GdkEventExpose gdkEvent = new GdkEventExpose ();
-						OS.memmove (gdkEvent, arg0, GdkEventExpose.sizeof);
 						long /*int*/ window = GTK.gtk_tree_view_get_bin_window (handle);
-						if (window == gdkEvent.window) {
-							drawBackground (control, window, gdkEvent.region, gdkEvent.area_x, gdkEvent.area_y, gdkEvent.area_width, gdkEvent.area_height);
+						if (window == GTK.gtk_widget_get_window(handle)) {
+							GdkRectangle rect = new GdkRectangle ();
+							GDK.gdk_cairo_get_clip_rectangle (arg0, rect);
+							drawBackground (control, window, arg0, 0, rect.x, rect.y, rect.width, rect.height);
 						}
 					}
 				}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
index 60e7e40..e9e5b82 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
@@ -1204,19 +1204,6 @@
 	sendEvent (eventType, event, false);
 }
 
-void propagateSnapshot (long /*int*/ widget, long /*int*/ snapshot) {
-	long /*int*/ list = GTK.gtk_container_get_children (widget);
-	long /*int*/ temp = list;
-	while (temp != 0) {
-		long /*int*/ child = OS.g_list_data (temp);
-		if (child != 0) {
-			GTK.gtk_widget_snapshot_child(widget, child, snapshot);
-		}
-		temp = OS.g_list_next (temp);
-	}
-	OS.g_list_free (list);
-}
-
 void register () {
 	if (handle == 0) return;
 	if ((state & HANDLE) != 0) display.addWidget (handle, this);
@@ -1868,13 +1855,8 @@
 	long /*int*/ rect = Graphene.graphene_rect_alloc();
 	Graphene.graphene_rect_init(rect, 0, 0, allocation.width, allocation.height);
 	long /*int*/ cairo = GTK.gtk_snapshot_append_cairo(snapshot, rect);
-	gtk_draw(handle, cairo);
+	if (cairo != 0) gtk_draw(handle, cairo);
 	Graphene.graphene_rect_free(rect);
-	// Propagates the snapshot down the widget hierarchy so that other widgets
-	// will draw.
-	if (GTK.GTK_IS_CONTAINER(handle)) {
-		propagateSnapshot(handle, snapshot);
-	}
 	return;
 }