After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 502997 - [quartz] User defined pixmap not shown in GtkImages
[quartz] User defined pixmap not shown in GtkImages
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: Quartz
2.12.x
Other Mac OS
: Normal major
: ---
Assigned To: gtk-quartz maintainers
gtk-bugs
: 529544 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2007-12-11 08:44 UTC by Gabriele Greco
Modified: 2010-06-27 09:03 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fix for the problem described in this bug (1.09 KB, patch)
2008-11-26 09:34 UTC, Stephen Fisher
none Details | Review

Description Gabriele Greco 2007-12-11 08:44:15 UTC
Please describe the problem:
It seems that the quartz backend have a few problem to show images loaded from in memory buffers in GtkImage widget but also non CList pixmap columns. The strange thing is that if you SET the GtkImage TWICE, the second time you "set" it the image is displayed. To reproduce the problem I've created a small C executable.

Steps to reproduce:
Here is a simple program to reproduce the problem:

#include "gtk/gtk.h"

static char * cross_xpm[] = {
"16 16 2 1",
" c None",
". c #FF0000",
" ",
" .. ",
" ... ... ",
" ... ... ",
" .. ... ",
" ... .. ",
" .... ",
" .. ",
" ... ",
" ...... ",
" ... ... ",
" ... ... ",
" ... ... ",
" .. .. ",
" ",
" "};

GtkWidget *create_pixmap(GtkWidget *ref, void *ptr)
{
GtkWidget *pixmap;
GdkPixmap *gdkpixmap;
GdkBitmap *mask;
gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
gtk_widget_get_colormap(ref), &mask, NULL, ptr);
pixmap = gtk_image_new_from_pixmap (gdkpixmap, mask);
gdk_pixmap_unref (gdkpixmap);
gdk_bitmap_unref (mask);
return pixmap;
}

int main(int argc, char *argv[])
{
GtkWidget *w, *b;
gtk_init(&argc, &argv);
w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
b = gtk_toggle_button_new();
gtk_container_add(GTK_CONTAINER(b), create_pixmap(w, cross_xpm));
gtk_container_add(GTK_CONTAINER(w), b);
gtk_widget_show_all(w);
gtk_main();
return 0;
}

Actual results:
The image in the toggle button is not shown.

Expected results:
Have a toggle button with a small cross inside.

Does this happen every time?
Yes.

Other information:
Comment 1 Richard Hult 2008-07-25 07:13:02 UTC
*** Bug 529544 has been marked as a duplicate of this bug. ***
Comment 2 Richard Hult 2008-08-15 09:42:37 UTC
I think the reason is that gdkgc-quartz.c is a bit confused with regards to clipping. It uses a CGImage as clip mask, but you are supposed to have a special CGImage for clip masks (see CGImageMaskCreate).

Comment 3 Stephen Fisher 2008-10-25 22:34:36 UTC
You're right on the mark, Richard :)  I was having the same problem with XPM images in Wireshark when compiling it against GTK 2.14.4 built from source or from the new GTK Framework I recently downloaded.

Below is the syntax of the fix you suggested on MacOS 10.5 (sorry, I don't have a patch against SVN as I haven't gotten gtk-doc to compile with the xml/xsl stuff yet). 

Note that the reference on Apple's developer site for CGImageMaskCreate() state that there are more parameters than my 10.5 SDK version of the CGImage.h header file (/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Headers/CGImage.h) specifies.  I don't have a 10.4 machine to try compiling this on to see if it too has fewer parameters.

In file gdkgc-quartz.c in the function gdk_quartz_gc_set_values(), I first added a variable called image:

  CGImageRef image;

Then under "if (values->clip_mask) {" in the same function, I added:

  image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT (values->clip_mask)->impl)->image; 

And right below that, I changed the "private->clip_mask =" to be:

 	private->clip_mask = CGImageMaskCreate (
						CGImageGetWidth (image),
						CGImageGetHeight (image),
						CGImageGetBitsPerComponent (image),
						CGImageGetBitsPerPixel (image),
						CGImageGetBytesPerRow (image),
						CGImageGetDataProvider (image),
						NULL,
						TRUE
						);

I recompiled GTK and the XPM images show up correctly now!  I hope this helps get this issue fixed :).
Comment 4 Guy Harris 2008-10-25 22:55:21 UTC
On my 10.5 system, the 10.4u SDK has

    CG_EXTERN CGImageRef CGImageMaskCreate(size_t width, size_t height,
        size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow,
        CGDataProviderRef provider, const float decode[],
        bool shouldInterpolate);

in all the versions of the header I could find, and the 10.5 SDK has

    CG_EXTERN CGImageRef CGImageMaskCreate(size_t width, size_t height,
        size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow,
        CGDataProviderRef provider, const CGFloat decode[],
        bool shouldInterpolate);

which differs only in the type of the "decode" argument.

The developer.apple.com documentation at

    http://developer.apple.com/documentation/GraphicsImaging/Reference/CGImage/Reference/reference.html

has

CGImageRef CGImageMaskCreate (
   size_t width,
   size_t height,
   size_t bitsPerComponent,
   size_t bitsPerPixel,
   size_t bytesPerRow,
   CGDataProviderRef provider,
   const CGFloat decode[],
   bool shouldInterpolate
);

which matches the 10.5 SDK.
Comment 5 Stephen Fisher 2008-10-25 23:03:48 UTC
Thanks for the clarification, Guy.  It looks like I had copied the parameters into the code from CGImageCreate() originally, which is quite similar but adds a few more fields.

Comment 6 Stephen Fisher 2008-11-26 09:34:51 UTC
Created attachment 123409 [details] [review]
Fix for the problem described in this bug
Comment 7 Stephen Fisher 2008-11-26 09:36:55 UTC
The patch I just attached (123409) fixes this bug in the same way that I described in comment #3 and is attached for your convenience.

Comment 8 Gabriele Greco 2009-01-15 16:36:24 UTC
I've tried to add the attached fix to the current SVN (updated as of today, revision 22121) and the patch doesn't fix the problem, it changes it, but the problem is still present.

After recompiling gdk and the test program I can see the pixmaps but only random parts of them, it seems that the mask for the blit is configured but the bitmap it points to is a random area... So maybe the problem is in the CGImage that is passed in values->clip_mask to gdk_quartz_gc_set_values()...

Comment 9 Stephen Fisher 2009-02-01 01:38:13 UTC
My patch is still working in the latest SVN (22268) for me.  Note that the problem my patch aims to fix is that pixmaps cannot be seen at all.  Is that the problem you're having, Gabriele?  Or do the random parts of the pixmap only show up after applying my patch?

Comment 10 Gabriele Greco 2009-03-19 08:38:26 UTC
Random parts of the pixmap shows instead of the correct pixmap after the patch is applied!
Comment 11 Hsivank 2010-05-26 21:33:08 UTC
I try the small example on Debian sid ( gtk v2.20.1 ) and it seems that it doesn't work too !
Someone can confirm ? Anyway ...

The patch provided by Stephen Fisher fixes bugs on Wireshark and Gimp2 and maybe some others apps on Macosx... 
I would like to know why it has not been integrated in Gtk source ?
Is it possible that a Gtk developer reviews this patch ?
Comment 12 Paul Davis 2010-05-26 22:02:52 UTC
possibly because there is a report above that the patch causes other problems that were not already there beforehand ?

for this to get integrated, the problem(s) referred to in comments 8-10 would need to be addressed and fixed first.
Comment 13 Hsivank 2010-05-26 22:42:27 UTC
Thanks for your quick answer !

I didn't find any reports that the patch causes other problems.
Have you some feedbacks ?

>for this to get integrated, the problem(s) referred to in comments 8-10 would need to be addressed and fixed first.

I'm very disappointed cause the example doesn't seem to work on gtk-x11 (Linux) too. ( i wonder if it has ever worked !!! )

Maybe there are 2 bugs ?

I can confirm that the patch of Stefen Fisher works great on Macosx 10.5 and 10.6 with *std* apps ... 
This bug is very old now ... and does not provide a good feeling of GTK on Macosx ...
A workaround could be to accept this patch ... and waiting for a potential report ... 

What is your opinion ?
Comment 14 Paul Davis 2010-05-26 22:51:43 UTC
comments 8-10 describe problems caused by this patch. please read them. the patch author has already commented on them. they are unresolved.

if the test program (also) doesn't work with the X11 backend, it would be very wise to look elsewhere for a solution to this problem. it doesn't mean that there could not be 2 different bugs in two different backends, but it does make it a little more unlikely that its actually the quartz backend that has an issue. 

however, i just tested it on fedora with gtk+ 2.18.9, and the test program works OK there.
Comment 15 Hsivank 2010-05-26 23:06:25 UTC
>comments 8-10 describe problems caused by this patch. please read them. the patch author has already commented on them. they are unresolved.
Sorry, I was thinking that this behavior was not a side effect of the patch cause my test was unsuccessful with gtk v2.20.1 on Linux ...

>but it does make it a little more unlikely that its actually the quartz backend that has an issue. 
Definitely yes ! there is a bug with the quartz backend
Comment 16 Hsivank 2010-05-29 03:40:26 UTC
i change cross_xpm with :

static char * cross_xpm2[] = {
	"16 16 2 1",
	"  c None",
	". c #FF0000",
	"                ",
	" ..             ",
	" ... ...        ",
	" ... ...        ",
	" .. ...         ",
	" ... ..         ",
	" ....           ",
	" ..             ",
	" ...            ",
	" ......         ",
	" ... ...        ",
	" ... ...        ",
	" ... ...        ",
	" .. ..          ",
	"                ",
	"                "};

it works !

looking at pixbuf_create_from_xpm (gdk-pixbuf/io-xpm.c)

for (ycnt = 0; ycnt < h; ycnt++) {
		pixtmp = pixbuf->pixels + ycnt * pixbuf->rowstride;

		buffer = (*get_buf) (op_body, handle);
		if ((!buffer) || (strlen (buffer) < wbytes))
			continue;

		for (n = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) {
Comment 17 Hsivank 2010-05-29 03:53:03 UTC
it will not fill image if it cannot find a correct line size ... and the content of buffer image will be unpredictable

This is why my test failed on Linux too ...

i'm curious to know how your test was successful?  Maybe  2.18.9 use a different pixbuf_create_from_xpm implementation or gtk links against a dedicated xpm library ...

I still consider the patch provided by Stephen Fisher as valid, and see no reason to not integrate it as soon as possible.
Comment 18 Hsivank 2010-05-29 04:12:43 UTC
small bug in my previous post :/

correct xpm : 

static char * cross_xpm2[] = {
	"16 16 2 1",
	" c None",
	". c #FF0000",
	"                ",
	" ..             ",
	" ... ...        ",
	" ... ...        ",
	" .. ...         ",
	" ... ..         ",
	" ....           ",
	" ..             ",
	" ...            ",
	" ......         ",
	" ... ...        ",
	" ... ...        ",
	" ... ...        ",
	" .. ..          ",
	"                ",
	"                "};
Comment 19 Hsivank 2010-06-05 00:05:02 UTC
The bug occurs when the pixmap has alpha channel ( as cross_xpm).
When i test the alpha channel property of image returned by  

image = GDK_PIXMAP_IMPL_QUARTZ (GDK_PIXMAP_OBJECT(values->clip_mask)->impl)->image;

with

CGImageAlphaInfo info = CGImageGetAlphaInfo(image);

i get kCGImageAlphaNone :/


it seems there is a second bug in :
GdkPixmap* _gdk_pixmap_new (GdkDrawable *drawable,...)

i think, it should not fix alpha_info to kCGImageAlphaNoneSkipLast for 24 bits depth ?

i try with kCGImageAlphaPremultipliedLast , the result seems correct :)
Comment 20 Kristian Rietveld 2010-06-14 21:17:14 UTC
As far as I understand the 24 bits depth does not contain space for the alpha channel (it would have to be 32 bits for that).  The alpha channel is actually stored in this "mask".

I suspect the clipping as well and it looks like more changes are necessary than done in the attachment in comment 6. I will investigate.
Comment 21 Hsivank 2010-06-14 21:44:34 UTC
 (In reply to comment #20)
> As far as I understand the 24 bits depth does not contain space for the alpha channel (it would have to be 32 bits for that).  
yes sure. 

The depth pass to _gdk_pixmap_new is not the depth of the pixmap. it seems to be obtained from the colormap of the widget 

( simplied shema )
GtkWidget *ref 
...
GdkColormap     *colormap = gtk_widget_get_colormap(ref);
...
gint depth = gdk_colormap_get_visual (colormap)->depth;


Then it fix the apha_info field according the depth value (gdk/quartz/gdkpixmap-quartz.c:139) :

GdkPixmap*_gdk_pixmap_new (GdkDrawable *drawable, gint width,gint  height,gint depth)
...
switch (depth)
    {
    case 24:
      alpha_info = kCGImageAlphaNoneSkipLast;
      ...
      break;
    case 32:
      alpha_info = kCGImageAlphaPremultipliedFirst;
      ...
      break;
    case 1:
      alpha_info = kCGImageAlphaNone;
      ...
      break;
       ....
    }
...
pix_impl->data = g_malloc (height * bytes_per_row);
data_provider = CGDataProviderCreateWithData (pix_impl->data, pix_impl->data, 
						height * bytes_per_row, data_provider_release);
pix_impl->image = CGImageCreate (width, height, 8, bits_per_pixel, 
				   bytes_per_row, colorspace,
				   alpha_info,
				   data_provider, NULL, FALSE, 
				   kCGRenderingIntentDefault);

Here, there is a problem cause the pixmap contains alpha channel but it is created with kCGImageAlphaNoneSkipLast flag ...
So the mask produced from this pixmap is not really correct
Comment 22 Kristian Rietveld 2010-06-16 08:27:02 UTC
(In reply to comment #21)
> Here, there is a problem cause the pixmap contains alpha channel but it is
> created with kCGImageAlphaNoneSkipLast flag ...
> So the mask produced from this pixmap is not really correct

The XPM contains an alpha channel and this is generally loaded into a GdkPixmap *and* GdkBitmap.  The GdkBitmap contains the mask for this image.  GdkPixmap does not contain an alpha channel.
Comment 23 Kristian Rietveld 2010-06-16 08:32:06 UTC
Comment on attachment 123409 [details] [review]
Fix for the problem described in this bug

I have been debugging some more, and the patch does not fix the bug.  This is due to the different semantics CGContextClipToMask() has depending on the nature of the provided CGImageRef (i.e. whether it is an image mask, created with CGImageMaskCreate(), or not).

The mask that is created by gdk_pixbuf_render_threshold_alpha() upon loading the pixmap has bits set to high that must appear on the screen and not be filtered out.  This corresponds with providing an image to CGContextClipToMask() and not an image mask.
Comment 24 Kristian Rietveld 2010-06-16 08:40:41 UTC
I have almost figured these issues out.  The main problem is that the mask that is being rendered by gdk_pixbuf_render_threshold_alpha() is rendered incorrectly because it is attempted to draw on a GdkBitmap that is backed by a gray colorspace CGImage with an RGBA color.  So the drawing that is attempted yields no changes in the mask bitmap (which is uninitialized memory, so you get a "garbage" mask).  When I added a hack to set the color in the gray color space, the mask was set up (almost) correctly and things seems to work almost fine.

Tonight I will work on a patch to the Quartz backend to properly take the different color spaces into account when setting colors.  This should fix the main part of this bug.

After that it looks like there are some small rounding or rotation issues remaining before the bug is fully solved.
Comment 25 Hsivank 2010-06-16 10:10:44 UTC
(In reply to comment #22)

> The XPM contains an alpha channel and this is generally loaded into a GdkPixmap
> *and* GdkBitmap.  The GdkBitmap contains the mask for this image.  GdkPixmap
> does not contain an alpha channel.

You mean : *GdkBitmap* does not contain an alpha channel.
Yes, the mask should be a gray space image. 
But if you pass an incorrect pixmap to CGImageMaskCreate it will create an incorrect mask ...
Comment 26 Kristian Rietveld 2010-06-16 10:21:52 UTC
(In reply to comment #25)
> (In reply to comment #22)
> You mean : *GdkBitmap* does not contain an alpha channel.

Both GdkPixmap and GdkBitmap do not have an alpha channel.

> Yes, the mask should be a gray space image. 
> But if you pass an incorrect pixmap to CGImageMaskCreate it will create an
> incorrect mask ...

That's what's going on, see comment 24.
Comment 27 Kristian Rietveld 2010-06-26 08:42:55 UTC
I got the masking working properly now.

(In reply to comment #24)
> After that it looks like there are some small rounding or rotation issues
> remaining before the bug is fully solved.

This was a flipping issue.  The clip mask that was created at run-time by drawing on the bitmap, had to be flipped before it was put to use.


I found a couple of issues that are likely related to pixmap/bitmap drawing in testgtk.  I want to have a look at these first before I test the patch set on Tiger as well and commit it to the git repo.
Comment 28 Kristian Rietveld 2010-06-27 08:50:06 UTC
(In reply to comment #27)
> I found a couple of issues that are likely related to pixmap/bitmap drawing in
> testgtk.  I want to have a look at these first before I test the patch set on
> Tiger as well and commit it to the git repo.

These issues seem to have been there before I started changing things.  Apparently related to GtkCList/GtkCTree drawing outside expose events which is unsupported.  And this widget is deprecated anyway ...
Comment 29 Kristian Rietveld 2010-06-27 09:03:44 UTC
Pushed to gtk-2-22: 42d07ad..9f5f47f and 3770d91
Pushed to master as well.