Closed Bug 410215 Opened 17 years ago Closed 17 years ago

GTK's .xpm decoding is weird, stop using XPM as the default window icon

Categories

(Core :: Widget: Gtk, defect)

Sun
OpenSolaris
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.9beta3

People

(Reporter: Dolske, Assigned: Dolske)

References

Details

Attachments

(1 file, 2 obsolete files)

While looking at Firefox's disk IO in bug 410131, I noticed some bizarre behavior when opening the Download Manager window (or any window, really). The process makes 1096 read() calls in a row, from objdir/dist/bin/chrome/icons/default.xpm. The first 885 are 8K reads, then they start dropping by 16 bytes per read until the final read of 4817 bytes. The file size (default.xpm) is 22346 bytes. I grabbed the call stack for these reads with DTrace: libc.so.1`_read+0x15 libc.so.1`getc+0x6c libpixbufloader-xpm.so`file_buffer+0x112 libpixbufloader-xpm.so`pixbuf_create_from_xpm+0x151 libpixbufloader-xpm.so`gdk_pixbuf__xpm_image_load+0x3f libgdk_pixbuf-2.0.so.0.1000.12`_gdk_pixbuf_generic_image_load+0x3d libgdk_pixbuf-2.0.so.0.1000.12`gdk_pixbuf_new_from_file+0x102 libwidget_gtk2.so`nsWindow::SetWindowIconList()+0x9c libwidget_gtk2.so`nsWindow::SetDefaultIcon()+0x1e2 libwidget_gtk2.so`nsWindow::NativeCreate()+0x8f8 libwidget_gtk2.so`nsWindow::Create()+0x4a libnsappshell.so`nsWebShellWindow::Initialize()+0x24a libnsappshell.so`nsAppShellService::JustCreateTopWindow() +0x286 libnsappshell.so`nsAppShellService::CreateTopLevelWindow()+0x57 libnsappshell.so`nsXULWindow::CreateNewChromeWindow()+0x167 libnsappshell.so`nsXULWindow::CreateNewWindow()+0x83 libtoolkitcomps.so` nsAppStartup::CreateChromeWindow2()+0x1bf libembedcomponents.so`nsWindowWatcher::OpenWindowJSInternal()+0xdea libembedcomponents.so` nsWindowWatcher::OpenWindowJS()+0xf0 So, it's not the XPM decoder in Mozilla's libpr0n doing this, but the decoder in GTK/GDK. Looking at nsWindow::SetWindowIconList() in the debugger confirms that all this stuff is happening with a single invocation the function, with only 1 entry ("default.xpm") in the icon list. The behavior on Linux (Ubuntu 7.04, Feisty) is a little different. Strace shows it making 6 4K reads and 1 1866 byte read. But those reads are embedded in 1085 _llseek() calls, which are also rather bizarre: ... _llseek(84, 4096, [4096], SEEK_SET) = 0 _llseek(84, 4096, [4096], SEEK_SET) = 0 _llseek(84, 4096, [4096], SEEK_SET) = 0 _llseek(84, 4096, [4096], SEEK_SET) = 0 read(84, "169ECF\",\n\"E+\tc #1D99CC\",\n\"F+\tc #"..., 4096) = 4096 _llseek(84, 8192, [8192], SEEK_SET) = 0 _llseek(84, 8192, [8192], SEEK_SET) = 0 _llseek(84, 8192, [8192], SEEK_SET) = 0 _llseek(84, 8192, [8192], SEEK_SET) = 0 ... The repeated seeks are basically no-ops, but are incurring overhead from the user/kernel context switches. This weird file IO takes about 45ms on Solaris, and 25ms on Linux. [Different hardware, so apples-to-oranges.] I had previously opened/closed a window to ensure default.xpm was in the OS disk cache. Txul on the Linux perf test box is about 200ms (on yet another box, so apples-to-oranges-to-pears). Between this not being Mozilla code and XPM being such a crufty old format, I think the best fix here is to replace the .xpm usage with PNG files. I wouldn't be surprised if the distros are already doing this. It looks like gdk_pixbuf_new_from_file() will happily accept arbitrary file formats, and I should think PNG wouldn't be a problem with our relatively-modern reference platform requirements. Indeed, a quick test of "cat foo.png > default.xpm" on my Solaris box shows that this works fine. Also, I suppose someone should file an upstream GDK bug on this?
Blocks: 400179
Attached patch Patch v.1 for review (obsolete) — Splinter Review
This changes the icon setting code to prefer a PNG, and if no PNG is found it falls back to looking for an XPM. This allow us to start switching apps over to PNG without forcing everyone to change at once. I went ahead and rolled in support for additional icon sizes, which would be needed by bug 404402. I only added the sizes recommended by: http://library.gnome.org/devel/gtk/2.8/GtkWindow.html#gtk-window-set-icon-list There's overhead for each size queried -- looks like we stat() in each extension's directory, each time a window is opened. So, we probably don't want this list to include every conceivable icon size. SetDefaultIcon() seemed to be needlessly duplicating code, so I just have it use SetIcon() now too. Tested on Solaris, confirmed the XPM fallback works and that when multiple icons are count GTK seems to prefer the right size.
Assignee: nobody → dolske
Status: NEW → ASSIGNED
Attachment #295160 - Flags: superreview?(roc)
Attachment #295160 - Flags: review?(roc)
The SetIcon API for setting icons by loading them from files seems ultra-lame. Why don't we just load image(s) using our own image loader(s), and convert to a pixbuf using pixbuf conversion code already in our tree (and similar for other platforms). Then the platform-specific code would be reduced quite a bit and we'd be able to use whatever image formats we support. Oh well.
How about just adding those .xpm extensions to the extensions array? You can have an extra check inside the loop so that if we've just looked up the last .png extension and the list is nonempty, we exit early. "extensions" would be better as an array of chars. So const char extensions[6][7] = { ".png", ... }; and use an nsAutoString local to copy the extension, or for bonus points, make ResolveIconName take a char* for the extension and do the conversion internally.
(In reply to comment #4) > How about just adding those .xpm extensions to the extensions array? I think it would be better to leave them separate, since it should be removed as soon as projects migrate away from .xpm. > "extensions" would be better as an array of chars. So > const char extensions[6][7] = { ".png", ... }; ok. > and use an nsAutoString local to copy the extension, or for bonus points, make > ResolveIconName take a char* for the extension and do the conversion > internally. How do I pound a char* into a nsAutoString? Wouldn't a nsDependentCString be better? *sigh* I hate our string API.
Attached patch Patch v.2 (obsolete) — Splinter Review
Like so?
Attachment #295160 - Attachment is obsolete: true
Attachment #296103 - Flags: superreview?(roc)
Attachment #296103 - Flags: review?(roc)
Attachment #295160 - Flags: superreview?(roc)
Attachment #295160 - Flags: review?(roc)
> I think it would be better to leave them separate, since it should be removed > as soon as projects migrate away from .xpm. there's no telling when that might happen. In the meantime we can save code. I would just write nsAutoString extension; extension.AppendASCII(...);
Attached patch Patch v.3Splinter Review
Third time's the charm!
Attachment #296103 - Attachment is obsolete: true
Attachment #296111 - Flags: superreview?(roc)
Attachment #296111 - Flags: review?(roc)
Attachment #296103 - Flags: superreview?(roc)
Attachment #296103 - Flags: review?(roc)
Attachment #296111 - Flags: superreview?(roc)
Attachment #296111 - Flags: superreview+
Attachment #296111 - Flags: review?(roc)
Attachment #296111 - Flags: review+
That version is probably better also for the reason that extensions can set their own icons and might use XPMs for some time to come, just to stay compatible with our old versions.
Blocks: 411494
Attachment #296111 - Flags: approval1.9?
Attachment #296111 - Flags: approval1.9? → approval1.9+
cvs commit: Examining widget/src/gtk2 Checking in widget/src/gtk2/nsWindow.cpp; /cvsroot/mozilla/widget/src/gtk2/nsWindow.cpp,v <-- nsWindow.cpp new revision: 1.248; previous revision: 1.247
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla1.9 M11
Blocks: 412049
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: