forked from AuroraMiddleware/gtk
f3fcdb4e0e
Mon Nov 15 17:17:51 GMT 1999 Tony Gale <gale@gtk.org> * docs/gtkfaq.sgml: s/gtk_main_iteration/g_main_iteration/
2610 lines
87 KiB
Plaintext
2610 lines
87 KiB
Plaintext
<!doctype linuxdoc system>
|
|
|
|
<article>
|
|
|
|
<!-- Title information -->
|
|
|
|
<title>GTK+ FAQ
|
|
|
|
<!-- NOTE: Use only one author tag, otherwise sgml2txt barfs - TRG -->
|
|
<author>Tony Gale, Shawn T. Amundson, Emmanuel Deloget, Nathan Froyd
|
|
|
|
<date>November 9th 1999
|
|
|
|
<abstract> 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+.
|
|
</abstract>
|
|
|
|
<!-- Table of contents -->
|
|
<toc>
|
|
|
|
<!-- Begin the document -->
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>General Information
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Before anything else: the greetings
|
|
<p>
|
|
The FAQ authors want to thank:
|
|
<itemize>
|
|
<item>Havoc Pennington
|
|
<item>Erik Mouw
|
|
<item>Owen Taylor
|
|
<item>Tim Janik
|
|
<item>Thomas Mailund Jensen
|
|
<item>Joe Pfeiffer
|
|
<item>Andy Kahn
|
|
<item>Federico Mena Quintero
|
|
<item>Damon Chaplin
|
|
<item>and all the members of the GTK+ lists
|
|
</itemize>
|
|
If we forgot you, please email us !
|
|
Thanks again (I know, it's really short :)
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Authors
|
|
<p>
|
|
The original authors of GTK+ were:
|
|
|
|
<itemize>
|
|
<item>Peter Mattis
|
|
<item>Spencer Kimball
|
|
<item>Josh MacDonald
|
|
</itemize>
|
|
|
|
Since then, much has been added by others. Please see the AUTHORS
|
|
file in the distribution for the GTK+ Team.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What is GTK+?
|
|
<p>
|
|
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.
|
|
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What is the + in GTK+?
|
|
<P>
|
|
Peter Mattis informed the gtk mailing list that:
|
|
<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>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Does the G in GTK+, GDK and GLib stand for?
|
|
<p>
|
|
GTK+ == Gimp Toolkit
|
|
|
|
GDK == Gtk+ Drawing Kit
|
|
|
|
GLib == G Libray
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Where is the documentation for GTK+?
|
|
<p>
|
|
In the GTK+ distribution's doc/ directory you will find the
|
|
reference material for both GTK and GDK, this FAQ and the
|
|
GTK Tutorial.
|
|
|
|
In addition, you can find links to HTML versions of these documents
|
|
by going to <htmlurl url="http://www.gtk.org/"
|
|
name="http://www.gtk.org/">. A packaged version of the GTK Tutorial,
|
|
with SGML, HTML, Postscript, DVI and text versions can be found in
|
|
<htmlurl url="ftp://ftp.gtk.org/pub/gtk/tutorial"
|
|
name="ftp://ftp.gtk.org/pub/gtk/tutorial">
|
|
|
|
There are now a couple of books available that deal with programming
|
|
GTK+, GDK and GNOME:
|
|
<itemize>
|
|
<item> Eric Harlows book entitled "Developing Linux Applications with
|
|
GTK+ and GDK". The ISBN is 0-7357-0021-4
|
|
<P>
|
|
The example code from Eric's book is available on-line at
|
|
<htmlurl url="http://www.bcpl.net/~eharlow/book"
|
|
name="http://www.bcpl.net/~eharlow/book">
|
|
|
|
<item> Havoc Pennington has released a book called "GTK+/GNOME
|
|
Application Development". The ISBN is 0-7357-0078-8
|
|
<P>
|
|
The free version of the book lives here:
|
|
<htmlurl url="http://developer.gnome.org/doc/GGAD/"
|
|
name="http://developer.gnome.org/doc/GGAD/">
|
|
<P>
|
|
And Havoc maintains information about it and errata here:
|
|
<htmlurl url="http://pobox.com/~hp/gnome-app-devel.html"
|
|
name="http://pobox.com/~hp/gnome-app-devel.html">
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Is there a mailing list (or mailing list archive) for GTK+?
|
|
<p>
|
|
Information on mailing lists relating to GTK+ can be found at:
|
|
|
|
<htmlurl url="http://www.gtk.org/mailinglists.html"
|
|
name="http://www.gtk.org/mailinglists.html">
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How to get help with GTK+
|
|
<p>
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How to report bugs in GTK+
|
|
<p>
|
|
Bugs should be reported to the GNOME bug tracking
|
|
system (<htmlurl url="http://bugs.gnome.org"
|
|
name="http://bugs.gnome.org">). To report a problem about GTK+, send
|
|
mail to submit@bugs.gnome.org.
|
|
|
|
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.
|
|
|
|
<verb>
|
|
Package: gtk+
|
|
Version: 1.2.0
|
|
</verb>
|
|
|
|
Substitute 1.2.0 with the version of GTK+ that you have installed.
|
|
|
|
Then describe the bug. Include:
|
|
|
|
<itemize>
|
|
<item> Information about your system. For instance:
|
|
<itemize>
|
|
<item> What operating system and version
|
|
<item> What version of X
|
|
<item> For Linux, what version of the C library
|
|
</itemize>
|
|
And anything else you think is relevant.
|
|
|
|
<item> How to reproduce the bug.
|
|
|
|
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.
|
|
|
|
(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)
|
|
|
|
<item> If the bug was a crash, the exact text that was printed out
|
|
when the crash occured.
|
|
|
|
<item> 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 <tt/--sync/ command line option.
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Is there a Windows version of GTK+?
|
|
<p>
|
|
There is an on going port of GTK+ to the Windows platform which is
|
|
making impressive progress.
|
|
|
|
See <htmlurl url="http://www.iki.fi/tml/gimp/win32"
|
|
name="http://www.iki.fi/tml/gimp/win32"> for more information.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What applications have been written with GTK+?
|
|
<p>
|
|
A list of some GTK+ based application can be found on the GTK+ web
|
|
server at <htmlurl url="http://www.gtk.org/apps/"
|
|
name="http://www.gtk.org/apps/"> and contains more than 350
|
|
applications.
|
|
|
|
Failing that, look for a project to work on for the GNOME project,
|
|
<htmlurl url="http://www.gnome.org/" name="http://www.gnome.org/">
|
|
Write a game. Write something that is useful.
|
|
|
|
Some of these are:
|
|
<itemize>
|
|
<item>GIMP (<htmlurl url="http://www.gimp.org/"
|
|
name="http://www.gimp.org/">),
|
|
an image manipulation program
|
|
<item>AbiWord (<htmlurl url="http://www.abisource.com/"
|
|
name="http://www.abisource.com/">),
|
|
a professional word processor
|
|
<item>GUBI (<htmlurl url="http://www.SoftHome.net/pub/users/timj/gubi/index.htm"
|
|
name="http://www.SoftHome.net/pub/users/timj/gubi/index.htm">),
|
|
a user interface builder
|
|
<item>Gzilla (<htmlurl url="http://www.levien.com/gzilla/"
|
|
name="http://www.levien.com/gzilla/">),
|
|
a web browser
|
|
<item>SANE (<htmlurl url="http://www.azstarnet.com/~axplinux/sane/"
|
|
name="http://www.azstarnet.com/~axplinux/sane/"> ),
|
|
a universal scanner interface
|
|
<item>XQF (<htmlurl url="http://www.botik.ru/~roma/quake/"
|
|
name="http://www.botik.ru/~roma/quake/">),
|
|
a QuakeWorld/Quake2 server browser and launcher
|
|
<item>ElectricEyes (<htmlurl url="http://www.labs.redhat.com/ee.shtml"
|
|
name="http://www.labs.redhat.com/ee.shtml">),
|
|
an image viewer that aims to be a free replacement for xv
|
|
<item>GPK - the General Proxy Kit (<htmlurl url="http://www.humanfactor.com/gpk/"
|
|
name="http://www.humanfactor.com/gpk/">),
|
|
an add-on library to permit thread-safe access to GTK+
|
|
<item>GCK - the General Convenience Kit (<htmlurl url="http://www.ii.uib.no/~tomb/gck.html"
|
|
name="http://www.ii.uib.no/~tomb/gck.html">),
|
|
miscellaneous functions intended to ease color handling, UI construction,
|
|
vector operations, and math functions
|
|
<item>GDK Imlib (<htmlurl url="http://www.labs.redhat.com/imlib/"
|
|
name="http://www.labs.redhat.com/imlib/">),
|
|
a fast image loading and manipulation library for GDK
|
|
<item>Glade (<htmlurl url="http://glade.pn.org/"
|
|
name="http://glade.pn.org/">),
|
|
a GTK+ based RAD tool which produces GTK+ applications
|
|
</itemize>
|
|
<p>
|
|
In addition to the above, the GNOME project (<htmlurl
|
|
url="http://www.gnome.org" name="http://www.gnome.org">) is using GTK+
|
|
to build a free desktop for Linux. Many more programs can be found
|
|
there.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I'm looking for an application to write in GTK+. How about an IRC client?
|
|
<p>
|
|
|
|
Ask on gtk-list for suggestions. There are at least three IRC clients
|
|
already under development (probably more in fact. The server at
|
|
<htmlurl url="http://www.forcix.cx/irc-clients.html"
|
|
name="http://www.forcix.cx/irc-clients.html"> list a bunch of them).
|
|
|
|
<itemize>
|
|
<item>X-Chat.
|
|
<item>girc. (Included with GNOME)
|
|
<item>gsirc. (In the gnome CVS tree)
|
|
</itemize>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>How to find, configure, install, and troubleshoot GTK+
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What do I need to run GTK+?
|
|
<p>
|
|
To compile GTK+, all you need is a C compiler (gcc) and the X Window System
|
|
and associated libraries on your system.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Where can I get GTK+?
|
|
<p>
|
|
The canonical site is:
|
|
<verb>
|
|
ftp://ftp.gtk.org/pub/gtk
|
|
</verb>
|
|
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
|
|
<htmlurl url="ftp://ftp.gtk.org/etc/mirrors"
|
|
name="ftp://ftp.gtk.org/etc/mirrors">
|
|
|
|
Here's a few mirror sites to get you started:
|
|
<itemize>
|
|
<item>Africa - ftp://ftp.is.co.za/applications/gimp/
|
|
<item>Australia - ftp://ftp.au.gimp.org/pub/gimp/
|
|
<item>Finland - ftp://ftp.funet.fi/pub/sci/graphics/packages/gimp
|
|
<item>Germany - ftp://infosoc.uni-koeln.de/pub/ftp.gimp.org/
|
|
<item>Japan - ftp://SunSITE.sut.ac.jp/pub/archives/packages/gimp/
|
|
<item>UK - ftp://ftp.flirble.org/pub/X/gimp/
|
|
<item>US - ftp://ftp.insync.net/pub/mirrors/ftp.gimp.org/
|
|
</itemize>
|
|
|
|
<sect1>How do I configure/compile GTK+?
|
|
<p>
|
|
Generally, all you will need to do is issue the commands:
|
|
<verb>
|
|
./configure
|
|
make
|
|
</verb>
|
|
in the gtk+-version/ directory.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>When compiling GTK+ I get an error like:
|
|
<tt/make: file `Makefile' line 456: Syntax error/
|
|
<p>
|
|
Make sure that you are using GNU make (use <tt/make -v/ to check). There are
|
|
many weird and wonderful versions of make out there, and not all of them
|
|
handle the automatically generated Makefiles.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect1>I've compiled and installed GTK+, but I can't get any programs to link with it!
|
|
<p>
|
|
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:
|
|
<itemize>
|
|
<item>Make sure that the libraries can be found. You want to edit
|
|
/etc/ld.so.conf to include the directories which contain the GTK libraries,
|
|
so it looks something like:
|
|
<verb>
|
|
/usr/X11R6/lib
|
|
/usr/local/lib
|
|
</verb>
|
|
Then you need to run /sbin/ldconfig as root. You can find what directory
|
|
GTK is in using
|
|
<verb>
|
|
gtk-config --libs
|
|
</verb>
|
|
|
|
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):
|
|
<verb>
|
|
export LD_LIBRARY_PATH=/usr/local/lib
|
|
</verb>
|
|
and in a csh, you can do:
|
|
<verb>
|
|
setenv LD_LIBRARY_PATH /usr/local/lib
|
|
</verb>
|
|
|
|
<item>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
|
|
<verb>
|
|
rpm -e gtk gtk-devel
|
|
</verb>
|
|
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 <verb>/usr/lib</verb> or <verb>/usr/local/lib</verb> contain any of
|
|
the libraries libgtk, libgdk, libglib, or libgck. If they do exist, remove them
|
|
(and any gtk include files, such as /usr/include/gtk and /usr/include/gdk)
|
|
and reinstall gtk+.
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>When compiling programs with GTK+, I get compiler error messages about not being able to find <tt/"glibconfig.h"/.
|
|
<p>
|
|
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/.
|
|
|
|
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.
|
|
|
|
GTK+ includes a shell script, <tt/gtk-config/, that
|
|
makes it easy to find out the correct include paths.
|
|
The GTK+ tutorial includes an example of using <tt/gtk-config/
|
|
for simple compilation from the command line. For information
|
|
about more complicated configuration, see the file
|
|
docs/gtk-config.txt in the GTK+ distribution.
|
|
|
|
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:
|
|
|
|
<tscreen><verb>
|
|
CPPFLAGS="-I/usr/local/include/glib/include" ./configure
|
|
</verb></tscreen>
|
|
|
|
for Bourne-compatible shells like bash, or for csh variants:
|
|
|
|
<tscreen><verb>
|
|
setenv CPPFLAGS "-I/usr/local/include/glib/include"
|
|
./configure
|
|
</verb></tscreen>
|
|
|
|
(Substitute the appropriate value of $exec_prefix for /usr/local.)
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>When installing a GTK+ application, configure reports that it can't find GTK.
|
|
<p>
|
|
There are several common reasons for this:
|
|
<itemize>
|
|
<item>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 <tt/control-panel/ applications.
|
|
<P>
|
|
<item><tt/gtk-config/ (or another component of GTK) isn't in your path, or
|
|
there is an old version on your system. Type:
|
|
<verb>
|
|
gtk-config --version
|
|
</verb>
|
|
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.
|
|
<P>
|
|
<item>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.
|
|
</itemize>
|
|
<p>
|
|
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.
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>Development of GTK+
|
|
<!-- ***************************************************************** -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Whats this CVS thing that everyone keeps talking about, and how do I access it?
|
|
<p>
|
|
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.
|
|
|
|
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.
|
|
|
|
The CVS toolset is available as RPM packages from the usual RedHat sites.
|
|
The latest version is available at
|
|
<htmlurl url="http://download.cyclic.com/pub/"
|
|
name="<http://download.cyclic.com/pub/>">
|
|
|
|
Anyone can download the latest CVS version of GTK+ by using anonymous access
|
|
using the following steps:
|
|
<itemize>
|
|
<item> In a bourne shell descendant (e.g. bash) type:
|
|
<verb>
|
|
CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome'
|
|
export CVSROOT
|
|
</verb>
|
|
<item>Next, the first time the source tree is checked out, a cvs login
|
|
is needed.
|
|
<verb>
|
|
cvs login
|
|
</verb>
|
|
This will ask you for a password. There is no password for cvs.gimp.org,
|
|
so just enter a carriage return.
|
|
<item>To get the tree and place it in a subdir of your current working
|
|
directory, issue the command:
|
|
<verb>
|
|
cvs -z3 get gtk+
|
|
</verb>
|
|
|
|
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:
|
|
<verb>
|
|
cvs -z3 get glib
|
|
</verb>
|
|
|
|
</itemize>
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How can I contribute to GTK+?
|
|
<p>
|
|
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 <tt/diff -ru <oldfile> <newfile>/.
|
|
Then upload the patchfile to:
|
|
<verb>
|
|
ftp://ftp.gtk.org/incoming
|
|
</verb>
|
|
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:
|
|
<verb>
|
|
gtk-<username>-<date yymmdd-n>.patch.gz
|
|
gtk-<username>-<date yymmdd-n>.patch.README
|
|
</verb>
|
|
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.
|
|
|
|
Example:
|
|
<verb>
|
|
gtk-gale-982701-0.patch.gz
|
|
gtk-gale-982701-0.patch.README
|
|
</verb>
|
|
Once you upload <em>anything</em>, send the README to ftp-admin@gtk.org
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I know if my patch got applied, and if not, why not?
|
|
<p>
|
|
Uploaded patches will be moved to <tt>ftp://ftp.gtk.org/pub/gtk/patches</tt>
|
|
where one of the GTK+ development team will pick them up. If applied, they
|
|
will be moved to <tt>/pub/gtk/patches/old</tt>.
|
|
|
|
Patches that aren't applied, for whatever reason, are moved to
|
|
<tt>/pub/gtk/patches/unapplied</tt> or <tt>/pub/gtk/patches/outdated</tt>.
|
|
At this point you can ask on the <tt/gtk-list/ 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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What is the policy on incorporating new widgets into the library?
|
|
<p>
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Is anyone working on bindings for languages other than C?
|
|
<p>
|
|
The GTK+ home page (<htmlurl url="http://www.gtk.org/"
|
|
name="http://www.gtk.org/">) presents a list of GTK+ bindings.
|
|
|
|
<itemize>
|
|
<item>There are several C++ wrappers for GTK+.
|
|
<itemize>
|
|
|
|
<item>the gtk-- package, which is a very small wrapper for GTK+.
|
|
You can find the home page at:
|
|
<htmlurl url="http://www.cs.tut.fi/~p150650/gtk/gtk--.html"
|
|
name="http://www.cs.tut.fi/~p150650/gtk/gtk--.html">.
|
|
The FTP site is
|
|
<htmlurl url="ftp://ftp.gtk.org/pub/gtk/gtk--"
|
|
name="ftp://ftp.gtk.org/pub/gtk/gtk--">.
|
|
|
|
<item>the VDK package, which was built as the base package of a GTK+
|
|
application Borland-like builder. The home page can be found at
|
|
<htmlurl url="www.guest.net/homepages/mmotta/VDKHome"
|
|
name="www.guest.net/homepages/mmotta/VDKHome">.
|
|
|
|
<item>The wxWindows/Gtk package, a free C++ library for cross-platform
|
|
GUI development. The home page of this package is
|
|
<htmlurl url="http://www.freiburg.linux.de/~wxxt/"
|
|
name="http://www.freiburg.linux.de/~wxxt/">.
|
|
|
|
</itemize>
|
|
<p>
|
|
|
|
<item>There are three known Objective-c bindings currently in development:
|
|
|
|
<itemize>
|
|
|
|
<item>The <htmlurl url="http://www.gnome.org/" name="GNOME project's"> package
|
|
of choice is objgtk. Objgtk is based on the Object class and is maintained by
|
|
<htmlurl url="mailto:sopwith@cuc.edu" name="Elliot Lee">. Apparently, objgtk
|
|
is being accepted as the `standard' Objective-C binding for GTK+.
|
|
|
|
<item>If you are more inclined towards the
|
|
<htmlurl url="http://www.gnustep.org/" name="GNUstep project">,
|
|
you may want to check out GTKKit by
|
|
<htmlurl url="mailto:helge@mdlink.de" name="Helge Heß">.
|
|
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.
|
|
|
|
<item>The GToolKit package, which can be found at
|
|
<htmlurl url="ftp://ftp.gtk.org/pub/gtk/objc-gtoolkit/"
|
|
name="ftp://ftp.gtk.org/pub/gtk/objc-gtoolkit/">.
|
|
|
|
</itemize>
|
|
<p>
|
|
<item>Perl bindings
|
|
<htmlurl url="ftp://ftp.gtk.org/pub/gtk/perl"
|
|
name="ftp://ftp.gtk.org/pub/gtk/perl">
|
|
<P>
|
|
<item>Guile bindings. The home page is at
|
|
<htmlurl url="http://www.ping.de/sites/zagadka/guile-gtk"
|
|
name="http://www.ping.de/sites/zagadka/guile-gtk">.
|
|
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.
|
|
<p>
|
|
|
|
<item>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
|
|
<htmlurl url="http://www.ens-lyon.fr/~dmonniau/arcs"
|
|
name="http://www.ens-lyon.fr/~dmonniau/arcs">
|
|
</quote>
|
|
|
|
<item> Several python bindings have been done:
|
|
<p>
|
|
<itemize>
|
|
<item>pygtk is at
|
|
<htmlurl url="http://www.daa.com.au/~james/pygtk"
|
|
name="http://www.daa.com.au/~james/pygtk"> and
|
|
<htmlurl url="ftp://ftp.gtk.org/pub/gtk/python"
|
|
name="ftp://ftp.gtk.org/pub/gtk/python">
|
|
|
|
<item>python-gtk is at
|
|
<htmlurl url="http://www.ucalgary.ca/~nascheme/python-gtk"
|
|
name="http://www.ucalgary.ca/~nascheme/python-gtk">
|
|
</itemize>
|
|
<p>
|
|
<item>There's are a couple of OpenGL/Mesa widgets available for
|
|
GTK+. I suggest you start at
|
|
<htmlurl url="http://www.student.oulu.fi/~jlof/gtkglarea/index.html"
|
|
name="http://www.student.oulu.fi/~jlof/gtkglarea/index.html">
|
|
<p>
|
|
<item>Last, there are a lot of other language bindings for languages such as
|
|
Eiffel, TOM, Pascal, Pike, etc.
|
|
|
|
</itemize>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>Development with GTK+: the begining
|
|
<!-- ***************************************************************** -->
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I get started?
|
|
<p>
|
|
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 <htmlurl url="http://www.gtk.org/tutorial/"
|
|
name="<http://www.gtk.org/tutorial/>">, which is undergoing
|
|
development. This will introduce you to writing applications using C.
|
|
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I tried to compile a small <tt/Hello World/ of mine, but it failed. Any clue?
|
|
<p>
|
|
Since you are good at coding, we will not deal with compile time error here :).
|
|
|
|
The classic command line to compile a GTK+ based program is
|
|
|
|
<verb>
|
|
gcc -o myprg [c files list] `gtk-config --cflags --libs`
|
|
</verb>
|
|
|
|
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 'gtk-config --cflags --libs'. The text in
|
|
backquotes is an instruction to your shell to substitute the output of
|
|
executing this text into the command line.
|
|
|
|
The command line above ensure that:
|
|
<itemize>
|
|
|
|
<item>the correct C compiler flags will be used to compile the program
|
|
(including the complete C header directory list)
|
|
|
|
<item>your program will be linked with the needed libraries.
|
|
|
|
</itemize>
|
|
|
|
<sect1>What about using the <tt/make/ utility?
|
|
<p>
|
|
This is a sample makefile which compile a GTK+ based program:
|
|
|
|
<tscreen><verb>
|
|
# 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
|
|
</verb></tscreen>
|
|
|
|
For more information about the <tt/make/ utility, you should read either the
|
|
related man page or the relevant info file.
|
|
|
|
<sect1>I use the backquote stuff in my makefiles, but my make process failed.
|
|
<p>
|
|
The backquote construction seems to not be accepted by some old <tt/make/
|
|
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
|
|
<htmlurl url="ftp://ftp.gnu.org/" name="ftp://ftp.gnu.org/">).
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I want to add some configure stuff, how could I do this?
|
|
<p>
|
|
To use autoconf/automake, you must first install the relevant packages. These
|
|
are:
|
|
|
|
<itemize>
|
|
<item>the m4 preprocessor v1.4 or better
|
|
<item>autoconf v2.13 or better
|
|
<item>automake v1.4 or better
|
|
</itemize>
|
|
|
|
You'll find these packages on the GNU main ftp server (<htmlurl
|
|
url="ftp://ftp.gnu.org/" name="ftp://ftp.gnu.org/">) or on any GNU mirror.
|
|
|
|
In order to use the powerfull autoconf/automake scheme, you must create
|
|
a configure.in which may look like:
|
|
|
|
<tscreen><verb>
|
|
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(mypkbname,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
|
|
</verb></tscreen>
|
|
|
|
You must add a Makefile.am file:
|
|
|
|
<tscreen><verb>
|
|
bin_PROGRAMS = myprg
|
|
myprg_SOURCES = myprg.c foo.c bar.c
|
|
INCLUDES = @GTK_CFLAGS@
|
|
LDADD = @GTK_LIBS@
|
|
CLEANFILES = *~
|
|
DISTCLEANFILES = .deps/*.P
|
|
</verb></tscreen>
|
|
|
|
then, to use these, simply type the following commands:
|
|
|
|
<verb>
|
|
aclocal
|
|
autoheader
|
|
autoconf
|
|
automake --add-missing --include-deps --foreign
|
|
</verb>
|
|
|
|
For further informations, 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/or automake).
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I try to debug my GTK+ application with gdb, but it hangs my X server when I hit some breakpoint. Any Idea ?
|
|
<p>
|
|
From Federico Mena Quintero:
|
|
<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.
|
|
<P>
|
|
Run your program with the "--sync" 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>
|
|
|
|
Eric Mouw had another solution:
|
|
<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>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>Development with GTK+: general questions
|
|
<!-- ***************************************************************** -->
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What widgets are in GTK?
|
|
<p>
|
|
The GTK+ Tutorial lists the following widgets:
|
|
|
|
<verb>
|
|
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
|
|
</verb>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Is GTK+ thread safe? How do I write multi-threaded GTK+ applications?
|
|
<p>
|
|
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.
|
|
|
|
When GLib is intialized to be thread-safe, GTK+ is
|
|
<em>thread aware</em>. 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.
|
|
|
|
A minimal main program for a threaded GTK+ application
|
|
looks like:
|
|
|
|
<verb>
|
|
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);
|
|
}
|
|
</verb>
|
|
|
|
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.
|
|
|
|
Erik Mouw contributed the following code example to illustrate how to
|
|
use threads within GTK+ programs.
|
|
|
|
<tscreen><verb>
|
|
/*-------------------------------------------------------------------------
|
|
* 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);
|
|
}
|
|
</verb></tscreen>
|
|
|
|
<!-- This is the old answer - TRG
|
|
|
|
|
|
Although GTK+, like many X toolkits, isn't thread safe, this does
|
|
not prohibit the development of multi-threaded applications with
|
|
GTK+.
|
|
|
|
Rob Browning (rlb@cs.utexas.edu) describes threading techniques for
|
|
use with GTK+ (slightly edited):
|
|
|
|
There are basically two main approaches, the first is simple, and the
|
|
second complicated. In the first, you just make sure that all GTK+ (or
|
|
X) interactions are handled by one, and
|
|
only one, thread. Any other thread that wants to draw something has
|
|
to somehow notify the "GTK+" thread, and let it handle the
|
|
actual work.
|
|
|
|
The second approach allows you to call GTK+ (or X) functions from any
|
|
thread, but it requires some careful synchronization. The
|
|
basic idea is that you create an X protection mutex, and no one may
|
|
make any X calls without first acquiring this mutex.
|
|
|
|
Note that this is a little effort, but it allows you to be
|
|
potentially more efficient than a completely thread safe GTK+. You
|
|
get to decide the granularity of the thread locking. You also have to
|
|
make sure that the thread that calls <tt/gtk_main()/ is holding the lock when
|
|
it calls <tt/gtk_main()/.
|
|
|
|
The next thing to worry about is that since you were holding the
|
|
global mutex when you entered <tt/gtk_main()/, all callbacks will also be
|
|
holding it. This means that the callback must release it if it's
|
|
going to call any other code that might reacquire it. Otherwise
|
|
you'll get deadlock. Also, you must be holding the mutex when you
|
|
finally return from the callback.
|
|
|
|
In order to allow threads other than the one calling <tt/gtk_main/ to
|
|
get access to the mutex, we also need to register a work function
|
|
with GTK that allows us to release the mutex periodically.
|
|
|
|
Why can't GTK+ be thread safe by default?
|
|
|
|
Complexity, overhead, and manpower. The proportion of threaded
|
|
programs is still reasonably small, and getting thread safety right is
|
|
both quite difficult and takes valuable time away from the main work
|
|
of getting a good graphics library finished. It would be nice to have
|
|
GTK+ thread safe "out of the box", but that's not practical right now,
|
|
and it also might make GTK+ substantially less efficient if not handled
|
|
carefully.
|
|
|
|
Regardless, it's especially not a priority since relatively good
|
|
workarounds exist. -->
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Why does this strange 'x io error' occur when I <tt/fork()/ in my GTK+ app?
|
|
<p>
|
|
This is not really a GTK+ problem, and the problem is not related to <tt/fork()/
|
|
either. If the 'x io error' occurs then you probably use the <tt/exit()/ function
|
|
in order to exit from the child process.
|
|
|
|
When GDK opens an X display, it creates a socket file descriptor. When you use
|
|
the <tt/exit()/ function, you implicitly close all the open file descriptors,
|
|
and the underlying X library really doesn't like this.
|
|
|
|
The right function to use here is <tt/_exit()/.
|
|
|
|
Erik Mouw contributed the following code example to illustrate handling
|
|
fork() and exit().
|
|
|
|
<tscreen><verb>
|
|
/*-------------------------------------------------------------------------
|
|
* 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);
|
|
}
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Why don't the contents of a button move when the button is pressed? Here's a patch to make it work that way...
|
|
<p>
|
|
From: Peter Mattis
|
|
|
|
<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.
|
|
<P>
|
|
On a more practical note, I did implement this at one point and
|
|
determined it didn't look good and removed it.
|
|
</quote>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How to I identifiy a widgets top level window or other ancestor?
|
|
<p>
|
|
There are a couple of ways to find the top level parent of a
|
|
widget. The easier way is to call the <tt/gtk_widget_top_level()/
|
|
function that returns a pointer to a GtkWidget that is the top level
|
|
window.
|
|
|
|
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
|
|
<tt/gtk_widget_get_ancestor()/ as in:
|
|
|
|
<tscreen><verb>
|
|
GtkWidget *widget;
|
|
|
|
widget = gtk_widget_get_ancestor(w, GTK_TYPE_WINDOW);
|
|
</verb></tscreen>
|
|
|
|
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 <tt/entry/ widget simply use:
|
|
|
|
<tscreen><verb>
|
|
GtkWidget *hbox;
|
|
hbox = gtk_widget_get_ancestor(w, GTK_TYPE_HBOX);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I get the Window ID of a GtkWindow?
|
|
<p>
|
|
The actual Gdk/X window will be created when the widget gets
|
|
realized. You can get the Window ID with:
|
|
|
|
<verb>
|
|
#include <gdk/gdkx.h>
|
|
|
|
Window xwin = GDK_WINDOW_XWINDOW (GTK_WIDGET (my_window)->window);
|
|
</verb>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I catch a double click event (in a list widget, for example)?
|
|
<p>
|
|
Tim Janik wrote to gtk-list (slightly modified):
|
|
|
|
Define a signal handler:
|
|
|
|
<tscreen><verb>
|
|
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;
|
|
}
|
|
</verb></tscreen>
|
|
|
|
And connect the handler to your object:
|
|
|
|
<tscreen><verb>
|
|
{
|
|
/* 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 */
|
|
}
|
|
</verb></tscreen>
|
|
|
|
and, Owen Taylor wrote:
|
|
|
|
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.)
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>By the way, what are the differences between signals and events?
|
|
<p>
|
|
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 <htmlurl url="http://www106.pair.com/rhp/sample_chapters.html"
|
|
name="http://www106.pair.com/rhp/sample_chapters.html">).
|
|
|
|
Moreover, Havoc posted this to the <tt/gtk-list/
|
|
<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.
|
|
<P>
|
|
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.
|
|
<P>
|
|
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>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I have my signal connected to the the (whatever) event, but it seems I don't catch it. What's wrong?
|
|
<p>
|
|
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.
|
|
|
|
For example,
|
|
|
|
<tscreen><verb>
|
|
gtk_widget_add_events(window, GDK_KEY_RELEASE_MASK);
|
|
</verb></tscreen>
|
|
|
|
lets you catch the key release events. If you want to catch every events,
|
|
simply us the GDK_ALL_EVENTS_MASK event mask.
|
|
|
|
All the event masks are defined in the <tt/gdktypes.h/ file.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Is it possible to get some text displayed which is truncated to fit inside its allocation?
|
|
<p>
|
|
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.
|
|
|
|
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 it's own window - one possible candidate would
|
|
be the viewport widget.
|
|
|
|
<tscreen><verb>
|
|
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);
|
|
</verb></tscreen>
|
|
|
|
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).
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
<sect1>How do I make my window modal? / How do I make a single window active?
|
|
<p>
|
|
After you create your window, do <tt/gtk_grab_add(my_window)/. And after
|
|
closing the window do <tt/gtk_grab_remove(my_window)/.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Why doesn't my widget (e.g. progressbar) update?
|
|
<p>
|
|
|
|
You are probably doing all the changes within a function
|
|
without returning control to <tt/gtk_main()/. 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 <tt/gtk_main()/. You can
|
|
force the drawing queue to be processed using something like:
|
|
|
|
<tscreen><verb>
|
|
while (g_main_iteration(FALSE));
|
|
</verb></tscreen>
|
|
|
|
inside you're function that changes the widget.
|
|
|
|
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).
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I attach data to some GTK+ object/widget?
|
|
<p>
|
|
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.
|
|
|
|
There are two (easy) ways to attach some data to a gtk object.
|
|
Using <tt/gtk_object_set_data()/ and <tt/gtk_object_get_data()/ seems to be the
|
|
most common way to do this, as it provides a powerfull interface
|
|
to connect objects and data.
|
|
|
|
<tscreen><verb>
|
|
void gtk_object_set_data(GtkObject *object, const gchar *key, gpointer data);
|
|
gpointer gtk_object_get_data(GtkObject *object, const gchar *key);
|
|
</verb></tscreen>
|
|
|
|
Since a short example is better than any lengthy speech:
|
|
|
|
<tscreen><verb>
|
|
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");
|
|
</verb></tscreen>
|
|
|
|
The <tt/gtk_object_set_user_data()/ and <tt/gtk_object_get_user_data()/
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I remove the data I have attached to an object?
|
|
<p>
|
|
When attaching the data to the object, you can use the
|
|
<tt/gtk_object_set_data_full()/
|
|
function. The three first arguments of the function are the same as in
|
|
<tt/gtk_object_set_data()/. The fourth one is a pointer to a callback function
|
|
which is called when the data is destroyed. The data is destroyed when
|
|
you:
|
|
|
|
<itemize>
|
|
<item> destroy the object
|
|
<item> replace the data with a new one (with the same key)
|
|
<item> replace the data with NULL (with the same key)
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How could I get any widgets position?
|
|
<p>
|
|
As Tim Janik pointed out, there are different cases, and each case requires
|
|
a different solution.
|
|
|
|
<itemize>
|
|
<item> If you want the position of a widget relative to its parent, you should
|
|
use <tt/widget->allocation.x/ and <tt/widget->allocation.y/.
|
|
<item> If you want the position of a window relative to the X root window,
|
|
you should use <tt/gdk_window_get_geometry()/ or
|
|
<tt/gdk_window_get_origin()/.
|
|
<item> Last but not least, if you want to get a Window Manager frame position,
|
|
you should use <tt/gdk_window_get_deskrelative_origin()/.
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I set the size of a widget/window? How do I prevent the user resizing my window?
|
|
<p>
|
|
The <tt/gtk_widget_set_uposition()/ function is used to set the
|
|
position of any widget.
|
|
|
|
The <tt/gtk_widget_set_usize()/ 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
|
|
<tt/gtk_window_set_policy/ function. The definition of these functions
|
|
is:
|
|
|
|
<tscreen><verb>
|
|
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);
|
|
</verb></tscreen>
|
|
|
|
<tt/Auto_shrink/ will automatically shrink the window when the
|
|
requested size of the child widgets goes below the current size of the
|
|
window. <tt/Allow_shrink/ will give the user the authorisation to
|
|
make the window smaller that it should normally be. <tt/Allow_grow/
|
|
will give the user will have the ability to make the window
|
|
bigger. The default values for these parameters are:
|
|
|
|
<tscreen><verb>
|
|
allow_shrink = FALSE
|
|
allow_grow = TRUE
|
|
auto_shrink = FALSE
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I add a popup menu to my GTK+ application?
|
|
<p>
|
|
The <tt/menu/ example in the examples/menu directory of the GTK+ distribution
|
|
implements a popup menu with this technique :
|
|
|
|
<tscreen><verb>
|
|
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;
|
|
}
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I disable or enable a widget, such as a button?
|
|
<p>
|
|
To disable (or to enable) a widget, use the <tt/gtk_widget_set_sensitive()/
|
|
function. The first parameter is you widget pointer. The second parameter
|
|
is a boolean value: when this value is TRUE, the widget is enabled.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Shouldn't the text argument in the gtk_clist_* functions be declared const?
|
|
<p>
|
|
For example:
|
|
<verb>
|
|
gint gtk_clist_prepend (GtkCList *clist,
|
|
gchar *text[]);
|
|
</verb>
|
|
|
|
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).
|
|
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I render pixels (image data) to the screen?
|
|
<p>
|
|
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.
|
|
|
|
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).
|
|
|
|
You do NOT want to use <tt/gdk_draw_point()/, that will be extremely
|
|
slow.
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>Development with GTK+: widget specific questions
|
|
<!-- ***************************************************************** -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I find out about the selection of a GtkList?
|
|
<p>
|
|
Get the selection something like this:
|
|
<tscreen><verb>
|
|
GList *sel;
|
|
sel = GTK_LIST(list)->selection;
|
|
</verb></tscreen>
|
|
|
|
This is how GList is defined (quoting glist.h):
|
|
<tscreen><verb>
|
|
typedef struct _GList GList;
|
|
|
|
struct _GList
|
|
{
|
|
gpointer data;
|
|
GList *next;
|
|
GList *prev;
|
|
};
|
|
</verb></tscreen>
|
|
|
|
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.
|
|
|
|
The selection_mode of the GtkList determines the selection
|
|
facilities of a GtkList and therefore the contents
|
|
of GTK_LIST(AnyGtkList)->selection:
|
|
|
|
<verb>
|
|
selection_mode GTK_LIST()->selection contents
|
|
------------------------------------------------------
|
|
|
|
GTK_SELECTION_SINGLE) selection is either NULL
|
|
or contains a GList* pointer
|
|
for a single selected item.
|
|
|
|
GTK_SELECTION_BROWSE) selection is NULL if the list
|
|
contains no widgets, otherwise
|
|
it contains a GList* pointer
|
|
for one GList structure.
|
|
GTK_SELECTION_MULTIPLE) 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
|
|
|
|
GTK_SELECTION_EXTENDED) selection is NULL.
|
|
</verb>
|
|
|
|
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:
|
|
|
|
Upon Initialization:
|
|
<tscreen><verb>
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
</verb></tscreen>
|
|
|
|
To get known about the selection:
|
|
<tscreen><verb>
|
|
{
|
|
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");
|
|
}
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- --><p>
|
|
<sect1>I don't want the user of my applications to enter text into a GtkCombo. Any idea?
|
|
<p>
|
|
A GtkCombo has an associated entry which can be accessed using the
|
|
following expression:
|
|
|
|
<tscreen><verb>
|
|
GTK_COMBO(combo_widget)->entry
|
|
</verb></tscreen>
|
|
|
|
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:
|
|
|
|
<tscreen><verb>
|
|
void gtk_entry_set_editable(GtkEntry *entry,
|
|
gboolean editable);
|
|
</verb></tscreen>
|
|
|
|
Set the editable parameter to FALSE to disable typing into the entry.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I catch a combo box change?
|
|
<p>
|
|
The entry which is associated to your GtkCombo send a "changed" signal when:
|
|
<itemize>
|
|
<item>some text is typed in
|
|
<item>the selection of the combo box is changed
|
|
</itemize>
|
|
|
|
To catch any combo box change, simply connect your signal handler with
|
|
|
|
<tscreen><verb>
|
|
gtk_signal_connect(GTK_COMBO(cb)->entry,
|
|
"changed",
|
|
GTK_SIGNAL_FUNC(my_cb_change_handler),
|
|
NULL);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How can I define a separation line in a menu?
|
|
<p>
|
|
See the <htmlurl url="http://www.gtk.org/tutorial/"
|
|
name="Tutorial"> for information on how to create menus.
|
|
However, to create a separation line in a menu, just insert an
|
|
empty menu item:
|
|
|
|
<tscreen><verb>
|
|
menuitem = gtk_menu_item_new();
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How can I right justify a menu, such as Help?
|
|
<p>
|
|
Depending on if you use the MenuFactory or not, there are two ways to proceed.
|
|
With the MenuFactory, use something like the following:
|
|
|
|
<tscreen><verb>
|
|
menu_path = gtk_menu_factory_find (factory, "<MyApp>/Help");
|
|
gtk_menu_item_right_justify(menu_path->widget);
|
|
</verb></tscreen>
|
|
|
|
If you do not use the MenuFactory, you should simply use:
|
|
|
|
<tscreen><verb>
|
|
gtk_menu_item_right_justify(my_menu_item);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I add some underlined accelerators to menu items?
|
|
<p>
|
|
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 <tt/File/ menu item with only one child (<tt/New/). The F in <tt/File/
|
|
and the N in <tt/New/ are underlined, and the relevant accelerators are
|
|
created.
|
|
|
|
<tscreen><verb>
|
|
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);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I right (or otherwise) justify a GtkLabel?
|
|
<p>
|
|
Are you sure you want to <em>justify</em> the labels? The label class contains
|
|
the <tt/gtk_label_set_justify()/ function that is used to control the
|
|
justification of a multi-line label.
|
|
|
|
What you probably want is to set the <em>alignment</em> of the label, ie right
|
|
align it, center it or left align it. If you want to do this, you
|
|
should use:
|
|
|
|
<tscreen><verb>
|
|
void gtk_misc_set_alignment (GtkMisc *misc,
|
|
gfloat xalign,
|
|
gfloat yalign);
|
|
</verb></tscreen>
|
|
|
|
where the <tt/xalign/ and <tt/yalign/ values are floats in [0.00;1.00].
|
|
|
|
<tscreen><verb>
|
|
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);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I set the background color of a GtkLabel widget?
|
|
<p>
|
|
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.
|
|
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I set the color and font of a GtkLabel using a Resource File?
|
|
<p>
|
|
The widget name path constructed for a Label consists of the widget
|
|
names of its object hierarchy as well, e.g.
|
|
|
|
<verb>
|
|
window (name: humphrey)
|
|
hbox
|
|
label (name: mylabel)
|
|
</verb>
|
|
|
|
The widget path your pattern needs to match would be:
|
|
<tt/humphrey.GtkHBox.mylabel/
|
|
|
|
The resource file may look something like:
|
|
|
|
<verb>
|
|
style "title"
|
|
{
|
|
fg[NORMAL] = {1.0, 0.0, 0.0}
|
|
font = "-adobe-helvetica-bold-r-normal--*-140-*-*-*-*-*-*"
|
|
}
|
|
widget "*mylabel" style "title"
|
|
</verb>
|
|
|
|
In your program, you would also need to give a name to the Label
|
|
widget, which can be done using:
|
|
<verb>
|
|
label = gtk_label_new("Some Label Text");
|
|
gtk_widget_set_name(label, "mylabel");
|
|
gtk_widget_show(label);
|
|
</verb>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I configure Tooltips in a Resource File?
|
|
<p>
|
|
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.
|
|
|
|
So, you resource file should look something like:
|
|
<verb>
|
|
style "postie"
|
|
{
|
|
bg[NORMAL] = {1.0, 1.0, 0.0}
|
|
}
|
|
widget "gtk-tooltips*" style "postie"
|
|
</verb>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I use horizontal scrollbars with a GtkText widget?
|
|
<p>
|
|
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.
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>I can't add more than (something like) 2000 chars in a GtkEntry. What's wrong?
|
|
<p>
|
|
There is now a known problem in the GtkEntry widget. In the
|
|
<tt/gtk_entry_insert_text()/ function, the following lines limit
|
|
the number of chars in the entry to 2047.
|
|
|
|
<tscreen><verb>
|
|
/* 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);
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I change the font of a GtkText widget?
|
|
<p>
|
|
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:
|
|
|
|
<tscreen><verb>
|
|
style "text"
|
|
{
|
|
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
|
|
}
|
|
</verb></tscreen>
|
|
|
|
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:
|
|
|
|
<tscreen><verb>
|
|
GdkFont *font;
|
|
font = gdk_font_load("-adobe-helvetica-medium-r-normal--*-140-*-*-*-*-*-*");
|
|
</verb></tscreen>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I set the cursor position in a GtkText object?
|
|
<p>
|
|
Notice that the response is valid for any object that inherits from the
|
|
GtkEditable class.
|
|
|
|
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 <tt/gtk_text_set_point()/ function. If you want to set the insertion point
|
|
at the current cursor position, use the following:
|
|
|
|
<tscreen><verb>
|
|
gtk_text_set_point(GTK_TEXT(text),
|
|
gtk_editable_get_position(GTK_EDITABLE(text)));
|
|
</verb></tscreen>
|
|
|
|
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:
|
|
|
|
<tscreen><verb>
|
|
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;
|
|
}
|
|
</verb></tscreen>
|
|
|
|
Now, if you really want to change the cursor position, you should use the
|
|
<tt/gtk_editable_set_position()/ function.
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>About gdk
|
|
<!-- ***************************************************************** -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What is GDK?
|
|
<p>
|
|
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.
|
|
|
|
<!-- Examples, anybody? I've been mulling some over. NF -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How do I use color allocation?
|
|
<p>
|
|
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:
|
|
<tscreen>
|
|
<verb>
|
|
{
|
|
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);
|
|
|
|
...
|
|
}
|
|
</verb>
|
|
</tscreen>
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>About GLib
|
|
<!-- ***************************************************************** -->
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What is GLib?
|
|
<p>
|
|
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.
|
|
<p>
|
|
It also provides routines for handling:
|
|
<itemize>
|
|
<item>Doubly Linked Lists
|
|
<item>Singly Linked Lists
|
|
<item>Timers
|
|
<item>String Handling
|
|
<item>A Lexical Scanner
|
|
<item>Error Functions
|
|
</itemize>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>How can I use the doubly linked lists?
|
|
<p>
|
|
The GList object is defined as:
|
|
|
|
<tscreen><verb>
|
|
typedef struct _GList GList;
|
|
|
|
struct _GList
|
|
{
|
|
gpointer data;
|
|
GList *next;
|
|
GList *prev;
|
|
};
|
|
</verb></tscreen>
|
|
|
|
To use the GList objects, simply :
|
|
|
|
<tscreen><verb>
|
|
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]);
|
|
</verb></tscreen>
|
|
|
|
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.
|
|
|
|
<!-- 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 -->
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>Why use g_print, g_malloc, g_strdup and fellow glib functions?
|
|
<p>
|
|
Thanks to Tim Janik who wrote to gtk-list: (slightly modified)
|
|
<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()).
|
|
<P>
|
|
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. ;)
|
|
<P>
|
|
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 <tt/gtk_print()/
|
|
(inside of gtkmain.c).
|
|
</quote>
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
<sect1>What's a GScanner and how do I use one?
|
|
<p>
|
|
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.
|
|
|
|
Here's a little test program supplied by Tim Janik that will parse
|
|
|
|
<verb>
|
|
<SYMBOL> = <OPTIONAL-MINUS> <NUMBER> ;
|
|
</verb>
|
|
|
|
constructs, while skipping "#\n" and "/**/" style comments.
|
|
|
|
<verb>
|
|
#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 untill it's 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;
|
|
}
|
|
</verb>
|
|
|
|
You need to understand that the scanner will parse it's 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:
|
|
|
|
<verb>
|
|
"hi i am 17"
|
|
| | | |
|
|
| | | v
|
|
| | v TOKEN_INT, value: 17
|
|
| v TOKEN_IDENTIFIER, value: "am"
|
|
v TOKEN_CHAR, value: 'i'
|
|
TOKEN_IDENTIFIER, value: "hi"
|
|
</verb>
|
|
|
|
If you configure the scanner with:
|
|
<verb>
|
|
scanner->config->int_2_float = TRUE;
|
|
scanner->config->char_2_token = TRUE;
|
|
scanner->config->scan_symbols = TRUE;
|
|
</verb>
|
|
|
|
and add "am" as a symbol with
|
|
<verb>
|
|
g_scanner_add_symbol (scanner, "am", "symbol value");
|
|
</verb>
|
|
|
|
GScanner will parse it as
|
|
|
|
<verb>
|
|
"hi i am 17"
|
|
| | | |
|
|
| | | v
|
|
| | v TOKEN_FLOAT, value: 17.0 (automatic int->float conversion)
|
|
| | TOKEN_SYMBOL, value: "symbol value" (a successfull hash table lookup
|
|
| | turned a TOKEN_IDENTIFIER into a
|
|
| | TOKEN_SYMBOL and took over the
|
|
| v symbol's value)
|
|
v 'i' ('i' can be a valid token as well, as all chars >0 and <256)
|
|
TOKEN_IDENTIFIER, value: "hi"
|
|
</verb>
|
|
|
|
You need to match the token sequence with your code, and if you encounter
|
|
something that you don't want, you error out:
|
|
|
|
<verb>
|
|
/* 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;
|
|
</verb>
|
|
|
|
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".
|
|
|
|
<!-- ***************************************************************** -->
|
|
<sect>GTK+ FAQ Contributions, Maintainers and Copyright
|
|
<p>
|
|
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!
|
|
|
|
This document is maintained by Nathan Froyd
|
|
<htmlurl url="mailto:maestrox@geocities.com"
|
|
name="<maestrox@geocities.com>">,
|
|
Tony Gale <htmlurl url="mailto:gale@gtk.org"
|
|
name="<gale@gtk.org>"> and
|
|
Emmanuel Deloget <htmlurl url="mailto:logout@free.fr"
|
|
name="<logout@free.fr>">.
|
|
This FAQ was created by Shawn T. Amundson
|
|
<htmlurl url="mailto:amundson@gimp.org"
|
|
name="<amundson@gimp.org>"> who continues to provide support.
|
|
|
|
The GTK+ FAQ is Copyright (C) 1997,1998, 1999 by Shawn T. Amundson,
|
|
Nathan Froyd and Tony Gale, Emmanuel Deloget.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Permission is granted to copy and distribute translations of
|
|
this document into another language, under the above conditions
|
|
for modified versions.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
</article>
|