Skip to content

Commit a360eeb

Browse files
committed
Fix PaintListener for GTK3 Table and Tree widgets
GTK3 emits two draw-related signals: * EXPOSE_EVENT_INVERSE (after=false) → before GTK draws items * EXPOSE_EVENT (after=true) → after GTK draws items SWT historically dispatched SWT.Paint during EXPOSE_EVENT_INVERSE. For widgets like Table and Tree, GTK draws all rows/cells after this point. Result: anything drawn in a PaintListener was immediately overwritten.
1 parent 24b4c49 commit a360eeb

2 files changed

Lines changed: 80 additions & 2 deletions

File tree

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2310,7 +2310,12 @@ long gtk_draw (long widget, long cairo) {
23102310
return 0;
23112311
}
23122312
drawInheritedBackground (cairo);
2313-
return super.gtk_draw (widget, cairo);
2313+
if (GTK.GTK4) {
2314+
return super.gtk_draw (widget, cairo);
2315+
} else {
2316+
// On GTK3 super.gtk_draw will be lost by items drawing thus handle explicitly in windowProc.
2317+
return 0;
2318+
}
23142319
}
23152320

23162321
@Override
@@ -4116,6 +4121,13 @@ long windowProc (long handle, long arg0, long user_data) {
41164121
}
41174122
propagateDraw(handle, arg0);
41184123
}
4124+
/*
4125+
* Ensure the paint listener's drawing appears on top of items rather than being
4126+
* overwritten by them.
4127+
*/
4128+
if (!GTK.GTK4) {
4129+
gtk3_paintEvent(arg0);
4130+
}
41194131
break;
41204132
}
41214133
case EXPOSE_EVENT_INVERSE: {
@@ -4194,6 +4206,33 @@ void checkSetDataInProcessBeforeRemoval(int start, int end) {
41944206
}
41954207
}
41964208

4209+
/**
4210+
* Fire the paint event explicitly, so the paint listener's drawing is not lost.
4211+
*/
4212+
private void gtk3_paintEvent(long cairo) {
4213+
if ((state & OBSCURED) != 0) return;
4214+
if (drawRegion) {
4215+
cairoClipRegion(cairo);
4216+
}
4217+
if (!hooksPaint()) return;
4218+
GdkRectangle rect = new GdkRectangle();
4219+
GDK.gdk_cairo_get_clip_rectangle(cairo, rect);
4220+
Event event = new Event();
4221+
event.count = 1;
4222+
Rectangle eventBounds = new Rectangle(rect.x, rect.y, rect.width, rect.height);
4223+
if ((style & SWT.MIRRORED) != 0) eventBounds.x = getClientWidth() - eventBounds.width - eventBounds.x;
4224+
event.setBounds(eventBounds);
4225+
GCData data = new GCData();
4226+
if (drawRegion) data.regionSet = eventRegion;
4227+
data.cairo = cairo;
4228+
GC gc = event.gc = GC.gtk_new(this, data);
4229+
gc.setClipping(eventBounds.x, eventBounds.y, eventBounds.width, eventBounds.height);
4230+
drawWidget(gc);
4231+
sendEvent(SWT.Paint, event);
4232+
gc.dispose();
4233+
event.gc = null;
4234+
}
4235+
41974236
@Override
41984237
public void dispose() {
41994238
super.dispose();

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2480,7 +2480,12 @@ long gtk_draw (long widget, long cairo) {
24802480
return 0;
24812481
}
24822482
drawInheritedBackground (cairo);
2483-
return super.gtk_draw (widget, cairo);
2483+
if (GTK.GTK4) {
2484+
return super.gtk_draw (widget, cairo);
2485+
} else {
2486+
// On GTK3 super.gtk_draw will be lost by items drawing thus handle explicitly in windowProc.
2487+
return 0;
2488+
}
24842489
}
24852490

24862491
@Override
@@ -4192,6 +4197,13 @@ long windowProc (long handle, long arg0, long user_data) {
41924197
}
41934198
propagateDraw(handle, arg0);
41944199
}
4200+
/*
4201+
* Ensure the paint listener's drawing appears on top of items rather than being
4202+
* overwritten by them.
4203+
*/
4204+
if (!GTK.GTK4) {
4205+
gtk3_paintEvent(arg0);
4206+
}
41954207
break;
41964208
}
41974209
case EXPOSE_EVENT_INVERSE: {
@@ -4267,6 +4279,33 @@ void checkSetDataInProcessBeforeRemoval() {
42674279
}
42684280
}
42694281

4282+
/**
4283+
* Fire the paint event explicitly, so the paint listener's drawing is not lost.
4284+
*/
4285+
private void gtk3_paintEvent(long cairo) {
4286+
if ((state & OBSCURED) != 0) return;
4287+
if (drawRegion) {
4288+
cairoClipRegion(cairo);
4289+
}
4290+
if (!hooksPaint()) return;
4291+
GdkRectangle rect = new GdkRectangle();
4292+
GDK.gdk_cairo_get_clip_rectangle(cairo, rect);
4293+
Event event = new Event();
4294+
event.count = 1;
4295+
Rectangle eventBounds = new Rectangle(rect.x, rect.y, rect.width, rect.height);
4296+
if ((style & SWT.MIRRORED) != 0) eventBounds.x = getClientWidth() - eventBounds.width - eventBounds.x;
4297+
event.setBounds(eventBounds);
4298+
GCData data = new GCData();
4299+
if (drawRegion) data.regionSet = eventRegion;
4300+
data.cairo = cairo;
4301+
GC gc = event.gc = GC.gtk_new(this, data);
4302+
gc.setClipping(eventBounds.x, eventBounds.y, eventBounds.width, eventBounds.height);
4303+
drawWidget(gc);
4304+
sendEvent(SWT.Paint, event);
4305+
gc.dispose();
4306+
event.gc = null;
4307+
}
4308+
42704309
private void throwCannotRemoveItem(int i) {
42714310
String message = "Cannot remove item with index " + i + ".";
42724311
throw new SWTException(message);

0 commit comments

Comments
 (0)