GNOME Bugzilla – Bug 538090
GCompositedIcon
Last modified: 2008-08-01 19:05:33 UTC
Hi, It would be useful to have support for compositing icons; for example in the gvfs volume monitor backend we want to convey that a given volume is encrypted. As it's not practical to require three times the amount of volume icons [1], another solution is to add emblems programmatically via the the GIcon interface.. First I thought of writing a GEmblemedIcon class. It would look something like this. GEmblemedIcon *icon, *main *emblem1, *emblem2; main = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-usb"); emblem1 = g_themed_icon_new_with_default_fallbacks ("emblem-encrypted-locked"); emblem2 = g_themed_icon_new_with_default_fallbacks ("some-other-emblem"); icon = g_emblemed_icon_new (main emblem1, emblem2, NULL); But after examining how emblems (as defined by the Icon Theme Specification [2]) really work I discovered two main problems with this approach 1. AFAICT it's not well-defined what size to use for emblems; I think implementations are free to choose their own size. Which makes things unpredictable. 2. Given the AttachPoints the resulting icon (e.g. after having added the emblems at the given attachment points) may be larger than the original image; IOW the emblems can't fit in the original image. This is a real show stopper with the way GIcon works. As such I decided a more direct approach. Enter GCompositedIcon back_icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk-ieee1394" front_icon = g_themed_icon_new_with_default_fallbacks ("emblem-encrypted-unlocked"); icon = g_composited_icon_new (back_icon, front_icon); Basically, GCompositedIcon will just compose two given GIcon's; there's a back and a front. That's it. Will attach code for both glib and gtk+ to support this. Thanks for considering. [1] : e.g. "drive-harddisk", "drive-harddisk-encrypted-locked", "drive-harddisk-encrypted-unlocked" - need to convey both that a volume is locked or unlocked. [2] : http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
Created attachment 112651 [details] gcompositedicon.h
Created attachment 112652 [details] gcompositedicon.c
Created attachment 112653 [details] [review] teach gtk+ about GCompositedIcon
Created attachment 112654 [details] what it looks like
Open questions - should we support positioning/size of the front icon? - should the user be able to specify an operator for compositing? - other?
Nack. I thought we had discussed this and agreed that general compositing is not the way to go
I don't really buy either of your problems: > 1. AFAICT it's not well-defined what size to use for emblems; I think > implementations are free to choose their own size. Which makes things > unpredictable. This is about themes, so what you get is unpredictable anyway. > 2. Given the AttachPoints the resulting icon (e.g. after having added > the emblems at the given attachment points) may be larger than the > original image; IOW the emblems can't fit in the original image. This > is a real show stopper with the way GIcon works. Nah. icon sizes are only nominal anyway. There is no guarantee that you'll get an icon at exactly the size you ask for. Well, there wasn't until current GTK+ trunk added a flag to force the size. And we can do similar things with emblems.
(In reply to comment #7) > I don't really buy either of your problems: > > > 1. AFAICT it's not well-defined what size to use for emblems; I think > > implementations are free to choose their own size. Which makes things > > unpredictable. > > This is about themes, so what you get is unpredictable anyway. Not really. And it doesn't answer how the size should be chosen. > > 2. Given the AttachPoints the resulting icon (e.g. after having added > > the emblems at the given attachment points) may be larger than the > > original image; IOW the emblems can't fit in the original image. This > > is a real show stopper with the way GIcon works. > > Nah. icon sizes are only nominal anyway. > There is no guarantee that you'll get an icon at exactly the size you ask for. > Well, there wasn't until current GTK+ trunk added a flag to force the size. > And we can do similar things with emblems. Maybe I was unclear. Anyway, suppose we somehow magically have chosen a size for the emblem (relative to the requested size). Remember that the attachment point is chosen by the theme. Here's the problem in a nutshell. +E------+ +I----------+ | | | | | | | | | | +----|--+ | | | | +-----------+ with E being an emblem for I. Clearly this won't fit. There are two options from here i. You take the smallest bounding box enclosing both E and I and downscale that stuff to the requested size. ii. You somehow make E fit bit translating/scaling E so it fits in I Option i. suck because one predominant use of GIcon's is in a treeview. So you'd want the icon without the emblem and the icon with the emblem to look similar modulo the existence of the emblem. If we downscale just to make the emblem fit this is going to look like crap. Option ii. suck because we're ignoring attachment points. I think the idea of generalizing emblems to something as low-level as GIcon doesn't really work. It works in Nautilus because it's able to special case the rendering and thus escape the problem of not making things fit.
> Not really. And it doesn't answer how the size should be chosen. Ideally, the icon theme should decide by putting emblems in the 'nominal size' for which they fit - ie emblems that are suitable for decorating size 32 icons would live in 32x32/emblems. This is how nautilus did things, traditionally. However, certain icon naming spec authors didn't like that... Here is how nautilus currently finds the size to use: if (size >= 96) return 48; if (size >= 64) return 32; if (size >= 48) return 24; if (size >= 32) return 16; return 0; /* no emblems for smaller sizes */ If you look at what NautilusCellRendererPixbufEmblem does, it actually does better than both of your ideas. It does allow the emblem to overshoot the icon like in your drawing: +E------+ +I----------+ | | | | | | | | | | +----|--+ | | | | +-----------+ by as much as there is padding in the cell around the pixbuf, and then it draws the emblem over the padding area, to not affect the cell size.
> I think the idea of generalizing emblems to something as low-level as GIcon > doesn't really work. It works in Nautilus because it's able to special case the > rendering and thus escape the problem of not making things fit. You have a point here. Maybe the right answer is to add gicon support to gtkcellrendererpixbuf, and have it do the same things nautiluscellrendererpixbufemblem does for GEmblemedIcon. Of course, GtkImage and GtkIconTheme also need to handle GEmblemedIcon somehow.
And btw, I believe the attach points are mostly a red herring. We should just ignore them when they don't make sense. nautiluscellrendererpixbufemblem does, too
> I think the idea of generalizing emblems to something as low-level as GIcon > doesn't really work. It works in Nautilus because it's able to special case the > rendering and thus escape the problem of not making things fit. It's a compounding problem. If we try to treat it as one problem, it doesn't generalize well, but if you split up the components, it works better. The first problem is providing a "container" icon, e.g. GCompositeIcon or GContainerIcon (blegh, no good with names), similar to GtkContainer; just add stuff to it (_add(), _remove(), maybe _find()/_contains()). It's perhaps a bit more silly to leave this unbounded, but it's simple to use, and is more flexible (rather than special casing "front"/"back" or "main"/"child"). The second problem is how to render it, and it's a bit more complex. Perhaps it would be better to provide some kind of interface (be it actually a GInterface which is probably overkill or just a vtable function in places where it makes sense) so applications can implement their own renderers and have Gtk+ use them. We could provide the simple cases with Gtk+ itself, e.g. Nautilus' "attach emblems to icons" and David's case of "combine the icons into one metaicon"; providing your own renderer in the case that the container icon may have many sensible child icons, but in your situation you only want a specific one if it exists or a maximum of two children at a time, or if you want to get fancy with compositing and layout in your canvas or Clutter app, etc. It's perhaps over-engineered, but at least it blends in with what we are already doing, and very simple to explain and understand.
Nack. All of this is on the one side over-engineered in that it leads to icons which are disguised scene graphs/rendering trees, and similar nonsense. On the other side, a gio/gtk+ specific solution falls short in that it doesn't allow to specify icon+emblem combinations to be specified anywhere outside of the toolkit, e.g in a desktop file.
The latter is a good point, and not one I considered. At some level, these changes are going to be desktop-specific, we can't expect it to be perfect everywhere and agree with us, but at the same time, having emblems in desktop files does make sense. One could add a key for emblems, but it's just spreading the problem around. I'm just not a big fan of the +emblem solution, as it feels "tacked-on", and that it will proliferate a lot of otherwise unused special-case icons vs. having a nice set of generic icon primitives and building necessary custom ones from there. (Sorry for rambling, I do that when I'm nervous...) But if we don't want to composite icons at all, your way is probably the way to go.
Just to update this bug: We'll end up with a gio-specific solution anyway. GEmblemedIcon has been committed recently. Exact details of the api are still being worked out.