Bug 301517

Summary: oxygen-gtk crashes on rendering background of offscreen windows
Product: [Plasma] Oxygen Reporter: Jakub Filak <filak.jakub>
Component: gtk3-engineAssignee: Hugo Pereira Da Costa <hugo.pereira.da.costa>
Status: RESOLVED FIXED    
Severity: normal CC: b7.10110111, hugo.pereira.da.costa, web
Priority: NOR    
Version: 4.0   
Target Milestone: ---   
Platform: Fedora RPMs   
OS: Linux   
Latest Commit: Version Fixed In:
Attachments: proposed patch

Description Jakub Filak 2012-06-09 16:29:52 UTC
I've found out that it is not possible to run glade in my KDE desktop with widget style oxygen-gtk. If I click on the new window icon from toolbar glage immeadiately crashes with SIGSEGV.

glade creates a GDK_WINDOW_OFFSCREEN window and oxygen-gtk wants to get frame extents for this window. The problem is that it is not possible to get frame extents of an offscreen window. 

I guess, this problem is related to those lines from oxygen-gtk "TODO"
	
44: Gtk3-Demo -> offscreen pixmap -> effects 
45: crash.

However, my gtk3-demo doesn't have 'offscreen pixmap' menu. My version of gtk3-demo have 'Offscreen windows' -> Effects and it works. (glade doesn't work)

The foloowing lines are copied from glade, gtk and oxygen-gtk sources.
The lines show steps to crash.

1. glade creates an attributes for offscreen window
glade_design_layout_realize() : gladeui/glade-design-layout.c : 1630
  attributes.window_type = GDK_WINDOW_OFFSCREEN;

2.
glade_design_layout_realize() : gladeui/glade-design-layout.c : 1644
  ipriv->offscreen_window = gdk_window_new (gtk_widget_get_root_window (widget),
                                            &attributes, attributes_mask);

3.
gdk_window_new () : gdk/gdkwindow.c 11375
  if (gdk_window_is_offscreen (window))
    {
      _gdk_offscreen_window_new (window, attributes, attributes_mask);

4. Private helper function
gdk_window_is_offscreen() : gdk/gdkwindow.c : 11375
  static gboolean
  gdk_window_is_offscreen (GdkWindow *window)
  {
        return window->window_type == GDK_WINDOW_OFFSCREEN;
  }

5.
_gdk_offscreen_window_new() : gdk/gdkoffscreenwindow.c : 803
  window->impl = g_object_new (GDK_TYPE_OFFSCREEN_WINDOW, NULL);

6.
gdk_offscreen_window_class_init() : gdk/gdkoffscreenwindow.c : 766
  impl_class->get_frame_extents = NULL;

-- Set implementation function to NULL. (IMHO it is not a good idea.)
  
-- And finally.

7.
Gtk::gdk_toplevel_get_frame_size() : src/oxygengtkutils.cpp : 882
  gdk_window_get_frame_extents( topLevel, &rect );

8.
gdk_window_get_frame_extents() : gdk/gdkwindow.c : 10443
  GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_frame_extents (window, rect);
                                               
-- Ooops, get_frame_extents is NULL here



Reproducible: Always

Steps to Reproduce:
1. run glade
2. click on the Window icon from Toplevels toolbar
Actual Results:  
glade crashes

Expected Results:  
a new window item appears in glade work area

I found this bug on Fedora 16 x86_64 with following configuration:
oxygen-gtk3-1.0.4-1.fc16.x86_64
gtk3-3.2.4-1.fc16.x86_64
glade3-3.10.0-6.fc16.x86_64

backtrace:
#0  0x0000000000000000 in ?? ()
#1  0x00007fa524b0f9c6 in gdk_toplevel_get_frame_size (h=0x7fff8f06a904, w=0x7fff8f06a900, window=<optimized out>)
    at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygengtkutils.cpp:882
#2  Oxygen::Gtk::gdk_toplevel_get_frame_size (window=<optimized out>, w=0x7fff8f06a900, h=0x7fff8f06a904)
        at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygengtkutils.cpp:868
#3  0x00007fa524b0fd25 in Oxygen::Gtk::gdk_window_map_to_toplevel (window=0x18cbd80 [GdkX11Window], x=0x7fff8f06a908, y=0x7fff8f06a90c, w=0x7fff8f06a900, h=
            0x7fff8f06a904, frame=true) at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygengtkutils.cpp:747
#4  0x00007fa524b2ba4e in gdk_map_to_toplevel (frame=<optimized out>, h=<optimized out>, w=<optimized out>, y=<optimized out>, x=<optimized out>, 
                widget=<optimized out>, window=<optimized out>) at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygengtkutils.h:117
#5  Oxygen::Style::renderWindowBackground (this=0xde2000, context=0x3e7b8a7860, window=0x18cbd80 [GdkX11Window], widget=0x0, x=0, y=0, w=440, h=250, options=
                    ..., tiles=...) at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygenstyle.cpp:264
#6  0x00007fa524b77af5 in renderWindowBackground (tiles=<optimized out>, o=..., h=0, w=0, y=0, x=0, window=0x18cbd80 [GdkX11Window], context=0x3e7b8a7860, 
                        this=<optimized out>) at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygenstyle.h:141
#7  Oxygen::render_background (engine=<optimized out>, context=0x3e7b8a7860, x=0, y=0, w=440, h=250)
                            at /usr/src/debug/oxygen-gtk3-1.0.4/src/oxygenthemingengine.cpp:311
#8  0x0000003e733d080e in gtk_render_background (context=0x1a8b030 [GtkStyleContext], cr=0x3e7b8a7860, x=0, y=0, width=440, height=250)
                                at gtkstylecontext.c:3740
#9  0x0000003e7349ade8 in gtk_window_draw (widget=0xf04470 [GtkWindow], cr=0x3e7b8a7860) at gtkwindow.c:7449
#10 0x0000003e733529d8 in _gtk_marshal_BOOLEAN__BOXED (closure=0xd68d30, return_value=0x7fff8f06b0e0, n_param_values=<optimized out>, param_values=0x1efacd0, 
                                    invocation_hint=<optimized out>, marshal_data=<optimized out>) at gtkmarshalers.c:85
#11 0x0000003e7347ccf0 in gtk_widget_draw_marshaller (closure=0xd68d30, return_value=0x7fff8f06b0e0, n_param_values=2, param_values=0x1efacd0, 
                                        invocation_hint=<optimized out>, marshal_data=<optimized out>) at gtkwidget.c:819
#12 0x0000003e6be0ea44 in g_closure_invoke (closure=0xd68d30, return_value=0x7fff8f06b0e0, n_param_values=2, param_values=0x1efacd0, 
                                            invocation_hint=<optimized out>) at gclosure.c:774
#13 0x0000003e6be20b7c in signal_emit_unlocked_R (node=<optimized out>, detail=0, instance=0xf04470, emission_return=0x7fff8f06b240, instance_and_params=
        0x1efacd0) at gsignal.c:3310
#14 0x0000003e6be29f33 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=<optimized out>)
            at gsignal.c:3013
#15 0x0000003e6be2a302 in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3060
#16 0x0000003e7348e46a in _gtk_widget_draw_internal (clip_to_size=1, cr=0x3e7b8a7860, widget=0xf04470 [GtkWindow]) at gtkwidget.c:5722
#17 _gtk_widget_draw_internal (widget=0xf04470 [GtkWindow], cr=0x3e7b8a7860, clip_to_size=<optimized out>) at gtkwidget.c:5698
#18 0x0000003e7348e5b1 in gtk_widget_send_expose (widget=0xf04470 [GtkWindow], event=<optimized out>) at gtkwidget.c:5969
#19 0x0000003e73352879 in gtk_main_do_event (event=0x7fff8f06b450) at gtkmain.c:1801
#20 0x0000003e72634c0f in _gdk_window_process_updates_recurse (window=0x18cbd80 [GdkX11Window], expose_region=0xf57740) at gdkwindow.c:3857
#21 0x0000003e72634baf in _gdk_window_process_updates_recurse (window=0x18cbc60 [GdkX11Window], expose_region=0x18e9130) at gdkwindow.c:3830
#22 0x0000003e726341df in gdk_window_process_updates_internal (window=0x18cbc60 [GdkX11Window]) at gdkwindow.c:4013
#23 0x0000003e72634650 in gdk_window_process_all_updates () at gdkwindow.c:4144
#24 0x0000003e732ccc56 in gtk_container_idle_sizer (data=<optimized out>) at gtkcontainer.c:1664
#25 0x0000003e7261a38f in gdk_threads_dispatch (data=0x1ad4900) at gdk.c:754
#26 0x0000003e69e44f3d in g_main_dispatch (context=0xd9ca20) at gmain.c:2441
#27 g_main_context_dispatch (context=0xd9ca20) at gmain.c:3011
#28 0x0000003e69e45738 in g_main_context_iterate (context=0xd9ca20, block=<optimized out>, dispatch=1, self=<optimized out>) at gmain.c:3089
#29 0x0000003e69e45c85 in g_main_loop_run (loop=0x1052e80) at gmain.c:3297
#30 0x0000003e7335198d in gtk_main () at gtkmain.c:1362
#31 0x00000000004087cc in main (argc=1, argv=0x7fff8f06b948) at main.c:187
Comment 1 Jakub Filak 2012-06-09 16:32:29 UTC
Created attachment 71684 [details]
proposed patch

I'm not sure where fix this bug. I usually choose the way of minimal changes therefore I added a special casing for offscreen windows to oxygen-gtk code.
Comment 2 Ruslan Kabatsayev 2012-06-09 16:42:37 UTC
> gdk_offscreen_window_class_init() : gdk/gdkoffscreenwindow.c : 766
>  impl_class->get_frame_extents = NULL;

Great... so they think we should know that for some windows the methods aren't implemented... especially if this is undocumented.
Your patch looks good, but... doesn't this look like a GTK bug? Have you asked GTK devs what they think of this?
Comment 3 Jakub Filak 2012-06-09 17:09:18 UTC
You are right, it looks like a GTK bug. But, according to the following comment from gtk/gtkoffscreenwindow.c file:

 * GtkOffscreenWindow derives from #GtkWindow only as an implementation
 * detail.  Applications should not use any API specific to #GtkWindow
 * to operate on this object.  It should be treated as a #GtkBin that
 * has no parent widget.

it is an intention to not treat an offscreen window as "general window". (now I doubt about correctness of my patch, but I saw similar lines in gtk code)

I haven't asked GTK devs ... I'm going to talk to someone from GTK on monday. As I wrote in details, I do think that implementation should always implement all of the inherited methods (if they want to simulate OOP in C they should simulate everything and only subset of features) ... I saw about a dozen of unimplemented methods in offscreen window impl and I bet they won't be willing to implement all of them. (IMHO it doesn't make sense to implement only get_frames_extent() function )
Comment 4 Hugo Pereira Da Costa 2012-06-21 14:33:15 UTC
Ruslan ? So what's the plan ? Push the patch ? Resolve as Upstream ? (that is not a fix) ? 
I think pushing the patch is good. Alternatively, we can actually check if the underlying function is actually implemented or not (similar to what's done in oxygenanimations, l245 or so, in current gtk3 branch, namely: )

            GtkWidgetClass* widgetClass = GTK_WIDGET_GET_CLASS( widget );
            if( widgetClass && widgetClass->style_updated )
            {...}
Comment 5 Ruslan Kabatsayev 2012-06-21 14:39:15 UTC
Well, if you are good with more and more hacks here, push it :) More seriously, I think we'll not get gtk devs to fix this on their side so I guess we'll have to do this. So, I'm ok with pushing this patch.
Comment 6 Jakub Filak 2012-06-21 14:40:03 UTC
I send an email to gtk-devel-list 14 days ago but the email wasn't approved after a week of waiting :( therefore I've created a bug for gtk 3 and I proposed a patch for this bug ... https://bugzilla.gnome.org/show_bug.cgi?id=678369
Comment 7 Hugo Pereira Da Costa 2012-06-21 14:48:07 UTC
@Ruslan ... I guess Jakub's patch (to oxygen-gtk3) is actually less hacky than mine so I'd rather push his. (to minimize hacks)

@Jakub,
The patch you submitted to gtk3 is impressive and cool. Keep us posted if it ever gets pushed.
Comment 8 Jakub Filak 2012-06-21 14:53:00 UTC
I spent about 4 hours with coding and testing but I have never believed that the patch can be accepted :D
Comment 9 Hugo Pereira Da Costa 2012-06-21 14:59:55 UTC
... mmm unless I misunderstood, I cannot reproduce with glade3 version 3.8.2
and gtk3 version 3.5.2

See: http://wstaw.org/m/2012/06/21/plasma-desktoppF2751.png

(after clicking from new project on the leftmost button (first row) below TopLevel).

What do I miss ?
Comment 10 Jakub Filak 2012-06-21 15:17:44 UTC
From glade git:

commit ebd9b9a5c28b5ec50c29c19f3b7f8f6d83ed93ac
Author: Juan Pablo Ugarte <jp@synctv.com>
Date:   Wed Jan 12 16:20:13 2011 -0300

    Experimental offscreen GladeDesignLayout

commit 121840b6082224fd5444af1eca61f9234b726eba
Author: Tristan Van Berkom <tristan.van.berkom@gmail.com>
Date:   Tue Feb 1 19:56:07 2011 +0900

...
NEWS
+Glade 3.9.2
...
+	- Added support for editing a GtkOffscreenWindow
...

So I guess, you have to use at least glade 3.9.2. I wrote glade3-3.10.0-6.fc16.x86_64 to bug description.
Comment 11 Jakub Filak 2012-06-21 15:22:23 UTC
And as you may see here https://bugs.launchpad.net/ubuntu/+source/anjuta/+bug/982645 glade is not the only app which uses offscreen windows.
Comment 12 Hugo Pereira Da Costa 2012-06-21 15:53:41 UTC
Git commit 99da2cf5a71b99d268ddee12c4b1c8ad678172ca by Hugo Pereira Da Costa.
Committed on 21/06/2012 at 17:50.
Pushed by hpereiradacosta into branch 'gtk3'.

do not call gdk_window_get_frame_extents on OFFSCREEN_WINDOWS, because underlying function is not implemented, which
results in crash.

M  +15   -4    src/oxygengtkutils.cpp

http://commits.kde.org/oxygen-gtk/99da2cf5a71b99d268ddee12c4b1c8ad678172ca
Comment 13 Hugo Pereira Da Costa 2012-06-21 15:53:42 UTC
Git commit 9ae5ad4fe0f393b8ebcda1050ee0a19e3da18650 by Hugo Pereira Da Costa.
Committed on 21/06/2012 at 17:50.
Pushed by hpereiradacosta into branch 'gtk3-1.0'.

do not call gdk_window_get_frame_extents on OFFSCREEN_WINDOWS, because underlying function is not implemented, which
results in crash.

M  +15   -4    src/oxygengtkutils.cpp

http://commits.kde.org/oxygen-gtk/9ae5ad4fe0f393b8ebcda1050ee0a19e3da18650
Comment 14 Hugo Pereira Da Costa 2012-06-21 15:56:54 UTC
So ... fixed.
As for the actual gtk3 bug, a 'simpler' patch, that might get accepted would be to just check for the validity of the get_frame_extents function pointer in the wrapper function gdk_window_get_frame_extents, dump an error string and leave the rect unchanged. At least this would result in no crash.

Closing. 
Thanks for tracking this down, reporting, and providing the patch
(that's ideal bug report I'd say. Wish we had more like these :))