Repository navigation
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Reused column model slots retain stale surfaces, causing removed images to reappear.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Uses scale-aware Cairo surfaces to render crisp Tree/Table images on GTK3 HiDPI displays.
Changes:
- Binds GTK3 cell renderers to stored image surfaces.
- Registers pixbuf data callbacks for all Tree/Table renderers.
- Adds the GTK
surfaceproperty constant.
| File | Description |
|---|---|
Tree.java |
Renders Tree images from Cairo surfaces. |
Table.java |
Renders Table images from Cairo surfaces. |
OS.java |
Defines the native surface property name. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
4734b80 to
ea39ed9
Compare
ea39ed9 to
cfece1f
Compare
|
There are all the details to handle here but it also fixes a nasty drawing problem: with GDK_SCALE=2 draws a solid gray instead of striped. |
cfece1f to
ab288e4
Compare
98c9281 to
010e9df
Compare
0ee8728 to
371ae10
Compare
|
Fixed |
371ae10 to
74ebb77
Compare
|
@akurtakov let me know if you have more feedback otherwise I plan to merge tomorrow. |
|
Thanks for this, the crisp icons are a real improvement. I have a few concerns, mostly about the GTK3 path.
I measured it on a plain 10,000-row Table on GTK3 at 100%, with nothing done after shell.open(). A TableItem subclass counts the isDisposed() calls that come from cellDataProc:
At scale 1 every one of those calls does nothing: item lookup, qdata, a scale and state query, then it falls through. So "unchanged at 100%" holds for what is drawn, but not for cost. Now that CELL_SURFACE is a boxed CairoSurface column on GTK3, could the renderer's surface property be bound with gtk_tree_view_column_add_attribute instead? The pixbuf/surface binding would be swapped when the scale or sensitivity changes, so nothing would run in Java per row, and plain widgets would keep master's cost.
|
74ebb77 to
73b133a
Compare
|
Thanks, all addressed and force-pushed. The image is now bound via |
|
There are conflicts |
73b133a to
6f860f9
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Runtime DPI changes reuse surfaces cached at the previous scale, leaving moved Trees and Tables blurry.
2 open findings
2 resolved since last review
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
| long dpiChanged (long object, long arg0) { | ||
| long result = super.dpiChanged (object, arg0); | ||
| updateCellImageBinding (); |
| long dpiChanged (long object, long arg0) { | ||
| long result = super.dpiChanged (object, arg0); | ||
| updateCellImageBinding (); |
|
I have split the getImage() part of this PR into #3695, so the bug fix can go in on its own while the HiDPI rendering is reviewed. #3695 contains:
It needs no new natives, behaves the same at every scale, and fixes getImage() returning another item's image once a disposed image's ImageList slot is reused. The Table, Tree, item and column tests (389) pass on GTK3 and GTK4. You're kept as the commit author. |
getImage() mapped the cell's surface address back to an Image through the ImageList. Once the slot of a disposed Image was reused, it returned the Image of another cell, and a column created after another one was disposed could report the old column's image. TableItem and TreeItem now keep the Image of each cell in a per column array, maintained like cellFont, and getImage() returns from it. getTextBounds() and the owner draw measure and paint code ignore a disposed cell image instead of failing in getBounds(). Split from eclipse-platform#3631. Assisted-by: multiple AI agents and layers of automated tooling 🤖 Assisted-by: Anthropic Claude Code (claude-opus-5-5)
getImage() mapped the cell's surface address back to an Image through the ImageList. Once the slot of a disposed Image was reused, it returned the Image of another cell, and a column created after another one was disposed could report the old column's image. TableItem and TreeItem now keep the Image of each cell in a per column array, maintained like cellFont, and getImage() returns from it. getTextBounds() and the owner draw measure and paint code ignore a disposed cell image instead of failing in getBounds(). Split from eclipse-platform#3631. Assisted-by: multiple AI agents and layers of automated tooling 🤖 Assisted-by: Anthropic Claude Code (claude-opus-5-5)
6f860f9 to
35961bc
Compare
getImage() mapped the cell's surface address back to an Image through the ImageList. Once the slot of a disposed Image was reused, it returned the Image of another cell, and a column created after another one was disposed could report the old column's image. TableItem and TreeItem now keep the Image of each cell in a per column array, maintained like cellFont, and getImage() returns from it. getTextBounds() and the owner draw measure and paint code ignore a disposed cell image instead of failing in getBounds(). Split from #3631. Assisted-by: multiple AI agents and layers of automated tooling 🤖 Assisted-by: Anthropic Claude Code (claude-opus-5-5)
35961bc to
dd1c1ad
Compare
GtkCellRendererPixbuf treats the "pixbuf" attribute as a scale 1 image, so at 200% zoom native Tree and Table cell images were reduced to 1x and upscaled again, while the same image drawn with GC.drawImage stayed sharp. On GTK3 at a widget scale factor above 1 the pixbuf renderer now binds its "surface" property to the CELL_SURFACE model column, a boxed cairo surface that carries the device scale, instead of "pixbuf". The binding is swapped through gtk_tree_view_column_add_attribute, so plain widgets run no Java code per row: the cell data function is still installed only for VIRTUAL, custom draw and owner draw, as before, and there it sets the surface or the pixbuf according to the same mode. The binding goes back to "pixbuf" when the control is disabled, because the surface bypasses GTK's insensitive icon effect, and when the scale factor drops to 1. Table and Tree rebind from enableWidget and from the existing scale factor notification (dpiChanged). At a scale above 1 the cell differs from the 100% rendering in ways inherent to the surface property: theme icon effects on selected or hovered rows are not applied, GTK's accessible image size is missing because it is read from the pixbuf, and the cell draws the surface of the Image itself rather than a pixbuf copy, so drawing into an Image after setImage shows up in the cell at that scale only. A snapshot copy was not added, since it would duplicate the pixels of every cell image that is shared between many rows. Disposing a column also clears its CELL_SURFACE slot, so a column that reuses the slot does not show the old image. getImage() relies on the per cell Image array from eclipse-platform#3695 rather than the surface address. The CELL_SURFACE column type is taken from the value type of the pixbuf renderer's "surface" GParamSpec and a missing type raises ERROR_NO_HANDLES instead of being cached as 0. The VIRTUAL path keeps setData = checkData (item), since binding by attribute needs no early return. Assisted-by: multiple AI agents and layers of automated tooling 🤖
dd1c1ad to
3117e06
Compare





On GTK3 at 200% zoom, images set with
TreeItem.setImageorTableItem.setImagewere rendered blurry, becauseGtkCellRendererPixbuftreats the bound pixbuf as a scale 1 image.At a scale factor above 1 the pixbuf renderer now binds its
surfaceproperty to theCELL_SURFACEmodel column, which carries the device scale, so native cell images are as sharp asGC.drawImageoutput.The binding is swapped with
gtk_tree_view_column_add_attributewhen the scale or the enabled state changes, so plain Trees and Tables run no Java code per row, and disabled controls keep GTK's dimmed icons.