mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
621639b754
Mon Jul 31 13:53:16 BST 2000 Tony Gale <gale@gtk.org> * docs/gtkfaq.sgml docs/gtk-faq.sgml: s/gtk_main_iteration/g_main_iteration/ Did this already in change: Mon Nov 15 17:17:51 GMT 1999 Tony Gale <gale@gtk.org> don't know how it got reverted.
3578 lines
107 KiB
Plaintext
3578 lines
107 KiB
Plaintext
<!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" []>
|
|
<book>
|
|
|
|
<bookinfo>
|
|
<date>June 28th 2000</date>
|
|
<title>GTK+ FAQ</title>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Tony</firstname>
|
|
<surname>Gale</surname>
|
|
</author>
|
|
<author>
|
|
<firstname>Shawn</firstname>
|
|
<surname>Amundson</surname>
|
|
</author>
|
|
<author>
|
|
<firstname>Emmanuel</firstname>
|
|
<surname>Deloget</surname>
|
|
</author>
|
|
</authorgroup>
|
|
<abstract>
|
|
<para> This document is intended to answer questions that are
|
|
likely to be frequently asked by programmers using GTK+ or
|
|
people who are just looking at using GTK+. </para>
|
|
</abstract>
|
|
</bookinfo>
|
|
|
|
<toc></toc>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<chapter>
|
|
<title>GTK+ FAQ</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect1>
|
|
<title>General Information</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Before anything else: the greetings</title>
|
|
<para>The FAQ authors want to thank:</para>
|
|
<itemizedlist spacing=Compact>
|
|
<listitem>
|
|
<simpara>Havoc Pennington</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Erik Mouw</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Owen Taylor</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Tim Janik</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Thomas Mailund Jensen</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Joe Pfeiffer</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Andy Kahn</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Federico Mena Quntero</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Damon Chaplin</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>and all the members of the GTK+ lists</simpara>
|
|
</listitem></itemizedlist>
|
|
<para> If we forgot you, please email us! Thanks again (I know,
|
|
it's really short :) </para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Authors</title>
|
|
|
|
<para>The original authors of GTK+ were:</para>
|
|
|
|
<itemizedlist spacing=Compact>
|
|
<listitem>
|
|
<simpara>Peter Mattis</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Spencer Kimball</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>Josh MacDonald</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Since then, much has been added by others. Please see the
|
|
AUTHORS file in the distribution for the GTK+ Team.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What is GTK+?</title>
|
|
|
|
<para>GTK+ is a small and efficient widget set designed with
|
|
the general look and feel of Motif. In reality, it looks much
|
|
better than Motif. It contains common widgets and some more
|
|
complex widgets such as a file selection, and color selection
|
|
widgets.</para>
|
|
|
|
<para>GTK+ provides some unique features. (At least, I know of
|
|
no other widget library which provides them). For example, a
|
|
button does not contain a label, it contains a child widget,
|
|
which in most instances will be a label. However, the child
|
|
widget can also be a pixmap, image or any combination possible
|
|
the programmer desires. This flexibility is adhered to
|
|
throughout the library.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What is the + in GTK+?</title>
|
|
|
|
<para>Peter Mattis informed the gtk mailing list that:</para>
|
|
|
|
<para><quote>I originally wrote gtk which included the three
|
|
libraries, libglib, libgdk and libgtk. It featured a flat
|
|
widget hierarchy. That is, you couldn't derive a new widget
|
|
from an existing one. And it contained a more standard
|
|
callback mechanism instead of the signal mechanism now present
|
|
in gtk+. The + was added to distinguish between the original
|
|
version of gtk and the new version. You can think of it as
|
|
being an enhancement to the original gtk that adds object
|
|
oriented features.</quote></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Does the G in GTK+, GDK and GLib stand for?</title>
|
|
|
|
<para>GTK+ == Gimp Toolkit</para>
|
|
<para>GDK == GTK+ Drawing Kit</para>
|
|
<para>GLib == G Libray</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Where is the documentation for GTK+?</title>
|
|
|
|
<para>In the GTK+ distribution's doc/ directory you will find
|
|
the reference material for both GTK and GDK, this FAQ and the
|
|
GTK Tutorial.</para>
|
|
|
|
<para>In addition, you can find links to HTML versions of
|
|
these documents by going to <ulink url="http://www.gtk.org/">
|
|
http://www.gtk.org/</ulink>. A
|
|
packaged version of the GTK Tutorial, with SGML, HTML,
|
|
Postscript, DVI and text versions can be found in <ulink
|
|
url="ftp://ftp.gtk.org/pub/gtk/tutorial">
|
|
ftp://ftp.gtk.org/pub/gtk/tutorial
|
|
</ulink></para>
|
|
|
|
<para>There are now a couple of books available that deal with
|
|
programming GTK+, GDK and GNOME:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>Eric Harlows book entitled "Developing
|
|
Linux Applications with GTK+ and GDK". The ISBN is
|
|
0-7357-0021-4</simpara>
|
|
</listitem>
|
|
<listitem><simpara>The example code from Eric's book is
|
|
available on-line at <ulink
|
|
url="http://www.bcpl.net/~eharlow/book">
|
|
http://www.bcpl.net/~eharlow/book</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara>Havoc Pennington has released a book called
|
|
"GTK+/GNOME Application Development". The ISBN is
|
|
0-7357-0078-8</simpara>
|
|
<simpara>The free version of the book lives here: <ulink
|
|
url="http://developer.gnome.org/doc/GGAD/">
|
|
http://developer.gnome.org/doc/GGAD/
|
|
</ulink></simpara>
|
|
<simpara>And Havoc maintains information about it and
|
|
errata here: <ulink
|
|
url="http://pobox.com/~hp/gnome-app-devel.html">
|
|
http://pobox.com/~hp/gnome-app-devel.html
|
|
</ulink></simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Is there a mailing list (or mailing list archive) for
|
|
GTK+?</title>
|
|
|
|
<para>Information on mailing lists relating to GTK+ can be
|
|
found at: <ulink
|
|
url="http://www.gtk.org/mailinglists.html">
|
|
http://www.gtk.org/mailinglists.html
|
|
</ulink></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How to get help with GTK+</title>
|
|
|
|
<para>First, make sure your question isn't answered in the
|
|
documentation, this FAQ or the tutorial. Done that? You're
|
|
sure you've done that, right? In that case, the best place to
|
|
post questions is to the GTK+ mailing list.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How to report bugs in GTK+</title>
|
|
|
|
<para>Bugs should be reported to the GNOME bug tracking system
|
|
(<ulink
|
|
url="http://bugs.gnome.org">http://bugs.gnome.org</ulink>). To
|
|
report a problem about GTK+, send mail to submit@bugs.gnome.org.</para>
|
|
|
|
<para>The subject of the mail should describe your problem. In
|
|
the body of the mail, you should first include a
|
|
"pseudo-header" that gives the package and version
|
|
number. This should be separated by a blank line from the
|
|
actual headers.</para>
|
|
|
|
<para><literallayout>
|
|
<literal>Package: gtk+</literal>
|
|
<literal>Version: 1.2.0</literal>
|
|
</literallayout></para>
|
|
|
|
<para>Substitute 1.2.0 with the version of GTK+ that you have
|
|
installed.</para>
|
|
|
|
<para>Then describe the bug. Include:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara> Information about your system. For
|
|
instance:</simpara>
|
|
<itemizedlist spacing=compact>
|
|
<listitem><simpara> What operating system and version</simpara>
|
|
</listitem>
|
|
<listitem><simpara> What version of X</simpara>
|
|
</listitem>
|
|
<listitem><simpara> For Linux, what version of the C library</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>And anything else you think is relevant.</para>
|
|
</listitem>
|
|
<listitem><simpara> How to reproduce the bug.</simpara>
|
|
<simpara>If you can reproduce it with the testgtk program
|
|
that is built in the gtk/ subdirectory, that will be most
|
|
convenient. Otherwise, please include a short test program
|
|
that exhibits the behavior. As a last resort, you can also
|
|
provide a pointer to a larger piece of software that can
|
|
be downloaded.</simpara>
|
|
<simpara>(Bugs that can be reproduced within the GIMP are
|
|
almost as good as bugs that can be reproduced in
|
|
testgtk. If you are reporting a bug found with the GIMP,
|
|
please include the version number of the GIMP you are
|
|
using)</simpara>
|
|
</listitem>
|
|
<listitem><simpara> If the bug was a crash, the exact text that was
|
|
printed out when the crash occured.</simpara>
|
|
</listitem>
|
|
<listitem><simpara> Further information such as stack traces
|
|
may be useful, but are not necessary. If you do send a stack trace,
|
|
and the error is an X error, it will be more useful if the stacktrace is
|
|
produced running the test program with the <literal>--sync</literal>
|
|
command line option.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Is there a Windows version of GTK+?</title>
|
|
|
|
<para>There is an on going port of GTK+ to the Windows
|
|
platform which is making impressive progress.</para>
|
|
|
|
<para>See <ulink
|
|
url="http://www.iki.fi/tml/gimp/win32">
|
|
http://www.iki.fi/tml/gimp/win32</ulink>
|
|
for more information.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What applications have been written with GTK+?</title>
|
|
|
|
<para>A list of some GTK+ based application can be found on
|
|
the GTK+ web server at <ulink
|
|
url="http://www.gtk.org/apps/">http://www.gtk.org/apps/</ulink>
|
|
and contains more than 350 applications.</para>
|
|
|
|
<para>Failing that, look for a project to work on for the
|
|
GNOME project, <ulink
|
|
url="http://www.gnome.org/">http://www.gnome.org/</ulink>
|
|
Write a game. Write something that is useful.</para>
|
|
<para>Some of these are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara> GIMP (<ulink
|
|
url="http://www.gimp.org/">http://www.gimp.org/</ulink>), an
|
|
image manipulation program</simpara>
|
|
</listitem>
|
|
<listitem><simpara> AbiWord (<ulink
|
|
url="http://www.abisource.com/">http://www.abisource.com/</ulink>),
|
|
a professional word processor</simpara>
|
|
</listitem>
|
|
<listitem><simpara> Gzilla (<ulink
|
|
url="http://www.levien.com/gzilla/">http://www.levien.com/gzilla/</ulink>),
|
|
a web browser</simpara>
|
|
</listitem>
|
|
<listitem><simpara> XQF (<ulink
|
|
url="http://www.botik.ru/~roma/quake/">
|
|
http://www.botik.ru/~roma/quake/</ulink>),
|
|
a QuakeWorld/Quake2 server browser and launcher</simpara>
|
|
</listitem>
|
|
<listitem><simpara> GDK Imlib (<ulink
|
|
url="http://www.rasterman.com/imlib.html">
|
|
http://www.rasterman.com/imlib.html</ulink>),
|
|
a fast image loading and manipulation library for GDK</simpara>
|
|
</listitem>
|
|
<listitem><simpara> Glade (<ulink
|
|
url="http://glade.pn.org/">http://glade.pn.org/</ulink>), a
|
|
GTK+ based RAD tool which produces GTK+ applications</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I'm looking for an application to write in GTK+. How
|
|
about an IRC client?</title>
|
|
|
|
<para>Ask on gtk-list for suggestions. There are at least
|
|
three IRC clients already under development (probably more in fact. The
|
|
server at <ulink url="http://www.forcix.cx/irc-clients.html">
|
|
http://www.forcix.cx/irc-clients.html</ulink> list a bunch of
|
|
them).</para>
|
|
|
|
<itemizedlist spacing=compact>
|
|
<listitem><simpara> X-Chat.</simpara>
|
|
</listitem>
|
|
<listitem><simpara> girc. (Included with GNOME)</simpara>
|
|
</listitem>
|
|
<listitem><simpara> gsirc. (In the gnome CVS tree)</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>How to find, configure, install, and troubleshoot GTK+</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What do I need to run GTK+?</title>
|
|
|
|
<para>To compile GTK+, all you need is a C compiler (gcc) and
|
|
the X Window System and associated libraries on your system.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Where can I get GTK+?</title>
|
|
|
|
<para>The canonical site is <ulink
|
|
url="ftp://ftp.gtk.org/pub/gtk">ftp://ftp.gtk.org/pub/gtk</ulink>.</para>
|
|
|
|
<para>This site tends to get busy around the time of a new
|
|
GTK+ release so try and use one of the mirror sites that are
|
|
listed in <ulink
|
|
url="ftp://ftp.gtk.org/etc/mirrors">ftp://ftp.gtk.org/etc/mirrors
|
|
</ulink></para>
|
|
|
|
<para>Here's a few mirror sites to get you started:</para>
|
|
|
|
<itemizedlist spacing=compact>
|
|
<listitem><simpara> Africa -
|
|
<ulink url="ftp://ftp.is.co.za/applications/gimp">
|
|
ftp://ftp.is.co.za/applications/gimp</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> Australia -
|
|
<ulink
|
|
url="ftp://ftp.au.gimp.org/pub/gimp">
|
|
ftp://ftp.au.gimp.org/pub/gimp</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> Finland -
|
|
<ulink url="ftp://ftp.funet.fi/pub/sci/graphics/packages/gimp">
|
|
ftp://ftp.funet.fi/pub/sci/graphics/packages/gimp</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> Germany -
|
|
<ulink url="ftp://infosoc.uni-koeln.de/pub/ftp.gimp.org">
|
|
ftp://infosoc.uni-koeln.de/pub/ftp.gimp.org"</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> Japan -
|
|
<ulink url="ftp://SunSITE.sut.ac.jp/pub/archives/packages/gimp">
|
|
ftp://SunSITE.sut.ac.jp/pub/archives/packages/gimp</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> UK -
|
|
<ulink url="ftp://ftp.flirble.org/pub/X/gimp">
|
|
ftp://ftp.flirble.org/pub/X/gimp</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara> US -
|
|
<ulink url="ftp://ftp.insync.net/pub/mirrors/ftp.gimp.org">
|
|
ftp://ftp.insync.net/pub/mirrors/ftp.gimp.org</ulink></simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I configure/compile GTK+?</title>
|
|
|
|
<para>Generally, all you will need to do is issue the commands:</para>
|
|
|
|
<para><literallayout><literal>./configure</literal>
|
|
<literal>make</literal></literallayout></para>
|
|
|
|
<para>in the gtk+-version/ directory.</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>When compiling GTK+ I get an error like: <literal>make:
|
|
file `Makefile' line 456: Syntax error</literal></title>
|
|
|
|
<para>Make sure that you are using GNU make
|
|
(use <literal>make -v</literal>
|
|
to check). There are many weird and wonderful versions of make
|
|
out there, and not all of them handle the automatically
|
|
generated Makefiles.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I've compiled and installed GTK+, but I can't get any
|
|
programs to link with it!</title>
|
|
|
|
<para>This problem is most often encountered when the GTK+
|
|
libraries can't be found or are the wrong version. Generally,
|
|
the compiler will complain about an 'unresolved symbol'.
|
|
There are two things you need to check:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>Make sure that the libraries can be
|
|
found. You want to edit <filename>/etc/ld.so.conf</filename> to
|
|
include the directories which contain the GTK libraries,
|
|
so it looks something like:</simpara>
|
|
|
|
<para><literallayout><literal>/usr/X11R6/lib</literal>
|
|
<literal>/usr/local/lib</literal></literallayout></para>
|
|
|
|
<para>Then you need to run /sbin/ldconfig as root. You can
|
|
find what directory GTK is in using</para>
|
|
|
|
<para><literallayout><literal>gtk-config --libs</literal>
|
|
</literallayout></para>
|
|
|
|
<para>If your system doesn't use ld.so to find libraries
|
|
(such as Solaris), then you will have to use the LD_LIBRARY_PATH
|
|
environment variable (or compile the path into your program, which I'm
|
|
not going to cover here). So, with a Bourne type shell you can do (if
|
|
your GTK libraries are in /usr/local/lib):</para>
|
|
|
|
<para><literallayout>
|
|
<literal>export LD_LIBRARY_PATH=/usr/local/lib</literal>
|
|
</literallayout></para>
|
|
|
|
<para>and in a csh, you can do:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>setenv LD_LIBRARY_PATH /usr/local/lib</literal>
|
|
</literallayout></para>
|
|
|
|
</listitem>
|
|
<listitem><simpara>Make sure the linker is finding the
|
|
correct set of libraries. If you have a Linux distribution that
|
|
installs GTK+ (e.g. RedHat 5.0) then this older version may be
|
|
used. Now (assuming you have a RedHat system), issue the
|
|
command</simpara>
|
|
|
|
<para><literallayout>
|
|
<literal>rpm -e gtk gtk-devel</literal>
|
|
</literallayout></para>
|
|
|
|
<para>You may also want to remove the packages that depend
|
|
on gtk (rpm will tell you which ones they are). If you don't have a
|
|
RedHat Linux system, check to make sure that neither
|
|
<filename>/usr/lib</filename> or <filename>/usr/local/lib</filename>
|
|
contain any of the libraries libgtk, libgdk, libglib, or libgck. If
|
|
they do exist, remove them (and any gtk include files, such as
|
|
<filename>/usr/include/gtk</filename> and
|
|
<filename>/usr/include/gdk</filename>) and reinstall gtk+.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>When compiling programs with GTK+, I get compiler error
|
|
messages about not being able to find
|
|
<literal>glibconfig.h</literal>.</title>
|
|
|
|
<para>The header file "glibconfig.h" was moved to the
|
|
directory $exec_prefix/lib/glib/include/. $exec_prefix is the
|
|
directory that was specified by giving the --exec-prefix flags
|
|
to ./configure when compiling GTK+. It defaults to $prefix,
|
|
(specified with --prefix), which in turn defaults to /usr/local/.</para>
|
|
|
|
<para>This was done because "glibconfig.h" includes
|
|
architecture dependent information, and the rest of the
|
|
include files are put in $prefix/include, which can be shared
|
|
between different architectures.</para>
|
|
|
|
<para>GTK+ includes a shell script, <literal>/gtk-config/</literal>,
|
|
that makes it easy to find out the correct include paths. The GTK+
|
|
Tutorial includes an example of using <literal>/gtk-config/</literal>
|
|
for simple compilation from the command line. For information about more
|
|
complicated configuration, see the file docs/gtk-config.txt in the GTK+
|
|
distribution.</para>
|
|
|
|
<para>If you are trying to compile an old program, you may be
|
|
able to work around the problem by configuring it with a
|
|
command line like:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>setenv CPPFLAGS "-I/usr/local/include/glib/include"</literal>
|
|
<literal>./configure</literal>
|
|
</literallayout></para>
|
|
|
|
<para>(Substitute the appropriate value of $exec_prefix for
|
|
/usr/local.)</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>When installing a GTK+ application, configure reports
|
|
that it can't find GTK.</title>
|
|
|
|
<para>There are several common reasons for this:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>You have an old version of GTK installed
|
|
somewhere. RedHat 5.0, for example, installs an older copy of GTK that
|
|
may not work with the latest applications. You should remove this old
|
|
copy, but note that in the case of RedHat 5.0 this will
|
|
break the <literal>control-panel</literal> applications.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara><literal>gtk-config</literal> (or another
|
|
component of GTK) isn't in your path, or there is an old
|
|
version on your system. Type:</simpara>
|
|
|
|
<para><literallayout>
|
|
<literal>gtk-config --version</literal>
|
|
</literallayout></para>
|
|
|
|
<para>to check for both of these. If it returns a value
|
|
different from what you expect, then you have an old
|
|
version of GTK on your system.</para>
|
|
</listitem>
|
|
|
|
<listitem><simpara>The ./configure script can't find the GTK
|
|
libraries. As ./configure compiles various test programs, it needs to be
|
|
able to find the GTK libraries. See the question above
|
|
for help on this. </simpara></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>If none of the above help, then have a look in
|
|
config.log, which is generated by ./configure as it runs. At the
|
|
bottom will be the last action it took before failing. If it is a
|
|
section of source code, copy the source code to a file and compile it
|
|
with the line just above it in config.log. If the compilation is
|
|
successful, try executing it.</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>Development of GTK+</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Whats this CVS thing that everyone keeps talking about,
|
|
and how do I access it?</title>
|
|
|
|
<para>CVS is the Concurent Version System and is a very
|
|
popular means of version control for software projects. It is
|
|
designed to allow multiple authors to be able to
|
|
simultanously operate on the same source tree. This source
|
|
tree is centrally maintained, but each developer has a local
|
|
mirror of this repository that they make there changes to.</para>
|
|
|
|
<para>The GTK+ developers use a CVS repository to store the
|
|
master copy of the current development version of GTK+. As
|
|
such, people wishing to contribute patches to GTK+ should
|
|
generate them against the CVS version. Normal people should
|
|
use the packaged releases.</para>
|
|
|
|
<para>The CVS toolset is available as RPM packages from the
|
|
usual RedHat sites. The latest version is available at <ulink
|
|
url="http://download.cyclic.com/pub/">http://download.cyclic.com/pub/
|
|
</ulink></para>
|
|
|
|
<para>Anyone can download the latest CVS version of GTK+ by
|
|
using anonymous access using the following steps:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara> In a bourne shell descendant (e.g. bash) type:</simpara>
|
|
<para><literallayout>
|
|
<literal>CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome'</literal>
|
|
<literal>export CVSROOT</literal>
|
|
</literallayout></para>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Next, the first time the source tree is
|
|
checked out, a cvs login is needed. </simpara>
|
|
<para><literallayout>
|
|
<literal>cvs login</literal>
|
|
</literallayout></para>
|
|
<para>This will ask you for a password. There is no
|
|
password for cvs.gimp.org, so just enter a carriage return.</para>
|
|
</listitem>
|
|
|
|
<listitem><simpara>To get the tree and place it in a subdir of your
|
|
current working directory, issue the command:</simpara>
|
|
<para><literallayout>
|
|
<literal>cvs -z3 get gtk+</literal>
|
|
</literallayout></para>
|
|
<para>Note that with the GTK+ 1.1 tree, glib has been moved to
|
|
a separate CVS module, so if you don't have glib installed you will
|
|
need to get that as well:</para>
|
|
<para><literallayout>
|
|
<literal>cvs -z3 get glib</literal>
|
|
</literallayout></para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How can I contribute to GTK+?</title>
|
|
|
|
<para>It's simple. If something doesn't work like you think it
|
|
should in a program, check the documentation to make sure
|
|
you're not missing something. If it is a true bug or missing
|
|
feature, track it down in the GTK+ source, change it, and
|
|
then generate a patch in the form of a 'context diff'. This
|
|
can be done using a command such as <literal>diff -ru
|
|
<oldfile> <newfile></literal>. Then upload the patchfile
|
|
to:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>ftp://ftp.gtk.org/incoming</literal>
|
|
</literallayout></para>
|
|
|
|
<para>along with a README file. Make sure you follow the
|
|
naming conventions or your patch will just be deleted! The
|
|
filenames should be of this form:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>gtk<username>-<date yymmdd-n>.patch.gz</literal>
|
|
<literal>gtk-<username>-<date yymmdd-n>.patch.README</literal>
|
|
</literallayout></para>
|
|
|
|
<para>The "n" in the date indicates a unique number (starting
|
|
from 0) of patches you uploaded that day. It should be 0,
|
|
unless you upload more than one patch in the same day.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>gtk-gale-982701-0.patch.gz</literal>
|
|
<literal>gtk-gale-982701-0.patch.README</literal>
|
|
</literallayout></para>
|
|
|
|
<para>Once you upload <emphasis>anything</emphasis>, send the README to
|
|
ftp-admin@gtk.org</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I know if my patch got applied, and if not, why
|
|
not?</title>
|
|
|
|
<para>Uploaded patches will be moved to
|
|
<filename>ftp://ftp.gtk.org/pub/gtk/patches</filename> where one of the
|
|
GTK+ development team will pick them up. If applied, they will be moved
|
|
to <filename>/pub/gtk/patches/old</filename>.</para>
|
|
|
|
<para>Patches that aren't applied, for whatever reason, are
|
|
moved to <filename>/pub/gtk/patches/unapplied</filename> or
|
|
<filename>/pub/gtk/patches/outdated</filename>. At this point you can ask
|
|
on the <literal>gtk-list</literal> mailing list why your patch wasn't
|
|
applied. There are many possible reasons why patches may not
|
|
be applied, ranging from it doesn't apply cleanly, to it isn't
|
|
right. Don't be put off if your patch didn't make it first
|
|
time round.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What is the policy on incorporating new widgets into
|
|
the library?</title>
|
|
|
|
<para>This is up to the authors, so you will have to ask them
|
|
once you are done with your widget. As a general guideline,
|
|
widgets that are generally useful, work, and are not a
|
|
disgrace to the widget set will gladly be included.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Is anyone working on bindings for languages other than
|
|
C?</title>
|
|
|
|
<para>The GTK+ home page (<ulink
|
|
url="http://www.gtk.org/">http://www.gtk.org/</ulink>)
|
|
presents a list of GTK+ bindings.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>There are several C++ wrappers for GTK+.</simpara>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>the gtk-- package, which is a very small wrapper for
|
|
GTK+. You can find the home page at <ulink
|
|
url="http://www.cs.tut.fi/~p150650/gtk/gtk--.html">
|
|
http://www.cs.tut.fi/~p150650/gtk/gtk--.html</ulink>. The FTP site is
|
|
<ulink url="ftp://ftp.gtk.org/pub/gtk/gtk--">
|
|
ftp://ftp.gtk.org/pub/gtk/gtk--</ulink>.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>the VDK package, which was built as
|
|
the base package of a GTK+ application Borland-like
|
|
builder. The home page can be found at <ulink
|
|
url="http://www.guest.net/homepages/mmotta/VDKHome">
|
|
http://www.guest.net/homepages/mmotta/VDKHome</ulink>.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>The wxWindows/Gtk package, a free C++ library for
|
|
cross-platform GUI development. The home page of this package is
|
|
<ulink url="http://www.freiburg.linux.de/~wxxt/">
|
|
http://www.freiburg.linux.de/~wxxt/</ulink>.</simpara>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem><simpara>There are three known Objective-c
|
|
bindings currently in development:</simpara>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>The <ulink
|
|
url="http://www.gnome.org/">http://www.gnome.org/</ulink>
|
|
package of choice is objgtk. Objgtk is based on the Object class and
|
|
is maintained by <ulink url="mailto:sopwith@cuc.edu">Elliot
|
|
Lee</ulink>. Apparently, objgtk is being accepted as the `standard'
|
|
Objective-C binding for GTK+.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>If you are more inclined towards the
|
|
<ulink url="http://www.gnustep.org/">GNUstep project</ulink>,
|
|
you may want to check out GTKKit by
|
|
<ulink url="mailto:helge@mdlink.de">Helge Heß</ulink>.
|
|
The intention is to setup a GTK+ binding using the FoundationKit.
|
|
GTKKit includes nicities like writing a XML-type template file to
|
|
construct a GTK+ interface.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>The GToolKit package, which can be found at
|
|
<ulink url="ftp://ftp.gtk.org/pub/gtk/objc-gtoolkit/">
|
|
ftp://ftp.gtk.org/pub/gtk/objc-gtoolkit/</ulink>.</simpara>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Perl bindings <ulink
|
|
url="ftp://ftp.gtk.org/pub/gtk/perl">
|
|
ftp://ftp.gtk.org/pub/gtk/perl</ulink></simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Guile bindings. The home page is at
|
|
<ulink url="http://www.ping.de/sites/zagadka/guile-gtk">
|
|
http://www.ping.de/sites/zagadka/guile-gtk</ulink>.
|
|
By the way, Guile is the GNU Project's implemention of R4RS Scheme (the
|
|
standard). If you like Scheme, you may want to take a look at
|
|
this.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>David Monniaux reports:
|
|
<quote>I've started a gtk-O'Caml binding system.
|
|
The basics of the system, including callbacks, work fine.
|
|
|
|
The current development is in
|
|
<ulink url="http://www.ens-lyon.fr/~dmonniau/arcs">
|
|
http://www.ens-lyon.fr/~dmonniau/arcs</ulink>
|
|
</quote></simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Several python bindings have been done:</simpara>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>pygtk is at
|
|
<ulink url="http://www.daa.com.au/~james/pygtk">
|
|
http://www.daa.com.au/~james/pygtk</ulink> and
|
|
<ulink url="ftp://ftp.gtk.org/pub/gtk/python">
|
|
ftp://ftp.gtk.org/pub/gtk/python</ulink></simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>python-gtk is at
|
|
<ulink url="http://www.ucalgary.ca/~nascheme/python-gtk">
|
|
http://www.ucalgary.ca/~nascheme/python-gtk</ulink></simpara>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem><simpara>There's are a couple of OpenGL/Mesa
|
|
widgets available for GTK+. I suggest you start at
|
|
<ulink url="http://www.student.oulu.fi/~jlof/gtkglarea/index.html">
|
|
http://www.student.oulu.fi/~jlof/gtkglarea/index.html</ulink></simpara>
|
|
</listitem>
|
|
<listitem><simpara>Last, there are a lot of other language
|
|
bindings for languages such as Eiffel, TOM, Pascal, Pike, etc.</simpara>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>Development with GTK+: the begining</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I get started?</title>
|
|
|
|
<para>So, after you have installed GTK+ there are a couple of
|
|
things that can ease you into developing applications with
|
|
it. There is the GTK+ Tutorial <ulink
|
|
url="http://www.gtk.org/tutorial/">
|
|
http://www.gtk.org/tutorial/</ulink>, which is undergoing
|
|
development. This will introduce you to writing applications
|
|
using C.</para>
|
|
|
|
<para>The Tutorial doesn't (yet) contain information on all of
|
|
the widgets that are in GTK+. For example code on how to use
|
|
the basics of all the GTK+ widgets you should look at the file
|
|
gtk/testgtk.c (and associated source files) within the GTK+
|
|
distribution. Looking at these examples will give you a good
|
|
grounding on what the widgets can do.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I tried to compile a small <command>Hello World</command> of mine,
|
|
but it failed. Any clue?</title>
|
|
|
|
<para>Since you are good at coding, we will not deal with
|
|
compile time error here :)</para>
|
|
|
|
<para>The classic command line to compile a GTK+ based program is</para>
|
|
<para><literallayout>
|
|
<literal>gcc -o myprog [c files] `gtk-config --cflags --libs`</literal>
|
|
</literallayout></para>
|
|
|
|
<para>You should notice the backquote character which is used
|
|
in this command line. A common mistake when you start a GTK+
|
|
based development is to use quote instead of backquotes. If
|
|
you do so, the compiler will complain about an unknown file
|
|
called <filename>gtk-config --cflags --libs</filename>. The
|
|
text in backquotes is an instruction to your shell to
|
|
substitute the output of executing this text into the
|
|
commandline.</para>
|
|
|
|
<para>The command line above ensure that:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>the correct C compiler flags will be used
|
|
to compile the program (including the complete C header
|
|
directory list)</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>your program will be linked with the
|
|
needed libraries.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What about using the <command>make</command>
|
|
utility?</title>
|
|
|
|
<para>This is a sample makefile which compile a GTK+ based
|
|
program:</para>
|
|
|
|
<programlisting role="C">
|
|
# basic GTK+ app makefile
|
|
SOURCES = myprg.c foo.c bar.c
|
|
OBJS = ${SOURCES:.c=.o}
|
|
CFLAGS = `gtk-config --cflags`
|
|
LDADD = `gtk-config --libs`
|
|
CC = gcc
|
|
PACKAGE = myprg
|
|
|
|
all : ${OBJS}
|
|
${CC} -o ${PACKAGE} ${OBJS} ${LDADD}
|
|
|
|
.c.o:
|
|
${CC} ${CFLAGS} -c $<
|
|
|
|
# end of file
|
|
</programlisting>
|
|
|
|
<para>For more information about the <command>make</command> utility, you
|
|
should read either the related man page or the relevant info file.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I use the backquote stuff in my makefiles, but my make
|
|
process failed.</title>
|
|
|
|
<para>The backquote construction seems to not be accepted by
|
|
some old <command>make</command> utilities. If you use one of these, the
|
|
make process will probably fail. In order to have the
|
|
backquote syntax working again, you should use the GNU make
|
|
utility (get it on the GNU ftp server at <ulink
|
|
url="ftp://ftp.gnu.org/">ftp://ftp.gnu.org/</ulink>).</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I want to add some configure stuff, how could I do
|
|
this?</title>
|
|
|
|
<para>To use autoconf/automake, you must first install the
|
|
relevant packages. These are:</para>
|
|
|
|
<itemizedlist spacing=Compact>
|
|
<listitem><simpara>the m4 preprocessor v1.4 or better</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>autoconf v2.13 or better</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>automake v1.4 or better</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>You'll find these packages on the GNU main ftp server
|
|
(<ulink url="ftp://ftp.gnu.org/">ftp://ftp.gnu.org/</ulink>)
|
|
or on any GNU mirror.</para>
|
|
|
|
<para>In order to use the powerful autoconf/automake scheme,
|
|
you must create a configure.in which may look like:</para>
|
|
|
|
<programlisting role="C">
|
|
dnl Process this file with autoconf to produce a configure script.
|
|
dnl configure.in for a GTK+ based program
|
|
|
|
AC_INIT(myprg.c)dnl
|
|
AM_INIT_AUTOMAKE(mypkgname,0.0.1)dnl
|
|
AM_CONFIG_HEADER(config.h)dnl
|
|
|
|
dnl Checks for programs.
|
|
AC_PROG_CC dnl check for the c compiler
|
|
dnl you should add CFLAGS="" here, 'cos it is set to -g by PROG_CC
|
|
|
|
dnl Checks for libraries.
|
|
AM_PATH_GTK(1.2.0,,AC_MSG_ERROR(mypkgname 0.1 needs GTK))dnl
|
|
|
|
AC_OUTPUT(
|
|
Makefile
|
|
)dnl
|
|
</programlisting>
|
|
|
|
<para>You must add a Makefile.am file:</para>
|
|
|
|
<programlisting role="C">
|
|
bin_PROGRAMS = myprg
|
|
myprg_SOURCES = myprg.c foo.c bar.c
|
|
INCLUDES = @GTK_CFLAGS@
|
|
LDADD = @GTK_LIBS@
|
|
CLEANFILES = *~
|
|
DISTCLEANFILES = .deps/*.P
|
|
</programlisting>
|
|
|
|
<para>If your project contains more than one subdirectory,
|
|
you'll have to create one Makefile.am in each directory plus a
|
|
master Makefile.am which will look like:</para>
|
|
|
|
<programlisting role="C">
|
|
SUBDIRS = mydir1 mydir2 mydir3
|
|
</programlisting>
|
|
|
|
<para>then, to use these, simply type the following
|
|
commands:</para>
|
|
|
|
<programlisting role="C">
|
|
aclocal
|
|
autoheader
|
|
autoconf
|
|
automake --add-missing --include-deps --foreign
|
|
</programlisting>
|
|
|
|
<para>For further information, you should look at the autoconf
|
|
and the automake documentation (the shipped info files are
|
|
really easy to understand, and there are plenty of web
|
|
resources that deal with autoconf and automake).</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I try to debug my GTK+ application with gdb, but it
|
|
hangs my X server when I hit some breakpoint. Any
|
|
Idea?</title>
|
|
|
|
<para>From Federico Mena Quintero:</para>
|
|
|
|
<para><quote>X is not locked up. It is likely that you are hitting a
|
|
breakpoint inside a callback that is called from a place in Gtk that has
|
|
a mouse grab.</quote></para>
|
|
|
|
<para><quote>Run your program with the <literal>--sync</literal>
|
|
option; it will make it easier to debug. Also, you may want to
|
|
use the console for running the debugger, and just let the
|
|
program run in another console with the X server.</quote></para>
|
|
|
|
<para>Eric Mouw had another solution:</para>
|
|
|
|
<para><quote>An old terminal connected to an otherwise unused serial
|
|
port is also great for debugging X programs. Old vt100/vt220
|
|
terminals are dirt cheap but a bit hard to get (here in The
|
|
Netherlands, YMMV).</quote></para>
|
|
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>Development with GTK+: general questions</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What widgets are in GTK?</title>
|
|
|
|
<para>The GTK+ Tutorial lists the following widgets:</para>
|
|
|
|
<programlisting role="C">
|
|
GtkObject
|
|
+GtkData
|
|
| +GtkAdjustment
|
|
| `GtkTooltips
|
|
`GtkWidget
|
|
+GtkContainer
|
|
| +GtkBin
|
|
| | +GtkAlignment
|
|
| | +GtkEventBox
|
|
| | +GtkFrame
|
|
| | | `GtkAspectFrame
|
|
| | +GtkHandleBox
|
|
| | +GtkItem
|
|
| | | +GtkListItem
|
|
| | | +GtkMenuItem
|
|
| | | | `GtkCheckMenuItem
|
|
| | | | `GtkRadioMenuItem
|
|
| | | `GtkTreeItem
|
|
| | +GtkViewport
|
|
| | `GtkWindow
|
|
| | +GtkColorSelectionDialog
|
|
| | +GtkDialog
|
|
| | | `GtkInputDialog
|
|
| | `GtkFileSelection
|
|
| +GtkBox
|
|
| | +GtkButtonBox
|
|
| | | +GtkHButtonBox
|
|
| | | `GtkVButtonBox
|
|
| | +GtkHBox
|
|
| | | +GtkCombo
|
|
| | | `GtkStatusbar
|
|
| | `GtkVBox
|
|
| | +GtkColorSelection
|
|
| | `GtkGammaCurve
|
|
| +GtkButton
|
|
| | +GtkOptionMenu
|
|
| | `GtkToggleButton
|
|
| | `GtkCheckButton
|
|
| | `GtkRadioButton
|
|
| +GtkCList
|
|
| `GtkCTree
|
|
| +GtkFixed
|
|
| +GtkList
|
|
| +GtkMenuShell
|
|
| | +GtkMenuBar
|
|
| | `GtkMenu
|
|
| +GtkNotebook
|
|
| +GtkPaned
|
|
| | +GtkHPaned
|
|
| | `GtkVPaned
|
|
| +GtkScrolledWindow
|
|
| +GtkTable
|
|
| +GtkToolbar
|
|
| `GtkTree
|
|
+GtkDrawingArea
|
|
| `GtkCurve
|
|
+GtkEditable
|
|
| +GtkEntry
|
|
| | `GtkSpinButton
|
|
| `GtkText
|
|
+GtkMisc
|
|
| +GtkArrow
|
|
| +GtkImage
|
|
| +GtkLabel
|
|
| | `GtkTipsQuery
|
|
| `GtkPixmap
|
|
+GtkPreview
|
|
+GtkProgressBar
|
|
+GtkRange
|
|
| +GtkScale
|
|
| | +GtkHScale
|
|
| | `GtkVScale
|
|
| `GtkScrollbar
|
|
| +GtkHScrollbar
|
|
| `GtkVScrollbar
|
|
+GtkRuler
|
|
| +GtkHRuler
|
|
| `GtkVRuler
|
|
`GtkSeparator
|
|
+GtkHSeparator
|
|
`GtkVSeparator
|
|
</programlisting>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Is GTK+ thread safe? How do I write multi-threaded GTK+
|
|
applications?</title>
|
|
|
|
<para>The GLib library can be used in a thread-safe mode by
|
|
calling g_thread_init() before making any other GLib
|
|
calls. In this mode GLib automatically locks all internal
|
|
data structures as needed. This does not mean that two
|
|
threads can simultaneously access, for example, a single hash
|
|
table, but they can access two different hash tables
|
|
simultaneously. If two different threads need to access the
|
|
same hash table, the application is responsible for locking
|
|
itself.</para>
|
|
|
|
<para>When GLib is intialized to be thread-safe, GTK+ is
|
|
<emphasis>thread aware</emphasis>. There is a single global
|
|
lock that you must acquire with gdk_threads_enter() before
|
|
making any GDK calls, and release with gdk_threads_leave()
|
|
afterwards.</para>
|
|
|
|
<para>A minimal main program for a threaded GTK+ application
|
|
looks like:</para>
|
|
|
|
<programlisting role="C">
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GtkWidget *window;
|
|
|
|
g_thread_init(NULL);
|
|
gtk_init(&argc, &argv);
|
|
|
|
window = create_window();
|
|
gtk_widget_show(window);
|
|
|
|
gdk_threads_enter();
|
|
gtk_main();
|
|
gdk_threads_leave();
|
|
|
|
return(0);
|
|
}
|
|
</programlisting>
|
|
|
|
<para>Callbacks require a bit of attention. Callbacks from
|
|
GTK+ (signals) are made within the GTK+ lock. However
|
|
callbacks from GLib (timeouts, IO callbacks, and idle
|
|
functions) are made outside of the GTK+ lock. So, within a
|
|
signal handler you do not need to call gdk_threads_enter(),
|
|
but within the other types of callbacks, you do.</para>
|
|
|
|
<para>Erik Mouw contributed the following code example to
|
|
illustrate how to use threads within GTK+ programs.</para>
|
|
|
|
<programlisting role="C">
|
|
/*-------------------------------------------------------------------------
|
|
* Filename: gtk-thread.c
|
|
* Version: 0.99.1
|
|
* Copyright: Copyright (C) 1999, Erik Mouw
|
|
* Author: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
|
* Description: GTK threads example.
|
|
* Created at: Sun Oct 17 21:27:09 1999
|
|
* Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
|
* Modified at: Sun Oct 24 17:21:41 1999
|
|
*-----------------------------------------------------------------------*/
|
|
/*
|
|
* Compile with:
|
|
*
|
|
* cc -o gtk-thread gtk-thread.c `gtk-config --cflags --libs gthread`
|
|
*
|
|
* Thanks to Sebastian Wilhelmi and Owen Taylor for pointing out some
|
|
* bugs.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib.h>
|
|
#include <pthread.h>
|
|
|
|
#define YES_IT_IS (1)
|
|
#define NO_IT_IS_NOT (0)
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *label;
|
|
int what;
|
|
} yes_or_no_args;
|
|
|
|
G_LOCK_DEFINE_STATIC (yes_or_no);
|
|
static volatile int yes_or_no = YES_IT_IS;
|
|
|
|
void destroy(GtkWidget *widget, gpointer data)
|
|
{
|
|
gtk_main_quit();
|
|
}
|
|
|
|
void *argument_thread(void *args)
|
|
{
|
|
yes_or_no_args *data = (yes_or_no_args *)args;
|
|
gboolean say_something;
|
|
|
|
for(;;)
|
|
{
|
|
/* sleep a while */
|
|
sleep(rand() / (RAND_MAX / 3) + 1);
|
|
|
|
/* lock the yes_or_no_variable */
|
|
G_LOCK(yes_or_no);
|
|
|
|
/* do we have to say something? */
|
|
say_something = (yes_or_no != data->what);
|
|
|
|
if(say_something)
|
|
{
|
|
/* set the variable */
|
|
yes_or_no = data->what;
|
|
}
|
|
|
|
/* Unlock the yes_or_no variable */
|
|
G_UNLOCK(yes_or_no);
|
|
|
|
if(say_something)
|
|
{
|
|
/* get GTK thread lock */
|
|
gdk_threads_enter();
|
|
|
|
/* set label text */
|
|
if(data->what == YES_IT_IS)
|
|
gtk_label_set_text(GTK_LABEL(data->label), "O yes, it is!");
|
|
else
|
|
gtk_label_set_text(GTK_LABEL(data->label), "O no, it isn't!");
|
|
|
|
/* release GTK thread lock */
|
|
gdk_threads_leave();
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *label;
|
|
yes_or_no_args yes_args, no_args;
|
|
pthread_t no_tid, yes_tid;
|
|
|
|
/* init threads */
|
|
g_thread_init(NULL);
|
|
|
|
/* init gtk */
|
|
gtk_init(&argc, &argv);
|
|
|
|
/* init random number generator */
|
|
srand((unsigned int)time(NULL));
|
|
|
|
/* create a window */
|
|
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT (window), "destroy",
|
|
GTK_SIGNAL_FUNC(destroy), NULL);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER (window), 10);
|
|
|
|
/* create a label */
|
|
label = gtk_label_new("And now for something completely different ...");
|
|
gtk_container_add(GTK_CONTAINER(window), label);
|
|
|
|
/* show everything */
|
|
gtk_widget_show(label);
|
|
gtk_widget_show (window);
|
|
|
|
/* create the threads */
|
|
yes_args.label = label;
|
|
yes_args.what = YES_IT_IS;
|
|
pthread_create(&yes_tid, NULL, argument_thread, &yes_args);
|
|
|
|
no_args.label = label;
|
|
no_args.what = NO_IT_IS_NOT;
|
|
pthread_create(&no_tid, NULL, argument_thread, &no_args);
|
|
|
|
/* enter the GTK main loop */
|
|
gdk_threads_enter();
|
|
gtk_main();
|
|
gdk_threads_leave();
|
|
|
|
return(0);
|
|
}
|
|
</programlisting>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Why does this strange 'x io error' occur when I
|
|
<literal>fork()</literal> in my GTK+ app?</title>
|
|
|
|
<para>This is not really a GTK+ problem, and the problem is
|
|
not related to <literal>fork()</literal> either. If the 'x io
|
|
error' occurs then you probably use the <literal>exit()</literal> function
|
|
in order to exit from the child process.</para>
|
|
|
|
<para>When GDK opens an X display, it creates a socket file
|
|
descriptor. When you use the <literal>exit()</literal>
|
|
function, you implicitly close all the open file descriptors,
|
|
and the underlying X library really doesn't like this.</para>
|
|
|
|
<para>The right function to use here is
|
|
<literal>_exit()</literal>.</para>
|
|
|
|
<para>Erik Mouw contributed the following code example to
|
|
illustrate handling fork() and exit().</para>
|
|
|
|
<programlisting role="C">
|
|
/*-------------------------------------------------------------------------
|
|
* Filename: gtk-fork.c
|
|
* Version: 0.99.1
|
|
* Copyright: Copyright (C) 1999, Erik Mouw
|
|
* Author: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
|
* Description: GTK+ fork example
|
|
* Created at: Thu Sep 23 21:37:55 1999
|
|
* Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
|
* Modified at: Thu Sep 23 22:39:39 1999
|
|
*-----------------------------------------------------------------------*/
|
|
/*
|
|
* Compile with:
|
|
*
|
|
* cc -o gtk-fork gtk-fork.c `gtk-config --cflags --libs`
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
void sigchld_handler(int num)
|
|
{
|
|
sigset_t set, oldset;
|
|
pid_t pid;
|
|
int status, exitstatus;
|
|
|
|
/* block other incoming SIGCHLD signals */
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGCHLD);
|
|
sigprocmask(SIG_BLOCK, &set, &oldset);
|
|
|
|
/* wait for child */
|
|
while((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0)
|
|
{
|
|
if(WIFEXITED(status))
|
|
{
|
|
exitstatus = WEXITSTATUS(status);
|
|
|
|
fprintf(stderr,
|
|
"Parent: child exited, pid = %d, exit status = %d\n",
|
|
(int)pid, exitstatus);
|
|
}
|
|
else if(WIFSIGNALED(status))
|
|
{
|
|
exitstatus = WTERMSIG(status);
|
|
|
|
fprintf(stderr,
|
|
"Parent: child terminated by signal %d, pid = %d\n",
|
|
exitstatus, (int)pid);
|
|
}
|
|
else if(WIFSTOPPED(status))
|
|
{
|
|
exitstatus = WSTOPSIG(status);
|
|
|
|
fprintf(stderr,
|
|
"Parent: child stopped by signal %d, pid = %d\n",
|
|
exitstatus, (int)pid);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr,
|
|
"Parent: child exited magically, pid = %d\n",
|
|
(int)pid);
|
|
}
|
|
}
|
|
|
|
/* re-install the signal handler (some systems need this) */
|
|
signal(SIGCHLD, sigchld_handler);
|
|
|
|
/* and unblock it */
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGCHLD);
|
|
sigprocmask(SIG_UNBLOCK, &set, &oldset);
|
|
}
|
|
|
|
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
void destroy(GtkWidget *widget, gpointer data)
|
|
{
|
|
gtk_main_quit();
|
|
}
|
|
|
|
void fork_me(GtkWidget *widget, gpointer data)
|
|
{
|
|
pid_t pid;
|
|
|
|
pid = fork();
|
|
|
|
if(pid == -1)
|
|
{
|
|
/* ouch, fork() failed */
|
|
perror("fork");
|
|
exit(-1);
|
|
}
|
|
else if(pid == 0)
|
|
{
|
|
/* child */
|
|
fprintf(stderr, "Child: pid = %d\n", (int)getpid());
|
|
|
|
execlp("ls", "ls", "-CF", "/", NULL);
|
|
|
|
/* if exec() returns, there is something wrong */
|
|
perror("execlp");
|
|
|
|
/* exit child. note the use of _exit() instead of exit() */
|
|
_exit(-1);
|
|
}
|
|
else
|
|
{
|
|
/* parent */
|
|
fprintf(stderr, "Parent: forked a child with pid = %d\n", (int)pid);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *button;
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
/* the basic stuff: make a window and set callbacks for destroy and
|
|
* delete events
|
|
*/
|
|
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT (window), "delete_event",
|
|
GTK_SIGNAL_FUNC(delete_event), NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT (window), "destroy",
|
|
GTK_SIGNAL_FUNC(destroy), NULL);
|
|
|
|
#if (GTK_MAJOR_VERSION == 1) && (GTK_MINOR_VERSION == 0)
|
|
gtk_container_border_width(GTK_CONTAINER (window), 10);
|
|
#else
|
|
gtk_container_set_border_width(GTK_CONTAINER (window), 10);
|
|
#endif
|
|
|
|
/* add a button to do something usefull */
|
|
button = gtk_button_new_with_label("Fork me!");
|
|
|
|
gtk_signal_connect(GTK_OBJECT (button), "clicked",
|
|
GTK_SIGNAL_FUNC(fork_me), NULL);
|
|
|
|
gtk_container_add(GTK_CONTAINER(window), button);
|
|
|
|
/* show everything */
|
|
gtk_widget_show (button);
|
|
gtk_widget_show (window);
|
|
|
|
|
|
/* install a signal handler for SIGCHLD signals */
|
|
signal(SIGCHLD, sigchld_handler);
|
|
|
|
|
|
/* main loop */
|
|
gtk_main ();
|
|
|
|
exit(0);
|
|
}
|
|
</programlisting>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Why don't the contents of a button move when the button
|
|
is pressed? Here's a patch to make it work that way...</title>
|
|
|
|
<para>From: Peter Mattis</para>
|
|
|
|
<para><quote>The reason buttons don't move their child down and to
|
|
the right when they are depressed is because I don't think
|
|
that's what is happening visually. My view of buttons is
|
|
that you are looking at them straight on. That is, the user
|
|
interface lies in a plane and you're above it looking
|
|
straight at it. When a button gets pressed it moves directly
|
|
away from you. To be absolutely correct I guess the child
|
|
should actually shrink a tiny amount. But I don't see why
|
|
the child should shift down and to the left. Remember, the
|
|
child is supposed to be attached to the buttons surface. Its
|
|
not good for it to appear like the child is slipping on the
|
|
surface of the button.</quote></para>
|
|
|
|
<para><quote>On a more practical note, I did implement this at one point
|
|
and determined it didn't look good and removed it.</quote></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I identifiy a widgets top level window or other
|
|
ancestor?</title>
|
|
|
|
<para>There are a couple of ways to find the top level parent
|
|
of a widget. The easier way is to call the
|
|
<literal>gtk_widget_top_level()</literal> function that
|
|
returns pointer to a GtkWidget that is the top level
|
|
window.</para>
|
|
|
|
<para>A more complicated way to do this (but less limited, as
|
|
it allows the user to get the closest ancestor of a known type) is to use
|
|
<literal>gtk_widget_get_ancestor()</literal> as in:</para>
|
|
|
|
<programlisting role="C">
|
|
GtkWidget *widget;
|
|
widget = gtk_widget_get_ancestor(w, GTK_TYPE_WINDOW);
|
|
</programlisting>
|
|
|
|
<para>Since virtually all the GTK_TYPEs can be used as the
|
|
second parameter of this function, you can get any parent
|
|
widget of a particular widget. Suppose you have an hbox which
|
|
contains a vbox, which in turn contains some other atomic
|
|
widget (entry, label, etc. To find the master hbox using the
|
|
<literal>entry</literal> widget simply use:</para>
|
|
|
|
<programlisting role="C">
|
|
GtkWidget *hbox;
|
|
hbox = gtk_widget_get_ancestor(w, GTK_TYPE_HBOX);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I get the Window ID of a GtkWindow?</title>
|
|
|
|
<para>The actual Gdk/X window will be created when the widget
|
|
gets realized. You can get the Window ID with:</para>
|
|
|
|
<programlisting role="C">
|
|
#include <gdk/gdkx.h>
|
|
|
|
Window xwin = GDK_WINDOW_XWINDOW (GTK_WIDGET (my_window)->window);
|
|
</programlisting>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I catch a double click event (in a list widget,
|
|
for example)?</title>
|
|
|
|
<para>Tim Janik wrote to gtk-list (slightly modified):</para>
|
|
|
|
<para>Define a signal handler:</para>
|
|
|
|
<programlisting role="C">
|
|
gint
|
|
signal_handler_event(GtkWiget *widget, GdkEvenButton *event, gpointer func_data)
|
|
{
|
|
if (GTK_IS_LIST_ITEM(widget) &&
|
|
(event->type==GDK_2BUTTON_PRESS ||
|
|
event->type==GDK_3BUTTON_PRESS) ) {
|
|
printf("I feel %s clicked on button %d\",
|
|
event->type==GDK_2BUTTON_PRESS ? "double" : "triple",
|
|
event->button);
|
|
}
|
|
|
|
return FALSE;
|
|
}</programlisting>
|
|
|
|
<para>And connect the handler to your object:</para>
|
|
|
|
<programlisting role="C">
|
|
{
|
|
/* list, list item init stuff */
|
|
|
|
gtk_signal_connect(GTK_OBJECT(list_item),
|
|
"button_press_event",
|
|
GTK_SIGNAL_FUNC(signal_handler_event),
|
|
NULL);
|
|
|
|
/* and/or */
|
|
|
|
gtk_signal_connect(GTK_OBJECT(list_item),
|
|
"button_release_event",
|
|
GTK_SIGNAL_FUNC(signal_handler_event),
|
|
NULL);
|
|
|
|
/* something else */
|
|
}
|
|
</programlisting>
|
|
|
|
<para>and, Owen Taylor wrote:</para>
|
|
|
|
<para><quote>Note that a single button press will be received
|
|
beforehand, and if you are doing this for a button, you will
|
|
therefore also get a "clicked" signal for the button. (This
|
|
is going to be true for any toolkit, since computers aren't
|
|
good at reading one's mind.)</quote></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>By the way, what are the differences between signals
|
|
and events?</title>
|
|
|
|
<para>First of all, Havoc Pennington gives a rather complete
|
|
description of the differences between events and signals in
|
|
his free book (two chapters can be found at <ulink
|
|
url="http://www106.pair.com/rhp/sample_chapters.html">
|
|
http://www106.pair.com/rhp/sample_chapters.html</ulink>).</para>
|
|
|
|
<para>Moreover, Havoc posted this to the <literal>gtk-list</literal>
|
|
<quote>Events are a stream of messages received from the X
|
|
server. They drive the Gtk main loop; which more or less
|
|
amounts to "wait for events, process them" (not exactly, it
|
|
is really more general than that and can wait on many
|
|
different input streams at once). Events are a Gdk/Xlib
|
|
concept.</quote></para>
|
|
|
|
<para><quote>Signals are a feature of GtkObject and its subclasses. They
|
|
have nothing to do with any input stream; really a signal is just a way
|
|
to keep a list of callbacks around and invoke them ("emit" the
|
|
signal). There are lots of details and extra features of
|
|
course. Signals are emitted by object instances, and are entirely
|
|
unrelated to the Gtk main loop. Conventionally, signals are emitted
|
|
"when something changes" about the object emitting the
|
|
signal.</quote></para>
|
|
|
|
<para><quote>Signals and events only come together because GtkWidget
|
|
happens to emit signals when it gets events. This is purely a
|
|
convenience, so you can connect callbacks to be invoked when a
|
|
particular widget receives a particular event. There is nothing about
|
|
this that makes signals and events inherently related concepts, any more
|
|
than emitting a signal when you click a button makes button clicking and
|
|
signals related concepts.</quote></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Data I pass to the <literal>delete_event</literal> (or other event)
|
|
handler gets corrupted.</title>
|
|
|
|
<para>All event handlers take an additional argument which
|
|
contains information about the event that triggered the
|
|
handler. So, a <literal>delete_event</literal> handler must
|
|
be declared as:</para>
|
|
|
|
|
|
<programlisting role="C">
|
|
gint delete_event_handler (GtkWidget *widget,
|
|
GdkEventAny *event,
|
|
gpointer data);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I have my signal connected to the the (whatever) event,
|
|
but it seems I don't catch it. What's wrong?</title>
|
|
|
|
<para>There is some special initialisation to do in order to
|
|
catch some particular events. In fact, you must set the
|
|
correct event mask bit of your widget before getting some
|
|
particular events.</para>
|
|
|
|
<para>For example,</para>
|
|
|
|
<programlisting role="C">
|
|
gtk_widget_add_events(window, GDK_KEY_RELEASE_MASK);
|
|
</programlisting>
|
|
|
|
<para>lets you catch the key release events. If you want to
|
|
catch every events, simply us the GDK_ALL_EVENTS_MASK event
|
|
mask.</para>
|
|
|
|
<para>All the event masks are defined in the
|
|
<filename>gdktypes.h</filename> file.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I need to add a new signal to a GTK+ widget. Any
|
|
idea?</title>
|
|
|
|
<para>If the signal you want to add may be beneficial for
|
|
other GTK+ users, you may want to submit a patch that
|
|
presents your changes. Check the tutorial for more
|
|
information about adding signals to a widget class.</para>
|
|
|
|
<para>If you don't think it is the case or if your patch is
|
|
not applied you'll have to use the
|
|
<literal>gtk_object_class_user_signal_new</literal>
|
|
function. <literal>gtk_object_class_user_signal_new</literal> allows you
|
|
to add a new signal to a predefined GTK+ widget without any
|
|
modification of the GTK+ source code. The new signal can be
|
|
emited with <literal>gtk_signal_emit</literal> and can be
|
|
handled in the same way as other signals.</para>
|
|
|
|
<para>Tim Janik posted this code snippet:</para>
|
|
|
|
<programlisting role="C">
|
|
static guint signal_user_action = 0;
|
|
|
|
signal_user_action =
|
|
gtk_object_class_user_signal_new (gtk_type_class (GTK_TYPE_WIDGET),
|
|
"user_action",
|
|
GTK_RUN_LAST | GTK_RUN_ACTION,
|
|
gtk_marshal_NONE__POINTER,
|
|
GTK_TYPE_NONE, 1,
|
|
GTK_TYPE_POINTER);
|
|
|
|
void
|
|
gtk_widget_user_action (GtkWidget *widget,
|
|
gpointer act_data)
|
|
{
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
gtk_signal_emit (GTK_OBJECT (widget), signal_user_action, act_data);
|
|
}
|
|
</programlisting>
|
|
|
|
<para>If you want your new signal to have more than the
|
|
classical gpointer parameter, you'll have to play with GTK+
|
|
marshallers.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Is it possible to get some text displayed which is
|
|
truncated to fit inside its allocation?</title>
|
|
|
|
<para>GTK's behavior (no clipping) is a consequence of its
|
|
attempts to conserve X resources. Label widgets (among
|
|
others) don't get their own X window - they just draw their
|
|
contents on their parent's window. While it might be possible
|
|
to have clipping occur by setting the clip mask before
|
|
drawing the text, this would probably cause a substantial
|
|
performance penalty.</para>
|
|
|
|
<para>Its possible that, in the long term, the best solution
|
|
to such problems might be just to change gtk to give labels X
|
|
windows. A short term workaround is to put the label widget
|
|
inside another widget that does get its own window - one
|
|
possible candidate would be the viewport widget.</para>
|
|
|
|
<programlisting role="C">
|
|
viewport = gtk_viewport (NULL, NULL);
|
|
gtk_widget_set_usize (viewport, 50, 25);
|
|
gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
|
|
gtk_widget_show(viewport);
|
|
|
|
label = gtk_label ("a really long label that won't fit");
|
|
gtk_container_add (GTK_CONTAINER(viewport), label);
|
|
gtk_widget_show (label);
|
|
</programlisting>
|
|
|
|
<para>If you were doing this for a bunch of widgets, you might
|
|
want to copy gtkviewport.c and strip out the adjustment and
|
|
shadow functionality (perhaps you could call it
|
|
GtkClipper).</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I make my window modal? / How do I make a single
|
|
window active?</title>
|
|
|
|
<para>After you create your window, do
|
|
<literal>gtk_grab_add(my_window)</literal>. And after closing the window
|
|
do <literal>gtk_grab_remove(my_window)</literal>.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Why doesn't my widget (e.g. progressbar)
|
|
update?</title>
|
|
|
|
<para>You are probably doing all the changes within a function without
|
|
returning control to <literal>gtk_main()</literal>. This may
|
|
be the case if you do some lengthy calculation in your
|
|
code. Most drawing updates are only placed on a queue, which
|
|
is processed within <literal>gtk_main()</literal>. You can force the
|
|
drawing queue to be processed using something like:</para>
|
|
|
|
|
|
<programlisting role="C">
|
|
while (g_main_iteration(FALSE));
|
|
</programlisting>
|
|
|
|
<para>inside you're function that changes the widget.</para>
|
|
|
|
<para>What the above snippet does is run all pending events
|
|
and high priority idle functions, then return immediately
|
|
(the drawing is done in a high priority idle function).</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I attach data to some GTK+ object/widget?</title>
|
|
|
|
<para>First of all, the attached data is stored in the
|
|
object_data field of a GtkObject. The type of this field is
|
|
GData, which is defined in glib.h. So you should read the
|
|
gdataset.c file in your glib source directory very
|
|
carefully.</para>
|
|
|
|
<para>There are two (easy) ways to attach some data to a gtk
|
|
object. Using <literal>gtk_object_set_data()</literal> and
|
|
<literal>gtk_object_get_data()</literal> seems to be the most
|
|
common way to do this, as it provides a powerful interface to
|
|
connect objects and data.</para>
|
|
|
|
<programlisting role="C">
|
|
void gtk_object_set_data(GtkObject *object, const gchar *key, gpointer data);
|
|
|
|
gpointer gtk_object_get_data(GtkObject *object, const gchar *key);
|
|
</programlisting>
|
|
|
|
<para>Since a short example is better than any lengthy speech:</para>
|
|
|
|
<programlisting role="C">
|
|
struct my_struct p1,p2,*result;
|
|
GtkWidget *w;
|
|
|
|
gtk_object_set_data(GTK_OBJECT(w),"p1 data",(gpointer)&p1);
|
|
gtk_object_set_data(GTK_OBJECT(w),"p2 data",(gpointer)&p2);
|
|
|
|
result = gtk_object_get_data(GTK_OBJECT(w),"p1 data");
|
|
</programlisting>
|
|
|
|
<para>The <literal>gtk_object_set_user_data()</literal> and
|
|
<literal>gtk_object_get_user_data()</literal> functions does
|
|
exactly the same thing as the functions above, but does not
|
|
let you specify the "key" parameter.Instead, it uses a
|
|
standard "user_data" key. Note that the use of these functions
|
|
is deprecated in 1.2. They only provide a compatibility mode
|
|
with some old gtk packages.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I remove the data I have attached to an
|
|
object?</title>
|
|
|
|
<para>When attaching the data to the object, you can use the
|
|
<literal>gtk_object_set_data_full()</literal> function. The three
|
|
first arguments of the function are the same as in
|
|
<literal>gtk_object_set_data()</literal>. The fourth one is a
|
|
pointer to a callback function which is called when the data
|
|
is destroyed. The data is destroyed when you:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara> destroy the object</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara> replace the data with a new one (with
|
|
the same key)</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara> replace the data with NULL (with the
|
|
same key)</simpara>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I reparent a widget?</title>
|
|
|
|
<para>The normal way to reparent (ie change the owner) of a
|
|
widget should be to use the function:</para>
|
|
|
|
<programlisting role="C">
|
|
void gtk_widget_reparent (GtkWidget *widget,
|
|
GtkWidget *new_parent)
|
|
</programlisting>
|
|
|
|
<para>But this is only a "should be" since this function does
|
|
not correctly do its job on some specific widgets. The main
|
|
goal of gtk_widget_reparent() is to avoid unrealizing widget
|
|
if both widget and new_parent are realized (in this case,
|
|
widget->window is successfully reparented). The problem here
|
|
is that some widgets in the GTK+ hierarchy have multiple
|
|
attached X subwindows and this is notably the case for the
|
|
GtkSpinButton widget. For those, gtk_widget_reparent() will
|
|
fail by leaving an unrealized child window where it should
|
|
not.</para>
|
|
|
|
<para>To avoid this problem, simply use the following code
|
|
snippet:</para>
|
|
|
|
<programlisting role="C">
|
|
gtk_widget_ref(widget);
|
|
gtk_container_remove(GTK_CONTAINER(old_parent), widget);
|
|
gtk_container_add(GTK_CONTAINER(new_parent), widget);
|
|
gtk_widget_unref(widget);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How could I get any widgets position?</title>
|
|
|
|
<para>As Tim Janik pointed out, there are different cases, and
|
|
each case requires a different solution.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara> If you want the position of a widget
|
|
relative to its parent, you should use
|
|
<literal>widget->allocation.x</literal> and
|
|
<literal>widget->allocation.y</literal>.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara> If you want the position of a window
|
|
relative to the X root window, you should use
|
|
<literal>gdk_window_get_geometry()</literal>
|
|
<literal>gdk_window_get_position()</literal> or
|
|
<literal>gdk_window_get_origin()</literal>.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara> If you want to get the position of the
|
|
window (including the WM decorations), you should use
|
|
<literal>gdk_window_get_root_origin()</literal>.</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara> Last but not least, if you want to get a Window
|
|
Manager frame position, you should use
|
|
<literal>gdk_window_get_deskrelative_origin()</literal>.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Your choice of Window Manager will have an effect of the
|
|
results of the above functions. You should keep this in mind
|
|
when writing your application. This is dependant upon how the
|
|
Window Managers manage the decorations that they add around
|
|
windows.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I set the size of a widget/window? How do I
|
|
prevent the user resizing my window?</title>
|
|
|
|
<para>The <literal>gtk_widget_set_uposition()</literal>
|
|
function is used to set the position of any widget.</para>
|
|
|
|
<para>The <literal>gtk_widget_set_usize()</literal> function
|
|
is used to set the size of a widget. In order to use all the
|
|
features that are provided by this function when it acts on a
|
|
window, you may want to use the
|
|
<literal>gtk_window_set_policy</literal> function. The
|
|
definition of these functions are:</para>
|
|
|
|
<programlisting role="C">
|
|
void gtk_widget_set_usize (GtkWidget *widget,
|
|
gint width,
|
|
gint height);
|
|
|
|
void gtk_window_set_policy (GtkWindow *window,
|
|
gint allow_shrink,
|
|
gint allow_grow,
|
|
gint auto_shrink);
|
|
</programlisting>
|
|
|
|
<para><literal>Auto_shrink</literal> will automatically shrink
|
|
the window when the requested size of the child widgets goes
|
|
below the current size of the
|
|
window. <literal>Allow_shrink</literal> will give the user the
|
|
authorisation to make the window smaller that it should
|
|
normally be. <literal>Allow_grow</literal> will give the user
|
|
will have the ability to make the window bigger. The default
|
|
values for these parameters are:</para>
|
|
|
|
<programlisting role="C">
|
|
allow_shrink = FALSE
|
|
allow_grow = TRUE
|
|
auto_shrink = FALSE
|
|
</programlisting>
|
|
|
|
<para>The <literal>gtk_widget_set_usize()</literal> functions
|
|
is not the easiest way to set a window size since you cannot
|
|
decrease this window size with another call to this function
|
|
unless you call it twice, as in:</para>
|
|
|
|
<programlisting role="C">
|
|
gtk_widget_set_usize(your_widget, -1, -1);
|
|
gtk_widget_set_usize(your_widget, new_x_size, new_y_size);
|
|
</programlisting>
|
|
|
|
<para>Another way to set the size of and/or move a window is to use
|
|
the <literal>gdk_window_move_resize()</literal> function which
|
|
uses to work fine both to grow or to shrink the window:</para>
|
|
|
|
<programlisting role="C">
|
|
gdk_window_move_resize(window->window,
|
|
x_pos, y_pos,
|
|
x_size, y_size);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I add a popup menu to my GTK+ application?</title>
|
|
|
|
<para>The <literal>menu</literal> example in the examples/menu
|
|
directory of the GTK+ distribution implements a popup menu
|
|
with this technique:</para>
|
|
|
|
<programlisting role="C">
|
|
static gint button_press (GtkWidget *widget, GdkEvent *event)
|
|
{
|
|
|
|
if (event->type == GDK_BUTTON_PRESS) {
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
|
|
bevent->button, bevent->time);
|
|
/* Tell calling code that we have handled this event; the buck
|
|
* stops here. */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Tell calling code that we have not handled this event; pass it on. */
|
|
return FALSE;
|
|
}
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I disable or enable a widget, such as a
|
|
button?</title>
|
|
|
|
<para>To disable (or to enable) a widget, use the
|
|
<literal>gtk_widget_set_sensitive()</literal> function. The
|
|
first parameter is you widget pointer. The second parameter is
|
|
a boolean value: when this value is TRUE, the widget is
|
|
enabled.</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Shouldn't the text argument in the gtk_clist_*
|
|
functions be declared const?</title>
|
|
|
|
<para>For example:</para>
|
|
|
|
<programlisting role="C">
|
|
gint gtk_clist_prepend (GtkCList *clist,
|
|
gchar *text[]);
|
|
</programlisting>
|
|
|
|
<para>Answer: No, while a type "gchar*" (pointer to char) can
|
|
automatically be cast into "const gchar*" (pointer to const
|
|
char), this does not apply for "gchar *[]" (array of an
|
|
unspecified number of pointers to char) into "const gchar *[]"
|
|
(array of an unspecified number of pointers to const char).</para>
|
|
|
|
<para>The type qualifier "const" may be subject to automatic
|
|
casting, but in the array case, it is not the array itself
|
|
that needs the (const) qualified cast, but its members, thus
|
|
changing the whole type.</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I render pixels (image data) to the
|
|
screen?</title>
|
|
|
|
<para>There are several ways to approach this. The simplest
|
|
way is to use GdkRGB, see gdk/gdkrgb.h. You create an RGB
|
|
buffer, render to your RGB buffer, then use GdkRGB routines to
|
|
copy your RGB buffer to a drawing area or custom widget. The
|
|
book "GTK+/Gnome Application Development" gives some details;
|
|
GdkRGB is also documented in the GTK+ reference
|
|
documentation.</para>
|
|
|
|
<para>If you're writing a game or other graphics-intensive
|
|
application, you might consider a more elaborate
|
|
solution. OpenGL is the graphics standard that will let you
|
|
access hardware accelaration in future versions of XFree86; so
|
|
for maximum speed, you probably want to use OpenGL. A
|
|
GtkGLArea widget is available for using OpenGL with GTK+ (but
|
|
GtkGLArea does not come with GTK+ itself). There are also
|
|
several open source game libraries, such as ClanLib and Loki's
|
|
Simple DirectMedia Layer library (SDL).</para>
|
|
|
|
<para>You do NOT want to use
|
|
<literal>gdk_draw_point()</literal>, that will be extremely
|
|
slow.</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I create a pixmap without having my window being
|
|
realized/shown?</title>
|
|
|
|
<para>Functions such as
|
|
<literal>gdk_pixmap_create_from_xpm()</literal> require a
|
|
valid window as a parameter. During the initialisation phase
|
|
of an application, a valid window may not be available without
|
|
showing a window, which may be inappropriate. In order to
|
|
avoid this, a function such as
|
|
<literal>gdk_pixmap_colormap_create_from_xpm</literal> can be
|
|
used, as in:</para>
|
|
|
|
<programlisting role="C">
|
|
char *pixfile = "foo.xpm";
|
|
GtkWidget *top, *box, *pixw;
|
|
GdkPixmap *pixmap, *pixmap_mask;
|
|
|
|
top = gtk_window_new (GKT_WINDOW_TOPLEVEL);
|
|
box = gtk_hbox_new (FALSE, 4);
|
|
gtk_conainer_add (GTK_CONTAINER(top), box);
|
|
|
|
pixmap = gdk_pixmap_colormap_create_from_xpm (
|
|
NULL, gtk_widget_get_colormap(top),
|
|
&pixmap_mask, NULL, pixfile);
|
|
pixw = gtk_pixmap_new (pixmap, pixmap_mask);
|
|
gdk_pixmap_unref (pixmap);
|
|
gdk_pixmap_unref (pixmap_mask);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>Development with GTK+: widget specific questions</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I find out about the selection of a GtkList?</title>
|
|
|
|
<para>Get the selection something like this:</para>
|
|
|
|
<programlisting role="C">
|
|
GList *sel;
|
|
sel = GTK_LIST(list)->selection;
|
|
</programlisting>
|
|
|
|
<para>This is how GList is defined (quoting glist.h):</para>
|
|
|
|
<programlisting role="C">
|
|
typedef struct _GList GList;
|
|
|
|
struct _GList
|
|
{
|
|
gpointer data;
|
|
GList *next;
|
|
GList *prev;
|
|
};
|
|
</programlisting>
|
|
|
|
<para>A GList structure is just a simple structure for doubly
|
|
linked lists. there exist several g_list_*() functions to
|
|
modify a linked list in glib.h. However the
|
|
GTK_LIST(MyGtkList)->selection is maintained by the
|
|
gtk_list_*() functions and should not be modified.</para>
|
|
|
|
|
|
<para>The selection_mode of the GtkList determines the
|
|
selection facilities of a GtkList and therefore the contents
|
|
of GTK_LIST(AnyGtkList)->selection:</para>
|
|
|
|
<informaltable frame="all">
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry><literal>selection_mode</literal></entry>
|
|
<entry><literal> GTK_LIST()->selection</literal>
|
|
contents</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><literal>GTK_SELECTION_SINGLE</literal></entry>
|
|
<entry>selection is either NULL or contains a GList*
|
|
pointer for a single selected item.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><literal>GTK_SELECTION_BROWSE</literal></entry>
|
|
<entry>selection is NULL if the list contains no
|
|
widgets, otherwise it contains a GList*
|
|
pointer for one GList structure.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><literal>GTK_SELECTION_MULTIPLE</literal></entry>
|
|
<entry>selection is NULL if no listitems are selected
|
|
or a a GList* pointer for the first selected
|
|
item. that in turn points to a GList structure
|
|
for the second selected item and so
|
|
on.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><literal>GTK_SELECTION_EXTENDED</literal></entry>
|
|
<entry>selection is NULL.</entry>
|
|
</row>
|
|
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>The data field of the GList structure
|
|
GTK_LIST(MyGtkList)->selection points to the first
|
|
GtkListItem that is selected. So if you would like to
|
|
determine which listitems are selected you should go like
|
|
this:</para>
|
|
|
|
<programlisting role="C">
|
|
{
|
|
gchar *list_items[]={
|
|
"Item0",
|
|
"Item1",
|
|
"foo",
|
|
"last Item",
|
|
};
|
|
guint nlist_items=sizeof(list_items)/sizeof(list_items[0]);
|
|
GtkWidget *list_item;
|
|
guint i;
|
|
|
|
list=gtk_list_new();
|
|
gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_MULTIPLE);
|
|
gtk_container_add(GTK_CONTAINER(AnyGtkContainer), list);
|
|
gtk_widget_show (list);
|
|
|
|
for (i = 0; i < nlist_items; i++)
|
|
{
|
|
list_item=gtk_list_item_new_with_label(list_items[i]);
|
|
gtk_object_set_user_data(GTK_OBJECT(list_item), (gpointer)i);
|
|
gtk_container_add(GTK_CONTAINER(list), list_item);
|
|
gtk_widget_show(list_item);
|
|
}
|
|
}
|
|
</programlisting>
|
|
|
|
<para>To get known about the selection:</para>
|
|
|
|
<programlisting role="C">
|
|
{
|
|
GList *items;
|
|
|
|
items=GTK_LIST(list)->selection;
|
|
|
|
printf("Selected Items: ");
|
|
while (items) {
|
|
if (GTK_IS_LIST_ITEM(items->data))
|
|
printf("%d ", (guint)
|
|
gtk_object_get_user_data(items->data));
|
|
items=items->next;
|
|
}
|
|
printf("\n");
|
|
}
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I stop the column headings of a GtkCList
|
|
disappearing when the list is scrolled?</title>
|
|
|
|
<para>This happens when a GtkCList is packed into a
|
|
GtkScrolledWindow using the function
|
|
<literal>gtk_scroll_window_add_with_viewport()</literal>. The prefered
|
|
method of adding a CList to a scrolled window is to use the
|
|
function <literal>gtk_container_add</literal>, as in:</para>
|
|
|
|
<programlisting role="C">
|
|
GtkWidget *scrolled, *clist;
|
|
char *titles[] = { "Title1" , "Title2" };
|
|
|
|
scrolled = gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
clist = gtk_clist_new_with_titles(2, titles);
|
|
gtk_container_add(GTK_CONTAINER(scrolled), clist);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I don't want the user of my applications to enter text
|
|
into a GtkCombo. Any idea?</title>
|
|
|
|
<para>A GtkCombo has an associated entry which can be accessed
|
|
using the following expression:</para>
|
|
|
|
<programlisting role="C">
|
|
GTK_COMBO(combo_widget)->entry
|
|
</programlisting>
|
|
|
|
<para>If you don't want the user to be able to modify the
|
|
content of this entry, you can use the
|
|
gtk_entry_set_editable() function:</para>
|
|
|
|
|
|
<programlisting role="C">
|
|
void gtk_entry_set_editable(GtkEntry *entry,
|
|
gboolean editable);
|
|
</programlisting>
|
|
|
|
<para>Set the editable parameter to FALSE to disable typing
|
|
into the entry.</para>
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I catch a combo box change?</title>
|
|
|
|
<para>The entry which is associated to your GtkCombo send a
|
|
"changed" signal when:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>some text is typed in</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>the selection of the combo box is changed</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>To catch any combo box change, simply connect your
|
|
signal handler with</para>
|
|
|
|
<programlisting role="C">
|
|
gtk_signal_connect(GTK_COMBO(cb)->entry,
|
|
"changed",
|
|
GTK_SIGNAL_FUNC(my_cb_change_handler),
|
|
NULL);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How can I define a separation line in a menu?</title>
|
|
|
|
<para>See the <ulink
|
|
url="http://www.gtk.org/tutorial/">Tutorial</ulink> for
|
|
information on how to create menus. However, to create a
|
|
separation line in a menu, just insert an empty menu item:</para>
|
|
|
|
<programlisting role="C">
|
|
menuitem = gtk_menu_item_new();
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How can I right justify a menu, such as Help?</title>
|
|
|
|
<para>Depending on if you use the MenuFactory or not, there
|
|
are two ways to proceed. With the MenuFactory, use something
|
|
like the following:</para>
|
|
|
|
<programlisting role="C">
|
|
menu_path = gtk_menu_factory_find (factory, "<MyApp>/Help");
|
|
gtk_menu_item_right_justify(menu_path->widget);
|
|
</programlisting>
|
|
|
|
<para>If you do not use the MenuFactory, you should simply
|
|
use:</para>
|
|
|
|
|
|
<programlisting role="C">
|
|
gtk_menu_item_right_justify(my_menu_item);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I add some underlined accelerators to menu
|
|
items?</title>
|
|
|
|
<para>Damon Chaplin, the technical force behind the Glade
|
|
project, provided the following code sample (this code is an
|
|
output from Glade). It creates a small <GUIMenu>File</guimenu> menu item
|
|
with only one child (<guimenu>New</guimenu>). The F in
|
|
<guimenu>File</guimenu> and the N in <guimenu>New</guimenu> are
|
|
underlined, and the relevant accelerators are created.</para>
|
|
|
|
<programlisting role="C">
|
|
menubar1 = gtk_menu_bar_new ();
|
|
gtk_object_set_data (GTK_OBJECT (window1), "menubar1", menubar1);
|
|
gtk_widget_show (menubar1);
|
|
gtk_box_pack_start (GTK_BOX (vbox1), menubar1, FALSE, FALSE, 0);
|
|
|
|
file1 = gtk_menu_item_new_with_label ("");
|
|
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (file1)->child),
|
|
_("_File"));
|
|
gtk_widget_add_accelerator (file1, "activate_item", accel_group,
|
|
tmp_key, GDK_MOD1_MASK, 0);
|
|
gtk_object_set_data (GTK_OBJECT (window1), "file1", file1);
|
|
gtk_widget_show (file1);
|
|
gtk_container_add (GTK_CONTAINER (menubar1), file1);
|
|
|
|
file1_menu = gtk_menu_new ();
|
|
file1_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (file1_menu));
|
|
gtk_object_set_data (GTK_OBJECT (window1), "file1_menu", file1_menu);
|
|
gtk_menu_item_set_submenu (GTK_MENU_ITEM (file1), file1_menu);
|
|
|
|
new1 = gtk_menu_item_new_with_label ("");
|
|
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (new1)->child),
|
|
_("_New"));
|
|
gtk_widget_add_accelerator (new1, "activate_item", file1_menu_accels,
|
|
tmp_key, 0, 0);
|
|
gtk_object_set_data (GTK_OBJECT (window1), "new1", new1);
|
|
gtk_widget_show (new1);
|
|
gtk_container_add (GTK_CONTAINER (file1_menu), new1);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How can I retrieve the text from a GtkMenuItem?</title>
|
|
|
|
<para>You can usually retrieve the label of a specific
|
|
GtkMenuItem with:</para>
|
|
|
|
<programlisting role="C">
|
|
if (GTK_BIN (menu_item)->child)
|
|
{
|
|
GtkWidget *child = GTK_BIN (menu_item)->child;
|
|
|
|
/* do stuff with child */
|
|
if (GTK_IS_LABEL (child))
|
|
{
|
|
gchar *text;
|
|
|
|
gtk_label_get (GTK_LABEL (child), &text);
|
|
g_print ("menu item text: %s\n", text);
|
|
}
|
|
}
|
|
</programlisting>
|
|
|
|
<para>To get the active menu item from a GtkOptionMenu you can
|
|
do:</para>
|
|
|
|
<programlisting role="C">
|
|
if (GTK_OPTION_MENU (option_menu)->menu_item)
|
|
{
|
|
GtkWidget *menu_item = GTK_OPTION_MENU (option_menu)->menu_item;
|
|
}
|
|
</programlisting>
|
|
|
|
<para>But, there's a catch. For this specific case, you can
|
|
<emphasis>not</emphasis> get the label widget from
|
|
<literal>menu_item</literal> with the above code, because the
|
|
option menu reparents the menu_item's child temporarily to
|
|
display the currently active contents. So to retrive the child
|
|
of the currently active menu_item of an option menu, you'll
|
|
have to do:</para>
|
|
|
|
<programlisting role="C">
|
|
if (GTK_BIN (option_menu)->child)
|
|
{
|
|
GtkWidget *child = GTK_BIN (option_menu)->child;
|
|
|
|
/* do stuff with child */
|
|
}
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I right (or otherwise) justify a
|
|
GtkLabel?</title>
|
|
|
|
<para>Are you sure you want to <emphasis>justify</emphasis>
|
|
the labels? The label class contains the
|
|
<literal>gtk_label_set_justify()</literal> function that is
|
|
used to control the justification of a multi-line
|
|
label.</para>
|
|
|
|
<para>What you probably want is to set the <emphasis>alignment</emphasis>
|
|
of the label, ie right align it, center it or left align
|
|
it. If you want to do this, you should use:</para>
|
|
|
|
<programlisting role="C">
|
|
void gtk_misc_set_alignment (GtkMisc *misc,
|
|
gfloat xalign,
|
|
gfloat yalign);
|
|
</programlisting>
|
|
|
|
<para>where the <literal>xalign</literal> and
|
|
<literal>yalign</literal> values are floats in
|
|
[0.00;1.00].</para>
|
|
|
|
<programlisting role="C">
|
|
GtkWidget *label;
|
|
|
|
/* horizontal : left align, vertical : top */
|
|
gtk_misc_set_alignment(GTK_MISK(label), 0.0f, 0.0f);
|
|
|
|
/* horizontal : centered, vertical : centered */
|
|
gtk_misc_set_alignment(GTK_MISK(label), 0.5f, 0.5f);
|
|
|
|
/* horizontal : right align, vertical : bottom */
|
|
gtk_misc_set_alignment(GTK_MISK(label), 1.0f, 1.0f);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I set the background color of a GtkLabel
|
|
widget?</title>
|
|
|
|
<para>The Gtklabel widget is one of a few GTK+ widgets that
|
|
don't create their own window to render themselves
|
|
into. Instead, they draw themselves directly onto their
|
|
parents window.</para>
|
|
|
|
<para>This means that in order to set the background color for
|
|
a GtkLabel widget, you need to change the background color of
|
|
its parent, i.e. the object that you pack it into.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I set the color and font of a GtkLabel using a
|
|
Resource File?</title>
|
|
|
|
<para>The widget name path constructed for a Label consists of
|
|
the widget names of its object hierarchy as well, e.g.</para>
|
|
|
|
<para><literallayout>
|
|
<literal>window (name: humphrey)</literal>
|
|
<literal> hbox</literal>
|
|
<literal> label (name: mylabel)</literal>
|
|
</literallayout></para>
|
|
|
|
<para>The widget path your pattern needs to match would be:
|
|
<literal>humphrey.GtkHBox.mylabel</literal></para>
|
|
|
|
<para>The resource file may look something like:</para>
|
|
|
|
<programlisting role="C">
|
|
style "title"
|
|
{
|
|
fg[NORMAL] = {1.0, 0.0, 0.0}
|
|
font = "-adobe-helvetica-bold-r-normal--*-140-*-*-*-*-*-*"
|
|
}
|
|
widget "*mylabel" style "title"
|
|
</programlisting>
|
|
|
|
<para>In your program, you would also need to give a name to
|
|
the Label widget, which can be done using:</para>
|
|
|
|
<programlisting role="C">
|
|
label = gtk_label_new("Some Label Text");
|
|
gtk_widget_set_name(label, "mylabel");
|
|
gtk_widget_show(label);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I configure Tooltips in a Resource File?</title>
|
|
|
|
<para>The tooltip's window is named "gtk-tooltips",
|
|
GtkTooltips in itself is not a GtkWidget (though a GtkObject)
|
|
and as such is not attempted to match any widget styles.</para>
|
|
|
|
<para>So, you resource file should look something like:</para>
|
|
|
|
<programlisting role="C">
|
|
style "postie"
|
|
{
|
|
bg[NORMAL] = {1.0, 1.0, 0.0}
|
|
}
|
|
widget "gtk-tooltips*" style "postie"
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>I can't add more than (something like) 2000 chars in a
|
|
GtkEntry. What's wrong?</title>
|
|
|
|
<para>There is now a known problem in the GtkEntry widget. In
|
|
the <literal>gtk_entry_insert_text()</literal> function, the
|
|
following lines limit the number of chars in the entry to
|
|
2047.</para>
|
|
|
|
<programlisting role="C">
|
|
/* The algorithms here will work as long as, the text size (a
|
|
* multiple of 2), fits into a guint16 but we specify a shorter
|
|
* maximum length so that if the user pastes a very long text, there
|
|
* is not a long hang from the slow X_LOCALE functions. */
|
|
|
|
if (entry->text_max_length == 0)
|
|
max_length = 2047;
|
|
else
|
|
max_length = MIN (2047, entry->text_max_length);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I make a GtkEntry widget activate on pressing
|
|
the Return key?</title>
|
|
|
|
<para>The Entry widget emits an 'activate' signal when you
|
|
press return in it. Just attach to the activate signal on the
|
|
entry and do whatever you want to do. Typical code would
|
|
be:</para>
|
|
|
|
<programlisting role="C">
|
|
entry = gtk_entry_new();
|
|
gtk_signal_connect (GTK_OBJECT(entry), "activate",
|
|
GTK_SIGNAL_FUNC(entry_callback),
|
|
NULL);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I validate/limit/filter the input to a GtkEntry?</title>
|
|
|
|
<para>If you want to validate the text that a user enters into
|
|
a GtkEntry widget you can attach to the "insert_text" signal
|
|
of the entry, and modify the text within the callback
|
|
function. The example below forces all characters to
|
|
uppercase, and limits the range of characters to A-Z. Note
|
|
that the entry is cast to an object of type GtkEditable, from
|
|
which GtkEntry is derived.</para>
|
|
|
|
<programlisting role="C">
|
|
#include <ctype.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
void insert_text_handler (GtkEntry *entry,
|
|
const gchar *text,
|
|
gint length,
|
|
gint *position,
|
|
gpointer data)
|
|
{
|
|
GtkEditable *editable = GTK_EDITABLE(entry);
|
|
int i, count=0;
|
|
gchar *result = g_new (gchar, length);
|
|
|
|
for (i=0; i < length; i++) {
|
|
if (!isalpha(text[i]))
|
|
continue;
|
|
result[count++] = islower(text[i]) ? toupper(text[i]) : text[i];
|
|
}
|
|
|
|
if (count > 0) {
|
|
gtk_signal_handler_block_by_func (GTK_OBJECT (editable),
|
|
GTK_SIGNAL_FUNC (insert_text_handler),
|
|
data);
|
|
gtk_editable_insert_text (editable, result, count, position);
|
|
gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable),
|
|
GTK_SIGNAL_FUNC (insert_text_handler),
|
|
data);
|
|
}
|
|
gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text");
|
|
|
|
g_free (result);
|
|
}
|
|
|
|
int main (int argc,
|
|
char *argv[])
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *entry;
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
/* create a new window */
|
|
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
|
|
gtk_signal_connect(GTK_OBJECT (window), "delete_event",
|
|
(GtkSignalFunc) gtk_exit, NULL);
|
|
|
|
entry = gtk_entry_new();
|
|
gtk_signal_connect(GTK_OBJECT(entry), "insert_text",
|
|
GTK_SIGNAL_FUNC(insert_text_handler),
|
|
NULL);
|
|
gtk_container_add(GTK_CONTAINER (window), entry);
|
|
gtk_widget_show(entry);
|
|
|
|
gtk_widget_show(window);
|
|
|
|
gtk_main();
|
|
return(0);
|
|
}
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I use horizontal scrollbars with a GtkText widget?</title>
|
|
|
|
<para>The short answer is that you can't. The current version
|
|
of the GtkText widget does not support horizontal
|
|
scrolling. There is an intention to completely rewrite the
|
|
GtkText widget, at which time this limitation will be
|
|
removed.</para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I change the font of a GtkText widget?</title>
|
|
|
|
<para>There are a couple of ways of doing this. As GTK+ allows
|
|
the appearance of applications to be changed at run time using
|
|
resources you can use something like the following in the
|
|
appropriate file:</para>
|
|
|
|
<programlisting role="C">
|
|
style "text"
|
|
{
|
|
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
|
|
}
|
|
</programlisting>
|
|
|
|
<para>Another way to do this is to load a font within your
|
|
program, and then use this in the functions for adding text to
|
|
the text widget. You can load a font using, for example:</para>
|
|
|
|
<programlisting role="C">
|
|
GdkFont *font;
|
|
font = gdk_font_load("-adobe-helvetica-medium-r-normal--*-140-*-*-*-*-*-*");
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I set the cursor position in a GtkText
|
|
object?</title>
|
|
|
|
<para>Notice that the response is valid for any object that
|
|
inherits from the GtkEditable class.</para>
|
|
|
|
<para>Are you sure that you want to move the cursor position?
|
|
Most of the time, while the cursor position is good, the
|
|
insertion point does not match the cursor position. If this
|
|
apply to what you really want, then you should use the
|
|
<literal>gtk_text_set_point()</literal> function. If you want
|
|
to set the insertion point at the current cursor position, use
|
|
the following:</para>
|
|
|
|
<programlisting role="C">
|
|
gtk_text_set_point(GTK_TEXT(text),
|
|
gtk_editable_get_position(GTK_EDITABLE(text)));
|
|
</programlisting>
|
|
|
|
<para>If you want the insertion point to follow the cursor at
|
|
all time, you should probably catch the button press event,
|
|
and then move the insertion point. Be careful : you'll have to
|
|
catch it after the widget has changed the cursor position
|
|
though. Thomas Mailund Jensen proposed the following
|
|
code:</para>
|
|
|
|
<programlisting role="C">
|
|
static void
|
|
insert_bar (GtkWidget *text)
|
|
{
|
|
/* jump to cursor mark */
|
|
gtk_text_set_point (GTK_TEXT (text),
|
|
gtk_editable_get_position (GTK_EDITABLE (text)));
|
|
|
|
gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL,
|
|
"bar", strlen ("bar"));
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GtkWidget *window, *text;
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
text = gtk_text_new (NULL, NULL);
|
|
gtk_text_set_editable (GTK_TEXT (text), TRUE);
|
|
gtk_container_add (GTK_CONTAINER (window), text);
|
|
|
|
/* connect after everything else */
|
|
gtk_signal_connect_after (GTK_OBJECT(text), "button_press_event",
|
|
GTK_SIGNAL_FUNC (insert_bar), NULL);
|
|
|
|
gtk_widget_show_all(window);
|
|
gtk_main();
|
|
|
|
return 0;
|
|
}
|
|
</programlisting>
|
|
|
|
<para>Now, if you really want to change the cursor position,
|
|
you should use the
|
|
<literal>gtk_editable_set_position()</literal>
|
|
function.</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>About GDK</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What is GDK?</title>
|
|
|
|
<para>GDK is basically a wrapper around the standard Xlib
|
|
function calls. If you are at all familiar with Xlib, a lot of
|
|
the functions in GDK will require little or no getting used
|
|
to. All functions are written to provide an way to access Xlib
|
|
functions in an easier and slightly more intuitive manner. In
|
|
addition, since GDK uses GLib (see below), it will be more
|
|
portable and safer to use on multiple platforms.</para>
|
|
|
|
<!-- Examples, anybody? I've been mulling some over. NF -->
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How do I use color allocation?</title>
|
|
|
|
<para>One of the nice things about GDK is that it's based on
|
|
top of Xlib; this is also a problem, especially in the area of
|
|
color management. If you want to use color in your program
|
|
(drawing a rectangle or such, your code should look something
|
|
like this:</para>
|
|
|
|
<programlisting role="C">
|
|
{
|
|
GdkColor *color;
|
|
int width, height;
|
|
GtkWidget *widget;
|
|
GdkGC *gc;
|
|
|
|
...
|
|
|
|
/* first, create a GC to draw on */
|
|
gc = gdk_gc_new(widget->window);
|
|
|
|
/* find proper dimensions for rectangle */
|
|
gdk_window_get_size(widget->window, &width, &height);
|
|
|
|
/* the color we want to use */
|
|
color = (GdkColor *)malloc(sizeof(GdkColor));
|
|
|
|
/* red, green, and blue are passed values, indicating the RGB triple
|
|
* of the color we want to draw. Note that the values of the RGB components
|
|
* within the GdkColor are taken from 0 to 65535, not 0 to 255.
|
|
*/
|
|
color->red = red * (65535/255);
|
|
color->green = green * (65535/255);
|
|
color->blue = blue * (65535/255);
|
|
|
|
/* the pixel value indicates the index in the colormap of the color.
|
|
* it is simply a combination of the RGB values we set earlier
|
|
*/
|
|
color->pixel = (gulong)(red*65536 + green*256 + blue);
|
|
|
|
/* However, the pixel valule is only truly valid on 24-bit (TrueColor)
|
|
* displays. Therefore, this call is required so that GDK and X can
|
|
* give us the closest color available in the colormap
|
|
*/
|
|
gdk_color_alloc(gtk_widget_get_colormap(widget), color);
|
|
|
|
/* set the foreground to our color */
|
|
gdk_gc_set_foreground(gc, color);
|
|
|
|
/* draw the rectangle */
|
|
gdk_draw_rectangle(widget->window, gc, 1, 0, 0, width, height);
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect1>
|
|
<title>About GLib</title>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What is GLib?</title>
|
|
|
|
<para>GLib is a library of useful functions and definitions
|
|
available for use when creating GDK and GTK applications. It
|
|
provides replacements for some standard libc functions, such
|
|
as malloc, which are buggy on some systems.</para>
|
|
|
|
<para>It also provides routines for handling:</para>
|
|
|
|
<itemizedlist spacing=compact>
|
|
<listitem><simpara>Doubly Linked Lists</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Singly Linked Lists</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Timers</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>String Handling</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>A Lexical Scanner</simpara>
|
|
</listitem>
|
|
|
|
<listitem><simpara>Error Functions</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>How can I use the doubly linked lists?</title>
|
|
|
|
<para>The GList object is defined as:</para>
|
|
|
|
<programlisting role="C">
|
|
typedef struct _GList GList;
|
|
|
|
struct _GList
|
|
{
|
|
gpointer data;
|
|
GList *next;
|
|
GList *prev;
|
|
};
|
|
</programlisting>
|
|
|
|
<para>To use the GList objects, simply:</para>
|
|
|
|
<programlisting role="C">
|
|
GList *list = NULL;
|
|
GList *listrunner;
|
|
gint array[] = { 1, 2, 3, 4, 5, 6 };
|
|
gint pos;
|
|
gint *value;
|
|
|
|
/* add data to the list */
|
|
for (pos=0;pos < sizeof array; pos++) {
|
|
list = g_list_append(list, (gpointer)&array[pos]);
|
|
}
|
|
|
|
/* run through the list */
|
|
listrunner = g_list_first(list);
|
|
while (listrunner) {
|
|
value = (gint *)listrunner->data;
|
|
printf("%d\n", *value);
|
|
listrunner = g_list_next(listrunner);
|
|
}
|
|
|
|
/* removing datas from the list */
|
|
listrunner = g_list_first(list);
|
|
list = g_list_remove_link(list, listrunner);
|
|
list = g_list_remove(list, &array[4]);
|
|
</programlisting>
|
|
|
|
<para>The same code is usable with singly linked lists (GSList
|
|
objects) by replacing g_list_* functions with the relevant
|
|
g_slist_* ones (g_slist_append, g_slist_remove, ...). Just
|
|
remember that since you can't go backward in a singly linked
|
|
list, there is no g_slist_first function - you'll need to keep
|
|
a reference on the first node of the list.</para>
|
|
|
|
<!-- Some Examples might be useful here! NF -->
|
|
<!-- I believe it should be better :) ED -->
|
|
<!-- Linked lists are pretty standard data structures - don't want to
|
|
over do it - TRG -->
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Memory does not seem to be released when I free the
|
|
list nodes I've allocated</title>
|
|
|
|
<para>GLib tries to be "intelligent" on this special issue: it
|
|
assumes that you are likely to reuse the objects, so caches
|
|
the allocated memory. If you do not want to use this behavior,
|
|
you'll probably want to set up a special allocator.</para>
|
|
|
|
<para>To quote Tim Janik:</para>
|
|
<para><quote>If you have a certain portion of code that uses *lots*
|
|
of GLists or GNodes, and you know you'd better want to release
|
|
all of them after a short while, you'd want to use a
|
|
GAllocator. Pushing an allocator into g_list will make all
|
|
subsequent glist operations private to that allocator's memory
|
|
pool (and thus you have to take care to pop the allocator
|
|
again, before making any external calls): </quote></para>
|
|
|
|
<programlisting role="C">
|
|
GAllocator *allocator;
|
|
GList *list = NULL;
|
|
guint i;
|
|
|
|
/* set a new allocation pool for GList nodes */
|
|
allocator = g_allocator_new ("list heap", 1024);
|
|
g_list_push_allocator (allocator);
|
|
|
|
/* do some list operations */
|
|
for (i = 0; i < 4096; i++)
|
|
list = g_list_prepend (list, NULL);
|
|
list = g_list_reverse (list);
|
|
|
|
/* beware to pop allocator befor calling external functions */
|
|
g_list_pop_allocator ();
|
|
gtk_label_set_text (GTK_LABEL (some_label), "some text");
|
|
|
|
/* and set our private glist pool again */
|
|
g_list_push_allocator (allocator);
|
|
|
|
/* do some list operations */
|
|
g_list_free (list);
|
|
list = NULL;
|
|
for (i = 0; i < 4096; i++)
|
|
list = g_list_prepend (list, NULL);
|
|
|
|
/* and back out (while freeing all of the list nodes in our pool) */
|
|
g_list_pop_allocator ();
|
|
g_allocator_free (allocator);
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>Why use g_print, g_malloc, g_strdup and fellow glib
|
|
functions?</title>
|
|
|
|
<para>Thanks to Tim Janik who wrote to gtk-list: (slightly
|
|
modified)</para>
|
|
|
|
<para><quote>Regarding g_malloc(), g_free() and siblings, these
|
|
functions are much safer than their libc equivalents. For
|
|
example, g_free() just returns if called with NULL. Also, if
|
|
USE_DMALLOC is defined, the definition for these functions
|
|
changes (in glib.h) to use MALLOC(), FREE() etc... If
|
|
MEM_PROFILE or MEM_CHECK are defined, there are even small
|
|
statistics made counting the used block sizes (shown by
|
|
g_mem_profile() / g_mem_check()).</quote></para>
|
|
|
|
<para><quote>Considering the fact that glib provides an interface for
|
|
memory chunks to save space if you have lots of blocks that
|
|
are always the same size and to mark them ALLOC_ONLY if
|
|
needed, it is just straight forward to create a small saver
|
|
(debug able) wrapper around the normal malloc/free stuff as
|
|
well - just like gdk covers Xlib. ;)</quote></para>
|
|
|
|
<para><quote>Using g_error() and g_warning() inside of applications
|
|
like the GIMP that fully rely on gtk even gives the
|
|
opportunity to pop up a window showing the messages inside of
|
|
a gtk window with your own handler (by using
|
|
g_set_error_handler()) along the lines of
|
|
<literal>gtk_print()</literal> (inside of
|
|
gtkmain.c).</quote></para>
|
|
|
|
</sect2>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect2>
|
|
<title>What's a GScanner and how do I use one?</title>
|
|
|
|
<para>A GScanner will tokenize your text, that is, it'll return
|
|
an integer for every word or number that appears in its input
|
|
stream, following certain (customizable) rules to perform this
|
|
translation. You still need to write the parsing functions on
|
|
your own though.</para>
|
|
|
|
<para>Here's a little test program supplied by Tim Janik that
|
|
will parse</para>
|
|
|
|
<para><literallayout>
|
|
<literal><SYMBOL> = <OPTIONAL-MINUS> <NUMBER> ;</literal>
|
|
</literallayout></para>
|
|
|
|
<para>constructs, while skipping "#\n" and "/**/" style
|
|
comments.</para>
|
|
|
|
<programlisting role="C">
|
|
#include <glib.h>
|
|
|
|
/* some test text to be fed into the scanner */
|
|
static const gchar *test_text =
|
|
( "ping = 5;\n"
|
|
"/* slide in some \n"
|
|
" * comments, just for the\n"
|
|
" * fun of it \n"
|
|
" */\n"
|
|
"pong = -6; \n"
|
|
"\n"
|
|
"# the next value is a float\n"
|
|
"zonk = 0.7;\n"
|
|
"# redefine ping\n"
|
|
"ping = - 0.5;\n" );
|
|
|
|
/* define enumeration values to be returned for specific symbols */
|
|
enum {
|
|
SYMBOL_PING = G_TOKEN_LAST + 1,
|
|
SYMBOL_PONG = G_TOKEN_LAST + 2,
|
|
SYMBOL_ZONK = G_TOKEN_LAST + 3
|
|
};
|
|
|
|
/* symbol array */
|
|
static const struct {
|
|
gchar *symbol_name;
|
|
guint symbol_token;
|
|
} symbols[] = {
|
|
{ "ping", SYMBOL_PING, },
|
|
{ "pong", SYMBOL_PONG, },
|
|
{ "zonk", SYMBOL_ZONK, },
|
|
{ NULL, 0, },
|
|
}, *symbol_p = symbols;
|
|
|
|
static gfloat ping = 0;
|
|
static gfloat pong = 0;
|
|
static gfloat zonk = 0;
|
|
|
|
static guint
|
|
parse_symbol (GScanner *scanner)
|
|
{
|
|
guint symbol;
|
|
gboolean negate = FALSE;
|
|
|
|
/* expect a valid symbol */
|
|
g_scanner_get_next_token (scanner);
|
|
symbol = scanner->token;
|
|
if (symbol < SYMBOL_PING ||
|
|
symbol > SYMBOL_ZONK)
|
|
return G_TOKEN_SYMBOL;
|
|
|
|
/* expect '=' */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != '=')
|
|
return '=';
|
|
|
|
/* feature optional '-' */
|
|
g_scanner_peek_next_token (scanner);
|
|
if (scanner->next_token == '-')
|
|
{
|
|
g_scanner_get_next_token (scanner);
|
|
negate = !negate;
|
|
}
|
|
|
|
/* expect a float (ints are converted to floats on the fly) */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != G_TOKEN_FLOAT)
|
|
return G_TOKEN_FLOAT;
|
|
|
|
/* make sure the next token is a ';' */
|
|
if (g_scanner_peek_next_token (scanner) != ';')
|
|
{
|
|
/* not so, eat up the non-semicolon and error out */
|
|
g_scanner_get_next_token (scanner);
|
|
return ';';
|
|
}
|
|
|
|
/* assign value, eat the semicolon and exit successfully */
|
|
switch (symbol)
|
|
{
|
|
case SYMBOL_PING:
|
|
ping = negate ? - scanner->value.v_float : scanner->value.v_float;
|
|
break;
|
|
case SYMBOL_PONG:
|
|
pong = negate ? - scanner->value.v_float : scanner->value.v_float;
|
|
break;
|
|
case SYMBOL_ZONK:
|
|
zonk = negate ? - scanner->value.v_float : scanner->value.v_float;
|
|
break;
|
|
}
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
return G_TOKEN_NONE;
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GScanner *scanner;
|
|
guint expected_token;
|
|
|
|
scanner = g_scanner_new (NULL);
|
|
|
|
/* adjust lexing behaviour to suit our needs
|
|
*/
|
|
/* convert non-floats (octal values, hex values...) to G_TOKEN_INT */
|
|
scanner->config->numbers_2_int = TRUE;
|
|
/* convert G_TOKEN_INT to G_TOKEN_FLOAT */
|
|
scanner->config->int_2_float = TRUE;
|
|
/* don't return G_TOKEN_SYMBOL, but the symbol's value */
|
|
scanner->config->symbol_2_token = TRUE;
|
|
|
|
/* load symbols into the scanner */
|
|
while (symbol_p->symbol_name)
|
|
{
|
|
g_scanner_add_symbol (scanner,
|
|
symbol_p->symbol_name,
|
|
GINT_TO_POINTER (symbol_p->symbol_token));
|
|
symbol_p++;
|
|
}
|
|
|
|
/* feed in the text */
|
|
g_scanner_input_text (scanner, test_text, strlen (test_text));
|
|
|
|
/* give the error handler an idea on how the input is named */
|
|
scanner->input_name = "test text";
|
|
|
|
/* scanning loop, we parse the input until its end is reached,
|
|
* the scanner encountered a lexing error, or our sub routine came
|
|
* across invalid syntax
|
|
*/
|
|
do
|
|
{
|
|
expected_token = parse_symbol (scanner);
|
|
|
|
g_scanner_peek_next_token (scanner);
|
|
}
|
|
while (expected_token == G_TOKEN_NONE &&
|
|
scanner->next_token != G_TOKEN_EOF &&
|
|
scanner->next_token != G_TOKEN_ERROR);
|
|
|
|
/* give an error message upon syntax errors */
|
|
if (expected_token != G_TOKEN_NONE)
|
|
g_scanner_unexp_token (scanner, expected_token, NULL, "symbol", NULL, NULL, TRUE);
|
|
|
|
/* finsish parsing */
|
|
g_scanner_destroy (scanner);
|
|
|
|
/* print results */
|
|
g_print ("ping: %f\n", ping);
|
|
g_print ("pong: %f\n", pong);
|
|
g_print ("zonk: %f\n", zonk);
|
|
|
|
return 0;
|
|
}
|
|
</programlisting>
|
|
|
|
<para>You need to understand that the scanner will parse its
|
|
input and tokenize it, it is up to you to interpret these
|
|
tokens, not define their types before they get parsed,
|
|
e.g. watch gscanner parse a string:</para>
|
|
|
|
<para><literallayout>
|
|
<literal>"hi i am 17"</literal>
|
|
<literal> | | | |</literal>
|
|
<literal> | | | v</literal>
|
|
<literal> | | v TOKEN_INT, value: 17</literal>
|
|
<literal> | v TOKEN_IDENTIFIER, value: "am"</literal>
|
|
<literal> v TOKEN_CHAR, value: 'i'</literal>
|
|
<literal>TOKEN_IDENTIFIER, value: "hi"</literal>
|
|
</literallayout></para>
|
|
|
|
<para>If you configure the scanner with:</para>
|
|
|
|
<programlisting role="C">
|
|
scanner->config->int_2_float = TRUE;
|
|
scanner->config->char_2_token = TRUE;
|
|
scanner->config->scan_symbols = TRUE;
|
|
</programlisting>
|
|
|
|
<para>and add "am" as a symbol with</para>
|
|
|
|
<programlisting role="C">
|
|
g_scanner_add_symbol (scanner, "am", "symbol value");
|
|
</programlisting>
|
|
|
|
<para>GScanner will parse it as</para>
|
|
|
|
<para><literallayout>
|
|
<literal>"hi i am 17"</literal>
|
|
<literal> | | | |</literal>
|
|
<literal> | | | v</literal>
|
|
<literal> | | v TOKEN_FLOAT, value: 17.0 (automatic int->float conversion)</literal>
|
|
<literal> | | TOKEN_SYMBOL, value: "symbol value" (a successfull hash table lookup</literal>
|
|
<literal> | | turned a TOKEN_IDENTIFIER into a</literal>
|
|
<literal> | | TOKEN_SYMBOL and took over the</literal>
|
|
<literal> | v symbol's value)</literal>
|
|
<literal> v 'i' ('i' can be a valid token as well, as all chars >0 and <256)</literal>
|
|
<literal>TOKEN_IDENTIFIER, value: "hi"</literal>
|
|
</literallayout></para>
|
|
|
|
<para>You need to match the token sequence with your code, and
|
|
if you encounter something that you don't want, you error
|
|
out:</para>
|
|
|
|
<programlisting role="C">
|
|
/* expect an identifier ("hi") */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != G_TOKEN_IDENTIFIER)
|
|
return G_TOKEN_IDENTIFIER;
|
|
/* expect a token 'i' */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != 'i')
|
|
return 'i';
|
|
/* expect a symbol ("am") */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != G_TOKEN_SYMBOL)
|
|
return G_TOKEN_SYMBOL;
|
|
/* expect a float (17.0) */
|
|
g_scanner_get_next_token (scanner);
|
|
if (scanner->token != G_TOKEN_FLOAT)
|
|
return G_TOKEN_FLOAT;
|
|
</programlisting>
|
|
|
|
<para>If you got past here, you have parsed "hi i am 17" and
|
|
would have accepted "dooh i am 42" and "bah i am 0.75" as
|
|
well, but you would have not accepted "hi 7 am 17" or "hi i hi
|
|
17".</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
<sect1>
|
|
<title>GTK+ FAQ Contributions, Maintainers and Copyright</title>
|
|
|
|
<para>If you would like to make a contribution to the FAQ, send either one
|
|
of us an e-mail message with the exact text you think should be
|
|
included (question and answer). With your help, this document can grow
|
|
and become more useful!</para>
|
|
|
|
<para>This document is maintained by
|
|
Tony Gale
|
|
<ulink url="mailto:gale@gtk.org"><gale@gtk.org></ulink>
|
|
|
|
Nathan Froyd
|
|
<ulink url="mailto:maestrox@geocities.com">
|
|
<maestrox@geocities.com></ulink>,
|
|
and
|
|
Emmanuel Deloget
|
|
<ulink url="mailto:logout@free.fr"><logout@free.fr></ulink>.
|
|
|
|
This FAQ was created by Shawn T. Amundson
|
|
<ulink url="mailto:amundson@gimp.org">
|
|
<amundson@gimp.org></ulink> who continues to provide support.
|
|
|
|
Contributions should be sent to Tony Gale <ulink
|
|
url="mailto:gale@gtk.org"><gale@gtk.org></ulink></para>
|
|
|
|
<para>The GTK+ FAQ is Copyright (C) 1997-2000 by Shawn T. Amundson,
|
|
Tony Gale, Emmanuel Deloget and Nathan Froyd.</para>
|
|
|
|
<para>Permission is granted to make and distribute verbatim copies of this
|
|
manual provided the copyright notice and this permission notice are
|
|
preserved on all copies.</para>
|
|
|
|
<para>Permission is granted to copy and distribute modified versions of this
|
|
document under the conditions for verbatim copying, provided that this
|
|
copyright notice is included exactly as in the original, and that the
|
|
entire resulting derived work is distributed under the terms of a
|
|
permission notice identical to this one.</para>
|
|
|
|
<para>Permission is granted to copy and distribute translations of this
|
|
document into another language, under the above conditions for
|
|
modified versions.</para>
|
|
|
|
<para>If you are intending to incorporate this document into a published
|
|
work, please contact one of the maintainers, and we will make an
|
|
effort to ensure that you have the most up to date information
|
|
available.</para>
|
|
|
|
<para>There is no guarentee that this document lives up to its intended
|
|
purpose. This is simply provided as a free resource. As such, the
|
|
authors and maintainers of the information provided within can not
|
|
make any guarentee that the information is even accurate.</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
</book>
|