2010-05-28 16:18:45 +00:00
|
|
|
|
<?xml version="1.0"?>
|
|
|
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
|
|
|
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
2010-12-07 17:59:17 +00:00
|
|
|
|
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
2010-05-28 16:18:45 +00:00
|
|
|
|
]>
|
|
|
|
|
<chapter id="gtk-migrating-2-to-3">
|
2010-06-03 05:09:53 +00:00
|
|
|
|
<title>Migrating from GTK+ 2.x to GTK+ 3</title>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
|
2010-06-03 05:09:53 +00:00
|
|
|
|
<para>
|
2010-08-11 03:12:49 +00:00
|
|
|
|
GTK+ 3 is a major new version of GTK+ that breaks both API and ABI
|
2010-08-11 01:21:01 +00:00
|
|
|
|
compared to GTK+ 2.x, which has remained API- and ABI-stable for a
|
|
|
|
|
long time. Thankfully, most of the changes are not hard to adapt to
|
|
|
|
|
and there are a number of steps that you can take to prepare your
|
|
|
|
|
GTK+ 2.x application for the switch to GTK+ 3. After that, there's
|
|
|
|
|
a small number of adjustments that you may have to do when you actually
|
|
|
|
|
switch your application to build against GTK+ 3.
|
2010-06-03 05:09:53 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<section>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<title>Preparation in GTK+ 2.x</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The steps outlined in the following sections assume that your
|
2010-10-03 02:59:23 +00:00
|
|
|
|
application is working with GTK+ 2.24, which is the final stable
|
2010-08-11 01:21:01 +00:00
|
|
|
|
release of GTK+ 2.x. It includes all the necessary APIs and tools
|
|
|
|
|
to help you port your application to GTK+ 3. If you are still using
|
|
|
|
|
an older version of GTK+ 2.x, you should first get your application
|
2010-10-03 02:59:23 +00:00
|
|
|
|
to build and work with 2.24.
|
2010-08-11 01:21:01 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<title>Do not include individual headers</title>
|
|
|
|
|
<para>
|
|
|
|
|
With GTK+ 2.x it was common to include just the header files for
|
|
|
|
|
a few widgets that your application was using, which could lead
|
|
|
|
|
to problems with missing definitions, etc. GTK+ 3 tightens the
|
|
|
|
|
rules about which header files you are allowed to include directly.
|
|
|
|
|
The allowed header files are are
|
|
|
|
|
<variablelist>
|
|
|
|
|
<varlistentry>
|
|
|
|
|
<term><filename>gtk/gtk.h</filename></term>
|
|
|
|
|
<listitem>for GTK</listitem>
|
|
|
|
|
</varlistentry>
|
2012-04-02 01:20:06 +00:00
|
|
|
|
<varlistentry>
|
|
|
|
|
<term><filename>gtk/gtkx.h</filename></term>
|
|
|
|
|
<listitem>for the X-specfic widgets #GtkSocket and #GtkPlug</listitem>
|
|
|
|
|
</varlistentry>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<varlistentry>
|
|
|
|
|
<term><filename>gtk/gtkunixprint.h</filename></term>
|
|
|
|
|
<listitem>for low-level, UNIX-specific printing functions</listitem>
|
|
|
|
|
</varlistentry>
|
|
|
|
|
<varlistentry>
|
|
|
|
|
<term><filename>gdk/gdk.h</filename></term>
|
|
|
|
|
<listitem>for GDK</listitem>
|
|
|
|
|
</varlistentry>
|
|
|
|
|
<varlistentry>
|
|
|
|
|
<term><filename>gdk/gdkx.h</filename></term>
|
|
|
|
|
<listitem>for GDK functions that are X11-specific</listitem>
|
|
|
|
|
</varlistentry>
|
|
|
|
|
<varlistentry>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
<term><filename>gdk/gdkwin32.h</filename></term>
|
|
|
|
|
<listitem>for GDK functions that are Windows-specific</listitem>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
</varlistentry>
|
|
|
|
|
</variablelist>
|
|
|
|
|
(these relative paths are assuming that you are using the include
|
|
|
|
|
paths that are specified in the gtk+-2.0.pc file, as returned by
|
|
|
|
|
<literal>pkg-config --cflags gtk+-2.0.pc</literal>.)
|
|
|
|
|
</para>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<para>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
To check that your application only includes the allowed headers,
|
|
|
|
|
you can use defines to disable inclusion of individual headers,
|
|
|
|
|
as follows:
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<programlisting>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
make CFLAGS+="-DGTK_DISABLE_SINGLE_INCLUDES"
|
2010-05-28 16:18:45 +00:00
|
|
|
|
</programlisting>
|
|
|
|
|
</para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
</section>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
|
2010-06-03 05:09:53 +00:00
|
|
|
|
<section>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<title>Do not use deprecated symbols</title>
|
|
|
|
|
<para>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
Over the years, a number of functions, and in some cases, entire
|
|
|
|
|
widgets have been deprecated. These deprecations are clearly spelled
|
|
|
|
|
out in the API reference, with hints about the recommended replacements.
|
2012-05-26 19:11:49 +00:00
|
|
|
|
The API reference for GTK+ 2 also includes an
|
2015-03-08 08:43:04 +00:00
|
|
|
|
<ulink url="https://developer.gnome.org/gtk2/2.24/api-index-deprecated.html">index</ulink> of all deprecated symbols.
|
2010-08-11 01:21:01 +00:00
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
To verify that your program does not use any deprecated symbols,
|
|
|
|
|
you can use defines to remove deprecated symbols from the header files,
|
|
|
|
|
as follows:
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<programlisting>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
make CFLAGS+="-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
|
2012-05-26 19:11:49 +00:00
|
|
|
|
</programlisting>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
</para>
|
2012-05-26 16:19:51 +00:00
|
|
|
|
<para>
|
|
|
|
|
Note that some parts of our API, such as enumeration values, are
|
|
|
|
|
not well covered by the deprecation warnings. In most cases, using
|
|
|
|
|
them will require you to also use deprecated functions, which will
|
|
|
|
|
trigger warnings. But some things, like the %GTK_DIALOG_NO_SEPARATOR
|
2012-05-26 19:11:49 +00:00
|
|
|
|
flag that has disappeared in GTK+ 3, may not.
|
2012-05-26 16:19:51 +00:00
|
|
|
|
</para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
</section>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
|
2010-06-03 05:09:53 +00:00
|
|
|
|
<section>
|
2010-08-11 03:12:49 +00:00
|
|
|
|
<title>Use accessor functions instead of direct access</title>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
GTK+ 3 removes many implementation details and struct members from
|
2010-08-11 01:21:01 +00:00
|
|
|
|
its public headers.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
To ensure that your application does not have problems with this, you
|
2011-01-06 00:00:14 +00:00
|
|
|
|
define the preprocessor symbol <literal>GSEAL_ENABLE</literal> while
|
|
|
|
|
building your application against GTK+ 2.x. This will make the compiler
|
|
|
|
|
catch all uses of direct access to struct fields so that you can go
|
|
|
|
|
through them one by one and replace them with a call to an accessor
|
|
|
|
|
function instead.
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<programlisting>
|
|
|
|
|
make CFLAGS+="-DGSEAL_ENABLE"
|
|
|
|
|
</programlisting>
|
|
|
|
|
</para>
|
2013-01-27 21:06:59 +00:00
|
|
|
|
<para>
|
|
|
|
|
While it may be painful to convert, this helps us keep API and ABI
|
|
|
|
|
compatibility when we change internal interfaces. As a quick example,
|
|
|
|
|
when adding GSEAL_ENABLE, if you see an error like:
|
|
|
|
|
<programlisting>
|
|
|
|
|
error: 'GtkToggleButton' has no member named 'active'
|
|
|
|
|
</programlisting>
|
|
|
|
|
this means that you are accessing the public structure of
|
|
|
|
|
GtkToggleButton directly, perhaps with some code like:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
on_toggled (GtkToggleButton *button)
|
|
|
|
|
{
|
|
|
|
|
if (button->active)
|
|
|
|
|
frob_active ();
|
|
|
|
|
else
|
|
|
|
|
frob_inactive ();
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
In most cases, this can easily be replaced with the correct accessor
|
|
|
|
|
method. The main rule is that if you have code like the above which
|
|
|
|
|
accesses the "active" field of a "GtkToggleButton", then the accessor
|
|
|
|
|
method becomes "gtk_toggle_button_get_active":
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
on_toggled (GtkToggleButton *button)
|
|
|
|
|
{
|
|
|
|
|
if (gtk_toggle_button_get_active (button))
|
|
|
|
|
frob_active ();
|
|
|
|
|
else
|
|
|
|
|
frob_inactive ();
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
In the case of setting field members directly, there's usually
|
|
|
|
|
a corresponding setter method.
|
|
|
|
|
</para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
</section>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
|
2010-09-08 22:25:52 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Replace GDK_<keyname> with GDK_KEY_<keyname></title>
|
|
|
|
|
|
|
|
|
|
<para>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
Key constants have gained a <literal>_KEY_</literal> infix.
|
2010-09-08 22:25:52 +00:00
|
|
|
|
For example, <literal>GDK_a</literal> is now
|
|
|
|
|
<literal>GDK_KEY_a</literal>. In GTK+ 2, the old names continue
|
|
|
|
|
to be available. In GTK+ 3 however, the old names will require
|
2010-09-24 22:59:24 +00:00
|
|
|
|
an explicit include of the <literal>gdkkeysyms-compat.h</literal> header.
|
2010-09-08 22:25:52 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-12-22 16:13:31 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Use GIO for launching applications</title>
|
|
|
|
|
<para>
|
|
|
|
|
The <literal>gdk_spawn</literal> family of functions has been
|
|
|
|
|
deprecated in GDK 2.24 and removed from GDK 3. Various replacements
|
2010-12-22 17:05:50 +00:00
|
|
|
|
exist; the best replacement depends on the circumstances:
|
2010-12-22 16:13:31 +00:00
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem>If you are opening a document or URI by launching a command
|
|
|
|
|
like <literal>firefox http://my-favourite-website.com</literal> or
|
|
|
|
|
<literal>gnome-open ghelp:epiphany</literal>, it is best to just use
|
|
|
|
|
gtk_show_uri(); as an added benefit, your application will henceforth
|
|
|
|
|
respect the users preference for what application to use.</listitem>
|
|
|
|
|
<listitem>If you are launching a regular, installed application that
|
|
|
|
|
has a desktop file, it is best to use GIOs #GAppInfo with a suitable
|
|
|
|
|
launch context.
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
GAppInfo *info;
|
|
|
|
|
GAppLaunchContext *context;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
2011-02-09 14:25:31 +00:00
|
|
|
|
info = (GAppInfo*) g_desktop_app_info_new ("epiphany.desktop");
|
|
|
|
|
context = (GAppLaunchContext*) gdk_display_get_app_launch_context (display);
|
2010-12-22 16:13:31 +00:00
|
|
|
|
g_app_info_launch (info, NULL, context, &error);
|
|
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
g_warning ("Failed to launch epiphany: %s", error->message);
|
|
|
|
|
g_error_free (error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_unref (info);
|
|
|
|
|
g_object_unref (context);
|
|
|
|
|
</programlisting></informalexample>
|
2011-02-09 14:01:16 +00:00
|
|
|
|
Remember that you have to include
|
|
|
|
|
<filename>gio/gdesktopappinfo.h</filename>
|
|
|
|
|
and use the <filename>gio-unix-2.0</filename> pkg-config file
|
|
|
|
|
when using g_desktop_app_info_new().
|
2010-12-22 16:13:31 +00:00
|
|
|
|
</listitem>
|
|
|
|
|
<listitem>If you are launching a custom commandline, you can
|
|
|
|
|
still use g_app_info_launch() with a GAppInfo that is constructed
|
|
|
|
|
with g_app_info_create_from_commandline(), or you can use the
|
|
|
|
|
more lowlevel <literal>g_spawn</literal> family of functions
|
|
|
|
|
(e.g. g_spawn_command_line_async()), and pass <envar>DISPLAY</envar>
|
|
|
|
|
in the environment. gdk_screen_make_display_name() can be
|
|
|
|
|
used to find the right value for the <envar>DISPLAY</envar>
|
|
|
|
|
environment variable.
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-06-03 05:09:53 +00:00
|
|
|
|
<section>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<title>Use cairo for drawing</title>
|
|
|
|
|
<para>
|
|
|
|
|
In GTK+ 3, the GDK drawing API (which closely mimics the X
|
|
|
|
|
drawing API, which is itself modeled after PostScript) has been
|
|
|
|
|
removed. All drawing in GTK+ 3 is done via cairo.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
The #GdkGC and #GdkImage objects, as well as all the functions using
|
2010-09-24 22:59:24 +00:00
|
|
|
|
them, are gone. This includes the <literal>gdk_draw</literal> family
|
2010-08-11 01:21:01 +00:00
|
|
|
|
of functions like gdk_draw_rectangle() and gdk_draw_drawable(). As
|
|
|
|
|
#GdkGC is roughly equivalent to #cairo_t and #GdkImage was used for
|
2010-11-24 13:26:04 +00:00
|
|
|
|
drawing images to GdkWindows, which cairo supports automatically,
|
2010-08-11 01:21:01 +00:00
|
|
|
|
a transition is usually straightforward.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
The following examples show a few common drawing idioms used by
|
|
|
|
|
applications that have been ported to use cairo and how the code
|
|
|
|
|
was replaced.
|
|
|
|
|
</para>
|
|
|
|
|
<example>
|
2010-11-24 13:26:04 +00:00
|
|
|
|
<title>Drawing a GdkPixbuf onto a GdkWindow</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<para>
|
|
|
|
|
Drawing a pixbuf onto a drawable used to be done like this:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
gdk_draw_pixbuf (window,
|
|
|
|
|
gtk_widget_get_style (widget)->black_gc,
|
|
|
|
|
pixbuf,
|
|
|
|
|
0, 0
|
|
|
|
|
x, y,
|
|
|
|
|
gdk_pixbuf_get_width (pixbuf),
|
|
|
|
|
gdk_pixbuf_get_height (pixbuf),
|
|
|
|
|
GDK_RGB_DITHER_NORMAL,
|
|
|
|
|
0, 0);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
Doing the same thing with cairo:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_t *cr = gdk_cairo_create (window);
|
|
|
|
|
gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
|
|
|
|
|
cairo_paint (cr);
|
|
|
|
|
cairo_destroy (cr);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2011-02-20 22:42:43 +00:00
|
|
|
|
Note that very similar code can be used when porting code
|
|
|
|
|
using GdkPixmap to #cairo_surface_t by calling
|
|
|
|
|
cairo_set_source_surface() instead of
|
|
|
|
|
gdk_cairo_set_source_pixbuf().
|
2010-08-11 01:21:01 +00:00
|
|
|
|
</para>
|
|
|
|
|
</example>
|
|
|
|
|
<example>
|
2010-11-24 13:26:04 +00:00
|
|
|
|
<title>Drawing a tiled GdkPixmap to a GdkWindow</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<para>
|
|
|
|
|
Tiled pixmaps are often used for drawing backgrounds.
|
|
|
|
|
Old code looked something like this:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
GdkGCValues gc_values;
|
|
|
|
|
GdkGC *gc;
|
|
|
|
|
|
|
|
|
|
/* setup */
|
|
|
|
|
gc = gtk_widget_get_style (widget)->black_gc;
|
|
|
|
|
gdk_gc_set_tile (gc, pixmap);
|
|
|
|
|
gdk_gc_set_fill (gc, GDK_TILED);
|
|
|
|
|
gdk_gc_set_ts_origin (gc, x_origin, y_origin);
|
|
|
|
|
/* use */
|
2011-02-20 22:42:43 +00:00
|
|
|
|
gdk_draw_rectangle (window, gc, TRUE, 0, 0, width, height);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
/* restore */
|
|
|
|
|
gdk_gc_set_tile (gc, NULL);
|
|
|
|
|
gdk_gc_set_fill (gc, GDK_SOLID);
|
|
|
|
|
gdk_gc_set_ts_origin (gc, 0, 0);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2011-02-20 23:06:08 +00:00
|
|
|
|
The equivalent cairo code to draw a tiled surface looks
|
2011-02-20 22:42:43 +00:00
|
|
|
|
like this:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_t *cr;
|
2011-02-20 22:03:45 +00:00
|
|
|
|
cairo_surface_t *surface;
|
2010-08-11 01:21:01 +00:00
|
|
|
|
|
2011-02-20 22:03:45 +00:00
|
|
|
|
surface = ...
|
|
|
|
|
cr = gdk_cairo_create (window);
|
2011-02-20 22:42:43 +00:00
|
|
|
|
cairo_set_source_surface (cr, surface, x_origin, y_origin);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
|
|
|
|
|
cairo_rectangle (cr, 0, 0, width, height);
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
cairo_destroy (cr);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2011-02-20 22:03:45 +00:00
|
|
|
|
The surface here can be either an image surface or a X surface,
|
|
|
|
|
and can either be created on the spot or kept around for caching purposes.
|
|
|
|
|
Another alternative is to use pixbufs instead of surfaces with
|
|
|
|
|
gdk_cairo_set_source_pixbuf() instead of cairo_set_source_surface().
|
2010-08-11 01:21:01 +00:00
|
|
|
|
</para>
|
|
|
|
|
</example>
|
|
|
|
|
<example>
|
|
|
|
|
<title>Drawing a PangoLayout to a clipped area</title>
|
|
|
|
|
<para>
|
|
|
|
|
Drawing layouts clipped is often used to avoid overdraw or to
|
|
|
|
|
allow drawing selections. Code would have looked like this:
|
2012-05-26 16:19:51 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
GdkGC *gc;
|
|
|
|
|
|
|
|
|
|
/* setup */
|
|
|
|
|
gc = gtk_widget_get_style (widget)->text_gc[state];
|
2011-02-18 22:09:40 +00:00
|
|
|
|
gdk_gc_set_clip_rectangle (gc, &area);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
/* use */
|
|
|
|
|
gdk_draw_layout (drawable, gc, x, y, layout);
|
|
|
|
|
/* restore */
|
|
|
|
|
gdk_gc_set_clip_rectangle (gc, NULL);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-08-11 03:12:49 +00:00
|
|
|
|
With cairo, the same effect can be achieved using:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2011-02-19 18:47:43 +00:00
|
|
|
|
GtkStyleContext *context;
|
|
|
|
|
GtkStateFlags flags;
|
|
|
|
|
GdkRGBA rgba;
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
|
|
cr = gdk_cairo_create (drawable);
|
|
|
|
|
/* clip */
|
2011-02-18 22:09:40 +00:00
|
|
|
|
gdk_cairo_rectangle (cr, &area);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_clip (cr);
|
|
|
|
|
/* set the correct source color */
|
2011-02-19 18:47:43 +00:00
|
|
|
|
context = gtk_widget_get_style_context (widget));
|
|
|
|
|
state = gtk_widget_get_state_flags (widget);
|
|
|
|
|
gtk_style_context_get_color (context, state, &rgba);
|
|
|
|
|
gdk_cairo_set_source_rgba (cr, &rgba);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
/* draw the text */
|
|
|
|
|
cairo_move_to (cr, x, y);
|
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
|
cairo_destroy (cr);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
Clipping using cairo_clip() is of course not restricted to text
|
|
|
|
|
rendering and can be used everywhere where GC clips were used.
|
|
|
|
|
And using gdk_cairo_set_source_color() with style colors should
|
|
|
|
|
be used in all the places where a style’s GC was used to achieve
|
|
|
|
|
a particular color.
|
|
|
|
|
</para>
|
|
|
|
|
</example>
|
|
|
|
|
<section>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
<title>What should you be aware of ?</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<formalpara><title>No more stippling</title>
|
|
|
|
|
<para>
|
|
|
|
|
Stippling is the usage of a bi-level mask, called a #GdkBitmap.
|
|
|
|
|
It was often used to achieve a checkerboard effect. You can use
|
|
|
|
|
cairo_mask() to achieve this effect. To get a checkerbox mask,
|
|
|
|
|
you can use code like this:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
static cairo_pattern_t *
|
|
|
|
|
gtk_color_button_get_checkered (void)
|
|
|
|
|
{
|
|
|
|
|
/* need to respect pixman's stride being a multiple of 4 */
|
|
|
|
|
static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0xFF, 0x00, 0x00 };
|
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
cairo_pattern_t *pattern;
|
|
|
|
|
|
|
|
|
|
surface = cairo_image_surface_create_for_data (data,
|
|
|
|
|
CAIRO_FORMAT_A8,
|
|
|
|
|
2, 2,
|
|
|
|
|
4);
|
|
|
|
|
pattern = cairo_pattern_create_for_surface (surface);
|
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
|
|
|
|
cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
|
|
|
|
|
|
|
|
|
|
return pattern;
|
|
|
|
|
}
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
Note that stippling looks very outdated in UIs, and is rarely
|
|
|
|
|
used in modern applications. All properties that made use of
|
|
|
|
|
stippling have been removed from GTK+ 3. Most prominently,
|
|
|
|
|
stippling is absent from text rendering, in particular #GtkTextTag.
|
|
|
|
|
</para>
|
|
|
|
|
</formalpara>
|
2011-02-20 22:03:45 +00:00
|
|
|
|
<formalpara><title>Using the target also as source or mask</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<para>
|
|
|
|
|
The gdk_draw_drawable() function allowed using the same drawable
|
|
|
|
|
as source and target. This was often used to achieve a scrolling
|
|
|
|
|
effect. Cairo does not allow this yet. You can however use
|
|
|
|
|
cairo_push_group() to get a different intermediate target that
|
|
|
|
|
you can copy to. So you can replace this code:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
gdk_draw_drawable (pixmap,
|
|
|
|
|
gc,
|
|
|
|
|
pixmap,
|
|
|
|
|
area.x + dx, area.y + dy,
|
|
|
|
|
area.x, area.y,
|
|
|
|
|
area.width, area.height);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
By using this code:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2011-02-20 22:42:43 +00:00
|
|
|
|
cairo_t *cr = cairo_create (surface);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
/* clipping restricts the intermediate surface's size, so it's a good idea
|
|
|
|
|
* to use it. */
|
2011-02-18 22:09:40 +00:00
|
|
|
|
gdk_cairo_rectangle (cr, &area);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_clip (cr);
|
|
|
|
|
/* Now push a group to change the target */
|
|
|
|
|
cairo_push_group (cr);
|
2011-02-20 22:42:43 +00:00
|
|
|
|
cairo_set_source_surface (cr, surface, dx, dy);
|
2010-08-11 01:21:01 +00:00
|
|
|
|
cairo_paint (cr);
|
|
|
|
|
/* Now copy the intermediate target back */
|
|
|
|
|
cairo_pop_group_to_source (cr);
|
|
|
|
|
cairo_paint (cr);
|
|
|
|
|
cairo_destroy (cr);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2011-02-20 22:03:45 +00:00
|
|
|
|
The surface here can be either an image surface or a X surface,
|
|
|
|
|
and can either be created on the spot or kept around for caching purposes.
|
|
|
|
|
Another alternative is to use pixbufs instead of surfaces with
|
|
|
|
|
gdk_cairo_set_source_pixbuf() instead of cairo_set_source_surface().
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
The cairo developers plan to add self-copies in the future to allow
|
|
|
|
|
exactly this effect, so you might want to keep up on cairo
|
|
|
|
|
development to be able to change your code.
|
|
|
|
|
</para>
|
|
|
|
|
</formalpara>
|
2010-09-24 22:59:24 +00:00
|
|
|
|
<formalpara><title>Using pango_cairo_show_layout(<!-- -->) instead of gdk_draw_layout_with_colors(<!-- -->)</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<para>
|
|
|
|
|
GDK provided a way to ignore the color attributes of text and use
|
|
|
|
|
a hardcoded text color with the gdk_draw_layout_with_colors()
|
|
|
|
|
function. This is often used to draw text shadows or selections.
|
|
|
|
|
Pango’s cairo support does not yet provide this functionality. If
|
|
|
|
|
you use Pango layouts that change colors, the easiest way to achieve
|
|
|
|
|
a similar effect is using pango_cairo_layout_path() and cairo_fill()
|
|
|
|
|
instead of gdk_draw_layout_with_colors(). Note that this results in
|
|
|
|
|
a slightly uglier-looking text, as subpixel anti-aliasing is not
|
|
|
|
|
supported.
|
|
|
|
|
</para>
|
|
|
|
|
</formalpara>
|
|
|
|
|
</section>
|
|
|
|
|
</section>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<title>Changes that need to be done at the time of the switch</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
This section outlines porting tasks that you need to tackle when
|
|
|
|
|
you get to the point that you actually build your application against
|
2010-10-03 02:59:23 +00:00
|
|
|
|
GTK+ 3. Making it possible to prepare for these in GTK+ 2.24 would
|
2010-08-11 01:21:01 +00:00
|
|
|
|
have been either impossible or impractical.
|
|
|
|
|
</para>
|
|
|
|
|
|
2010-10-27 19:55:33 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Replace size_request by get_preferred_width/height</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The request-phase of the traditional GTK+ geometry management
|
|
|
|
|
has been replaced by a more flexible height-for-width system,
|
|
|
|
|
which is described in detail in the API documentation
|
|
|
|
|
(see <xref linkend="geometry-management"/>). As a consequence,
|
|
|
|
|
the ::size-request signal and vfunc has been removed from
|
|
|
|
|
#GtkWidgetClass. The replacement for size_request() can
|
|
|
|
|
take several levels of sophistication:
|
|
|
|
|
<itemizedlist>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<listitem>
|
|
|
|
|
<para>
|
|
|
|
|
As a minimal replacement to keep current functionality,
|
|
|
|
|
you can simply implement the #GtkWidgetClass.get_preferred_width() and
|
|
|
|
|
#GtkWidgetClass.get_preferred_height() vfuncs by calling your existing
|
2010-10-27 19:55:33 +00:00
|
|
|
|
size_request() function. So you go from
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
my_widget_class_init (MyWidgetClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
|
|
|
|
|
widget_class->size_request = my_widget_size_request;
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
to something that looks more like this:
|
2010-11-19 03:44:42 +00:00
|
|
|
|
</para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
my_widget_get_preferred_width (GtkWidget *widget,
|
|
|
|
|
gint *minimal_width,
|
|
|
|
|
gint *natural_width)
|
|
|
|
|
{
|
|
|
|
|
GtkRequisition requisition;
|
|
|
|
|
|
|
|
|
|
my_widget_size_request (widget, &requisition);
|
|
|
|
|
|
|
|
|
|
*minimal_width = *natural_width = requisition.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
my_widget_get_preferred_height (GtkWidget *widget,
|
|
|
|
|
gint *minimal_height,
|
|
|
|
|
gint *natural_height)
|
|
|
|
|
{
|
|
|
|
|
GtkRequisition requisition;
|
|
|
|
|
|
|
|
|
|
my_widget_size_request (widget, &requisition);
|
|
|
|
|
|
|
|
|
|
*minimal_height = *natural_height = requisition.height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
my_widget_class_init (MyWidgetClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
|
|
|
|
|
widget_class->get_preferred_width = my_widget_get_preferred_width;
|
|
|
|
|
widget_class->get_preferred_height = my_widget_get_preferred_height;
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
Sometimes you can make things a little more streamlined
|
|
|
|
|
by replacing your existing size_request() implementation by
|
|
|
|
|
one that takes an orientation parameter:
|
2010-11-19 03:44:42 +00:00
|
|
|
|
</para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
my_widget_get_preferred_size (GtkWidget *widget,
|
|
|
|
|
GtkOrientation orientation,
|
|
|
|
|
gint *minimal_size,
|
|
|
|
|
gint *natural_size)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* do things that are common for both orientations ... */
|
|
|
|
|
|
|
|
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
|
|
|
{
|
|
|
|
|
/* do stuff that only applies to width... */
|
|
|
|
|
|
|
|
|
|
*minimal_size = *natural_size = ...
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* do stuff that only applies to height... */
|
|
|
|
|
|
|
|
|
|
*minimal_size = *natural_size = ...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
my_widget_get_preferred_width (GtkWidget *widget,
|
|
|
|
|
gint *minimal_width,
|
|
|
|
|
gint *natural_width)
|
|
|
|
|
{
|
|
|
|
|
my_widget_get_preferred_size (widget,
|
|
|
|
|
GTK_ORIENTATION_HORIZONTAL,
|
|
|
|
|
minimal_width,
|
|
|
|
|
natural_width);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
my_widget_get_preferred_height (GtkWidget *widget,
|
|
|
|
|
gint *minimal_height,
|
|
|
|
|
gint *natural_height)
|
|
|
|
|
{
|
|
|
|
|
my_widget_get_preferred_size (widget,
|
|
|
|
|
GTK_ORIENTATION_VERTICAL,
|
|
|
|
|
minimal_height,
|
|
|
|
|
natural_height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ... */
|
|
|
|
|
</programlisting></informalexample>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
</para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
</listitem>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<listitem>
|
|
|
|
|
<para>If your widget can cope with a small size,
|
2010-10-27 19:55:33 +00:00
|
|
|
|
but would appreciate getting some more space (a common
|
|
|
|
|
example would be that it contains ellipsizable labels),
|
2010-11-19 03:44:42 +00:00
|
|
|
|
you can do that by making your #GtkWidgetClass.get_preferred_width() /
|
|
|
|
|
#GtkWidgetClass.get_preferred_height()
|
2010-10-27 19:55:33 +00:00
|
|
|
|
functions return a smaller value for @minimal than for @natural.
|
|
|
|
|
For @minimal, you probably want to return the same value
|
|
|
|
|
that your size_request() function returned before (since
|
|
|
|
|
size_request() was defined as returning the minimal size
|
|
|
|
|
a widget can work with). A simple way to obtain good
|
|
|
|
|
values for @natural, in the case of containers, is to use
|
|
|
|
|
gtk_widget_get_preferred_width() and
|
|
|
|
|
gtk_widget_get_preferred_height() on the children of the
|
|
|
|
|
container, as in the following example:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static void
|
|
|
|
|
gtk_fixed_get_preferred_height (GtkWidget *widget,
|
|
|
|
|
gint *minimum,
|
|
|
|
|
gint *natural)
|
|
|
|
|
{
|
|
|
|
|
GtkFixed *fixed = GTK_FIXED (widget);
|
|
|
|
|
GtkFixedPrivate *priv = fixed->priv;
|
|
|
|
|
GtkFixedChild *child;
|
|
|
|
|
GList *children;
|
|
|
|
|
gint child_min, child_nat;
|
|
|
|
|
|
|
|
|
|
*minimum = 0;
|
|
|
|
|
*natural = 0;
|
|
|
|
|
|
|
|
|
|
for (children = priv->children; children; children = children->next)
|
|
|
|
|
{
|
|
|
|
|
child = children->data;
|
|
|
|
|
|
|
|
|
|
if (!gtk_widget_get_visible (child->widget))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
gtk_widget_get_preferred_height (child->widget, &child_min, &child_nat);
|
|
|
|
|
|
|
|
|
|
*minimum = MAX (*minimum, child->y + child_min);
|
|
|
|
|
*natural = MAX (*natural, child->y + child_nat);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
</para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
</listitem>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<listitem>
|
|
|
|
|
<para>
|
|
|
|
|
Note that the #GtkWidgetClass.get_preferred_width() /
|
|
|
|
|
#GtkWidgetClass.get_preferred_height() functions
|
2010-11-01 02:16:41 +00:00
|
|
|
|
only allow you to deal with one dimension at a time. If your
|
2010-10-30 02:48:26 +00:00
|
|
|
|
size_request() handler is doing things that involve both
|
|
|
|
|
width and height at the same time (e.g. limiting the aspect
|
2010-11-19 03:44:42 +00:00
|
|
|
|
ratio), you will have to implement
|
|
|
|
|
#GtkWidgetClass.get_preferred_height_for_width()
|
|
|
|
|
and #GtkWidgetClass.get_preferred_width_for_height().
|
|
|
|
|
</para>
|
2010-10-30 02:48:26 +00:00
|
|
|
|
</listitem>
|
2010-11-19 03:44:42 +00:00
|
|
|
|
<listitem>
|
|
|
|
|
<para>
|
|
|
|
|
To make full use of the new capabilities of the
|
2010-10-27 19:55:33 +00:00
|
|
|
|
height-for-width geometry management, you need to additionally
|
2010-11-19 03:44:42 +00:00
|
|
|
|
implement the #GtkWidgetClass.get_preferred_height_for_width() and
|
|
|
|
|
#GtkWidgetClass.get_preferred_width_for_height(). For details on
|
|
|
|
|
these functions, see <xref linkend="geometry-management"/>.
|
|
|
|
|
</para>
|
2010-10-27 19:55:33 +00:00
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Replace GdkRegion by cairo_region_t</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Starting with version 1.10, cairo provides a region API that is
|
|
|
|
|
equivalent to the GDK region API (which was itself copied from
|
|
|
|
|
the X server). Therefore, the region API has been removed in GTK+ 3.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
Porting your application to the cairo region API should be a straight
|
|
|
|
|
find-and-replace task. Please refer to the following table:
|
|
|
|
|
<table>
|
|
|
|
|
<tgroup cols="2">
|
2011-01-23 17:26:23 +00:00
|
|
|
|
<title>GdkRegion to cairo_region_t</title>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<thead>
|
|
|
|
|
<row><entry>GDK</entry><entry>cairo</entry></row>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<row><entry>#GdkRegion</entry><entry>#cairo_region_t</entry></row>
|
|
|
|
|
<row><entry>#GdkRectangle</entry><entry>#cairo_rectangle_int_t</entry></row>
|
|
|
|
|
<row><entry>gdk_rectangle_intersect()</entry><entry>this function is still there</entry></row>
|
|
|
|
|
<row><entry>gdk_rectangle_union()</entry><entry>this function is still there</entry></row>
|
|
|
|
|
<row><entry>gdk_region_new()</entry><entry>cairo_region_create()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_copy()</entry><entry>cairo_region_copy()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_destroy()</entry><entry>cairo_region_destroy()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_rectangle()</entry><entry>cairo_region_create_rectangle()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_get_clipbox()</entry><entry>cairo_region_get_extents()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_get_rectangles()</entry><entry>cairo_region_num_rectangles() and
|
|
|
|
|
cairo_region_get_rectangle()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_empty()</entry><entry>cairo_region_is_empty()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_equal()</entry><entry>cairo_region_equal()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_point_in()</entry><entry>cairo_region_contains_point()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_rect_in()</entry><entry>cairo_region_contains_rectangle()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_offset()</entry><entry>cairo_region_translate()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_union_with_rect()</entry><entry>cairo_region_union_rectangle()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_intersect()</entry><entry>cairo_region_intersect()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_union()</entry><entry>cairo_region_union()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_subtract()</entry><entry>cairo_region_subtract()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_xor()</entry><entry>cairo_region_xor()</entry></row>
|
|
|
|
|
<row><entry>gdk_region_shrink()</entry><entry>no replacement</entry></row>
|
|
|
|
|
<row><entry>gdk_region_polygon()</entry><entry>no replacement, use cairo paths instead</entry></row>
|
|
|
|
|
</tbody>
|
|
|
|
|
</tgroup>
|
|
|
|
|
</table>
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-09-16 14:49:56 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Replace GdkPixmap by cairo surfaces</title>
|
|
|
|
|
<para>
|
|
|
|
|
The #GdkPixmap object and related functions have been removed.
|
2010-10-01 18:54:11 +00:00
|
|
|
|
In the cairo-centric world of GTK+ 3, cairo surfaces take over
|
|
|
|
|
the role of pixmaps.
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</para>
|
2010-10-01 18:54:11 +00:00
|
|
|
|
<example>
|
|
|
|
|
<title>Creating custom cursors</title>
|
|
|
|
|
<para>
|
|
|
|
|
One place where pixmaps were commonly used is to create custom
|
|
|
|
|
cursors:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-10-01 18:54:11 +00:00
|
|
|
|
GdkCursor *cursor;
|
|
|
|
|
GdkPixmap *pixmap;
|
|
|
|
|
cairo_t *cr;
|
|
|
|
|
GdkColor fg = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
|
|
pixmap = gdk_pixmap_new (NULL, 1, 1, 1);
|
|
|
|
|
|
|
|
|
|
cr = gdk_cairo_create (pixmap);
|
|
|
|
|
cairo_rectangle (cr, 0, 0, 1, 1);
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
|
|
cursor = gdk_cursor_new_from_pixmap (pixmap, pixmap, &fg, &fg, 0, 0);
|
|
|
|
|
|
|
|
|
|
g_object_unref (pixmap);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-10-01 18:54:11 +00:00
|
|
|
|
The same can be achieved without pixmaps, by drawing onto
|
|
|
|
|
an image surface:
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-10-01 18:54:11 +00:00
|
|
|
|
GdkCursor *cursor;
|
|
|
|
|
cairo_surface_t *s;
|
|
|
|
|
cairo_t *cr;
|
|
|
|
|
GdkPixbuf *pixbuf;
|
|
|
|
|
|
|
|
|
|
s = cairo_image_surface_create (CAIRO_FORMAT_A1, 3, 3);
|
|
|
|
|
cr = cairo_create (s);
|
|
|
|
|
cairo_arc (cr, 1.5, 1.5, 1.5, 0, 2 * M_PI);
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
2011-07-06 10:59:56 +00:00
|
|
|
|
pixbuf = gdk_pixbuf_get_from_surface (s,
|
|
|
|
|
0, 0,
|
2010-10-01 18:54:11 +00:00
|
|
|
|
3, 3);
|
|
|
|
|
|
|
|
|
|
cairo_surface_destroy (s);
|
|
|
|
|
|
|
|
|
|
cursor = gdk_cursor_new_from_pixbuf (display, pixbuf, 0, 0);
|
|
|
|
|
|
|
|
|
|
g_object_unref (pixbuf);
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-10-01 18:54:11 +00:00
|
|
|
|
</para>
|
|
|
|
|
</example>
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
2011-01-23 17:26:23 +00:00
|
|
|
|
<title>Replace GdkColormap by GdkVisual</title>
|
2010-09-16 14:49:56 +00:00
|
|
|
|
<para>
|
|
|
|
|
For drawing with cairo, it is not necessary to allocate colors, and
|
|
|
|
|
a #GdkVisual provides enough information for cairo to handle colors
|
|
|
|
|
in 'native' surfaces. Therefore, #GdkColormap and related functions
|
|
|
|
|
have been removed in GTK+ 3, and visuals are used instead. The
|
|
|
|
|
colormap-handling functions of #GtkWidget (gtk_widget_set_colormap(),
|
2011-01-11 15:36:19 +00:00
|
|
|
|
etc) have been removed and gtk_widget_set_visual() has been added.
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</para>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
<example><title>Setting up a translucent window</title>
|
|
|
|
|
<para>You might have a screen-changed handler like the following
|
|
|
|
|
to set up a translucent window with an alpha-channel:
|
|
|
|
|
</para>
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
static void
|
|
|
|
|
on_alpha_screen_changed (GtkWidget *widget,
|
|
|
|
|
GdkScreen *old_screen,
|
|
|
|
|
GtkWidget *label)
|
|
|
|
|
{
|
|
|
|
|
GdkScreen *screen = gtk_widget_get_screen (widget);
|
|
|
|
|
GdkColormap *colormap = gdk_screen_get_rgba_colormap (screen);
|
|
|
|
|
|
|
|
|
|
if (colormap == NULL)
|
|
|
|
|
colormap = gdk_screen_get_default_colormap (screen);
|
|
|
|
|
|
|
|
|
|
gtk_widget_set_colormap (widget, colormap);
|
|
|
|
|
}
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-09-16 14:49:56 +00:00
|
|
|
|
<para>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
With visuals instead of colormaps, this will look as follows:
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</para>
|
2011-02-18 22:09:40 +00:00
|
|
|
|
<informalexample><programlisting>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
static void
|
|
|
|
|
on_alpha_screen_changed (GtkWindow *window,
|
|
|
|
|
GdkScreen *old_screen,
|
|
|
|
|
GtkWidget *label)
|
|
|
|
|
{
|
|
|
|
|
GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (window));
|
|
|
|
|
GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
|
|
|
|
|
|
|
|
|
|
if (visual == NULL)
|
|
|
|
|
visual = gdk_screen_get_system_visual (screen);
|
|
|
|
|
|
2011-01-11 15:36:19 +00:00
|
|
|
|
gtk_widget_set_visual (window, visual);
|
2010-09-25 00:02:01 +00:00
|
|
|
|
}
|
2011-02-18 22:09:40 +00:00
|
|
|
|
</programlisting></informalexample>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
</example>
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2011-01-23 17:26:23 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>GdkDrawable is gone</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
#GdkDrawable has been removed in GTK+ 3, together with #GdkPixmap
|
|
|
|
|
and #GdkImage. The only remaining drawable class is #GdkWindow.
|
2011-02-20 22:42:43 +00:00
|
|
|
|
For dealing with image data, you should use a #cairo_surface_t or
|
|
|
|
|
a #GdkPixbuf.
|
2011-01-23 17:26:23 +00:00
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
GdkDrawable functions that are useful with windows have been replaced
|
|
|
|
|
by corresponding GdkWindow functions:
|
|
|
|
|
<table>
|
|
|
|
|
<title>GdkDrawable to GdkWindow</title>
|
|
|
|
|
<tgroup cols="2">
|
|
|
|
|
<thead>
|
|
|
|
|
<row><entry>GDK 2.x</entry><entry>GDK 3</entry></row>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<row><entry>gdk_drawable_get_visual()</entry><entry>gdk_window_get_visual()</entry></row>
|
|
|
|
|
<row><entry>gdk_drawable_get_size()</entry><entry>gdk_window_get_width()
|
|
|
|
|
gdk_window_get_height()</entry></row>
|
|
|
|
|
<row><entry>gdk_pixbuf_get_from_drawable()</entry><entry>gdk_pixbuf_get_from_window()</entry></row>
|
|
|
|
|
<row><entry>gdk_drawable_get_clip_region()</entry><entry>gdk_window_get_clip_region()</entry></row>
|
|
|
|
|
<row><entry>gdk_drawable_get_visible_region()</entry><entry>gdk_window_get_visible_region()</entry></row>
|
|
|
|
|
</tbody>
|
|
|
|
|
</tgroup>
|
|
|
|
|
</table>
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2011-02-05 06:56:19 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Event filtering</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
If your application uses the low-level event filtering facilities in GDK,
|
|
|
|
|
there are some changes you need to be aware of.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The special-purpose GdkEventClient events and the gdk_add_client_message_filter() and gdk_display_add_client_message_filter() functions have been
|
|
|
|
|
removed. Receiving X11 ClientMessage events is still possible, using
|
|
|
|
|
the general gdk_window_add_filter() API. A client message filter like
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static GdkFilterReturn
|
|
|
|
|
message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
XClientMessageEvent *evt = (XClientMessageEvent *)xevent;
|
|
|
|
|
|
|
|
|
|
/* do something with evt ... */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
message_type = gdk_atom_intern ("MANAGER", FALSE);
|
|
|
|
|
gdk_display_add_client_message_filter (display, message_type, message_filter, NULL);
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
then looks like this:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
static GdkFilterReturn
|
|
|
|
|
event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
XClientMessageEvent *evt;
|
|
|
|
|
GdkAtom message_type;
|
|
|
|
|
|
|
|
|
|
if (((XEvent *)xevent)->type != ClientMessage)
|
|
|
|
|
return GDK_FILTER_CONTINUE;
|
|
|
|
|
|
|
|
|
|
evt = (XClientMessageEvent *)xevent;
|
|
|
|
|
message_type = XInternAtom (evt->display, "MANAGER", FALSE);
|
|
|
|
|
|
|
|
|
|
if (evt->message_type != message_type)
|
|
|
|
|
return GDK_FILTER_CONTINUE;
|
|
|
|
|
|
|
|
|
|
/* do something with evt ... */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
gdk_window_add_filter (NULL, message_filter, NULL);
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
One advantage of using an event filter is that you can actually
|
|
|
|
|
remove the filter when you don't need it anymore, using
|
|
|
|
|
gdk_window_remove_filter().
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The other difference to be aware of when working with event filters
|
|
|
|
|
in GTK+ 3 is that GDK now uses XI2 by default when available. That
|
|
|
|
|
means that your application does not receive core X11 key or button
|
|
|
|
|
events. Instead, all input events are delivered as XIDeviceEvents.
|
|
|
|
|
As a short-term workaround for this, you can force your application
|
|
|
|
|
to not use XI2, with gdk_disable_multidevice(). In the long term,
|
|
|
|
|
you probably want to rewrite your event filter to deal with
|
|
|
|
|
XIDeviceEvents.
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2011-01-14 04:40:47 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Backend-specific code</title>
|
|
|
|
|
<para>
|
|
|
|
|
In GTK+ 2.x, GDK could only be compiled for one backend at a time,
|
|
|
|
|
and the %GDK_WINDOWING_X11 or %GDK_WINDOWING_WIN32 macros could
|
|
|
|
|
be used to find out which one you are dealing with:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
|
if (timestamp != GDK_CURRENT_TIME)
|
|
|
|
|
gdk_x11_window_set_user_time (gdk_window, timestamp);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
|
|
|
/* ... win32 specific code ... */
|
|
|
|
|
#endif
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
In GTK+ 3, GDK can be built with multiple backends, and currently
|
|
|
|
|
used backend has to be determined at runtime, typically using
|
|
|
|
|
type-check macros on a #GdkDisplay or #GdkWindow. You still need
|
2014-01-21 22:45:58 +00:00
|
|
|
|
to use the GDK_WINDOWING macros to only compile code referring
|
2011-01-14 04:40:47 +00:00
|
|
|
|
to supported backends:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
|
if (GDK_IS_X11_DISPLAY (display))
|
|
|
|
|
{
|
|
|
|
|
if (timestamp != GDK_CURRENT_TIME)
|
|
|
|
|
gdk_x11_window_set_user_time (gdk_window, timestamp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
|
|
|
if (GDK_IS_WIN32_DISPLAY (display))
|
|
|
|
|
{
|
|
|
|
|
/* ... win32 specific code ... */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
g_warning ("Unsupported GDK backend");
|
|
|
|
|
}
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
</para>
|
2011-02-16 15:53:20 +00:00
|
|
|
|
<para>
|
|
|
|
|
If you used the pkg-config variable <varname>target</varname> to
|
|
|
|
|
conditionally build part of your project depending on the GDK backend,
|
|
|
|
|
for instance like this:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
AM_CONDITIONAL(BUILD_X11, test `$PKG_CONFIG --variable=target gtk+-2.0` = "x11")
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
then you should now use the M4 macro provided by GTK+ itself:
|
|
|
|
|
<informalexample><programlisting>
|
2011-02-17 09:33:07 +00:00
|
|
|
|
GTK_CHECK_BACKEND([x11], [3.0.2], [have_x11=yes], [have_x11=no])
|
2011-02-16 15:53:20 +00:00
|
|
|
|
AM_CONDITIONAL(BUILD_x11, [test "x$have_x11" = "xyes"])
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
</para>
|
2011-01-14 04:40:47 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2011-02-05 06:56:19 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>GtkPlug and GtkSocket</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The #GtkPlug and #GtkSocket widgets are now X11-specific, and you
|
|
|
|
|
have to include the <filename><gtk/gtkx.h></filename> header
|
|
|
|
|
to use them. The previous section about proper handling of
|
|
|
|
|
backend-specific code applies, if you care about other backends.
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-09-16 14:49:56 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>The GtkWidget::draw signal</title>
|
|
|
|
|
<para>
|
|
|
|
|
The GtkWidget #GtkWidget::expose-event signal has been replaced by
|
|
|
|
|
a new #GtkWidget::draw signal, which takes a #cairo_t instead of
|
|
|
|
|
an expose event. The cairo context is being set up so that the origin
|
|
|
|
|
at (0, 0) coincides with the upper left corner of the widget, and
|
2010-09-24 22:59:24 +00:00
|
|
|
|
is properly clipped.
|
|
|
|
|
</para>
|
|
|
|
|
<note><para>In other words, the cairo context of the draw signal is set
|
|
|
|
|
up in 'widget coordinates', which is different from traditional expose
|
|
|
|
|
event handlers, which always assume 'window coordinates'.
|
|
|
|
|
</para></note>
|
|
|
|
|
<para>
|
|
|
|
|
The widget is expected to draw itself with its allocated size, which
|
|
|
|
|
is available via the new gtk_widget_get_allocated_width() and
|
|
|
|
|
gtk_widget_get_allocated_height() functions. It is not necessary to
|
2014-01-21 22:47:24 +00:00
|
|
|
|
check for gtk_widget_is_drawable(), since GTK+ already does this check
|
2011-02-18 22:17:04 +00:00
|
|
|
|
before emitting the #GtkWidget::draw signal.
|
2010-09-24 22:59:24 +00:00
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
There are some special considerations for widgets with multiple windows.
|
|
|
|
|
Expose events are window-specific, and widgets with multiple windows
|
|
|
|
|
could expect to get an expose event for each window that needs to be
|
|
|
|
|
redrawn. Therefore, multi-window expose event handlers typically look
|
|
|
|
|
like this:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
if (event->window == widget->window1)
|
|
|
|
|
{
|
|
|
|
|
/* ... draw window1 ... */
|
|
|
|
|
}
|
|
|
|
|
else if (event->window == widget->window2)
|
|
|
|
|
{
|
|
|
|
|
/* ... draw window2 ... */
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
</programlisting></informalexample>
|
2011-02-18 22:17:04 +00:00
|
|
|
|
In contrast, the #GtkWidget::draw signal handler may have to draw multiple
|
2010-09-24 22:59:24 +00:00
|
|
|
|
windows in one call. GTK+ has a convenience function
|
|
|
|
|
gtk_cairo_should_draw_window() that can be used to find out if
|
|
|
|
|
a window needs to be drawn. With that, the example above would look
|
|
|
|
|
like this (note that the 'else' is gone):
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
if (gtk_cairo_should_draw_window (cr, widget->window1)
|
|
|
|
|
{
|
|
|
|
|
/* ... draw window1 ... */
|
|
|
|
|
}
|
|
|
|
|
if (gtk_cairo_should_draw_window (cr, widget->window2)
|
|
|
|
|
{
|
|
|
|
|
/* ... draw window2 ... */
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
Another convenience function that can help when implementing
|
|
|
|
|
::draw for multi-window widgets is gtk_cairo_transform_to_window(),
|
|
|
|
|
which transforms a cairo context from widget-relative coordinates
|
2012-05-26 17:45:06 +00:00
|
|
|
|
to window-relative coordinates. You may want to use cairo_save() and
|
|
|
|
|
cairo_restore() when modifying the cairo context in your draw function.
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
All GtkStyle drawing functions (gtk_paint_box(), etc) have been changed
|
|
|
|
|
to take a #cairo_t instead of a window and a clip area. ::draw
|
|
|
|
|
implementations will usually just use the cairo context that has been
|
|
|
|
|
passed in for this.
|
|
|
|
|
</para>
|
2010-09-25 00:02:01 +00:00
|
|
|
|
<example><title>A simple ::draw function</title>
|
|
|
|
|
<programlisting>
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_arrow_draw (GtkWidget *widget,
|
|
|
|
|
cairo_t *cr)
|
|
|
|
|
{
|
2011-02-19 18:47:43 +00:00
|
|
|
|
GtkStyleContext *context;
|
2010-09-25 00:02:01 +00:00
|
|
|
|
gint x, y;
|
|
|
|
|
gint width, height;
|
|
|
|
|
gint extent;
|
|
|
|
|
|
2011-02-19 18:47:43 +00:00
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
|
|
|
|
2010-09-25 00:02:01 +00:00
|
|
|
|
width = gtk_widget_get_allocated_width (widget);
|
|
|
|
|
height = gtk_widget_get_allocated_height (widget);
|
|
|
|
|
|
|
|
|
|
extent = MIN (width - 2 * PAD, height - 2 * PAD);
|
|
|
|
|
x = PAD;
|
|
|
|
|
y = PAD;
|
|
|
|
|
|
2011-02-19 18:47:43 +00:00
|
|
|
|
gtk_render_arrow (context, rc, G_PI / 2, x, y, extent);
|
2010-09-25 00:02:01 +00:00
|
|
|
|
}
|
|
|
|
|
</programlisting>
|
|
|
|
|
</example>
|
2010-09-16 14:49:56 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2010-09-02 04:05:32 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>GtkProgressBar orientation</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
In GTK+ 2.x, #GtkProgressBar and #GtkCellRendererProgress were using the
|
|
|
|
|
GtkProgressBarOrientation enumeration to specify their orientation and
|
|
|
|
|
direction. In GTK+ 3, both the widget and the cell renderer implement
|
|
|
|
|
#GtkOrientable, and have an additional 'inverted' property to determine
|
|
|
|
|
their direction. Therefore, a call to gtk_progress_bar_set_orientation()
|
|
|
|
|
needs to be replaced by a pair of calls to
|
|
|
|
|
gtk_orientable_set_orientation() and gtk_progress_bar_set_inverted().
|
|
|
|
|
The following values correspond:
|
|
|
|
|
<table>
|
|
|
|
|
<tgroup cols="3">
|
2010-09-02 11:59:03 +00:00
|
|
|
|
<colspec colname="1"/>
|
|
|
|
|
<colspec colname="2"/>
|
|
|
|
|
<colspec colname="3"/>
|
2010-09-02 04:05:32 +00:00
|
|
|
|
<thead>
|
2010-09-02 11:59:03 +00:00
|
|
|
|
<row><entry>GTK+ 2.x</entry><entry namest="2" nameend="3">GTK+ 3</entry></row>
|
2010-09-02 04:05:32 +00:00
|
|
|
|
<row><entry>GtkProgressBarOrientation</entry><entry>GtkOrientation</entry><entry>inverted</entry></row>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<row><entry>GTK_PROGRESS_LEFT_TO_RIGHT</entry><entry>GTK_ORIENTATION_HORIZONTAL</entry><entry>FALSE</entry></row>
|
|
|
|
|
<row><entry>GTK_PROGRESS_RIGHT_TO_LEFT</entry><entry>GTK_ORIENTATION_HORIZONTAL</entry><entry>TRUE</entry></row>
|
|
|
|
|
<row><entry>GTK_PROGRESS_TOP_TO_BOTTOM</entry><entry>GTK_ORIENTATION_VERTICAL</entry><entry>FALSE</entry></row>
|
|
|
|
|
<row><entry>GTK_PROGRESS_BOTTOM_TO_TOP</entry><entry>GTK_ORIENTATION_VERTICAL</entry><entry>TRUE</entry></row>
|
|
|
|
|
</tbody>
|
|
|
|
|
</tgroup>
|
|
|
|
|
</table>
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-09-25 15:18:28 +00:00
|
|
|
|
<section>
|
2011-01-30 03:52:02 +00:00
|
|
|
|
<title>Check your expand and fill flags</title>
|
2010-10-30 02:48:26 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The behaviour of expanding widgets has changed slightly in GTK+ 3,
|
|
|
|
|
compared to GTK+ 2.x. It is now 'inherited', i.e. a container that
|
|
|
|
|
has an expanding child is considered expanding itself. This is often
|
|
|
|
|
the desired behaviour. In places where you don't want this to happen,
|
|
|
|
|
setting the container explicity as not expanding will stop the
|
|
|
|
|
expand flag of the child from being inherited. See
|
|
|
|
|
gtk_widget_set_hexpand() and gtk_widget_set_vexpand().
|
|
|
|
|
</para>
|
2011-01-30 03:52:02 +00:00
|
|
|
|
<para>
|
|
|
|
|
If you experience sizing problems with widgets in ported code,
|
2014-01-21 22:48:53 +00:00
|
|
|
|
carefully check the #GtkBox expand and #GtkBox fill child properties of your
|
2011-01-30 03:52:02 +00:00
|
|
|
|
boxes.
|
|
|
|
|
</para>
|
2010-10-30 02:48:26 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<title>Scrolling changes</title>
|
2010-09-25 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
2010-09-27 00:42:07 +00:00
|
|
|
|
The default values for the #GtkScrolledWindow:hscrollbar-policy and
|
|
|
|
|
#GtkScrolledWindow:vscrollbar-policy properties have been changed from
|
|
|
|
|
'never' to 'automatic'. If your application was relying on the default
|
|
|
|
|
value, you will have explicitly set it explicitly.
|
|
|
|
|
</para>
|
2010-10-30 02:48:26 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The ::set-scroll-adjustments signal on GtkWidget has been replaced
|
|
|
|
|
by the #GtkScrollable interface which must be implemented by a widget
|
|
|
|
|
that wants to be placed in a #GtkScrolledWindow. Instead of emitting
|
|
|
|
|
::set-scroll-adjustments, the scrolled window simply sets the
|
2014-01-21 22:50:21 +00:00
|
|
|
|
#GtkScrollable:hadjustment and #GtkScrollable:vadjustment properties.
|
2010-10-30 02:48:26 +00:00
|
|
|
|
</para>
|
2010-09-25 15:18:28 +00:00
|
|
|
|
</section>
|
2010-09-27 02:29:33 +00:00
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<title>GtkObject is gone</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
GtkObject has been removed in GTK+ 3. Its remaining functionality,
|
|
|
|
|
the ::destroy signal, has been moved to GtkWidget. If you have non-widget
|
|
|
|
|
classes that are directly derived from GtkObject, you have to make
|
|
|
|
|
them derive from #GInitiallyUnowned (or, if you don't need the floating
|
|
|
|
|
functionality, #GObject). If you have widgets that override the
|
2011-02-19 18:34:42 +00:00
|
|
|
|
destroy class handler, you have to adjust your class_init function,
|
2010-09-27 02:29:33 +00:00
|
|
|
|
since destroy is now a member of GtkWidgetClass:
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
|
|
|
|
|
|
|
|
|
|
object_class->destroy = my_destroy;
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
becomes
|
|
|
|
|
<informalexample><programlisting>
|
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
|
|
|
|
|
|
|
|
|
widget_class->destroy = my_destroy;
|
|
|
|
|
</programlisting></informalexample>
|
|
|
|
|
In the unlikely case that you have a non-widget class that is derived
|
|
|
|
|
from GtkObject and makes use of the destroy functionality, you have
|
|
|
|
|
to implement ::destroy yourself.
|
|
|
|
|
</para>
|
2013-01-27 22:22:53 +00:00
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
If your program used functions like gtk_object_get or gtk_object_set,
|
|
|
|
|
these can be replaced directly with g_object_get or g_object_set. In
|
|
|
|
|
fact, most every gtk_object_* function can be replaced with the
|
|
|
|
|
corresponding g_object_ function, even in GTK+ 2 code. The one exception
|
|
|
|
|
to this rule is gtk_object_destroy, which can be replaced with
|
|
|
|
|
gtk_widget_destroy, again in both GTK+ 2 and GTK+ 3.
|
|
|
|
|
</para>
|
2010-09-27 02:29:33 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2011-01-28 15:47:36 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>GtkEntryCompletion signal parameters</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The #GtkEntryCompletion::match-selected and
|
|
|
|
|
#GtkEntryCompletion::cursor-on-match signals were erroneously
|
|
|
|
|
given the internal filter model instead of the users model.
|
|
|
|
|
This oversight has been fixed in GTK+ 3; if you have handlers
|
|
|
|
|
for these signals, they will likely need slight adjustments.
|
2011-01-29 18:40:19 +00:00
|
|
|
|
</para>
|
2011-01-28 15:47:36 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2010-10-08 06:18:15 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Resize grips</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
The resize grip functionality has been moved from #GtkStatusbar
|
|
|
|
|
to #GtkWindow. Any window can now have resize grips, regardless whether
|
|
|
|
|
it has a statusbar or not. The functions
|
|
|
|
|
gtk_statusbar_set_has_resize_grip() and gtk_statusbar_get_has_resize_grip()
|
|
|
|
|
have disappeared, and instead there are now
|
|
|
|
|
gtk_window_set_has_resize_grip() and gtk_window_get_has_resize_grip().
|
2010-10-12 05:05:39 +00:00
|
|
|
|
</para>
|
2010-10-08 06:18:15 +00:00
|
|
|
|
</section>
|
|
|
|
|
|
2010-08-11 01:21:01 +00:00
|
|
|
|
<section>
|
|
|
|
|
<title>Prevent mixed linkage</title>
|
|
|
|
|
<para>
|
|
|
|
|
Linking against GTK+ 2.x and GTK+ 3 in the same process is problematic
|
|
|
|
|
and can lead to hard-to-diagnose crashes. The gtk_init() function in
|
|
|
|
|
both GTK+ 2.22 and in GTK+ 3 tries to detect this situation and abort
|
|
|
|
|
with a diagnostic message, but this check is not 100% reliable (e.g. if
|
|
|
|
|
the problematic linking happens only in loadable modules).
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
Direct linking of your application against both versions of GTK+ is
|
|
|
|
|
easy to avoid; the problem gets harder when your application is using
|
|
|
|
|
libraries that are themselves linked against some version of GTK+.
|
|
|
|
|
In that case, you have to verify that you are using a version of the
|
|
|
|
|
library that is linked against GTK+ 3.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
If you are using packages provided by a distributor, it is likely that
|
|
|
|
|
parallel installable versions of the library exist for GTK+ 2.x and
|
|
|
|
|
GTK+ 3, e.g for vte, check for vte3; for webkitgtk look for webkitgtk3,
|
|
|
|
|
and so on.
|
|
|
|
|
</para>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<title>Install GTK+ modules in the right place</title>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
<para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
Some software packages install loadable GTK+ modules such as theme engines,
|
|
|
|
|
gdk-pixbuf loaders or input methods. Since GTK+ 3 is parallel-installable
|
|
|
|
|
with GTK+ 2.x, the two GTK+ versions have separate locations for their
|
|
|
|
|
loadable modules. The location for GTK+ 2.x is
|
|
|
|
|
<filename><replaceable>libdir</replaceable>/gtk-2.0</filename>
|
|
|
|
|
(and its subdirectories), for GTK+ 3 the location is
|
|
|
|
|
<filename><replaceable>libdir</replaceable>/gtk-3.0</filename>
|
2010-05-28 16:18:45 +00:00
|
|
|
|
(and its subdirectories).
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
For some kinds of modules, namely input methods and pixbuf loaders,
|
2010-05-28 16:18:45 +00:00
|
|
|
|
GTK+ keeps a cache file with extra information about the modules.
|
2010-06-03 05:09:53 +00:00
|
|
|
|
For GTK+ 2.x, these cache files are located in
|
|
|
|
|
<filename><replaceable>sysconfdir</replaceable>/gtk-2.0</filename>.
|
|
|
|
|
For GTK+ 3, they have been moved to
|
|
|
|
|
<filename><replaceable>libdir</replaceable>/gtk-3.0/3.0.0/</filename>.
|
2010-05-28 16:18:45 +00:00
|
|
|
|
The commands that create these cache files have been renamed with a -3
|
|
|
|
|
suffix to make them parallel-installable.
|
|
|
|
|
</para>
|
|
|
|
|
<para>
|
|
|
|
|
Note that GTK+ modules often link against libgtk, libgdk-pixbuf, etc.
|
|
|
|
|
If that is the case for your module, you have to be careful to link the
|
|
|
|
|
GTK+ 2.x version of your module against the 2.x version of the libraries,
|
|
|
|
|
and the GTK+ 3 version against hte 3.x versions. Loading a module linked
|
|
|
|
|
against libgtk 2.x into an application using GTK+ 3 will lead to
|
|
|
|
|
unhappiness and must be avoided.
|
|
|
|
|
</para>
|
2010-06-03 05:09:53 +00:00
|
|
|
|
</section>
|
2010-08-11 01:21:01 +00:00
|
|
|
|
|
|
|
|
|
</section>
|
|
|
|
|
|
2010-05-28 16:18:45 +00:00
|
|
|
|
</chapter>
|