Re: deprecated gtk_cairo_create



Hi, Emmanuele
thanks for your help in last days of last year. Well, in the
attachment there are codes of the (perhaps) simplest usage of Drawing
Area widget. It goes without gdk_window_create_similar_surface.

I'd like to summarize several ideas mentioned in "the deprecated
gtk_cairo_create()" thread.

1. On-screen drawing in Drawing Area against GTK+3 is much more easy
than in GTK+2. But this simplification has been achieved by
significant changes in API. In particular, the GtkWidget::draw signal
is quite different from GtkWidget::expose in GTK+2. GtkWidget::draw
takes a cairo_t* as the second parameter, not a GdkEventExpose like
did ::expose.  And here one can have the Cairo context required. In
other words one SHOULD DO NOTHING to create a cairo context BECAUSE IT
HAS BEEN ALREADY CREATED BEFORE A DRAW EVENT EMISSION and put by GTK+3
as the second parameter of a draw event callback function. Don't
create it, don't destroy it, just use it!

/*a standard main, except a new type of signal, "draw"*/
gint
main ()
{
   GtkWidget *window;      /* pointer to the app main window */
   GtkWidget *area;

   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   area = gtk_drawing_area_new();

   gtk_widget_add_events(window,...);
   gtk_widget_add_events(area,...);

   g_signal_connect(G_OBJECT(area), "draw",
                             G_CALLBACK(draw_callback),
                             NULL);

   g_signal_connect(G_OBJECT(area),
                             "configure_event",
                              G_CALLBACK(configure_callback),
                              NULL);

   gtk_container_add(GTK_CONTAINER(window), area);
   gtk_widget_show_all(window);
   gtk_main();

}
/*-----------------------------------------------------------------------------*/
gboolean
draw_callback (GtkWidget *widget, cairo_t *cr)
{
   GtkStyleContext *context;
   context = gtk_widget_get_style_context (widget);
    // do your own drawing
}

It is sobering to be informed that the API reference is generated via
gtk-doc, which queries the type for signals and properties using the
GType API; Cairo provides GType wrappers for property and signal
marshalling, and those have CamelCase names to better fit in. This
means that a C `cairo_t` type is a `CairoContext` GType, and a
`cairo_surface_t` C type is a `CairoSurface` GType.


2. If you want to draw outside of the ::draw() handler and paint the
cached thing then, use a cairo_surface_t as the offscreen surface, and
paint on it then. You either create your own Cairo surface, or you ask
GDK to create a similar surface (or similar image surface) to the one
used by the GdkWindow that is the target of the rendering. Then, you
call 'cairo_create()` to get a Cairo context. The latter is possible
as cairo_create () is still not deprecated, but only
gtk_cairo_create() is.

GdkWindow *window = gtk_widget_get_window (widget);
cairo_surface_t *surface = gdk_window_create_similar_surface (window,
CAIRO_CONTENT_COLOR_ALPHA, width, height);

/* then create a Cairo context from it, and draw:*/

  cairo_t *cr = cairo_create (surface);
  // draw
  cairo_destroy (cr);

/* Now you can use the surface as a source on the Cairo context that
GtkWIdget::draw gives you:*/

  static gboolean
  on_draw (GtkWidget *widget, cairo_t *cr)
  {
    // render your surface on the widget's context
    cairo_set_source_surface (cr, surface, x, y);
    cairo_paint (cr);

    // do your own drawing
  }

3. But reasons (except compatibility) for such a way of drawing are
*now* a bit hazy, taking into account your comment :"creating an
intermediate surface on configure-event (something that's there only
for backward compatibility with GTK+ 1.2, and it's an X11-ism) just to
source it again is much more expensive than drawing on the provided
Cairo context".  The obvious reason was to pack all redrawing
procedures hooked to configure_event into a special drawing function
and put it into configure call-back function. Configure event happens
much less often than draw event. So there is a hope to be more
efficient...  One could find additional discussions with almost the
same context here
https://lists.cairographics.org/archives/cairo/2007-December/012211.html
and here https://lists.cairographics.org/archives/cairo/2007-December/012211.html.
For example, when I draw a dynamic figure with complex axes (with
sophisticated ticks' marks and other elements) why should I draw them
(axes) every time I redraw the main line? It's definitely a good idea
to gather all codes of axes drawing into special function and put it
into a configure event handler. What do you recommend that I do now
(if "off-screen' drawing is much more expensive and in general is a
very niche use cases)?

Regards,
Sergey







2016-12-30 18:15 GMT+03:00 Sergei Kolomeeyets <kolomeeyets gmail com>:
Hi, Emmanuele
thanks for not leaving me alone with my first attemts to navigate through
'uncharted' water of GTK+3.
You have touched several interesting points. Could we discuss it briefly?


You wrote:
Drawing *on widgets* outside of their rendering cycle is not possible in
GTK+ 3.x.
Was it possible in GTK2? I thought that it is the rule for all widgets
except Drawing Area. The latter gives more freedom and poses more
responsibility on the developer (in terms of event handling). This is a
paraphrase of documentation. But anyway I do not need that type of drawing.
I need the maximal speed, therefore - and to be on a safe side - I follow
only standard approaches. I want to draw in the standard rendering cycle. I
try to write an oscilloscope (more precise it is written with GTK2 but works
not stable with a very strange slow down happend somewhere in expose_event
callback function). I've spent a lot of time with 'perf' and 'gdb' with no
results and idea on how to fix that slow down except the migration to GTK3.

If you want to draw something off screen and then composite it inside your
widget,
What do you mean by "off screen" term? If, for instance, I have a convenient
widget (with a known and predefined image) and want to draw something new
above it, then this term is more or less clear for me. But Drawing Area has
no predefined widget image. When should I use
gdk_window_create_similar_surface (window, CAIRO_CONTENT_COLOR_ALPHA, width,
height) while dealing with Drawing Area? And how to compose it with that of
has been drown within a standart virtual draw-function "inside my widget" to
get a consistent image? Is there a special function or it will happen
automatically at the end of "on draw" function?

but you really need to look at the documentation when it comes to signal
handlers.
Yes. Thanks. I've got it :-) It looks like (and you wrote it clearly for me)
I need to do nothing to create a cairo context because (in my very simple
case) GTK will do 'everything' instead of me and then grandmotherly 'put'
the right pointer into the second parameter of a draw event virtual
function. (So I can just happily use it inside that function.) That sounds
wise (any window has its cairo context automatically) and I beginning to
love GTK+3, (if I understood the state of the matter right, of course).

Best regards,
Sergey


2016-12-30 15:47 GMT+03:00 Emmanuele Bassi <ebassi gmail com>:

Hi;

On 30 December 2016 at 11:38, Sergei Kolomeeyets <kolomeeyets gmail com>
wrote:
Hi, Emmanuele
thanks a lot for your prompt response! Yes It looks I need to go back to
profound manual's reading... :-(
I have not understood almost nothing

You can ignore the offscreen rendering with an intermediate surface,
since you clearly don't need it; but you really need to look at the
documentation when it comes to signal handlers: the compiler cannot do
type checks for you, there.

(except I used an old version of gtk3 and a wrong callback for the draw
event). My Goodness! Why such a dramatic changes?

"Dramatic"? The rendering model is simpler and gives you all you need
without having to call intermediate functions.

As for your other email:

Is there any working and simple example with DrawingArea? If any could
you please give me the reference to it?

Using GtkDrawingArea does not require any special example. Add it to a
container and set the area to expand both horizontally and vertically,
so that it occupies all the available space given to it by the parent;
then connect to the "draw" signal (with the correct signature) and
render your content using the Cairo context given to you.

You know, in GTK2 it was one of the poorest - in terms of documentation
- widget.

Because it doesn't do anything. :-)

It's literally a blank canvas with no intrinsic style or size, so
there's really no documentation for it other than "hook to this signal
and draw inside the callback", which is literally common to all
GtkWidget classes. Since everything happens in your own code, there's
not much that can be said.

And in GTK3 we are getting again the same or I failed to find right
manuals?

Since you're porting from GTK 2.x to 3.x, you probably want to read
the porting manual:

  https://developer.gnome.org/gtk3/stable/migrating.html

And the documentation on the rendering model:

  https://developer.gnome.org/gtk3/stable/chap-drawing-model.html

Anyway it was very useful to get these hints from you, Thank you very
much
and Happy Ney Year!

Thanks, and to you as well.

Ciao,
 Emmanuele.

2016-12-30 14:25 GMT+03:00 Emmanuele Bassi <ebassi gmail com>:

Hi;

On 30 December 2016 at 11:15, Sergei Kolomeeyets
<kolomeeyets gmail com>
wrote:
Hi, everyone
I'm struggling with migration from gtk2. Well gtk_cairo_create is
deprecated
in gtk3. And it looks  the changes are very serious (or I'm sach
silly
that
even do not understand what should I do instead of it ). Is there
anybody
who use Drawing Area in GTK3 and can explain the right way of its
cairo
context creation and drawing on it to me. It would be so appreciated.

Connect to the GtkWidget::draw signal (or subclass GtkDrawingArea and
override the GtkWidgetClass.draw virtual function, which is
essentially the same) and use the Cairo context that's given to you.

Drawing *on widgets* outside of their rendering cycle is not possible
in GTK+ 3.x.

If you want to draw something off screen and then composite it inside
your widget, you'll need to create a Cairo surface yourself, using
something like:

  GdkWindow *window = gtk_widget_get_window (widget);
  cairo_surface_t *surface = gdk_window_create_similar_surface
(window, CAIRO_CONTENT_COLOR_ALPHA, width, height);

then create a Cairo context from it, and draw:

  cairo_t *cr = cairo_create (surface);
  // draw
  cairo_destroy (cr);

Now you can use the surface as a source on the Cairo context that
GtkWIdget::draw gives you:

  static gboolean
  on_draw (GtkWidget *widget, cairo_t *cr)
  {
    // render your surface on the widget's context
    cairo_set_source_surface (cr, surface, x, y);
    cairo_paint (cr);

    // do your own drawing
  }

Documentation says the following:
***gtk_cairo_create
gdk_cairo_create has been deprecated since version 3.22 and should
not
be
used in newly-written code. Use gdk_window_begin_draw_frame() and
gdk_drawing_context_get_cairo_context() instead.

This is only needed if you're literally implementing a toolkit (like
GTK) on top of GDK.


gboolean draw_callback(GtkWidget *area, GdkEventExpose *event, GArray
*ptLinePoints) {
...
cairo_t *cr = gdk_drawing_context_get_cairo_context (area);
...
}

This is *not* a GtkWidget::draw callback. You should read the API
reference:

  https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-draw

The second argument of the callback is a Cairo context; use it.

But linker (gcc package) writes  "undefined reference to
`gdk_drawing_context_get_cairo_context"... :-(
Everything indicated that I missed several lines of code before
gdk_drawing_context_get_cairo_context. But what lines exactly?
Googling
gives nothing...

It means you're not using GTK+ 3.22, but likely an earlier version.

In any case, you should just forget about the drawing context, and use
the Cairo context that GTK itself gives you.

Ciao,
 Emmanuele.

--
https://www.bassi.io
[@] ebassi [@gmail.com]





--
https://www.bassi.io
[@] ebassi [@gmail.com]




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