Re: gtk_widget_draw()



On Tue, 2010-08-17 at 13:43 -0500, Federico Mena Quintero wrote:
> On Tue, 2010-08-17 at 17:28 +0200, Benjamin Otte wrote:
> > The biggest problem for me when reading the GdkWindow code is that I
> > have no idea what a window is. So I have a hard time understanding the
> > code and if what it does is sane.
> 
> One pattern we see a lot is when widgets want to paint themselves on
> their parent container's background, but still receive events.  They are
> NO_WINDOW widgets, which means "I want to share my parent's window", and
> then they also create INPUT_ONLY windows to catch events.
> 
> This is a very useful pattern.  Such widgets are basically saying:
> 
> - "Just give me a nicely-prepared surface to draw on" (i.e. with the
> parent's contents already drawn)
> 
> - "And let me catch events, too".
> 
> The funny thing is that not only "non-square" widgets like labels do
> this; buttons also do this for aesthetic purposes.

Yeah, they do it to avoid the window resize being asynchronous with
respect to the repainting, etc, causing ugly looking resizes.

> I think it seems sane to move to a model where
> 
> 1. The only native windows (with an XID) are toplevels, with a few
> exceptions (see below),
> 
> 2. All subwindows are all GDK-side abstractions.  They define a clipping
> region and a coordinate system.  See below for transparency issues.
> 
> 3. The exception is when you need a native window to do funky stuff
> (OpenGL, plug/socket, xv, etc.).  These (sub)windows are understood to
> be limited - you may not be able to transform them and such.

This is exactly the current model with client side windows.

> The interesting part is (2), or what happens with subwindows.
> 
> Non-square widgets that want to paint to their parent's background would
> still benefit from having a "transparent" window to paint on - this
> would give you an already-prepared surface (with whatever the parent
> painted), a clipping region and a coordinate system.  That is, GtkLabel
> wouldn't have to clip the text itself and add allocation->{x,y} all the
> time.

Yes. I've long thought about having something like this. Then we could
just drop no-window widgets. This might make widget rendering a bit more
regular as there is at least a simple relationship between a window and
a widget (each window belongs to a single widget, one widget may have
multiple windows).

This is very similar to input-only window really. Its kinda inbetween.
Input only windows only do the events, transparent windows do the
rendering and clipping, but render the parent first without clipping to
the transparent childs (like it doesn't clip to input-only children).

Additionally I was thinking one could specify a "border" on the window
such that for clipping purposes and calculation of what has to be
repainted we grow the window by the border width, while for events and
the rest we use the normal size. This makes it easy to implement themes
that have a more organic look, for instance having a "glow" on an active
button that extends outside the button without affecting events, etc.

> Square widgets that completely cover their area are of course trivial to
> implement in that model - they would just overwrite their parent's
> contents with their own.  I don't know if we want to be able to avoid
> painting the parent's regions that we *know* will be completely
> obscured.  Think of a white text area over a gradient window background
> - drawing that gradient may be expensive and so you certainly want to
> paint only the areas that will *not* be the white text area... or maybe
> not, if you can just ask the GPU to draw the whole gradient.

Well, the white text area would just not be transparent and then the
drawing in the parent would be clipped to the child just like now.

Also, for the current no-window widget this is what we do already
anyway.

> Do we need a "window->need_parent_background" flag?  I.e. the "paint the
> parent first, don't clip to the subwindow" flag?

Not sure what you mean. We need a single flag "is this window
transparent". If it is that means:
1) It does not add to its parents clip-region
2) When redrawing it we must draw all parents and lower stacked siblings
before drawing it.

> This is the core of Alex's argument for keeping the impls separate, I
> think.  GdkWindow exposes a public API (with a few leaks such as
> gimme_the_native_window_id()); the internal impls switch in and out as
> you reparent things.
> 
> Who uses reparenting, anyway?

Dnd of toolbars items, detachable docks, putting plugs in sockets, etc. 

> > - What do we do with event masks? I learned yesterday that widgets
> > without EXPOSURE_MASK don't get their background cleared. Is that
> > documented? Or should that even be the case? Do we even need event
> > masks?
> 
> Clearing the background or not depends on the hypothetical
> "is-this-window-transparent" flag that we discussed above.
> 
> Event masks are an X-ism, I think... I really don't know if they matter
> much with local connections (except maybe to save context switches);
> they may definitely help in remote connections.  Something tells me that
> Owen will know more about this from when he was profiling GTK+'s X
> stream.

Event masks affect more than performance though. They are combined to
decide which window gets each event. For instance, if you have a window
somewhere with a bunch of child hierarchies, and the window has the
event mask for mouse motion, then it will get mouse motion even over the
child windows, unless the child window sets mask for mouse motion too.
So, just sending everything everywhere is not a solution.

> > But there are operations that do not make sense at all on a
> > non-toplevel window. Like setting the icon or the title. And I'd argue
> > that it's confusing for widget implementors that they need to think
> > about this stuff when creating a window for their widget.
> > For offscreen windows, a lot more of the window operations don't make sense.
> 
> If you wanted to really segregate functionality based on the window
> type, I guess you could have
> 
>   if (gdk_is_toplevel (some_window)) {
>      GdkToplevelWindow *t = gdk_window_get_toplevel_iface (some_window);
>      gdk_window_set_title (t, "hello world");
>   }
> 
> I.e. force the caller to get an iface that really supports the window
> functions based on the window's type.  I don't know if that is
> gratuitously painful or actually cleaner :)

Just more pain. :)

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
       alexl redhat com            alexander larsson gmail com 
He's a time-tossed devious grifter on a search for his missing sister. She's 
an artistic streetsmart femme fatale on the trail of a serial killer. They 
fight crime! 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]