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 630203 - Prepare mutter code for GTK3 rendering-cleanup
Prepare mutter code for GTK3 rendering-cleanup
Status: RESOLVED FIXED
Product: mutter
Classification: Core
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: mutter-maint
mutter-maint
Depends on:
Blocks:
 
 
Reported: 2010-09-20 19:45 UTC by Benjamin Otte (Company)
Modified: 2010-09-27 15:17 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
ui: Clip the region once, not every rectangle manually (2.68 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Make clip_to_screen() actually clip to the screen (1.34 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove workaround now that clip_to_screen() works properly (2.71 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove client area from region in expose event (3.14 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove NULL checks (913 bytes, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Move begin_paint() handling to expose handler (3.99 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove meta_ui_get_pixbuf_from_pixmap() function (1.63 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove MetaArea widget (8.48 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Remove unused code (920 bytes, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Simplify code: Use cairo_paint() to paint the whole pixmap (980 bytes, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Do not create pixmaps when there's nothing to draw (1.14 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Change the cached rectangle ares to a GdkRectangle (2.25 KB, patch)
2010-09-20 19:45 UTC, Benjamin Otte (Company)
committed Details | Review
Simplify cached area subtraction code (1.80 KB, patch)
2010-09-20 19:46 UTC, Benjamin Otte (Company)
committed Details | Review
Remove MetaImageWindow (4.55 KB, patch)
2010-09-21 11:07 UTC, Benjamin Otte (Company)
committed Details | Review
ui: gtk_widget_show() the MetaFrames object (3.12 KB, patch)
2010-09-21 11:07 UTC, Benjamin Otte (Company)
committed Details | Review
Make Mutter work with GTK3 after the latest changes (74.71 KB, patch)
2010-09-21 11:08 UTC, Benjamin Otte (Company)
needs-work Details | Review
ui: Remove unused meta_gdk_pixbuf_get_from_window() (2.87 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
committed Details | Review
build: Only install libmutter-private for GTK3 builds (2.38 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
committed Details | Review
theme: Upgrade to use Cairo for painting (changes API) (32.67 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
none Details | Review
frames.c: Change meta_frames_paint() to take a cairo_t (5.43 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
committed Details | Review
frames.c: Merge clear_backing() function into its only user (1.50 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
committed Details | Review
Introduce MetaPixmap compatibility wrapper (3.39 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
none Details | Review
ui: Port draw_workspace() to take a cairo_t (4.78 KB, patch)
2010-09-23 22:34 UTC, Benjamin Otte (Company)
committed Details | Review
Introduce MetaPixmap compatibility wrapper (4.07 KB, patch)
2010-09-24 12:07 UTC, Benjamin Otte (Company)
none Details | Review
frames.c: Make cached_pixels_draw() take a cairo_t (1.54 KB, patch)
2010-09-24 12:09 UTC, Benjamin Otte (Company)
committed Details | Review
Fix compilation against latest GTK3 changes (46.88 KB, patch)
2010-09-24 12:09 UTC, Benjamin Otte (Company)
none Details | Review
theme: Upgrade to use Cairo for painting (changes API) (44.70 KB, patch)
2010-09-24 18:30 UTC, Benjamin Otte (Company)
committed Details | Review
Introduce MetaPixmap compatibility wrapper (4.75 KB, patch)
2010-09-24 18:30 UTC, Benjamin Otte (Company)
committed Details | Review
Fix compilation against latest GTK3 changes (36.16 KB, patch)
2010-09-24 18:31 UTC, Benjamin Otte (Company)
committed Details | Review
frames.c: Clip the client area correctly (978 bytes, patch)
2010-09-27 12:01 UTC, Benjamin Otte (Company)
committed Details | Review
theme: Get rid of x/y_offset usage when drawing frames (13.13 KB, patch)
2010-09-27 12:02 UTC, Benjamin Otte (Company)
committed Details | Review

Description Benjamin Otte (Company) 2010-09-20 19:45:16 UTC
This is the first bunch of patches that reorganize (and hopefully clean up) things inside the code. These reorganizations target future patches that try to abstract the expose_event from GTK2 and the draw event from GTK3 into the same code with nasty defines. So one goal is to reduce the amount of functionality used and constrain them to expose events.

I think the patches are fine on their own without the full set of patches. If you have any questions though, feel free to ask - or wait until I send more patches your way.
Comment 1 Benjamin Otte (Company) 2010-09-20 19:45:20 UTC
Created attachment 170694 [details] [review]
ui: Clip the region once, not every rectangle manually
Comment 2 Benjamin Otte (Company) 2010-09-20 19:45:24 UTC
Created attachment 170695 [details] [review]
Make clip_to_screen() actually clip to the screen
Comment 3 Benjamin Otte (Company) 2010-09-20 19:45:27 UTC
Created attachment 170696 [details] [review]
Remove workaround now that clip_to_screen() works properly
Comment 4 Benjamin Otte (Company) 2010-09-20 19:45:30 UTC
Created attachment 170697 [details] [review]
Remove client area from region in expose event
Comment 5 Benjamin Otte (Company) 2010-09-20 19:45:33 UTC
Created attachment 170698 [details] [review]
Remove NULL checks

This function actually handles NULL. (And I'm going to pass some NULLs
soon).
Comment 6 Benjamin Otte (Company) 2010-09-20 19:45:38 UTC
Created attachment 170699 [details] [review]
Move begin_paint() handling to expose handler

This way, we can remove the special casing in
meta_frames_paint_to_drawable().
Comment 7 Benjamin Otte (Company) 2010-09-20 19:45:41 UTC
Created attachment 170700 [details] [review]
Remove meta_ui_get_pixbuf_from_pixmap() function
Comment 8 Benjamin Otte (Company) 2010-09-20 19:45:45 UTC
Created attachment 170701 [details] [review]
Remove MetaArea widget

It's unused.
Comment 9 Benjamin Otte (Company) 2010-09-20 19:45:48 UTC
Created attachment 170702 [details] [review]
Remove unused code
Comment 10 Benjamin Otte (Company) 2010-09-20 19:45:51 UTC
Created attachment 170703 [details] [review]
Simplify code: Use cairo_paint() to paint the whole pixmap

Also, gdk_drawable_get_size() is going away soon
Comment 11 Benjamin Otte (Company) 2010-09-20 19:45:55 UTC
Created attachment 170704 [details] [review]
Do not create pixmaps when there's nothing to draw
Comment 12 Benjamin Otte (Company) 2010-09-20 19:45:59 UTC
Created attachment 170705 [details] [review]
Change the cached rectangle ares to a GdkRectangle

Simplifies the code as the rectangle is mainly interacting with GDK
APIs.
Comment 13 Benjamin Otte (Company) 2010-09-20 19:46:03 UTC
Created attachment 170706 [details] [review]
Simplify cached area subtraction code

Because we store the affected rectangle in the piece, we can just
subtract it and don't need any complicated computations.
Comment 14 Owen Taylor 2010-09-20 20:51:36 UTC
Review of attachment 170694 [details] [review]:

Looks good
Comment 15 Owen Taylor 2010-09-20 20:55:06 UTC
Review of attachment 170698 [details] [review]:

Good to commit except subject line which is undescriptive - nothing in the subject line or body mentions where you are making changes

 meta_frame_layout_get_borders: remove NULL checks on parameters

Or something.
Comment 16 Owen Taylor 2010-09-20 20:57:45 UTC
Review of attachment 170701 [details] [review]:

Good to commit
Comment 17 Owen Taylor 2010-09-20 21:01:02 UTC
Review of attachment 170702 [details] [review]:

Fine to commit, except again the commit message needs to be something that isn't 100% generic
Comment 18 Owen Taylor 2010-09-20 21:04:04 UTC
Review of attachment 170703 [details] [review]:

Fine.
Comment 19 Owen Taylor 2010-09-20 21:22:49 UTC
Review of attachment 170704 [details] [review]:

Subject: frame.c: Do not create pixmaps when there's nothing to draw

And in body:

 'Take advantage of existing handling for CachedFramePiece.piece == NULL to avoid
  generating pixmaps when width/height are 0'

(or something like that). And then in an appropriate place in populate_cache() add
a:

 /* Returns NULL for 0 width/height pieces, but returns NULL cheaply so we
  * don't need to cache the NULL return */

(or something like that). Since the patch is basically conceptually wrong and just
works out OK, it needs an explanatory comment.
Comment 20 Owen Taylor 2010-09-20 21:27:08 UTC
Review of attachment 170705 [details] [review]:

Looks good
Comment 21 Benjamin Otte (Company) 2010-09-20 21:27:37 UTC
Yeah, I suspect it'd be best if I did another patch that unmessed the populate_cache() function and didn't try to populate an already existing cache. Shouldn't be too hard to do.
Comment 22 Owen Taylor 2010-09-20 21:34:13 UTC
Review of attachment 170706 [details] [review]:

Looks fine, would prefer a 'frames.c: ' on the Subject
Comment 23 Owen Taylor 2010-09-20 21:35:13 UTC
Review of attachment 170700 [details] [review]:

Sure
Comment 24 Owen Taylor 2010-09-20 21:42:24 UTC
Review of attachment 170699 [details] [review]:

Sure, except for the below. Add to body of the commit message:

 Since the setup in meta_frames_paint_to_drawable() is relatively cheap,
 doing it once per rectangle in the expose area should be fine.

::: src/ui/frames.c
@@ +2364,3 @@
+      area_region = meta_region_new_from_rectangle (&areas[i]);
+
+      gdk_window_begin_paint_rect (event->window, &areas[i]);

Use gdk_window_begin_paint_region() to avoid double rect => region conversion - MetaRegion is always compatible with the signature of that.
Comment 25 Owen Taylor 2010-09-20 22:09:49 UTC
Review of attachment 170696 [details] [review]:

Explanation for the border seems to be:

 Havoc Pennington   [metacity developer]      2007-01-23 14:53:00 UTC 

 One possible fix would be to clip the painting to the screen extents (there is
 a race condition here - the window could move in relation to the screen while
 drawing - maybe one fix for that would be to clip to a bit larger area than the
 screen, and skip the clipping for windows smaller than the screen, so only
 large windows that get moved a lot would repaint incorrectly)

I don't understand the race condition though - the position we have for a window
will be more up to date than any expose events and in fact is synchronoously
in sync with the painting screen (since we are the window manager). So, if according
to the current position, something is offscreen, it's offscreen and doesn't need to
be painted.

And the clipping code is completely broken, as far as I can see - it clips the
region in window coordinates against the screen in absolute coordinates.

<light bulb dawns>

 https://bugzilla.redhat.com/show_bug.cgi?id=557402
 https://bugzilla.gnome.org/show_bug.cgi?id=538438

So I think it's fine to go and remove this code. Needs a commit message that
actually describes what is going on.
Comment 26 Owen Taylor 2010-09-20 22:23:49 UTC
Review of attachment 170697 [details] [review]:

Looks OK. (Not convinced that this is really independent from "Move begin_paint() handling to expose handler" - without that patch, this would just be unmotivated random code motion.)
Comment 27 Owen Taylor 2010-09-20 22:24:56 UTC
Review of attachment 170695 [details] [review]:

Looks good to me (frames.c: in Subject line)
Comment 28 Benjamin Otte (Company) 2010-09-21 11:07:51 UTC
Created attachment 170747 [details] [review]
Remove MetaImageWindow

The code isn't used anymore.
Comment 29 Benjamin Otte (Company) 2010-09-21 11:07:56 UTC
Created attachment 170748 [details] [review]
ui: gtk_widget_show() the MetaFrames object

The widget needs to be visible and mapped for GTK3 to deliver expose
events to the widget. This is achieved by making the map function a
no-op and calling gtk_widget_show() instead of just calling
gtk_widget_realize().
Apart from making GTK think the widget is drawable, the effect is the
same.
Comment 30 Benjamin Otte (Company) 2010-09-21 11:08:01 UTC
Created attachment 170749 [details] [review]
Make Mutter work with GTK3 after the latest changes

With the newest changes to GTK3, some things were changed. This patch
introduces an ugly macro compatibility layer in drawcompat.[ch] that
ensures compilation against both GTK2 and GTK3.
The following changes were necessary:

- MetaPixmap
MetaPixmap is the replacement for GdkPixmap. It uses GdkPixmap on GTK2
and cairo_surface_t on GTK3 and is just simple defines.

- MetaDrawContext
MetaDrawContext encapsulates the 2nd argument passed to the
expose_event/draw signal from GtkWidget. A small API is layered on top
that fulfills all the current needs. In particular, it is used to create
a cairo context.

- switching theme drawing to a cairo_t
Instead of passing a drawable and a clip area, the code now passes a
cairo_t around. The cairo_t must not be scaled, rotated or skewed and be
created from a MetaDrawContext though (see next point), so the cairo_t
is pretty much only a tool to cary around the drawable and the clip
area.

- gtk_paint_foo()
the GtkStyle paint functions now take a cairo_t instead of a drawable
and clip area. The GTK2 code implements this by extracting the
GdkExposeEvent/MetaDrawContext and the clip area from the cairo_t and
passing those to the old-style paint functions.
Comment 31 Benjamin Otte (Company) 2010-09-21 11:25:33 UTC
(In reply to comment #24)
> ::: src/ui/frames.c
> @@ +2364,3 @@
> +      area_region = meta_region_new_from_rectangle (&areas[i]);
> +
> +      gdk_window_begin_paint_rect (event->window, &areas[i]);
> 
> Use gdk_window_begin_paint_region() to avoid double rect => region conversion -
> MetaRegion is always compatible with the signature of that.

I used begin_paint_rect() because in the large refactoring I used rectangles, so I could gdk_cairo_rectangle(); cairo_clip(); in the GTK3 code. So it makes the large patch conform more to the code I'm introducing here.
Comment 32 Owen Taylor 2010-09-21 20:17:10 UTC
Review of attachment 170747 [details] [review]:

Sure.
Comment 33 Owen Taylor 2010-09-21 20:25:49 UTC
Review of attachment 170748 [details] [review]:

Looks good except for comments

::: src/ui/frames.c
@@ +680,3 @@
 {
+  /* We override the parent map function to a no-op because we don't
+   * want to actually whow the GDK window. We only use the GDK window

type 'whow'

Not sure what you mean by "only use the GDK window" - theme changes are notified using GtkWidget facilities. Do you mean "We only derive from GtkWidget ..." ?

@@ +683,3 @@
+   * so it notifies us about theme changes and other useful things.
+   */
+  gtk_widget_set_mapped (widget, TRUE);

This probably needs an entry in src/gdk-compat.h since it is 'Since 2.20' (probably could up the GTK+ requirement at this point to 2.20 if the list of things we have to compat define gets too long.)

It's a little scary to bypass gtk_window_map() since it does a *lot* of stuff other than map the window, but I can't find anything else in there that matters here, so OK.

::: src/ui/ui.c
@@ +129,3 @@
   g_assert (xdisplay == GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
   ui->frames = meta_frames_new (XScreenNumberOfScreen (screen));
+  gtk_widget_show (GTK_WIDGET (ui->frames));

Needs a comment, maybe:

 /* meta_frames_map() has been hacked so that showing a meta_frames doesn't
  * actually show anything. But we need the VISIBLE flag set so events
  * get delivered */
Comment 34 Owen Taylor 2010-09-21 23:34:36 UTC
Review of attachment 170749 [details] [review]:

This is where I usually end up with splitty approaches to Git patches - I split about 20% off as nice little chunks for pre-cleanup, then I have a huge piece that actually does something that can't be split up :-)

So, two main things I see here - first the handling of ::expose-event vs ::draw is a bit too clever for me. Described in detail below.

The second issue is that, as far as I can see, you've changed the public header theme.h so that it takes cairo_t, but for GTK+-2.0, it has to be a "special" cairo_t with a GdkEventExpose tagged on it. And there's not even a way of creating such a cairo_t in anything installed publicly.

I'm perfectly happy addressing that as follows:

 - Document the problem in the missing block comment at the top of drawcompat.h (you do a pretty good job of describing things in your commit message, but commit messages aren't available reading the code without a bit of digging so information needed to understand what's going on should generally not be hidden in commit messages.... historical rationales, alternate approaches, etc, are fine in commit messages, or even bugzilla, but "how do I use this" should be in the code)

 - g_error more informatively than g_assert(event != NULL);

 - Don't install libmutter-private for GTK+-2.0 builds. GTK+ 2 builds are for:

    Meego: As I understand it, they've hacked out Metacity themes and are putting clutter actors around windows
    People using Mutter for alternate interfaces to GNOME 2: GNOME 2 links to libmetacity-private not libmutter-private (so does GNOME 3, but might change at some point)

::: src/gdk-compat.h
@@ +27,3 @@
+gdk_drawable_get_size (GdkWindow *window,
+                       int       *width,
+                       int       *height)

All compat needs to be single-directional. Emulating both ways is too confusing - so you need compat implementations of gdk_window_get_width()/height()

::: src/ui/drawcompat.c
@@ +28,3 @@
+#if GTK_CHECK_VERSION (2, 90, 0)
+
+#else /* GTK_CHECK_VERSION */

as noted elsewhere, please use /* GTK+ < 2.90.0 */ so that the #else is interpretable in isolation

@@ +48,3 @@
+      cairo_translate (cr,
+                       allocation.x,
+                       allocation.y);

Unless you've changed the meaning of allocation.x/.y in GTK+ 3, this is wrong. (it's right only for no-window widgets)

@@ +102,3 @@
+}
+
+void meta_paint_vline (GtkStyle           *style,

Bad indentation, and throughout after this - void needs to be on a separate line

::: src/ui/drawcompat.h
@@ +34,3 @@
+
+#define DRAW_EVENT draw
+#define DRAW_EVENT_NAME "draw"

I'm of mixed feelings here. On one hand, what you've done by exploiting the fact that ::expose-event and ::draw have similar signatures keeps things compact and very clean looking. (I'm not completely sure I agree with the boolean return from ::draw - the boolean return from ::expose-event is a frequent trap where people inadvertently return TRUE and prevent people from "decorating" on top of the standard drawing, but anyways, a different topic.) But the cleanliness also makes it pretty unclear what is going on looking locally at the code. Someone has to look at the code, scratch their head, read draw-compat.h, understand it, then say "Oh, that's what they are doing here". My preference is really to make the code messier and do something like:

#ifdef USE_GTK2_DRAWING
gboolean
meta_foo_expose_event (GtkWidget *widget, MetaDrawContext *context)
/* MetaDrawContext == GdkEventExpose */
#else
gboolean
meta_foo_draw (GtkWidget *widget, MetaDrawContext *context)
/* MetaDrawContext == cairo_t */
#endif

That gives a strong hint to someone reading a local portion of the code going on - and if they don't actually have to do anything complex the MetaDrawContext they'll have a sufficient picture of the situation to go on and do what they actually needed to do in the code. I know it's annoying to have to do that not just for the definitions, but for the declarations and for the places where the vfuncs are assigned, but we're talking 10 or so places total.

@@ +37,3 @@
+
+#define meta_pixmap_cairo_create(pixmap) cairo_create (pixmap)
+#define meta_pixmap_create(window, w, h) \

meta_pixmap_create => construct a MetaPixmap

Implies:

 meta_pixmap_cairo_create => construct a MetaPixmapCairo

Suggest 'meta_pixmap_new' for the first - after all, you called it like GdkPixmap not cairo_surface_t, so use GDK/Metacity conventions for constructors.

@@ +41,3 @@
+#define meta_pixmap_destroy(pixmap) cairo_surface_destroy (pixmap)
+#define meta_cairo_set_source_pixmap(cr, pixmap, x, y) \
+  cairo_set_source_surface (cr, pixmap, x, y)

Mixture of line breaking and non-line breaking isn't readable. We aren't on VT100's, just keep each #define on one line

@@ +52,3 @@
+}
+static inline Window
+meta_draw_get_xid(cairo_t *cr)

This is a method on "MetaDrawContext", so 'meta_draw_context_get_xid - reduces general namespace pollution as well.

@@ +63,3 @@
+
+#define meta_draw_create(ctx, widget) cairo_reference (ctx)
+#define meta_draw_begin_paint_rect(ctx, rect) G_STMT_START{ \

If you are going to use static inlines for some things, then use them here too.

@@ +92,3 @@
+#define meta_paint_layout gtk_paint_layout
+
+#else /* GTK_CHECK_VERSION */

This isn't a useful comment on the else - better to have /* GTK+ < 2.90.0 */ or something

::: src/ui/frames.c
@@ +2367,2 @@
 static void
+meta_frames_paint_to_drawable (MetaFrames      *frames,

This function needs a rename to go along with the signature change (meta_frames_paint() would be fine if it's not used elsewhere)

::: src/ui/metaaccellabel.c
@@ +286,3 @@
 	  layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
 
+          cr = meta_draw_create (ctx, widget);

You leak this cr

::: src/ui/tabpopup.c
@@ +79,3 @@
+outline_window_draw (GtkWidget       *widget,
+                     MetaDrawContext *ctx,
+                     gpointer         data)

This creates a cairo_t internally, should be able to use the one passed in

@@ +706,3 @@
 static gboolean
+meta_select_image_draw (GtkWidget       *widget,
+                        MetaDrawContext *ctx)

As does this

::: src/ui/theme.c
@@ +3861,3 @@
         rheight = parse_size_unchecked (op->data.tile.height, env);
 
+        cairo_save (cr);

Don't see why this save/restore pair is necessary

@@ +3865,2 @@
+        cairo_rectangle (cr, rx, ry, rwidth, rheight);
+        cairo_clip (cr);

I think the completely-clipped-out optimization you've removed here is probably significant - it's never worth doing:

 if (!<completely clipped>) 
     cairo_rectangle (cr, ...);
     cairo_fill();
 }

Because cairo should take care of it itself, but there's more going on inside here - parsing, drawing a list of operations, etc.

@@ +4010,1 @@
+  cairo_save (cr);

You have a function takes a cr as an argument, does a save/restore around the body of the function, but *modifies* the cr that is passed in. That's going to confuse someone! Probably best if functions in the publically installed theme.h leave their cairo_t arguments as they found them and don't require the caller to save/restore.

@@ +4027,1 @@
+          cairo_save (cr);

Maybe you meant to move this save() before the cairo_rectangle/clip pair?

@@ -4595,1 @@
-              if (combined_clip.width > 0 && combined_clip.height > 0)

Same comment about removing the "completely out of the scene" check here. (Would be handy if cairo had a predicate for "is this rectangle completely clipped away")

::: src/ui/ui.c
@@ +171,3 @@
   GdkWindow *window;
   GdkVisual *visual;
+  //GdkColormap *cmap = gdk_screen_get_default_colormap (screen);

This and more in-progress leftovers in this file. Not sure where you are going with it.

@@ +359,2 @@
 GdkPixbuf*
 meta_gdk_pixbuf_get_from_window (GdkPixbuf   *dest,

Don't really trust the colormap handling in your replacement in the gtk2 version, but this function is unused right? Any reason you didn't just remove it? I think this might have been used by the Xlib compositor for some ugly effects.
Comment 35 Owen Taylor 2010-09-22 03:00:32 UTC
(In reply to comment #34)
> My preference is really to make the code messier and do something like:
> 
> #ifdef USE_GTK2_DRAWING
> gboolean
> meta_foo_expose_event (GtkWidget *widget, MetaDrawContext *context)
> /* MetaDrawContext == GdkEventExpose */
> #else
> gboolean
> meta_foo_draw (GtkWidget *widget, MetaDrawContext *context)
> /* MetaDrawContext == cairo_t */
> #endif
> 
> That gives a strong hint to someone reading a local portion of the code going
> on - and if they don't actually have to do anything complex the MetaDrawContext
> they'll have a sufficient picture of the situation to go on and do what they
> actually needed to do in the code. I know it's annoying to have to do that not
> just for the definitions, but for the declarations and for the places where the
> vfuncs are assigned, but we're talking 10 or so places total.

Quick clarification here - by "do that not just for the definitions, but for the declarations and the places where the vfuncs are assigned" I meant the #ifdefs, not the comments.
Comment 36 Tomas Frydrych 2010-09-22 06:27:20 UTC
(In reply to comment #34)
>  - Don't install libmutter-private for GTK+-2.0 builds. GTK+ 2 builds are for:
> 
>     Meego: As I understand it, they've hacked out Metacity themes and are
> putting clutter actors around windows

That is not the case, MeeGo uses normal metacity themes for theming applications, and we do need libmutter-private installed.
Comment 37 Owen Taylor 2010-09-22 13:46:09 UTC
(In reply to comment #36)
> (In reply to comment #34)
> >  - Don't install libmutter-private for GTK+-2.0 builds. GTK+ 2 builds are for:
> > 
> >     Meego: As I understand it, they've hacked out Metacity themes and are
> > putting clutter actors around windows
> 
> That is not the case, MeeGo uses normal metacity themes for theming
> applications, and we do need libmutter-private installed.

OK, I must have misunderstood a plan or experiment for what you were doing.

 - You are using libmutter-private for a theme selector?
 - Are you using functions like meta_frame_style_draw() that take a GdkDrawable as an argument?
Comment 38 Benjamin Otte (Company) 2010-09-22 13:51:11 UTC
Question: Could we make Mutter use GtkAccelLabel instead of its
own widget? Or is the accelerator handling too different in Mutter and GTK?
That'd get rid of a rather large #ifdef case for expose events.

For the other widgets, I'd say ifdeffing is a valid use case.

But making theme drawing work without a cairo_t in GTK 3 is pretty much impossible I guess.

I might be able to fix the special requirements for GTK2 by creating a pixmap and gtk_paint_foo() to it and then blit that onto the cairo_t, so the special case wouldn't be needed, but that'd still require different APIs.
Comment 39 Owen Taylor 2010-09-22 14:02:48 UTC
(In reply to comment #38)
> Question: Could we make Mutter use GtkAccelLabel instead of its
> own widget? Or is the accelerator handling too different in Mutter and GTK?
> That'd get rid of a rather large #ifdef case for expose events.

GtkAccelLabel hard-codes the GTK+ accelerator system:

void       gtk_accel_label_set_accel_widget  (GtkAccelLabel *accel_label,
                                              GtkWidget     *accel_widget);

Etc. There's very little commonality between what Mutter is doing with passive grabs and GTK+ accelerator handling. Without actually trying to figure out the massive hacks that would be required to try and make it to work, I'm pretty sure it would be a bad idea.

> For the other widgets, I'd say ifdeffing is a valid use case.
> 
> But making theme drawing work without a cairo_t in GTK 3 is pretty much
> impossible I guess.
> 
> I might be able to fix the special requirements for GTK2 by creating a pixmap
> and gtk_paint_foo() to it and then blit that onto the cairo_t, so the special
> case wouldn't be needed, but that'd still require different APIs.

I think we need to wait and get more details from Tomas about what they are doing. One possible approach would be to have compatibility wrappers for GTK+ 2 users that export the old API and then create the magic cairo_t internally and call the real implementation. Another approach would be to export a meta_draw_context_new (...); function in the GTK+ 2. case.
Comment 40 Tomas Frydrych 2010-09-22 14:44:11 UTC
(In reply to comment #37)
> (In reply to comment #36)
> > (In reply to comment #34)
> > >  - Don't install libmutter-private for GTK+-2.0 builds. GTK+ 2 builds are for:
> > > 
> > >     Meego: As I understand it, they've hacked out Metacity themes and are
> > > putting clutter actors around windows
> > 
> > That is not the case, MeeGo uses normal metacity themes for theming
> > applications, and we do need libmutter-private installed.
> 
> OK, I must have misunderstood a plan or experiment for what you were doing.
> 
>  - You are using libmutter-private for a theme selector?

We do, but on reflection it does not make much sense to hold onto the gtk2 code paths simply because of MeeGo (I can't see us developing these codepaths for MeeGo much further), so if nobody else is using these, then I would say let's excise it for sake of a cleaner codebase when that is convenient from the Gnome pov.
Comment 41 Owen Taylor 2010-09-22 14:52:14 UTC
(In reply to comment #40)
> (In reply to comment #37)
> > (In reply to comment #36)
> > > (In reply to comment #34)
> > > >  - Don't install libmutter-private for GTK+-2.0 builds. GTK+ 2 builds are for:
> > > > 
> > > >     Meego: As I understand it, they've hacked out Metacity themes and are
> > > > putting clutter actors around windows
> > > 
> > > That is not the case, MeeGo uses normal metacity themes for theming
> > > applications, and we do need libmutter-private installed.
> > 
> > OK, I must have misunderstood a plan or experiment for what you were doing.
> > 
> >  - You are using libmutter-private for a theme selector?
> 
> We do, but on reflection it does not make much sense to hold onto the gtk2 code
> paths simply because of MeeGo (I can't see us developing these codepaths for
> MeeGo much further), so if nobody else is using these, then I would say let's
> excise it for sake of a cleaner codebase when that is convenient from the Gnome
> pov.

OK, there's still Ubuntu Unity using a GTK+ 2 build of Mutter. (It's obviously lower priority for me than GNOME 3, but I'm reluctant to rip GTK+ 2.0 support out if I'm then going to get a push to add it back in.)

But if you don't have firm plans for when you'll be using this version of Mutter and what GTK+ version with that, then I don't want to make a lot of extra work to create a usable GTK+ 2 libmutter-private. The approaches in comment 39 could be implemented later. So, I think we should go with my plan in comment 34 for now.
Comment 42 Benjamin Otte (Company) 2010-09-23 10:58:44 UTC
Comment on attachment 170696 [details] [review]
Remove workaround now that clip_to_screen() works properly

Added in your comments and put links to all the bugs into the commit message.
Comment 43 Benjamin Otte (Company) 2010-09-23 11:01:30 UTC
Comment on attachment 170699 [details] [review]
Move begin_paint() handling to expose handler

Committed with the improvements noted in comment 24
Comment 44 Benjamin Otte (Company) 2010-09-23 11:03:14 UTC
Comment on attachment 170704 [details] [review]
Do not create pixmaps when there's nothing to draw

Committed with added comments.
Comment 45 Benjamin Otte (Company) 2010-09-23 11:05:36 UTC
Comment on attachment 170748 [details] [review]
ui: gtk_widget_show() the MetaFrames object

Added comments as per comment 33. gtk_widget_set_mapped() was already existing in gtk-compat.h.
Comment 46 Florian Müllner 2010-09-23 11:06:06 UTC
(In reply to comment #30)
> Created an attachment (id=170749) [details] [review]
> Make Mutter work with GTK3 after the latest changes

Looks like tile-preview is missing from the patch?

/me ducks
Comment 47 Benjamin Otte (Company) 2010-09-23 22:34:00 UTC
Created attachment 170985 [details] [review]
ui: Remove unused meta_gdk_pixbuf_get_from_window()
Comment 48 Benjamin Otte (Company) 2010-09-23 22:34:06 UTC
Created attachment 170986 [details] [review]
build: Only install libmutter-private for GTK3 builds

Define INSTALL_LIBMUTTER_PRIVATE with AM_CONDITIONAL and use it to build
an installed or uninstalled libmutter-private.so
Comment 49 Benjamin Otte (Company) 2010-09-23 22:34:11 UTC
Created attachment 170987 [details] [review]
theme: Upgrade to use Cairo for painting (changes API)

This commit is in preparation for the work happening in GTK3, which will
use Cairo for drawing exclusively. So it is necessary to move all
drawing code to Cairo.
For compatibility with older GTK versions, the file gtk3-compat.h
provides a compatibility layer.

The commit changes the API of libmutter-private.
Comment 50 Benjamin Otte (Company) 2010-09-23 22:34:17 UTC
Created attachment 170988 [details] [review]
frames.c: Change meta_frames_paint() to take a cairo_t

Rename meta_frames_paint_to_drawable() to meta_frames_paint() and make
it take a cairo_t as an argument instead of creating the cairo_t itself.

This patch refactors code for GTK3 changes where code needs to handle
cairo_t and not GdkDrawable arguments.
Comment 51 Benjamin Otte (Company) 2010-09-23 22:34:21 UTC
Created attachment 170989 [details] [review]
frames.c: Merge clear_backing() function into its only user

Avoids creating a cairo_t twice. And without the code to create a
cairo_t, there was not a lot left to warrant a separate function.
Comment 52 Benjamin Otte (Company) 2010-09-23 22:34:26 UTC
Created attachment 170990 [details] [review]
Introduce MetaPixmap compatibility wrapper

Similar to the region compatibility shim, we will soon need a
compatibility shim around GdkPixmap/cairo_surface_t. For now, the patch
just introduces the compatibility layer.

This patch also does not include the function
meta_gdk_pixbuf_get_from_pixmap() as that function will need special
treatment in GTK3 anyway.
Comment 53 Benjamin Otte (Company) 2010-09-23 22:34:32 UTC
Created attachment 170991 [details] [review]
ui: Port draw_workspace() to take a cairo_t
Comment 54 Benjamin Otte (Company) 2010-09-24 08:05:56 UTC
I just found a comment that reads:

  /* We make an assumption that gdk_window_new() is going to call
   * XCreateWindow as it's first operation; this seems to be true currently
   * as long as you pass in a colormap.
   */

I'm not sure how important this is, but it doesn't hold true for GTK3 anymore, because you cannot pass in a colormap and GTK3 will create one if it hasn't yet for the given visual. Do we need any API that ensures the first thing gdk_window_new() does is create a window? Or can we lift that requirement? Because it's certainly not guaranteed by GTK...
Comment 55 Benjamin Otte (Company) 2010-09-24 12:07:59 UTC
Created attachment 171022 [details] [review]
Introduce MetaPixmap compatibility wrapper

Similar to the region compatibility shim, we will soon need a
compatibility shim around GdkPixmap/cairo_surface_t. For now, the patch
just introduces the compatibility layer.

This patch also does not include the function
meta_gdk_pixbuf_get_from_pixmap() as that function will need special
treatment in GTK3 anyway.
Comment 56 Benjamin Otte (Company) 2010-09-24 12:09:29 UTC
Created attachment 171023 [details] [review]
frames.c: Make cached_pixels_draw() take a cairo_t

This basically just moves the creation of the cairo_t out of the
function. It is done in preparation for GTK3.
Comment 57 Benjamin Otte (Company) 2010-09-24 12:09:34 UTC
Created attachment 171024 [details] [review]
Fix compilation against latest GTK3 changes

With the newest changes to GTK3, some things were changed. This patch
now uses the features introduced in gtk3-compat.h in previous patches.

This patch also introduces a macro named USE_GTK3 that is used to
differentiate between GTK3 and GTK2. Its main use is differenting
between expose and draw handlers for GtkWidget subclasses.

The draw vs expose handlers question is usually handled by using ifdefs
at the beginning and end to set up/tear down a cairo_t and then use it.

However, when the function is too different and too many ifdefs would be
necessary, two versions of the function are written. This is currently
the case for:
- MetaAccelLabel
- MetaFrames
Comment 58 Owen Taylor 2010-09-24 12:16:40 UTC
(In reply to comment #54)
> I just found a comment that reads:
> 
>   /* We make an assumption that gdk_window_new() is going to call
>    * XCreateWindow as it's first operation; this seems to be true currently
>    * as long as you pass in a colormap.
>    */
> 
> I'm not sure how important this is, but it doesn't hold true for GTK3 anymore,
> because you cannot pass in a colormap and GTK3 will create one if it hasn't yet
> for the given visual. Do we need any API that ensures the first thing
> gdk_window_new() does is create a window? Or can we lift that requirement?
> Because it's certainly not guaranteed by GTK...

I told Florian when he was asking about getting the serial in meta_tile_preview_new() that it didn't matter if the request was a few early - but that wasn't 100% right. There's a race condition where things go mildly wrong if we have a too early serial.

 CreateColormap - serial=100, recorded in STACK_OP_ADD,
 Some other app creates a window, CreateWindowEvent has serial 100
 w = CreateWindow - serial=101, CreateWindowEvent has serial 101
 RaiseWindow(w) - serial=102, recorded in STACK_OP_RAISE_ABOVE

 Receive CreateWindowEvent for other app with serial 100
   Discard STACK_OP_ADD because the serial is <= the serial of received events
   Replay remaining recorded requests
   STACK_OP_RAISE_ABOVE produces warning
     "STACK_OP_RAISE_ABOVE: window %#lx not in stack"
   Repaint screen, window is missing because not in stack

 Receive CreateWindowEvent for our window
   Replay remaining recorded requests
   Repaint screen, window is back everything is fine
   
Of course, for your described case, the race occurs at most once in the lifetime of Mutter, and only when some other client is scheduled at exactly that point. So, while gdk_x11_window_get_creation_serial() would be handy, I'd be pretty comfortable ignoring this problem or just adding a:

  (In GTK+ 3 this is not strictly true; in some circumstances GDK will
  create a colormap from gdk_window_new() before creating the window.
  which would cause a race condition and in rare cases, problems,
  but we'd recover -
  see https://bugzilla.gnome.org/show_bug.cgi?id=630203#c55 for details)
Comment 59 Benjamin Otte (Company) 2010-09-24 12:39:29 UTC
(In reply to comment #58)
> Of course, for your described case, the race occurs at most once in the
> lifetime of Mutter, and only when some other client is scheduled at exactly
> that point. So, while gdk_x11_window_get_creation_serial() would be handy
>
I was more thinking about an API like:
Colormap gdk_x11_visual_get_colormap (GdkVisual *visual);
which you could call to ensure the colormap was created already. It's currently a function private to gdk-x11, but wouldn't be too hard to export.
On the other hand, having less APIs exported is always better.
Comment 60 Owen Taylor 2010-09-24 18:13:10 UTC
Review of attachment 170985 [details] [review]:

Good
Comment 61 Owen Taylor 2010-09-24 18:16:34 UTC
Review of attachment 170986 [details] [review]:

Looks like it is right, if you wanted to try a 'make distcheck' to make sure that everything still gets disted that should get disted, that would be appreciated.
Comment 62 Owen Taylor 2010-09-24 18:17:23 UTC
Review of attachment 170986 [details] [review]:

(Though actually, since I'll always be disting with a gtk3 compilation, that's pretty unlikely to break from this patch)
Comment 63 Benjamin Otte (Company) 2010-09-24 18:30:37 UTC
Created attachment 171055 [details] [review]
theme: Upgrade to use Cairo for painting (changes API)

This commit is in preparation for the work happening in GTK3, which will
use Cairo for drawing exclusively. So it is necessary to move all
drawing code to Cairo.
For compatibility with older GTK versions, the file gtk3-compat.h
provides a compatibility layer.

The commit changes the API of libmutter-private.
Comment 64 Benjamin Otte (Company) 2010-09-24 18:30:49 UTC
Created attachment 171057 [details] [review]
Introduce MetaPixmap compatibility wrapper

Similar to the region compatibility shim, we will soon need a
compatibility shim around GdkPixmap/cairo_surface_t. For now, the patch
just introduces the compatibility layer.

This patch also does not include the function
meta_gdk_pixbuf_get_from_pixmap() as that function will need special
treatment in GTK3 anyway.
Comment 65 Benjamin Otte (Company) 2010-09-24 18:31:11 UTC
Created attachment 171058 [details] [review]
Fix compilation against latest GTK3 changes

With the newest changes to GTK3, some things were changed. This patch
now uses the features introduced in gtk3-compat.h in previous patches.

This patch also introduces a macro named USE_GTK3 that is used to
differentiate between GTK3 and GTK2. Its main use is differenting
between expose and draw handlers for GtkWidget subclasses.

The draw vs expose handlers question is usually handled by using ifdefs
at the beginning and end to set up/tear down a cairo_t and then use it.

However, when the function is too different and too many ifdefs would be
necessary, two versions of the function are written. This is currently
the case for:
- MetaAccelLabel
- MetaFrames
Comment 66 Benjamin Otte (Company) 2010-09-24 18:33:01 UTC
Comment on attachment 171024 [details] [review]
Fix compilation against latest GTK3 changes

I forgot to add gtk3-compat.[ch] in those patches, here's the new versions of those. I think the fact that patches now are not in order anymore doesn't matter, they should still apply.
Comment 67 Owen Taylor 2010-09-24 20:17:55 UTC
Review of attachment 171055 [details] [review]:

Find this commit a little confusing in where it's going. Commit message should have something like "In this commit the "gtk2" code is used for both gtk2 and gtk3; compatibility with newer versions of gtk3 where different code is needed will be added subsequently."

Once I understood that, mostly made sense to me.

::: src/gtk3-compat.c
@@ +67,3 @@
+
+static GdkWindow *
+extract_event (cairo_t *cr, int *dx, int *dy, GdkRectangle *area)

This doesn't extract an event
Parameters on separate lines

@@ +123,3 @@
+}
+
+void meta_paint_arrow (GtkStyle           *style,

void on the wrong line (and the same elsewhere in this file)

::: src/gtk3-compat.h
@@ +25,3 @@
+#include <gtk/gtk.h>
+
+gboolean      gdk_cairo_get_clip_rectangle (cairo_t            *cr,

This should be handled in gdk-compat.h - it's conceptually different from the rest of the stuff here. If you don't feel comfortable with it as a static online, then add src/gdk-compat.c.

::: src/ui/frames.c
@@ +40,2 @@
 #include "gtk-compat.h"
 #include "gdk-compat.h"

There's obviously a header file naming problem when you look at the above. Suggest 'gdk2-drawing-utils.[ch]"

::: src/ui/theme.c
@@ +4553,1 @@
+              if (op_list)

You are still dropping the completely clipped-check. I need one of three things:

 - An explanation of why it was a stupid idea
 - A comment saying /* This code to check if 'rect' was completely outside of the
   clip region; that's probably a good idea, but it's hard to do with cairo */
 - Restoration of the check
Comment 68 Owen Taylor 2010-09-24 20:19:05 UTC
Review of attachment 170988 [details] [review]:

Looks good
Comment 69 Owen Taylor 2010-09-24 20:21:01 UTC
Review of attachment 170989 [details] [review]:

Fine
Comment 70 Owen Taylor 2010-09-24 20:22:44 UTC
Review of attachment 170991 [details] [review]:

Looks fine
Comment 71 Owen Taylor 2010-09-24 20:23:40 UTC
Review of attachment 171023 [details] [review]:

Sure
Comment 72 Owen Taylor 2010-09-24 20:25:12 UTC
Review of attachment 171057 [details] [review]:

Sure
Comment 73 Owen Taylor 2010-09-24 20:52:14 UTC
Review of attachment 171058 [details] [review]:

I would have been more free with the #ifdefs to avoid extensive duplicated code for the accel label and frames, but it's clearly a matter of judgement, so your approach is fine too.

It was a little hard for me to check the accel label and frames code, so I'm taking that on faith and a quick scan, the rest looks good, except for some details below.

::: src/gtk3-compat.c
@@ +69,3 @@
 
+int
+gdk_window_get_width (GdkWindow *window)

Would like to see these in gdk-compat.h, and not split up compatibility wrappers multiple places. These look fine as static inlines.

::: src/gtk3-compat.h
@@ +55,3 @@
+#define gdk_window_get_screen gdk_drawable_get_screen
+#define gdk_pixbuf_get_from_window(dest, window, src_x, src_y, dest_x, dest_y, width, height) \
+    gdk_pixbuf_get_from_drawable(dest, window, NULL, src_x, src_y, dest_x, dest_y, width, height)

Really don't like defining away a parameter like this - would rather it was a dual define of meta_gdk_pixbuf_get_from_window

::: src/ui/frames.c
@@ +2340,3 @@
+      cairo_clip (cr);
+
+      cairo_push_group (cr);

Not really sure why you are inlining gdk_window_begin_paint_* unless you've axed it in GDK, but OK

::: src/ui/metaaccellabel.c
@@ +249,3 @@
+
+  direction = gtk_widget_get_direction (widget);
+  ac_width = meta_accel_label_get_accel_width (accel_label);

Either you've cut-and-pasted extensively from gtkaccellabel.c (haven't compared the two code bases) or you've made a bunch of irrelevant changes for no apparent reason. If the former, you should include a source acknowledgment in a comment.
Comment 74 Benjamin Otte (Company) 2010-09-26 15:31:54 UTC
Comment on attachment 171055 [details] [review]
theme: Upgrade to use Cairo for painting (changes API)

Committed with the changes you mentioned. I put the all-clipped check back in.
Comment 75 Benjamin Otte (Company) 2010-09-26 15:34:05 UTC
Comment on attachment 171058 [details] [review]
Fix compilation against latest GTK3 changes

> Not really sure why you are inlining gdk_window_begin_paint_* unless you've
> axed it in GDK, but OK
>
I used cairo_push_group() because it was less code and does the same thing under the hood. Otherwise I'd have had to create a new cairo_t for the region that was started to paint and destroy it.
It's also more future-proof because I'm still toying with the idea of moving double-buffering out of GDK and into GTK but I'm not yet 100% sure about how to do it.
Comment 76 Benjamin Otte (Company) 2010-09-26 16:20:22 UTC
Merged everything from GTK to Mutter. The whole jhbuild should keep working.
Comment 77 Benjamin Otte (Company) 2010-09-27 12:01:58 UTC
Created attachment 171193 [details] [review]
frames.c: Clip the client area correctly

The code switched the x and y variables. Oops.
Comment 78 Benjamin Otte (Company) 2010-09-27 12:02:04 UTC
Created attachment 171194 [details] [review]
theme: Get rid of x/y_offset usage when drawing frames

The cairo_t can take care of offsets, so no need to use them.
And since offsets seem to be broken, it's the easiest thing to just
remove them instead of fixing them.

This patch changes API.
Comment 79 Benjamin Otte (Company) 2010-09-27 12:03:31 UTC
Seems I messed some things up in the patch. Here's two more patches that should fix things up hopefully for real now.
Comment 80 Owen Taylor 2010-09-27 14:33:09 UTC
Review of attachment 171193 [details] [review]:

Looks right. 

(I was going to ask you to use top/left temporaries on this code on my earlier review, and then decided it didn't matter. Don't know if would have actually helped prevent this error - top/bottom/left/right get ordered in many different ways in different places.)
Comment 81 Owen Taylor 2010-09-27 14:57:18 UTC
Review of attachment 171194 [details] [review]:

The changes all look sensible.

Suggest slight wording change to the commit message since "seem to be broken"
read to me as "never worked". Change:

 And since offsets seem to be broken, it's the easiest thing to just
 remove them instead of fixing them.

To:

 The change to passing cairo_t around broke offsets, since passing
 cairo_t makes them unnecessary, remove them rather than fixing them.