3644 lines
		
	
	
		
			111 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			3644 lines
		
	
	
		
			111 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| <!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" []>
 | |
| <book>
 | |
| 
 | |
| <bookinfo>
 | |
|   <date>January 14th 2004</date>
 | |
|   <title>GTK+ FAQ</title>
 | |
|   <authorgroup>
 | |
|     <author>
 | |
| <firstname>Tony</firstname>
 | |
| <surname>Gale</surname>
 | |
|     </author>
 | |
|     <author>
 | |
| <firstname>Shawn</firstname>
 | |
| <surname>Amundson</surname>
 | |
|     </author>
 | |
|     <author>
 | |
| <firstname>Emmanuel</firstname>
 | |
| <surname>Deloget</surname>
 | |
|     </author>
 | |
|   </authorgroup>
 | |
|   <abstract>
 | |
|     <para> This document is intended to answer questions that are
 | |
|     likely to be frequently asked by programmers using GTK+ or
 | |
|     people who are just looking at using GTK+. </para>
 | |
|     <para><emphasis>Note: </emphasis> This FAQ mainly covers GTK+ 1.2. 
 | |
| 	Where the text covers GTK+ 2.x this will be indicated</para>
 | |
|   </abstract>
 | |
| </bookinfo>
 | |
| 
 | |
| <toc></toc>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>General Information</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Note: This FAQ is undergoing conversion to GTK+ 2.x</title>
 | |
| <para>This FAQ is undergoing conversion to GTK+ 2.x.
 | |
| Where the text covers GTK+ 2.x this will be indicated by prefixing the
 | |
| text with: <emphasis>[GTK+ 2.x]</emphasis>. Where this is not
 | |
| indicated, the text has not yet been updated from GTK+ 1.2 and may
 | |
| not be totally correct.
 | |
| </para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Before anything else: the greetings <emphasis>[GTK 2.x]</emphasis></title>
 | |
| <para>The FAQ authors want to thank:</para>
 | |
| <itemizedlist spacing=Compact>
 | |
| <listitem>
 | |
| <simpara>Havoc Pennington</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Erik Mouw</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Owen Taylor</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Tim Janik</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Thomas Mailund Jensen</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Joe Pfeiffer</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Andy Kahn</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Federico Mena Quntero</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Damon Chaplin</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>and all the members of the GTK+ lists</simpara>
 | |
| </listitem></itemizedlist>
 | |
| <para> If we forgot you, please email us! Thanks again (I know,
 | |
| it's really short :) </para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Authors <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The original authors of GTK+ were:</para>
 | |
| 
 | |
| <itemizedlist spacing=Compact>
 | |
| <listitem>
 | |
| <simpara>Peter Mattis</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Spencer Kimball</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Josh MacDonald</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>Since then, much has been added by others. Please see the
 | |
| AUTHORS file in the distribution for the GTK+ Team. The people currently
 | |
| contributing the most code to GTK+ are (in no particular order):</para>
 | |
| 
 | |
| 
 | |
| <itemizedlist spacing=Compact>
 | |
| <listitem>
 | |
| <simpara>Owen Taylor</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Matthias Clasen</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Federico Mena Quintero</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Soeren Sandmann</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Padraig O'Briain</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Manish Singh</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Kristian Rietveld</simpara>
 | |
| </listitem>
 | |
| <listitem>
 | |
| <simpara>Tor Lillqvist</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What is GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>GTK+ is a multi-platform toolkit for creating graphical user
 | |
| interfaces, originally designed with
 | |
| the general look and feel of Motif.  In reality, it looks much
 | |
| better than Motif.  It contains common and complex widgets, such as
 | |
| file selection, and color selection widgets.</para>
 | |
| 
 | |
| <para>GTK+ was initially developed as a widget set for the GIMP (GNU Image
 | |
| Manipulation Program). It has grown extensively since then, and is today
 | |
| used by a large number of applications, and is the toolkit used by the
 | |
| <ulink url="http://www.gnome.org/">GNOME</ulink> desktop project.</para>
 | |
| 
 | |
| <para>GTK+ is free software and part of the GNU Project. However, the
 | |
| licensing terms for GTK+, the GNU LGPL, allow it to be used by all developers,
 | |
| including those developing proprietary software, without any license fees
 | |
| or royalties.</para>
 | |
| 
 | |
| <para>GTK+ has been designed from the ground up to support a range of
 | |
| <ulink url="http://www.gtk.org/bindings.html">
 | |
| language bindings</ulink>, not only C/C++. Using GTK+ from languages
 | |
| such as Perl and Python (especially in combination with the Glade GUI
 | |
| builder) provides an effective method of rapid application
 | |
| development..</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What is the + in GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Peter Mattis informed the gtk mailing list that:</para>
 | |
| 
 | |
| <para><quote>I originally wrote gtk which included the three
 | |
| libraries, libglib, libgdk and libgtk. It featured a flat
 | |
| widget hierarchy. That is, you couldn't derive a new widget
 | |
| from an existing one. And it contained a more standard
 | |
| callback mechanism instead of the signal mechanism now present
 | |
| in gtk+. The + was added to distinguish between the original
 | |
| version of gtk and the new version. You can think of it as
 | |
| being an enhancement to the original gtk that adds object
 | |
| oriented features.</quote></para>
 | |
| 
 | |
| <para>Although much has changed with GTK+, and Peter, Spencer and Josh
 | |
| don't have any direct involvement these days, the name is kept to keep
 | |
| a link with the heritage of GTK+.</para>
 | |
| 
 | |
| <para>GTK+ is now additionally based upon the Pango and ATK
 | |
| libraries, that provide text layout and rendering and accessibility
 | |
| interfaces.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Does the G in GTK+, GDK and GLib stand for? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>GTK+ == The GIMP Toolkit</para>
 | |
| <para>GDK == GTK+ Drawing Kit</para>
 | |
| <para>GLib == G Library</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Where is the documentation for GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>In the GTK+ distribution's doc/ directory you will find
 | |
| the API Reference for both GTK and GDK, this FAQ and the
 | |
| GTK Tutorial.</para>
 | |
| 
 | |
| <para>In addition, you can find links to HTML versions of
 | |
| these documents by going to <ulink url="http://www.gtk.org/">
 | |
| http://www.gtk.org/</ulink>. A
 | |
| packaged version of the GTK Tutorial, with SGML, HTML,
 | |
| Postscript, DVI and text versions can be found in <ulink
 | |
| url="ftp://ftp.gtk.org/pub/gtk/tutorial">
 | |
| ftp://ftp.gtk.org/pub/gtk/tutorial
 | |
| </ulink></para>
 | |
| 
 | |
| <para>There are now a few books available that deal with
 | |
| programming GTK+, GDK and GNOME. Unfortunately, they
 | |
| currently are all based upon GTK+ 1.x:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara>Eric Harlows book entitled "Developing
 | |
| Linux Applications with GTK+ and GDK". The ISBN is
 | |
| 0-7357-0021-4</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>The example code from Eric's book is
 | |
| available on-line at <ulink
 | |
| url="http://www.bcpl.net/~eharlow/book">
 | |
| http://www.bcpl.net/~eharlow/book</ulink></simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>Havoc Pennington has released a book called
 | |
| "GTK+/GNOME Application Development". The ISBN is
 | |
| 0-7357-0078-8</simpara>
 | |
| <simpara>The free version of the book lives here: <ulink
 | |
| url="http://developer.gnome.org/doc/GGAD/">
 | |
| http://developer.gnome.org/doc/GGAD/
 | |
| </ulink></simpara>
 | |
| <simpara>And Havoc maintains information about it and
 | |
| errata here: <ulink
 | |
| url="http://pobox.com/~hp/gnome-app-devel.html">
 | |
| http://pobox.com/~hp/gnome-app-devel.html
 | |
| </ulink></simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>"GTK+ Programming in C" by
 | |
| Syd Logan. ISBN: 0-1301-4264-6</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>"Linux GNOME/GTK+ Programming Bible" by
 | |
| Arthur Griffith. ISBN: 0-7645-4640-6</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>"Beginning GTK+/GNOME Programming" by
 | |
| Peter Wright. ISBN: 1-8610-0381-1</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara>"Sams Teach Yourself GTK+ Programming
 | |
| in 21 Days" by Donna Martin
 | |
| . ISBN: 0-6723-1829-6</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1 id="faq-MailLists">
 | |
| <title>Is there a mailing list (or mailing list archive) for
 | |
| GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Information on mailing lists relating to GTK+ can be
 | |
| found at: <ulink
 | |
| url="http://www.gtk.org/mailinglists.html">
 | |
| http://www.gtk.org/mailinglists.html
 | |
| </ulink></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How to get help with GTK+ <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>First, make sure your question isn't answered in the
 | |
| documentation, this FAQ or the tutorial. Done that? You're
 | |
| sure you've done that, right? In that case, the best place to
 | |
| post questions is to the GTK+ mailing list.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How to report bugs in GTK+ <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Bugs should be reported to the GNOME bug tracking system
 | |
| (<ulink url="http://bugzilla.gnome.org">http://bugzilla.gnome.org</ulink>).
 | |
| You will need to enter your email address and receive a password before
 | |
| you can use the system to register a new bug report.</para>
 | |
| 
 | |
| <para>There are a number of options to select and boxes to fill in when
 | |
| submitting a bug report. Please remember that the more information you
 | |
| give, the easier it will be to track the problem down. Extra information
 | |
| that may prove useful includes:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara> How to reproduce the bug.</simpara>
 | |
| <simpara>If you can reproduce it with the testgtk program
 | |
| that is built in the gtk/ subdirectory, that will be most
 | |
| convenient. Otherwise, please include a complete, short test
 | |
| program that exhibits the behavior. As a last resort, you can also
 | |
| provide a pointer to a larger piece of software that can
 | |
| be downloaded.</simpara>
 | |
| 
 | |
| <simpara>(Bugs that can be reproduced within the GIMP are
 | |
| almost as good as bugs that can be reproduced in
 | |
| testgtk. If you are reporting a bug found with the GIMP,
 | |
| please include the version number of the GIMP you are
 | |
| using)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> If the bug was a crash, the exact text that was
 | |
| printed out when the crash occurred. If you can easily reproduce this
 | |
| crash then running the program under a debugger (e.g. gdb) and getting
 | |
| a backtrace when the crash occurs is very useful.</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Further information such as stack traces
 | |
| may be useful. If you do send a stack trace,
 | |
| and the error is an X error, it will be more useful if the stacktrace is
 | |
| produced running the test program with the <literal>--sync</literal>
 | |
| command line option.</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Is there a Windows version of GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The Win32 port of GTK+ is maintained concurrently with the Xwindows
 | |
| version in CVS. As such it is a supported architecture.</para>
 | |
| 
 | |
| <para>The Win32 port has been predominately done by Tor Lillqvist. Tor
 | |
| maintains some information on <ulink url="http://www.gimp.org/~tml/gimp/win32/">
 | |
| GTK+ and GIMP for Windows</ulink>.</para>
 | |
| 
 | |
| <para>There is a pre-compiled, easy-to-install version of GTK+ for
 | |
| windows on the <ulink url="http://www.dropline.net/gtk/">
 | |
| Dropline GTK+</ulink> site.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What applications have been written with GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The GNOME software map contains a catalogue of software that is
 | |
| built using GNOME and GTK+. The catalogue is searchable and browsable, so
 | |
| provides easy access.</para>
 | |
| 
 | |
| <para>Some of the best known projects utilising GTK+ are:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara> GIMP (<ulink
 | |
| url="http://www.gimp.org/">http://www.gimp.org/</ulink>), an
 | |
| image manipulation program</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> AbiWord (<ulink
 | |
| url="http://www.abiword.org/">http://www.abiword.com/</ulink>),
 | |
| a professional word processor</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> Dia (<ulink
 | |
| url="http://www.lysator.liu.se/~alla/dia/dia.html">
 | |
| http://www.lysator.liu.se/~alla/dia/dia.html</ulink>),
 | |
| a diagram creation program</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> GnuCash (<ulink
 | |
| url="http://www.gnucash.org/">
 | |
| http://www.gnucash.org/</ulink>),
 | |
| a personal finance manager</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> Gnumeric (<ulink
 | |
| url="http://www.gnome.org/projects/gnumeric/">
 | |
| http://www.gnome.org/projects/gnumeric/</ulink>),
 | |
| the GNOME spreadsheet application</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> Glade (<ulink
 | |
| url="http://glade.gnome.org/">http://glade.gnome.org/</ulink>), a
 | |
| GTK+ based RAD tool which produces GTK+ and GNOME applications</simpara>
 | |
| </listitem>
 | |
| <listitem><simpara> Anjuta (<ulink
 | |
| url="http://anjuta.sourceforge.net/">http://anjuta.sourceforge.net/</ulink>),
 | |
| a versatile Integrated Development Environment (IDE) using C and C++ for GTK+
 | |
| and GIMP.</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>How to find, configure, install, and troubleshoot GTK+</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1 id="faq-Compile">
 | |
| <title>What do I need to compile GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>GTK+ is a large package that is dependent on a number of other
 | |
| tools and libraries. It is recommended that you use precompiled
 | |
| binary packages for your system if possible</para>
 | |
| 
 | |
| <para>To compile GTK+ from source you need a C compiler (gcc) and
 | |
| the X Window System and associated development libraries and packages
 | |
| on your system.</para>
 | |
| 
 | |
| <para>You will also need to have installed the tools
 | |
| and libraries that GTK+ depends upon. These are listed below in the order
 | |
| in which they need to be installed:</para>
 | |
| 
 | |
| <itemizedlist spacing=compact>
 | |
| <listitem><simpara> pkg-config
 | |
| (<ulink url="http://pkg-config.freedesktop.org/wiki">
 | |
| pkg-config Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> GNU make
 | |
| (<ulink url="http://www.gnu.org/software/make/">
 | |
| GNU make Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> JPEG, PNG and TIFF image libraries
 | |
| (<ulink url="ftp://ftp.gtk.org/pub/gtk/v2.2/dependencies/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> FreeType
 | |
| (<ulink url="http://www.freetype.org/">
 | |
| FreeType Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> fontconfig
 | |
| (<ulink url="http://www.fontconfig.org/">
 | |
| fontconfig Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> GNU libiconv library (if your system doesn't have iconv())
 | |
| (<ulink url="http://www.gnu.org/software/libiconv/">
 | |
| GNU libiconv Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> GNU gettext (if your system doesn't have gettext())
 | |
| (<ulink url="http://www.gnu.org/software/gettext/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> GLib
 | |
| (<ulink url="ftp://ftp.gtk.org/pub/gtk/v2.2/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Pango
 | |
| (<ulink url="ftp://ftp.gtk.org/pub/gtk/v2.2/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> ATK
 | |
| (<ulink url="ftp://ftp.gtk.org/pub/gtk/v2.2/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> GTK+
 | |
| (<ulink url="ftp://ftp.gtk.org/pub/gtk/v2.2/">
 | |
| GTK+ Site</ulink>)</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Where can I get GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The canonical site is <ulink
 | |
| url="ftp://ftp.gtk.org/pub/gtk">ftp://ftp.gtk.org/pub/gtk</ulink>.</para>
 | |
| 
 | |
| <para>This site tends to get busy around the time of a new
 | |
| GTK+ release so try and use one of the mirror sites that are
 | |
| listed in <ulink
 | |
| url="ftp://ftp.gtk.org/etc/mirrors">ftp://ftp.gtk.org/etc/mirrors
 | |
| </ulink></para>
 | |
| 
 | |
| <para>Here's a few mirror sites to get you started:</para>
 | |
| 
 | |
| <itemizedlist spacing=compact>
 | |
| <listitem><simpara> Africa -
 | |
| <ulink url="ftp://ftp.is.co.za/applications/gimp">
 | |
| ftp://ftp.is.co.za/applications/gimp</ulink></simpara> 
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Australia -
 | |
| <ulink
 | |
| url="ftp://ftp.planetmirror.com/pub/gimp/gtk">
 | |
| ftp://ftp.planetmirror.com/pub/gimp/gtk</ulink></simpara> 
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Finland -
 | |
| <ulink url="ftp://ftp.funet.fi/pub/sci/graphics/packages/gimp/gtk">
 | |
| ftp://ftp.funet.fi/pub/sci/graphics/packages/gimp/gtk</ulink></simpara> 
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Germany -
 | |
| <ulink url="ftp://ftp.gwdg.de/pub/misc/grafik/gimp/gtk">
 | |
| ftp://ftp.gwdg.de/pub/misc/grafik/gimp/gtk</ulink></simpara> 
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Japan -
 | |
| <ulink url="ftp://sunsite.sut.ac.jp/pub/archives/packages/gimp/gtk">
 | |
| ftp://sunsite.sut.ac.jp/pub/archives/packages/gimp/gtk</ulink></simpara> 
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> UK - 
 | |
| <ulink url="http://www.mirror.ac.uk/sites/ftp.gimp.org/pub/gtk/">
 | |
| http://www.mirror.ac.uk/sites/ftp.gimp.org/pub/gtk/</ulink></simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I configure/compile GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Generally, the minimum you need to do is issue the commands:</para>
 | |
| 
 | |
| <para><literallayout><literal>./configure</literal>
 | |
| <literal>make</literal>
 | |
| <literal>make install</literal></literallayout></para>
 | |
| 
 | |
| <para>in the GTK+ source directory.</para>
 | |
| 
 | |
| <para>This generally also holds true for each of the packages that GTK+
 | |
| depends upon, listed <link linkend="faq-Compile">above</link>.</para>
 | |
| 
 | |
| <para>There are various options that you can pass to the configure script
 | |
| in order to change its default settings. The one that you are most likely
 | |
| to want to use is the <literal>--prefix</literal>
 | |
| argument, which defines where the package is to be install, e.g.</para>
 | |
| 
 | |
| <para>
 | |
| <literallayout><literal>./configure --prefix=/usr</literal></literallayout>
 | |
| </para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>When compiling GTK+ I get an error like: <literal>make:
 | |
| file `Makefile' line 456: Syntax error</literal> <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Make sure that you are using GNU make
 | |
| (use <literal>make -v</literal>
 | |
| to check). There are many weird and wonderful versions of make
 | |
| out there, and not all of them handle the automatically
 | |
| generated Makefiles.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I've compiled and installed GTK+, but I can't get any
 | |
| programs to link with it! <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>This problem is most often encountered when the GTK+
 | |
| libraries can't be  found or are the wrong version. Generally,
 | |
| the compiler will complain about an 'unresolved symbol'.</para>
 | |
| 
 | |
| <para>Make sure that the libraries can be
 | |
| found. You want to edit <filename>/etc/ld.so.conf</filename> to
 | |
| include the directories which contain the GTK libraries,
 | |
| so it looks something like:</para>
 | |
| 
 | |
| <para><literallayout><literal>/usr/X11R6/lib</literal>
 | |
| <literal>/usr/local/lib</literal></literallayout></para>
 | |
| 
 | |
| <para>Then you need to run /sbin/ldconfig as root. You can
 | |
| find what libraries GTK requires using</para>
 | |
| 
 | |
| <para><literallayout><literal>pkg-config gtk+-2.0 --libs</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>If your system doesn't use ld.so to find libraries
 | |
| (such as Solaris), then you will have to use the LD_LIBRARY_PATH
 | |
| environment variable (or compile the path into your program, which I'm
 | |
| not going to cover here). So, with a Bourne type shell you can do (if
 | |
| your GTK libraries are in /usr/local/lib):</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>export LD_LIBRARY_PATH=/usr/local/lib</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>and in a csh, you can do:</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>setenv LD_LIBRARY_PATH /usr/local/lib</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>When installing a GTK+ application, configure reports
 | |
| that it can't find GTK. <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>There are several common reasons for this:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara>You have an old version of GTK installed
 | |
| somewhere. You should remove this old copy, but note that
 | |
| this may break applications that have been compiled against
 | |
| the old version.</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara><literal>pkg-config</literal> (or another
 | |
| component of GTK) isn't in your path, or there is an old
 | |
| version on your system. Type:</simpara>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>pkg-config gtk+-2.0 --modversion</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>to check for both of these. If it returns a value
 | |
| different from what you expect, then you have an old
 | |
| version of GTK on your system.</para>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>The ./configure script can't find the GTK
 | |
| libraries. As ./configure compiles various test programs, it needs to be
 | |
| able to find the GTK libraries. See the question above
 | |
| for help on this. </simpara></listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>If none of the above help, then have a look in
 | |
| config.log, which is generated by ./configure as it runs. At the
 | |
| bottom will be the last action it took before failing. If it is a
 | |
| section of source code, copy the source code to a file and compile it
 | |
| with the line just above it in config.log. If the compilation is
 | |
| successful, try executing it.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>Development of GTK+</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Whats this CVS thing that everyone keeps talking about,
 | |
| and how do I access it? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>CVS is the Concurrent Version System and is a very
 | |
| popular means of version control for software projects. It is
 | |
| designed to allow multiple authors 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
 | |
| their changes to.</para>
 | |
| 
 | |
| <para>The GTK+ developers use a CVS repository to store the
 | |
| master copy of the current development version of GTK+. As
 | |
| such, people wishing to contribute patches to GTK+ should
 | |
| generate them against the CVS version. Normal people should
 | |
| use the packaged releases.</para>
 | |
| 
 | |
| <para>The CVS toolset is available as RPM packages from the
 | |
| usual RedHat sites. The latest version is available at <ulink
 | |
| url="http://download.cyclic.com/pub/">http://download.cyclic.com/pub/
 | |
| </ulink></para>
 | |
| 
 | |
| <para>Anyone can download the latest CVS version of GTK+ by
 | |
| using anonymous access using the following steps:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara> In a bourne shell descendant (e.g. bash) type:</simpara>
 | |
| <para><literallayout>
 | |
| <literal>CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome'</literal>
 | |
| <literal>export CVSROOT</literal>
 | |
| </literallayout></para>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>Next, the first time the source tree is
 | |
| checked out, a cvs login is needed. </simpara>
 | |
| <para><literallayout>
 | |
| <literal>cvs login</literal>
 | |
| </literallayout></para>
 | |
| <para>This will ask you for a password. There is no
 | |
| password for cvs.gimp.org, so just enter a carriage return.</para>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>To get the tree and place it in a subdir of your
 | |
| current working directory, issue the command:</simpara>
 | |
| <para><literallayout>
 | |
| <literal>cvs -z3 get gtk+</literal>
 | |
| </literallayout></para>
 | |
| <para>Note that with the GTK+ 1.1 tree, glib has been moved to
 | |
| a separate CVS module, so if you don't have glib installed you will
 | |
| need to get that as well:</para>
 | |
| <para><literallayout>
 | |
| <literal>cvs -z3 get glib</literal>
 | |
| </literallayout></para>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>The CVS archive stores both the current development version of
 | |
| GTK+ (the CVS HEAD branch) and all current and past stable versions.
 | |
| If you want to retrieve a specific version of GTK+ you have to specify
 | |
| the CVS tag corresponding to the version you want to checkout. If you
 | |
| want to checkout the current GTK+ 2.2 stable source code, you would need
 | |
| to use the following command:</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>cvs -z3 get -r gtk-2-2 gtk+</literal>
 | |
| </literallayout></para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1 id="faq-Patches">
 | |
| <title>How can I contribute to GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>It's simple. If something doesn't work like you think it
 | |
| should in a program, check the documentation to make sure
 | |
| you're not missing something. If it is a true bug or missing
 | |
| feature, track it down in the GTK+ source, change it,  and
 | |
| then generate a patch in the form of a 'context diff'. This
 | |
| can be done using a command such as <literal>diff -ru
 | |
| <oldfile> <newfile></literal>.</para>
 | |
| 
 | |
| <para>The patch should then be attached to a bug report in
 | |
| the GNOME bug tracking system, which can also be used to store
 | |
| general patches
 | |
| (<ulink url="http://bugzilla.gnome.org">http://bugzilla.gnome.org</ulink>).
 | |
| </para>
 | |
| 
 | |
| <para>This method ensures that the patch will not be lost.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I know if my patch got applied, and if not, why
 | |
| not? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>If you have used the GNOME bug tracking system (as stated
 | |
| <link linkend="faq-Patches">above</link>) then the status
 | |
| of your patch should be reflected in the bug report.</para>
 | |
| 
 | |
| <para>The GTK+ developers will generally add comments to the bug
 | |
| report stating what needs to be done to get the patch applied,
 | |
| or why the patch is not appropriate.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What is the policy on incorporating new widgets into
 | |
| the library? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>This is up to the authors, so you will have to ask them
 | |
| once you are done with your widget. As a general guideline,
 | |
| widgets that are generally useful, work, and are not a
 | |
| disgrace to the widget set will gladly be included.</para>
 | |
| 
 | |
| <para>The new widgets that get added to GTK+ are generally either
 | |
| replacements for existing widgets that are no longer
 | |
| deemed to be adequate, or have been developed externally to GTK+ but
 | |
| have been widely tested. 
 | |
| 
 | |
| <para>Before you spend months of your valuable time implementing your
 | |
| revolutionary widget, it is highly recommended that you get some
 | |
| feedback on your idea via the appropriate 
 | |
| <link linkend="faq-MailLists">mailing list</link>.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Is anyone working on bindings for languages other than
 | |
| C? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>There is a list of <ulink url="http://www.gtk.org/bindings.html">
 | |
| language bindings</ulink> on the GTK+ website.</para>
 | |
| 
 | |
| <para>The 'official' language bindings are C++, Ada and Python.
 | |
| However, bindings for many other languages are available.</para>
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>Development with GTK+: the begining</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I get started? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>So, after you have installed GTK+ there are a couple of
 | |
| things that can ease you into developing applications with
 | |
| it. There is the GTK+ Tutorial <ulink
 | |
| url="http://library.gnome.org/devel/gtk-tutorial/stable/">
 | |
| http://library.gnome.org/devel/gtk-tutorial/stable/</ulink>, which is undergoing
 | |
| development. This will introduce you to writing applications
 | |
| using C.</para>
 | |
| 
 | |
| <para>The GTK+ Tutorial doesn't 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 in the
 | |
| directory 'tests' (and associated source files) within the GTK+
 | |
| distribution. Looking at these examples will give you a good
 | |
| grounding on what the widgets can do.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I use the Glade GUI builder with GTK+? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>There are two ways to use Glade. The first way is to use
 | |
| Glade's facilities for generating code; the second
 | |
| way is to use the libglade library which directly loads
 | |
| the XML user interface description files that Glade
 | |
| generates into a running program.</para>
 | |
| 
 | |
| <para>Experienced GTK+ programmers generally strongly recommend
 | |
| using libglade; you don't have to worry about the interaction
 | |
| between Glade generating the source and you editing it,
 | |
| and its been shown to be a method that works better
 | |
| for large projects, so there is a lot of example code
 | |
| out there you can look at.</para>
 | |
| 
 | |
| <para>An introduction to using libglade can be found in the 
 | |
| libglade API docs
 | |
| (<ulink url="http://developer.gnome.org/doc/API/2.0/libglade/libglade-notes.html#libglade-basics">
 | |
| http://developer.gnome.org/doc/API/2.0/libglade/libglade-notes.html#libglade-basics</ulink>)
 | |
| .</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I write security sensitive/SUID/SGID programs with GTK+?
 | |
| Is GTK+ secure? What's this GTK_MODULES security hole I heard about?
 | |
| <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The short answer to this question is: you can't, so don't write SUID/SGID
 | |
| programs with GTK+</para>
 | |
| 
 | |
| <para>GTK+ will refuse to run with elevated privileges, as it is not designed
 | |
| to be used in this manner. The only correct way to write a setuid program with
 | |
| a graphical user interface is to have a setuid backend that communicates with
 | |
| the non-setuid graphical user interface via a mechanism such as a pipe and that
 | |
| considers the input it receives to be untrusted.</para>
 | |
| 
 | |
| <para>For a more thorough explanation of the GTK+ Developers position on
 | |
| this issue see <ulink
 | |
| url="http://www.gtk.org/setuid.html">http://www.gtk.org/setuid.html</ulink>.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I tried to compile a small <command>Hello World</command> of mine,
 | |
| but it failed. Any clue? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Since you are good at coding, we will not deal with
 | |
| compile time errors here :)</para>
 | |
| 
 | |
| <para>The classic command line to compile a GTK+ based program is</para>
 | |
| <para><literallayout>
 | |
| <literal>gcc -o myprog [c files] `pkg-config gtk+-2.0 --cflags --libs`</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>You should notice the backquote character which is used
 | |
| in this command line. A common mistake when you start a GTK+
 | |
| based development is to use quotes instead of backquotes. If
 | |
| you do so, the compiler will complain about an unknown file
 | |
| called <filename>pkg-config gtk+-2.0 --cflags --libs</filename>. The
 | |
| text in backquotes is an instruction to your shell to
 | |
| substitute the output of executing this command into the
 | |
| commandline.</para>
 | |
| 
 | |
| <para>The command line above ensures that:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara>the correct C compiler flags will be used
 | |
| to compile the program (including the complete C header
 | |
| directory list)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>your program will be linked with the
 | |
| needed libraries.</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What about using the <command>make</command>
 | |
| utility? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>This is a sample makefile which compiles a GTK+ based
 | |
| program:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| # basic GTK+ app makefile
 | |
| SOURCES = myprg.c foo.c bar.c
 | |
| OBJS    = ${SOURCES:.c=.o}
 | |
| CFLAGS  = `pkg-config gtk+-2.0 --cflags`
 | |
| LDADD   = `pkg-config gtk+-2.0 --libs`
 | |
| CC      = gcc
 | |
| PACKAGE = myprg
 | |
| 
 | |
| all : ${OBJS}
 | |
|   ${CC} -o ${PACKAGE} ${OBJS} ${LDADD}
 | |
| 
 | |
| .c.o:
 | |
|   ${CC} ${CFLAGS} -c $<
 | |
| 
 | |
| # end of file
 | |
| </programlisting>
 | |
| 
 | |
| <para>For more information about the <command>make</command> utility, you
 | |
| should read either the related man page or the relevant info file.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I use the backquote stuff in my makefiles, but my make
 | |
| process failed. <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The backquote construction seems to not be accepted by
 | |
| some old <command>make</command> utilities. If you use one of these, the
 | |
| make process will probably fail. In order to have the
 | |
| backquote syntax working again, you should use the GNU make
 | |
| utility (get it on the GNU ftp server at <ulink
 | |
| url="ftp://ftp.gnu.org/gnu/make/">ftp://ftp.gnu.org/gnu/make/</ulink>).</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I want to add some configure stuff, how could I do
 | |
| this? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>To use autoconf/automake, you must first install the
 | |
| relevant packages. These are:</para>
 | |
| 
 | |
| <itemizedlist spacing=Compact>
 | |
| <listitem><simpara>the m4 preprocessor v1.4 or better</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>autoconf v2.54 or better</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>automake v1.7 or better suggested</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>You'll find these packages on the main GNU ftp server
 | |
| (<ulink url="ftp://ftp.gnu.org/">ftp://ftp.gnu.org/</ulink>)
 | |
| or on any GNU mirror.</para>
 | |
| 
 | |
| <para>In order to use the powerful autoconf/automake scheme,
 | |
| you must create a configure.in which may look like:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| dnl Process this file with autoconf to produce a configure script.
 | |
| dnl configure.in for a GTK+ based program
 | |
| 
 | |
| AC_INIT(myprg.c)
 | |
| AM_INIT_AUTOMAKE(mypkgname, 0.0.1)
 | |
| AM_CONFIG_HEADER(config.h)
 | |
| 
 | |
| 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_2_0(2.2.0,,AC_MSG_ERROR(mypkgname 0.1 needs GTK+ 2.2.0))
 | |
| 
 | |
| AC_OUTPUT(
 | |
| 	Makefile
 | |
| )
 | |
| </programlisting>
 | |
| 
 | |
| <para>You must add a Makefile.am file:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| bin_PROGRAMS    = myprg
 | |
| myprg_SOURCES   = myprg.c foo.c bar.c
 | |
| INCLUDES        = @GTK_CFLAGS@
 | |
| LDADD           = @GTK_LIBS@
 | |
| CLEANFILES      = *~
 | |
| DISTCLEANFILES  = .deps/*.P
 | |
| </programlisting>
 | |
| 
 | |
| <para>If your project contains more than one subdirectory,
 | |
| you'll have to create one Makefile.am in each directory plus a
 | |
| master Makefile.am which will look like:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| SUBDIRS         = mydir1 mydir2 mydir3
 | |
| </programlisting>
 | |
| 
 | |
| <para>then, to use these, simply type the following
 | |
| commands:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| aclocal
 | |
| autoheader
 | |
| autoconf
 | |
| automake --add-missing --include-deps --foreign 
 | |
| </programlisting>
 | |
| 
 | |
| <para>For further information, you should look at the autoconf
 | |
| and the automake documentation (the shipped info files are
 | |
| really easy to understand, and there are plenty of web
 | |
| resources that deal with autoconf and automake).</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I try to debug my GTK+ application with gdb, but it
 | |
| hangs my X server when I hit some breakpoint. Any
 | |
| Idea? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>From Federico Mena Quintero:</para>
 | |
| 
 | |
| <para><quote>X is not locked up.  It is likely that you are hitting a
 | |
| breakpoint inside a callback that is called from a place in Gtk that has
 | |
| a mouse grab.</quote></para>
 | |
| 
 | |
| <para><quote>Run your program with the <literal>--sync</literal>
 | |
| option; it will make it easier to debug. Also, you may want to
 | |
| use the console for running the debugger, and just let the
 | |
| program run in another console with the X server.</quote></para>
 | |
| 
 | |
| <para>Eric Mouw had another solution:</para>
 | |
| 
 | |
| <para><quote>An old terminal connected to an otherwise unused serial
 | |
| port is also great for debugging X programs. Old vt100/vt220
 | |
| terminals are dirt cheap but a bit hard to get (here in The
 | |
| Netherlands, YMMV).</quote></para>
 | |
| 
 | |
| <para>
 | |
| Another option is to run your application on Xnest. Xnest is an X server
 | |
| which displays its root window in a regular window of another X server.  
 | |
| A pointer grab on the Xnest display will not affect the GUI of your debugger
 | |
| running on your regular X server.
 | |
| <programlisting>
 | |
| Xnest :1
 | |
| twm -display :1
 | |
| myapp --display=:1
 | |
| </programlisting>
 | |
| </para>
 | |
| </sect1>
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>Development with GTK+: general questions</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What widgets are in GTK?</title>
 | |
| 
 | |
| <para>The GTK+ Tutorial lists the following widgets:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   GtkObject
 | |
|    +GtkData
 | |
|    | +GtkAdjustment
 | |
|    | `GtkTooltips
 | |
|    `GtkWidget
 | |
|      +GtkContainer
 | |
|      | +GtkBin
 | |
|      | | +GtkAlignment
 | |
|      | | +GtkEventBox
 | |
|      | | +GtkFrame
 | |
|      | | | `GtkAspectFrame
 | |
|      | | +GtkHandleBox
 | |
|      | | +GtkItem
 | |
|      | | | +GtkListItem
 | |
|      | | | +GtkMenuItem
 | |
|      | | | | `GtkCheckMenuItem
 | |
|      | | | |   `GtkRadioMenuItem
 | |
|      | | | `GtkTreeItem
 | |
|      | | +GtkViewport
 | |
|      | | `GtkWindow
 | |
|      | |   +GtkColorSelectionDialog
 | |
|      | |   +GtkDialog
 | |
|      | |   | `GtkInputDialog
 | |
|      | |   `GtkFileSelection
 | |
|      | +GtkBox
 | |
|      | | +GtkButtonBox
 | |
|      | | | +GtkHButtonBox
 | |
|      | | | `GtkVButtonBox
 | |
|      | | +GtkHBox
 | |
|      | | | +GtkCombo
 | |
|      | | | `GtkStatusbar
 | |
|      | | `GtkVBox
 | |
|      | |   +GtkColorSelection
 | |
|      | |   `GtkGammaCurve
 | |
|      | +GtkButton
 | |
|      | | +GtkOptionMenu
 | |
|      | | `GtkToggleButton
 | |
|      | |   `GtkCheckButton
 | |
|      | |     `GtkRadioButton
 | |
|      | +GtkCList
 | |
|      |   `GtkCTree
 | |
|      | +GtkFixed
 | |
|      | +GtkList
 | |
|      | +GtkMenuShell
 | |
|      | | +GtkMenuBar
 | |
|      | | `GtkMenu
 | |
|      | +GtkNotebook
 | |
|      | +GtkPaned
 | |
|      | | +GtkHPaned
 | |
|      | | `GtkVPaned
 | |
|      | +GtkScrolledWindow
 | |
|      | +GtkTable
 | |
|      | +GtkToolbar
 | |
|      | `GtkTree
 | |
|      +GtkDrawingArea
 | |
|      | `GtkCurve
 | |
|      +GtkEditable
 | |
|      | +GtkEntry
 | |
|      | | `GtkSpinButton
 | |
|      | `GtkText
 | |
|      +GtkMisc
 | |
|      | +GtkArrow
 | |
|      | +GtkImage
 | |
|      | +GtkLabel
 | |
|      | | `GtkTipsQuery
 | |
|      | `GtkPixmap
 | |
|      +GtkPreview
 | |
|      +GtkProgressBar
 | |
|      +GtkRange
 | |
|      | +GtkScale
 | |
|      | | +GtkHScale
 | |
|      | | `GtkVScale
 | |
|      | `GtkScrollbar
 | |
|      |   +GtkHScrollbar
 | |
|      |   `GtkVScrollbar
 | |
|      +GtkRuler
 | |
|      | +GtkHRuler
 | |
|      | `GtkVRuler
 | |
|      `GtkSeparator
 | |
|        +GtkHSeparator
 | |
|        `GtkVSeparator
 | |
| </programlisting>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Is GTK+ thread safe? How do I write multi-threaded GTK+
 | |
| applications? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The GLib library can be used in a thread-safe mode by
 | |
| calling g_thread_init() before making any other GLib
 | |
| calls. In this mode GLib automatically locks all internal
 | |
| data structures as needed.  This does not mean that two
 | |
| threads can simultaneously access, for example, a single hash
 | |
| table, but they can access two different hash tables
 | |
| simultaneously. If two different threads need to access the
 | |
| same hash table, the application is responsible for locking
 | |
| itself.</para>
 | |
| 
 | |
| <para>In order to make GDK thread aware, you also need to
 | |
| call gdk_threads_init() in conjunction with the above call.
 | |
| 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 throughout your code.</para>
 | |
| 
 | |
| <para>A minimal main program for a threaded GTK+ application
 | |
| looks like:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| int
 | |
| main (int argc, char *argv[])
 | |
| {
 | |
|   GtkWidget *window;
 | |
| 
 | |
|   /* init threads */	
 | |
|   g_thread_init(NULL);
 | |
|   gdk_threads_init();
 | |
|   
 | |
|   /* init gtk */
 | |
|   gtk_init(&argc, &argv);
 | |
| 
 | |
|   window = create_window();
 | |
|   gtk_widget_show(window);
 | |
| 
 | |
|   gdk_threads_enter();
 | |
|   gtk_main();
 | |
|   gdk_threads_leave();
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>Callbacks require a bit of attention. Callbacks from
 | |
| GTK+ (signals) are made within the GTK+ lock. However
 | |
| callbacks from GLib (timeouts, IO callbacks, and idle
 | |
| functions) are made outside of the GTK+ lock. So, within a
 | |
| signal handler you do not need to call gdk_threads_enter(),
 | |
| but within the other types of callbacks, you do.</para>
 | |
| 
 | |
| <para>Erik Mouw contributed the following code example to
 | |
| illustrate how to use threads within GTK+ programs.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| /*-------------------------------------------------------------------------
 | |
|  * Filename:      gtk-thread.c
 | |
|  * Version:       1.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:   Owen Taylor <otaylor@gtk.org>
 | |
|  * Modified at:   Wed May 28 10:43:00 2003
 | |
|  *-----------------------------------------------------------------------*/
 | |
| /*
 | |
|  * Compile with:
 | |
|  *
 | |
|  * cc -o gtk-thread gtk-thread.c `pkg-config --cflags --libs gtk+-2.0 gthread-2.0`
 | |
|  *
 | |
|  * Thanks to Sebastian Wilhelmi for pointing out some bugs in earlier versions.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <unistd.h>
 | |
| #include <gtk/gtk.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(g_random_int_range (1, 4));
 | |
| 
 | |
|       /* 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!");
 | |
| 
 | |
| 	  /* Make sure all X commands are sent to the X server; not strictly
 | |
| 	   * necessary here, but always a good idea when you do anything
 | |
| 	   * from a thread other than the one where the main loop is running.
 | |
| 	   */
 | |
| 	  gdk_flush ();
 | |
| 
 | |
| 	  /* release GTK thread lock */
 | |
| 	  gdk_threads_leave();
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
|   GtkWidget *window;
 | |
|   GtkWidget *label;
 | |
|   GError *error = NULL;
 | |
|   yes_or_no_args yes_args, no_args;
 | |
| 
 | |
|   /* init threads */
 | |
|   g_thread_init(NULL);
 | |
|   gdk_threads_init();
 | |
| 
 | |
|   /* init gtk */
 | |
|   gtk_init(&argc, &argv);
 | |
| 
 | |
|   /* create a window */
 | |
|   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 | |
| 
 | |
|   g_signal_connect(window, "destroy",
 | |
| 		   G_CALLBACK(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;
 | |
|   if (!g_thread_create(argument_thread, &yes_args, FALSE, &error))
 | |
|     {
 | |
|       g_printerr ("Failed to create YES thread: %s\n", error->message);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   no_args.label = label;
 | |
|   no_args.what = NO_IT_IS_NOT;
 | |
|   if (!g_thread_create(argument_thread, &no_args, FALSE, &error))
 | |
|     {
 | |
|       g_printerr ("Failed to create NO thread: %s\n", error->message);
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   /* enter the GTK main loop */
 | |
|   gdk_threads_enter();
 | |
|   gtk_main();
 | |
|   gdk_threads_leave();
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| </programlisting>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I'm doing some stuff with GTK+ in a separate thread, and
 | |
| properly locking with gdk_threads_enter/gdk_threads_leave()
 | |
| but the display doesn't update properly. <emphasis>[GTK 2.x]</emphasis>
 | |
| </title>
 | |
| 
 | |
| <para>For efficiency, the X window system batches up commands
 | |
| and sends them to the X server in batches instead of sending
 | |
| out immediately.</para>
 | |
| 
 | |
| <para>In a non-multithreaded program, you don't have to worry about
 | |
| this, since the first thing that happens when control returns
 | |
| to the main loop is that any outstanding X requests are 
 | |
| sent to the X server.</para>
 | |
| 
 | |
| <para>However, if you are making GTK+ calls from a thread other
 | |
| than the main loop, then GTK+ doesn't know when to send batched
 | |
| commands out. For that reason, after making GTK+ calls 
 | |
| in a separate thread, it is usually a good idea to call
 | |
| gdk_flush() before gdk_thread_leave().</para>
 | |
| 
 | |
| <para>Actually, gdk_flush() is more expensive than is necessary here,
 | |
| since it waits for the X server to finish outstanding commands
 | |
| as well; if performance is an issue, you may want to call
 | |
| XFlush() directly:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| 
 | |
| #include <gdk/gdkx.h>
 | |
| 
 | |
| void my_flush_commands (void)
 | |
| {
 | |
|   GdkDisplay *display = gdk_display_get_default ();
 | |
|   XFlush (GDK_DISPLAY_XDISPLAY (display);
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What's an easy way to run a function in the thread with
 | |
| the main loop? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Sometimes the simplest way to set up a threaded program
 | |
| is to make all the GTK+ calls in a single thread. In such
 | |
| a program, you should still call g_threads_init(), but
 | |
| don't need to call gdk_threads_init(), gkd_threads_enter(),
 | |
| and gdk_threads_leave().</para>
 | |
| 
 | |
| <para>If you set your program up this way, how then do you get
 | |
| the thread making GTK+ calls and running the main loop
 | |
| to do something in response to another thread?</para>
 | |
| 
 | |
| <para>An easy way to do it is to take advantage of the fact that
 | |
| the GLib main loop functions are all thread safe, and can
 | |
| be called from any thread by adding an idle function
 | |
| with g_idle_add(). The function provided will be called
 | |
| at the next opportunity by the main thread. If you want
 | |
| your function to take priority over event handling and
 | |
| drawing, you can instead use g_idle_add_full() and pass
 | |
| in a priority of G_PRIORITY_HIGH.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Why does this strange 'x io error' occur when I
 | |
| <literal>fork()</literal> in my GTK+ app? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>This is not really a GTK+ problem, and the problem is
 | |
| not related to <literal>fork()</literal> either. If the 'x io
 | |
| error' occurs then you probably use the <literal>exit()</literal> function
 | |
| in order to exit from the child process.</para>
 | |
| 
 | |
| <para>When GDK opens an X display, it creates a socket file
 | |
| descriptor. When you use the <literal>exit()</literal>
 | |
| function, you implicitly close all the open file descriptors,
 | |
| and the underlying X library really doesn't like this.</para>
 | |
| 
 | |
| <para>The right function to use here is
 | |
| <literal>_exit()</literal>.</para> 
 | |
| 
 | |
| <para>Erik Mouw contributed the following code example to
 | |
| illustrate handling fork() and exit().</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| /*-------------------------------------------------------------------------
 | |
|  * Filename:      gtk-fork.c
 | |
|  * Version:       0.99.2
 | |
|  * 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
 | |
|  * Modified by:   Tony Gale <gale@gtk.org>
 | |
|  * Modified at:   Wed Jan 14 12:38:00 2004
 | |
|  *-----------------------------------------------------------------------*/
 | |
| /*
 | |
|  * Compile with:
 | |
|  *
 | |
|  * cc -o gtk-fork gtk-fork.c `pkg-config gtk+-2.0 --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);
 | |
| 
 | |
|   g_signal_connect(G_OBJECT (window), "delete_event",
 | |
| 		     G_CALLBACK(delete_event), NULL);
 | |
|           
 | |
|   g_signal_connect(G_OBJECT (window), "destroy",
 | |
| 		     G_CALLBACK(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 useful */
 | |
|   button = gtk_button_new_with_label("Fork me!");
 | |
|           
 | |
|   g_signal_connect(G_OBJECT (button), "clicked",
 | |
| 		     G_CALLBACK(fork_me), NULL);
 | |
| 
 | |
|   gtk_container_add(GTK_CONTAINER(window), button);
 | |
|           
 | |
|   /* show everything */
 | |
|   gtk_widget_show (button);
 | |
|   gtk_widget_show (window);
 | |
| 
 | |
| 
 | |
|   /* install a signal handler for SIGCHLD signals */
 | |
|   signal(SIGCHLD, sigchld_handler);
 | |
| 
 | |
|   
 | |
|   /* main loop */
 | |
|   gtk_main ();
 | |
| 
 | |
|   exit(0);         
 | |
| }
 | |
| </programlisting>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Why don't the contents of a button move when the button
 | |
| is pressed? Here's a patch to make it work that way... <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>From: Peter Mattis</para>
 | |
| 
 | |
| <para><quote>The reason buttons don't move their child down and to
 | |
| the right when they are depressed is because I don't think
 | |
| that's what is happening visually. My view of buttons is
 | |
| that you are looking at them straight on. That is, the user
 | |
| interface lies in a plane and you're above it looking
 | |
| straight at it. When a button gets pressed it moves directly
 | |
| away from you. To be absolutely correct I guess the child
 | |
| should actually shrink a tiny amount. But I don't see why
 | |
| the child should shift down and to the left. Remember, the
 | |
| child is supposed to be attached to the buttons surface. Its
 | |
| not good for it to appear like the child is slipping on the
 | |
| surface of the button.</quote></para>
 | |
| 
 | |
| <para><quote>On a more practical note, I did implement this at one point
 | |
| and determined it didn't look good and removed it.</quote></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I identifiy a widgets top level window or other
 | |
| ancestor? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>There are a couple of ways to find the top level parent
 | |
| of a widget. The easiest way is to call the
 | |
| <literal>gtk_widget_get_toplevel()</literal> function that
 | |
| returns a pointer to a GtkWidget that is the top level
 | |
| window.</para>
 | |
| 
 | |
| <para>A more complicated way to do this (but less limited, as
 | |
| it allows the user to get the closest ancestor of a known type) is to use
 | |
| <literal>gtk_widget_get_ancestor()</literal> as in:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|       GtkWidget       *widget;
 | |
|       widget = gtk_widget_get_ancestor(w, GTK_TYPE_WINDOW);
 | |
| </programlisting>
 | |
| 
 | |
| <para>Since virtually all the GTK_TYPEs can be used as the
 | |
| second parameter of this function, you can get any parent
 | |
| widget of a particular widget. Suppose you have an hbox which
 | |
| contains a vbox, which in turn contains some other atomic
 | |
| widget (entry, label, etc. To find the master hbox using the
 | |
| <literal>entry</literal> widget simply use:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|       GtkWidget       *hbox;
 | |
|       hbox = gtk_widget_get_ancestor(w, GTK_TYPE_HBOX);
 | |
| </programlisting>
 | |
| 
 | |
| <para>You can also follow the a widgets ancestry by using the function
 | |
| <literal>gtk_widget_get_parent()</literal> that returns a pointer
 | |
| to a widgets parent widget.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I get the Window ID of a GtkWindow? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The actual Gdk/X window will be created when the widget
 | |
| gets realized. You can get the Window ID with:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| #include <gdk/gdkx.h>
 | |
| 
 | |
| Window xwin = GDK_WINDOW_XWINDOW (GTK_WIDGET (my_window)->window);
 | |
| </programlisting>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I catch a double click event? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>Tim Janik wrote to gtk-list (slightly modified):</para>
 | |
| 
 | |
| <para>Define a signal handler:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| gint
 | |
| signal_handler_event(GtkWidget *widget, GdkEventButton *event, gpointer func_data)
 | |
| {
 | |
|   if (GTK_IS_BUTTON(widget) &&
 | |
|        (event->type==GDK_2BUTTON_PRESS ||
 | |
|         event->type==GDK_3BUTTON_PRESS) ) {
 | |
|     printf("I feel %s clicked with button %d\n",
 | |
|            event->type==GDK_2BUTTON_PRESS ? "double" : "triple",
 | |
|            event->button);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }</programlisting>
 | |
| 
 | |
| <para>And connect the handler to your object:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| {
 | |
|   /* button init stuff */     
 | |
| 
 | |
|   g_signal_connect(G_OBJECT(button),
 | |
|                      "button_press_event",
 | |
|                      G_CALLBACK(signal_handler_event),
 | |
|                      NULL);
 | |
| 
 | |
|   /* and/or */
 | |
| 
 | |
|   g_signal_connect(G_OBJECT(button),
 | |
|                      "button_release_event",
 | |
|                      G_CALLBACK(signal_handler_event),
 | |
|                      NULL);
 | |
| 
 | |
|   /* something else */
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>and, Owen Taylor wrote:</para>
 | |
| 
 | |
| <para><quote>Note that a single button press will be received
 | |
| beforehand, and if you are doing this for a button, you will
 | |
| therefore also get a "clicked" signal for the button. (This
 | |
| is going to be true for any toolkit, since computers aren't
 | |
| good at reading one's mind.)</quote></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>By the way, what are the differences between signals
 | |
| and events?</title>
 | |
| 
 | |
| <para>First of all, Havoc Pennington gives a rather complete
 | |
| description of the differences between events and signals in
 | |
| his free book (two chapters can be found at <ulink
 | |
| url="http://www106.pair.com/rhp/sample_chapters.html">
 | |
| http://www106.pair.com/rhp/sample_chapters.html</ulink>).</para>
 | |
| 
 | |
| <para>Moreover, Havoc posted this to the <literal>gtk-list</literal>
 | |
| <quote>Events are a stream of messages received from the X
 | |
| server. They drive the Gtk main loop; which more or less
 | |
| amounts to "wait for events, process them" (not exactly, it
 | |
| is really more general than that and can wait on many
 | |
| different input streams at once). Events are a Gdk/Xlib
 | |
| concept.</quote></para>
 | |
| 
 | |
| <para><quote>Signals are a feature of GtkObject and its subclasses. They
 | |
| have nothing to do with any input stream; really a signal is just a way
 | |
| to keep a list of callbacks around and invoke them ("emit" the
 | |
| signal). There are lots of details and extra features of
 | |
| course. Signals are emitted by object instances, and are entirely
 | |
| unrelated to the Gtk main loop.  Conventionally, signals are emitted
 | |
| "when something changes" about the object emitting the
 | |
| signal.</quote></para>
 | |
| 
 | |
| <para><quote>Signals and events only come together because GtkWidget
 | |
| happens to emit signals when it gets events. This is purely a
 | |
| convenience, so you can connect callbacks to be invoked when a
 | |
| particular widget receives a particular event. There is nothing about
 | |
| this that makes signals and events inherently related concepts, any more
 | |
| than emitting a signal when you click a button makes button clicking and
 | |
| signals related concepts.</quote></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Data I pass to the <literal>delete_event</literal> (or other event)
 | |
| handler gets corrupted.</title>
 | |
| 
 | |
| <para>All event handlers take an additional argument which
 | |
| contains information about the event that triggered the
 | |
| handler. So, a <literal>delete_event</literal> handler must
 | |
| be declared as:</para>
 | |
| 
 | |
| 
 | |
| <programlisting role="C">
 | |
| gint delete_event_handler (GtkWidget   *widget,
 | |
|                            GdkEventAny *event,
 | |
|                            gpointer     data);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I have my signal connected to the the (whatever) event,
 | |
| but it seems I don't catch it. What's wrong?</title>
 | |
| 
 | |
| <para>There is some special initialisation to do in order to
 | |
| catch some particular events. In fact, you must set the
 | |
| correct event mask bit of your widget before getting some
 | |
| particular events.</para>
 | |
| 
 | |
| <para>For example,</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   gtk_widget_add_events(window, GDK_KEY_RELEASE_MASK);
 | |
| </programlisting>
 | |
| 
 | |
| <para>lets you catch the key release events. If you want to
 | |
| catch every events, simply us the GDK_ALL_EVENTS_MASK event
 | |
| mask.</para>
 | |
| 
 | |
| <para>All the event masks are defined in the
 | |
| <filename>gdktypes.h</filename> file.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I need to add a new signal to a GTK+ widget. Any
 | |
| idea?</title>
 | |
| 
 | |
| <para>If the signal you want to add may be beneficial for
 | |
| other GTK+ users, you may want to submit a patch that
 | |
| presents your changes. Check the tutorial for more
 | |
| information about adding signals to a widget class.</para>
 | |
| 
 | |
| <para>If you don't think it is the case or if your patch is
 | |
| not applied you'll have to use the
 | |
| <literal>gtk_object_class_user_signal_new</literal>
 | |
| function. <literal>gtk_object_class_user_signal_new</literal> allows you
 | |
| to add a new signal to a predefined GTK+ widget without any
 | |
| modification of the GTK+ source code. The new signal can be
 | |
| emited with <literal>gtk_signal_emit</literal> and can be
 | |
| handled in the same way as other signals.</para>
 | |
| 
 | |
| <para>Tim Janik posted this code snippet:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| static guint signal_user_action = 0;
 | |
| 
 | |
| signal_user_action =
 | |
|   gtk_object_class_user_signal_new (gtk_type_class (GTK_TYPE_WIDGET),
 | |
|                     "user_action",
 | |
|                     GTK_RUN_LAST | GTK_RUN_ACTION,
 | |
|                     gtk_marshal_NONE__POINTER,
 | |
|                     GTK_TYPE_NONE, 1,
 | |
|                     GTK_TYPE_POINTER);
 | |
| 
 | |
| void
 | |
| gtk_widget_user_action (GtkWidget *widget,
 | |
|                         gpointer   act_data)
 | |
| {
 | |
|   g_return_if_fail (GTK_IS_WIDGET (widget));
 | |
| 
 | |
|   gtk_signal_emit (GTK_OBJECT (widget), signal_user_action, act_data);
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you want your new signal to have more than the
 | |
| classical gpointer parameter, you'll have to play with GTK+
 | |
| marshallers.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Is it possible to get some text displayed which is
 | |
| truncated to fit inside its allocation?</title>
 | |
| 
 | |
| <para>GTK's behavior (no clipping) is a consequence of its
 | |
| attempts to conserve X resources. Label widgets (among
 | |
| others) don't get their own X window - they just draw their
 | |
| contents on their parent's window. While it might be possible
 | |
| to have clipping occur by setting the clip mask before
 | |
| drawing the text, this would probably cause a substantial
 | |
| performance penalty.</para>
 | |
| 
 | |
| <para>Its possible that, in the long term, the best solution
 | |
| to such problems might be just to change gtk to give labels X
 | |
| windows. A short term workaround is to put the label widget
 | |
| inside another widget that does get its own window - one
 | |
| possible candidate would be the viewport widget.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| viewport = gtk_viewport (NULL, NULL);
 | |
| gtk_widget_set_usize (viewport, 50, 25);
 | |
| gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
 | |
| gtk_widget_show(viewport);
 | |
| 
 | |
| label = gtk_label ("a really long label that won't fit");
 | |
| gtk_container_add (GTK_CONTAINER(viewport), label);
 | |
| gtk_widget_show (label);
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you were doing this for a bunch of widgets, you might
 | |
| want to copy gtkviewport.c and strip out the adjustment and
 | |
| shadow functionality (perhaps you could call it
 | |
| GtkClipper).</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I make my window modal? / How do I make a single
 | |
| window active?</title>
 | |
| 
 | |
| <para>After you create your window, do
 | |
| <literal>gtk_grab_add(my_window)</literal>. And after closing the window
 | |
| do <literal>gtk_grab_remove(my_window)</literal>.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Why doesn't my widget (e.g. progressbar)
 | |
| update? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>You are probably doing all the changes within a function without
 | |
| returning control to <literal>gtk_main()</literal>. This may
 | |
| be the case if you do some lengthy calculation in your
 | |
| code. Most drawing updates are only placed on a queue, which
 | |
| is processed within <literal>gtk_main()</literal>. You can force the
 | |
| drawing queue to be processed using something like:</para>
 | |
| 
 | |
| 
 | |
| <programlisting role="C">
 | |
| while (g_main_context_iteration(NULL, FALSE));
 | |
| </programlisting>
 | |
| 
 | |
| <para>inside you're function that changes the widget.</para>
 | |
| 
 | |
| <para>What the above snippet does is run all pending events
 | |
| and high priority idle functions, then return immediately
 | |
| (the drawing is done in a high priority idle function).</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I attach data to some GTK+ object/widget?
 | |
| <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>First of all, the attached data is stored in the
 | |
| object_data field of a GtkObject. The type of this field is
 | |
| GData, which is defined in glib.h.  So you should read the
 | |
| gdataset.c file in your glib source directory very
 | |
| carefully.</para>
 | |
| 
 | |
| <para>There are two (easy) ways to attach some data to a gtk
 | |
| object.  Using <literal>g_object_set_data()</literal> and
 | |
| <literal>g_object_get_data()</literal> seems to be the most
 | |
| common way to do this, as it provides a powerful interface to
 | |
| connect objects and data.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| void g_object_set_data(GObject *object, const gchar *key, gpointer data);
 | |
| 
 | |
| gpointer g_object_get_data(GObject *object, const gchar *key);
 | |
| </programlisting>
 | |
| 
 | |
| <para>Since a short example is better than any lengthy speech:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| struct my_struct	p1,p2,*result;
 | |
| GtkWidget		*w;
 | |
| 
 | |
| g_object_set_data(G_OBJECT(w),"p1 data",(gpointer)&p1);
 | |
| g_object_set_data(G_OBJECT(w),"p2 data",(gpointer)&p2);
 | |
| 
 | |
| result = g_object_get_data(G_OBJECT(w),"p1 data");
 | |
| </programlisting>
 | |
| 
 | |
| <para>The <literal>gtk_object_set_user_data()</literal> and
 | |
| <literal>gtk_object_get_user_data()</literal> functions does
 | |
| exactly the same thing as the functions above, but does not
 | |
| let you specify the "key" parameter.Instead, it uses a
 | |
| standard "user_data" key. Note that the use of these functions
 | |
| is deprecated in 1.2. They only provide a compatibility mode
 | |
| with some old gtk packages.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I remove the data I have attached to an
 | |
| object?</title>
 | |
| 
 | |
| <para>When attaching the data to the object, you can use the
 | |
| <literal>gtk_object_set_data_full()</literal> function. The three
 | |
| first arguments of the function are the same as in
 | |
| <literal>gtk_object_set_data()</literal>. The fourth one is a
 | |
| pointer to a callback function which is called when the data
 | |
| is destroyed. The data is destroyed when you:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara> destroy the object</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> replace the data with a new one (with
 | |
| the same key)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> replace the data with NULL (with the
 | |
| same key)</simpara>
 | |
| </listitem>
 | |
| 
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I reparent a widget?</title>
 | |
| 
 | |
| <para>The normal way to reparent (ie change the owner) of a
 | |
| widget should be to use the function:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| void gtk_widget_reparent (GtkWidget *widget, 
 | |
|                           GtkWidget *new_parent)
 | |
| </programlisting>
 | |
| 
 | |
| <para>But this is only a "should be" since this function does
 | |
| not correctly do its job on some specific widgets. The main
 | |
| goal of gtk_widget_reparent() is to avoid unrealizing widget
 | |
| if both widget and new_parent are realized (in this case,
 | |
| widget->window is successfully reparented). The problem here
 | |
| is that some widgets in the GTK+ hierarchy have multiple
 | |
| attached X subwindows and this is notably the case for the
 | |
| GtkSpinButton widget. For those, gtk_widget_reparent() will
 | |
| fail by leaving an unrealized child window where it should
 | |
| not.</para>
 | |
| 
 | |
| <para>To avoid this problem, simply use the following code
 | |
| snippet:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|      gtk_widget_ref(widget);
 | |
|      gtk_container_remove(GTK_CONTAINER(old_parent), widget);
 | |
|      gtk_container_add(GTK_CONTAINER(new_parent), widget);
 | |
|      gtk_widget_unref(widget);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How could I get any widgets position?</title>
 | |
| 
 | |
| <para>As Tim Janik pointed out, there are different cases, and
 | |
| each case requires a different solution.</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara> If you want the position of a widget
 | |
| relative to its parent, you should use
 | |
| <literal>widget->allocation.x</literal> and
 | |
| <literal>widget->allocation.y</literal>.</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> If you want the position of a window
 | |
| relative to the X root window, you should use
 | |
| <literal>gdk_window_get_geometry()</literal>
 | |
| <literal>gdk_window_get_position()</literal> or
 | |
| <literal>gdk_window_get_origin()</literal>.</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> If you want to get the position of the
 | |
| window (including the WM decorations), you should use
 | |
| <literal>gdk_window_get_root_origin()</literal>.</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara> Last but not least, if you want to get a Window
 | |
| Manager frame position, you should use
 | |
| <literal>gdk_window_get_deskrelative_origin()</literal>.</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>Your choice of Window Manager will have an effect of the
 | |
| results of the above functions. You should keep this in mind
 | |
| when writing your application. This is dependant upon how the
 | |
| Window Managers manage the decorations that they add around
 | |
| windows.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I set the size of a widget/window? How do I
 | |
| prevent the user resizing my window? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>The <literal>gtk_widget_set_size_request()</literal> function
 | |
| is used to set the size of a widget to a specific size.
 | |
| 
 | |
| The function
 | |
| <literal>gtk_window_set_resizable()</literal> function sets whether
 | |
| the user can resize a window, which they can by default. The
 | |
| definition of these functions are:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| void gtk_widget_set_size_request (GtkWidget *widget,
 | |
|                                   gint       width,
 | |
|                                   gint       height);
 | |
| 
 | |
| void gtk_window_set_resizable (GtkWindow *window,
 | |
|                                gboolean   resizable);
 | |
| 
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I add a popup menu to my GTK+ application?</title>
 | |
| 
 | |
| <para>The <literal>menu</literal> example in the examples/menu
 | |
| directory of the GTK+ distribution implements a popup menu
 | |
| with this technique:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| static gint button_press (GtkWidget *widget, GdkEvent *event)
 | |
| {
 | |
| 
 | |
|     if (event->type == GDK_BUTTON_PRESS) {
 | |
|         GdkEventButton *bevent = (GdkEventButton *) event; 
 | |
|         gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
 | |
|                         bevent->button, bevent->time);
 | |
|         /* Tell calling code that we have handled this event; the buck
 | |
|          * stops here. */
 | |
|         return TRUE;
 | |
|     }
 | |
| 
 | |
|     /* Tell calling code that we have not handled this event; pass it on. */
 | |
|     return FALSE;
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I disable or enable a widget, such as a
 | |
| button?</title>
 | |
| 
 | |
| <para>To disable (or to enable) a widget, use the
 | |
| <literal>gtk_widget_set_sensitive()</literal> function. The
 | |
| first parameter is you widget pointer. The second parameter is
 | |
| a boolean value: when this value is TRUE, the widget is
 | |
| enabled.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Shouldn't the text argument in the gtk_clist_*
 | |
| functions be declared const?</title>
 | |
| 
 | |
| <para>For example:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| gint gtk_clist_prepend (GtkCList *clist,
 | |
|                         gchar    *text[]);
 | |
| </programlisting>
 | |
| 
 | |
| <para>Answer: No, while a type "gchar*" (pointer to char) can
 | |
| automatically be cast into "const gchar*" (pointer to const
 | |
| char), this does not apply for "gchar *[]" (array of an
 | |
| unspecified number of pointers to char) into "const gchar *[]"
 | |
| (array of an unspecified number of pointers to const char).</para>
 | |
| 
 | |
| <para>The type qualifier "const" may be subject to automatic
 | |
| casting, but in the array case, it is not the array itself
 | |
| that needs the (const) qualified cast, but its members, thus
 | |
| changing the whole type.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I render pixels (image data) to the
 | |
| screen?</title>
 | |
| 
 | |
| <para>There are several ways to approach this. The simplest
 | |
| way is to use GdkRGB, see gdk/gdkrgb.h. You create an RGB
 | |
| buffer, render to your RGB buffer, then use GdkRGB routines to
 | |
| copy your RGB buffer to a drawing area or custom widget. The
 | |
| book "GTK+/Gnome Application Development" gives some details;
 | |
| GdkRGB is also documented in the GTK+ reference
 | |
| documentation.</para>
 | |
| 
 | |
| <para>If you're writing a game or other graphics-intensive
 | |
| application, you might consider a more elaborate
 | |
| solution. OpenGL is the graphics standard that will let you
 | |
| access hardware accelaration in future versions of XFree86; so
 | |
| for maximum speed, you probably want to use OpenGL. A
 | |
| GtkGLArea widget is available for using OpenGL with GTK+ (but
 | |
| GtkGLArea does not come with GTK+ itself). There are also
 | |
| several open source game libraries, such as ClanLib and Loki's
 | |
| Simple DirectMedia Layer library (SDL).</para>
 | |
| 
 | |
| <para>You do NOT want to use
 | |
| <literal>gdk_draw_point()</literal>, that will be extremely
 | |
| slow.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I create a pixmap without having my window being
 | |
| realized/shown?</title>
 | |
| 
 | |
| <para>Functions such as
 | |
| <literal>gdk_pixmap_create_from_xpm()</literal> require a
 | |
| valid window as a parameter. During the initialisation phase
 | |
| of an application, a valid window may not be available without
 | |
| showing a window, which may be inappropriate. In order to
 | |
| avoid this, a function such as
 | |
| <literal>gdk_pixmap_colormap_create_from_xpm</literal> can be
 | |
| used, as in:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   char *pixfile = "foo.xpm";
 | |
|   GtkWidget *top, *box, *pixw;
 | |
|   GdkPixmap *pixmap, *pixmap_mask;
 | |
| 
 | |
|   top = gtk_window_new (GKT_WINDOW_TOPLEVEL);
 | |
|   box = gtk_hbox_new (FALSE, 4);
 | |
|   gtk_conainer_add (GTK_CONTAINER(top), box);
 | |
|  
 | |
|   pixmap = gdk_pixmap_colormap_create_from_xpm (
 | |
|                NULL, gtk_widget_get_colormap(top),
 | |
|                &pixmap_mask, NULL, pixfile);
 | |
|   pixw = gtk_pixmap_new (pixmap, pixmap_mask);
 | |
|   gdk_pixmap_unref (pixmap);
 | |
|   gdk_pixmap_unref (pixmap_mask);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I do drag-and-drop?</title>
 | |
| 
 | |
| <para>GTK+ has a high level set of functions for doing inter-process
 | |
| communication via the drag-and-drop system. GTK+ can perform
 | |
| drag-and-drop on top of the low level Xdnd and Motif drag-and-drop
 | |
| protocols.</para>
 | |
| 
 | |
| <para>The documentation on GTK+ drag-and-drop isn't complete, but there
 | |
| is some information in the <ulink
 | |
| url="http://www.gtk.org/tutorial/">Tutorial</ulink>. You should also
 | |
| look at the drag-and-drop example code that is part of the GTK+ source
 | |
| distribution, in the file <filename>gtk/testdnd.c</filename>.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Why does GTK+/GLib leak memory?</title>
 | |
| 
 | |
| <para>It doesn't. Both GLib and the C library (malloc implementation)
 | |
| will cache allocated memory on occasion, even if you free it with
 | |
| free().</para>
 | |
| 
 | |
| <para>So you can't generally use tools such as top to see if you are
 | |
| using free() properly (aside from the very roughest of estimations, i.e.
 | |
| if you are really, really screwing up top will show that, but you can't
 | |
| distinguish small mistakes from the GLib/malloc caches).</para>
 | |
| 
 | |
| <para>In order to find memory leaks, use proper memory profiling
 | |
| tools.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>Development with GTK+: widget specific questions</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I find out about the selection of a GtkList?</title>
 | |
| 
 | |
| <para>Get the selection something like this:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| GList *sel;
 | |
| sel = GTK_LIST(list)->selection;
 | |
| </programlisting>
 | |
| 
 | |
| <para>This is how GList is defined (quoting glist.h):</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| typedef struct _GList GList;
 | |
| 
 | |
| struct _GList
 | |
| {
 | |
|   gpointer data;
 | |
|   GList *next;
 | |
|   GList *prev;
 | |
| };
 | |
| </programlisting>
 | |
| 
 | |
| <para>A GList structure is just a simple structure for doubly
 | |
| linked lists. There exist several g_list_*() functions to
 | |
| modify a linked list in glib.h.  However the
 | |
| GTK_LIST(MyGtkList)->selection is maintained by the
 | |
| gtk_list_*() functions and should not be modified.</para>
 | |
| 
 | |
| 
 | |
| <para>The selection_mode of the GtkList determines the
 | |
| selection facilities of a GtkList and therefore the contents
 | |
| of GTK_LIST(AnyGtkList)->selection:</para>
 | |
| 
 | |
| <informaltable frame="all">
 | |
| <tgroup cols="2">
 | |
| <thead>
 | |
| <row>
 | |
| <entry><literal>selection_mode</literal></entry>
 | |
| <entry><literal> GTK_LIST()->selection</literal>
 | |
| contents</entry>
 | |
| </row>
 | |
| </thead>
 | |
| 
 | |
| <tbody>
 | |
| <row>
 | |
| <entry><literal>GTK_SELECTION_SINGLE</literal></entry>
 | |
| <entry>selection is either NULL or contains a GList*
 | |
| pointer for a single selected item.</entry>
 | |
| </row>
 | |
| 
 | |
| <row>
 | |
| <entry><literal>GTK_SELECTION_BROWSE</literal></entry>
 | |
| <entry>selection is NULL if the list contains no
 | |
| widgets, otherwise it contains a GList*
 | |
| pointer for one GList structure.</entry>
 | |
| </row>
 | |
| 
 | |
| <row>
 | |
| <entry><literal>GTK_SELECTION_MULTIPLE</literal></entry>
 | |
| <entry>selection is NULL if no listitems are selected
 | |
| or a a GList* pointer for the first selected
 | |
| item. that in turn points to a GList structure
 | |
| for the second selected item and so
 | |
| on.</entry>
 | |
| </row>
 | |
| 
 | |
| <row>
 | |
| <entry><literal>GTK_SELECTION_EXTENDED</literal></entry>
 | |
| <entry>selection is NULL.</entry>
 | |
| </row>
 | |
| 
 | |
| </tbody>
 | |
| </tgroup>
 | |
| </informaltable>
 | |
| 
 | |
| <para>The data field of the GList structure
 | |
| GTK_LIST(MyGtkList)->selection points to the first
 | |
| GtkListItem that is selected.  So if you would like to
 | |
| determine which listitems are selected you should go like
 | |
| this:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| {
 | |
|         gchar           *list_items[]={
 | |
|                                 "Item0",
 | |
|                                 "Item1",
 | |
|                                 "foo",
 | |
|                                 "last Item",
 | |
|                         };
 | |
|         guint           nlist_items=sizeof(list_items)/sizeof(list_items[0]);
 | |
|         GtkWidget       *list_item;
 | |
|         guint           i;
 | |
| 
 | |
|         list=gtk_list_new();
 | |
|         gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_MULTIPLE);
 | |
|         gtk_container_add(GTK_CONTAINER(AnyGtkContainer), list);
 | |
|         gtk_widget_show (list);
 | |
| 
 | |
|         for (i = 0; i < nlist_items; i++)
 | |
|         {
 | |
|                 list_item=gtk_list_item_new_with_label(list_items[i]);
 | |
|                 gtk_object_set_user_data(GTK_OBJECT(list_item), (gpointer)i);
 | |
|                 gtk_container_add(GTK_CONTAINER(list), list_item);
 | |
|                 gtk_widget_show(list_item);
 | |
|         }
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>To get known about the selection:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| {
 | |
|         GList   *items;
 | |
| 
 | |
|         items=GTK_LIST(list)->selection;
 | |
| 
 | |
|         printf("Selected Items: ");
 | |
|         while (items) {
 | |
|                 if (GTK_IS_LIST_ITEM(items->data))
 | |
|                         printf("%d ", (guint) 
 | |
|                 gtk_object_get_user_data(items->data));
 | |
|                 items=items->next;
 | |
|         }
 | |
|         printf("\n");
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I stop the column headings of a GtkCList
 | |
| disappearing when the list is scrolled?</title>
 | |
| 
 | |
| <para>This happens when a GtkCList is packed into a
 | |
| GtkScrolledWindow using the function
 | |
| <literal>gtk_scroll_window_add_with_viewport()</literal>. The prefered
 | |
| method of adding a CList to a scrolled window is to use the
 | |
| function <literal>gtk_container_add</literal>, as in:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|     GtkWidget *scrolled, *clist;
 | |
|     char *titles[] = { "Title1" , "Title2" };
 | |
| 
 | |
|     scrolled = gtk_scrolled_window_new(NULL, NULL);
 | |
| 
 | |
|     clist = gtk_clist_new_with_titles(2, titles);
 | |
|     gtk_container_add(GTK_CONTAINER(scrolled), clist);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I don't want the user of my applications to enter text
 | |
| into a GtkCombo. Any idea?</title>
 | |
| 
 | |
| <para>A GtkCombo has an associated entry which can be accessed
 | |
| using the following expression:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|       GTK_COMBO(combo_widget)->entry
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you don't want the user to be able to modify the
 | |
| content of this entry, you can use the
 | |
| gtk_entry_set_editable() function:</para>
 | |
| 
 | |
| 
 | |
| <programlisting role="C">
 | |
|       void gtk_entry_set_editable(GtkEntry *entry, 
 | |
|                                   gboolean editable);
 | |
| </programlisting>
 | |
| 
 | |
| <para>Set the editable parameter to FALSE to disable typing
 | |
| into the entry.</para>
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I catch a combo box change?</title>
 | |
| 
 | |
| <para>The entry which is associated to your GtkCombo send a
 | |
| "changed" signal when:</para>
 | |
| 
 | |
| <itemizedlist>
 | |
| <listitem><simpara>some text is typed in</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>the selection of the combo box is changed</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| <para>To catch any combo box change, simply connect your
 | |
| signal handler with</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|       gtk_signal_connect(GTK_COMBO(cb)->entry,
 | |
|                          "changed",
 | |
|                          GTK_SIGNAL_FUNC(my_cb_change_handler),
 | |
|                          NULL);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How can I define a separation line in a menu?</title>
 | |
| 
 | |
| <para>See the <ulink
 | |
| url="http://www.gtk.org/tutorial/">Tutorial</ulink> for
 | |
| information on how to create menus. However, to create a
 | |
| separation line in a menu, just insert an empty menu item:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| menuitem = gtk_menu_item_new();
 | |
| gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 | |
| gtk_widget_show(menuitem);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How can I right justify a menu, such as Help?</title>
 | |
| 
 | |
| <para>Depending on if you use the MenuFactory or not, there
 | |
| are two ways to proceed. With the MenuFactory, use something
 | |
| like the following:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| menu_path = gtk_menu_factory_find (factory,  "<MyApp>/Help");
 | |
| gtk_menu_item_right_justify(menu_path->widget);
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you do not use the MenuFactory, you should simply
 | |
| use:</para>
 | |
| 
 | |
| 
 | |
| <programlisting role="C">
 | |
| gtk_menu_item_right_justify(my_menu_item);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I add some underlined accelerators to menu
 | |
| items?</title>
 | |
| 
 | |
| <para>Damon Chaplin, the technical force behind the Glade
 | |
| project, provided the following code sample (this code is an
 | |
| output from Glade). It creates a small <GUIMenu>File</guimenu> menu item
 | |
| with only one child (<guimenu>New</guimenu>). The F in
 | |
| <guimenu>File</guimenu> and the N in <guimenu>New</guimenu> are
 | |
| underlined, and the relevant accelerators are created.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   menubar1 = gtk_menu_bar_new ();
 | |
|   gtk_object_set_data (GTK_OBJECT (window1), "menubar1", menubar1);
 | |
|   gtk_widget_show (menubar1);
 | |
|   gtk_box_pack_start (GTK_BOX (vbox1), menubar1, FALSE, FALSE, 0);
 | |
| 
 | |
|   file1 = gtk_menu_item_new_with_label ("");
 | |
|   tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (file1)->child),
 | |
|                                    _("_File"));
 | |
|   gtk_widget_add_accelerator (file1, "activate_item", accel_group,
 | |
|                               tmp_key, GDK_MOD1_MASK, 0);
 | |
|   gtk_object_set_data (GTK_OBJECT (window1), "file1", file1);
 | |
|   gtk_widget_show (file1);
 | |
|   gtk_container_add (GTK_CONTAINER (menubar1), file1);
 | |
| 
 | |
|   file1_menu = gtk_menu_new ();
 | |
|   file1_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (file1_menu));
 | |
|   gtk_object_set_data (GTK_OBJECT (window1), "file1_menu", file1_menu);
 | |
|   gtk_menu_item_set_submenu (GTK_MENU_ITEM (file1), file1_menu);
 | |
| 
 | |
|   new1 = gtk_menu_item_new_with_label ("");
 | |
|   tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (new1)->child),
 | |
|                                    _("_New"));
 | |
|   gtk_widget_add_accelerator (new1, "activate_item", file1_menu_accels,
 | |
|                               tmp_key, 0, 0);
 | |
|   gtk_object_set_data (GTK_OBJECT (window1), "new1", new1);
 | |
|   gtk_widget_show (new1);
 | |
|   gtk_container_add (GTK_CONTAINER (file1_menu), new1);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How can I retrieve the text from a GtkMenuItem?</title>
 | |
| 
 | |
| <para>You can usually retrieve the label of a specific
 | |
| GtkMenuItem with:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|     if (GTK_BIN (menu_item)->child)
 | |
|     {
 | |
|       GtkWidget *child = GTK_BIN (menu_item)->child;
 | |
|   
 | |
|       /* do stuff with child */
 | |
|       if (GTK_IS_LABEL (child))
 | |
|       {
 | |
|         gchar *text;
 | |
|     
 | |
|         gtk_label_get (GTK_LABEL (child), &text);
 | |
|         g_print ("menu item text: %s\n", text);
 | |
|       }
 | |
|     }
 | |
| </programlisting>
 | |
| 
 | |
| <para>To get the active menu item from a GtkOptionMenu you can
 | |
| do:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| if (GTK_OPTION_MENU (option_menu)->menu_item)
 | |
| {
 | |
|   GtkWidget *menu_item = GTK_OPTION_MENU (option_menu)->menu_item;
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>But, there's a catch. For this specific case, you can
 | |
| <emphasis>not</emphasis> get the label widget from
 | |
| <literal>menu_item</literal> with the above code, because the
 | |
| option menu reparents the menu_item's child temporarily to
 | |
| display the currently active contents. So to retrive the child
 | |
| of the currently active menu_item of an option menu, you'll
 | |
| have to do:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|     if (GTK_BIN (option_menu)->child)
 | |
|     {
 | |
|       GtkWidget *child = GTK_BIN (option_menu)->child;
 | |
| 
 | |
|       /* do stuff with child */
 | |
|     }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I right (or otherwise) justify a
 | |
| GtkLabel?</title>
 | |
| 
 | |
| <para>Are you sure you want to <emphasis>justify</emphasis>
 | |
| the labels? The label class contains the
 | |
| <literal>gtk_label_set_justify()</literal> function that is
 | |
| used to control the justification of a multi-line
 | |
| label.</para>
 | |
| 
 | |
| <para>What you probably want is to set the <emphasis>alignment</emphasis>
 | |
| of the label, ie right align it, center it or left align
 | |
| it. If you want to do this, you should use:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| void gtk_misc_set_alignment (GtkMisc *misc,
 | |
|                              gfloat xalign,
 | |
|                              gfloat yalign);
 | |
| </programlisting>
 | |
| 
 | |
| <para>where the <literal>xalign</literal> and
 | |
| <literal>yalign</literal> values are floats in
 | |
| [0.00;1.00].</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| GtkWidget       *label;
 | |
| 
 | |
| /* horizontal : left align, vertical : top */
 | |
| gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.0f);
 | |
| 
 | |
| /* horizontal : centered, vertical : centered */
 | |
| gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
 | |
| 
 | |
| /* horizontal : right align, vertical : bottom */
 | |
| gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 1.0f);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I set the background color of a GtkLabel
 | |
| widget?</title>
 | |
| 
 | |
| <para>The GtkLabel widget is one of a few GTK+ widgets that
 | |
| don't create their own window to render themselves
 | |
| into. Instead, they draw themselves directly onto their
 | |
| parents window.</para>
 | |
| 
 | |
| <para>This means that in order to set the background color for
 | |
| a GtkLabel widget, you need to change the background color of
 | |
| its parent, i.e. the object that you pack it into.</para>
 | |
| 
 | |
| </sect1> 
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I set the color and font of a GtkLabel using a
 | |
| Resource File?</title>
 | |
| 
 | |
| <para>The widget name path constructed for a Label consists of
 | |
| the widget names of its object hierarchy as well, e.g.</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>window (name: humphrey)</literal>
 | |
| <literal>  hbox</literal>
 | |
| <literal>     label (name: mylabel)</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>The widget path your pattern needs to match would be:
 | |
| <literal>humphrey.GtkHBox.mylabel</literal></para>
 | |
| 
 | |
| <para>The resource file may look something like:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| style "title"
 | |
| {
 | |
|       fg[NORMAL] = {1.0, 0.0, 0.0}
 | |
|       font = "-adobe-helvetica-bold-r-normal--*-140-*-*-*-*-*-*"
 | |
| }
 | |
| widget "*mylabel" style "title"
 | |
| </programlisting>
 | |
| 
 | |
| <para>In your program, you would also need to give a name to
 | |
| the Label widget, which can be done using:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   label = gtk_label_new("Some Label Text");
 | |
|   gtk_widget_set_name(label, "mylabel");
 | |
|   gtk_widget_show(label);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I configure Tooltips in a Resource File?</title>
 | |
| 
 | |
| <para>The tooltip's window is named "gtk-tooltips",
 | |
| GtkTooltips in itself is not a GtkWidget (though a GtkObject)
 | |
| and as such is not attempted to match any widget styles.</para>
 | |
| 
 | |
| <para>So, your resource file should look something like:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| style "postie"
 | |
| {
 | |
|       bg[NORMAL] = {1.0, 1.0, 0.0}
 | |
| }
 | |
| widget "gtk-tooltips*" style "postie"
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>I can't add more than (something like) 2000 chars in a
 | |
| GtkEntry. What's wrong?</title>
 | |
| 
 | |
| <para>There is now a known problem in the GtkEntry widget. In
 | |
| the <literal>gtk_entry_insert_text()</literal> function, the
 | |
| following lines limit the number of chars in the entry to
 | |
| 2047.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   /* The algorithms here will work as long as, the text size (a
 | |
|    * multiple of 2), fits into a guint16 but we specify a shorter
 | |
|    * maximum length so that if the user pastes a very long text, there
 | |
|    * is not a long hang from the slow X_LOCALE functions.  */
 | |
| 
 | |
|   if (entry->text_max_length == 0)
 | |
|     max_length = 2047;
 | |
|   else
 | |
|     max_length = MIN (2047, entry->text_max_length);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I make a GtkEntry widget activate on pressing
 | |
| the Return key?</title>
 | |
| 
 | |
| <para>The Entry widget emits an 'activate' signal when you
 | |
| press return in it. Just attach to the activate signal on the
 | |
| entry and do whatever you want to do. Typical code would
 | |
| be:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   entry = gtk_entry_new();
 | |
|   gtk_signal_connect (GTK_OBJECT(entry), "activate",
 | |
|                       GTK_SIGNAL_FUNC(entry_callback),
 | |
|                       NULL);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I validate/limit/filter the input to a GtkEntry? <emphasis>[GTK 2.x]</emphasis></title>
 | |
| 
 | |
| <para>If you want to validate the text that a user enters into
 | |
| a GtkEntry widget you can attach to the "insert_text" signal
 | |
| of the entry, and modify the text within the callback
 | |
| function. The example below forces all characters to
 | |
| uppercase, and limits the range of characters to A-Z. Note
 | |
| that the entry is cast to an object of type GtkEditable, from
 | |
| which GtkEntry is derived.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| #include <ctype.h>
 | |
| #include <gtk/gtk.h>
 | |
| 
 | |
| void insert_text_handler (GtkEntry    *entry,
 | |
|                           const gchar *text,
 | |
|                           gint         length,
 | |
|                           gint        *position,
 | |
|                           gpointer     data)
 | |
| {
 | |
|   GtkEditable *editable = GTK_EDITABLE(entry);
 | |
|   int i, count=0;
 | |
|   gchar *result = g_new (gchar, length);
 | |
| 
 | |
|   for (i=0; i < length; i++) {
 | |
|     if (!isalpha(text[i]))
 | |
|       continue;
 | |
|     result[count++] = islower(text[i]) ? toupper(text[i]) : text[i];
 | |
|   }
 | |
|   
 | |
|   if (count > 0) {
 | |
|     g_signal_handlers_block_by_func (G_OBJECT (editable),
 | |
|                                      G_CALLBACK (insert_text_handler),
 | |
|                                      data);
 | |
|     gtk_editable_insert_text (editable, result, count, position);
 | |
|     g_signal_handlers_unblock_by_func (G_OBJECT (editable),
 | |
|                                        G_CALLBACK (insert_text_handler),
 | |
|                                        data);
 | |
|   }
 | |
|   g_signal_stop_emission_by_name (G_OBJECT (editable), "insert_text");
 | |
| 
 | |
|   g_free (result);
 | |
| }
 | |
| 
 | |
| int main (int   argc,
 | |
|           char *argv[])
 | |
| {
 | |
|   GtkWidget *window;
 | |
|   GtkWidget *entry;
 | |
|   
 | |
|   gtk_init (&argc, &argv);
 | |
|   
 | |
|   /* create a new window */
 | |
|   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 | |
|   gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
 | |
|   g_signal_connect (G_OBJECT (window), "destroy",
 | |
|                     G_CALLBACK (gtk_main_quit),
 | |
|                     NULL);
 | |
| 
 | |
|   entry = gtk_entry_new();
 | |
|   g_signal_connect(G_OBJECT(entry), "insert_text",
 | |
| 		     G_CALLBACK(insert_text_handler),
 | |
| 		     NULL);
 | |
|   gtk_container_add(GTK_CONTAINER (window), entry);
 | |
|   gtk_widget_show(entry);
 | |
|   
 | |
|   gtk_widget_show(window);
 | |
|   
 | |
|   gtk_main();
 | |
|   return(0);
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I use horizontal scrollbars with a GtkText widget?</title>
 | |
| 
 | |
| <para>The short answer is that you can't. The current version
 | |
| of the GtkText widget does not support horizontal
 | |
| scrolling. There is an intention to completely rewrite the
 | |
| GtkText widget, at which time this limitation will be
 | |
| removed.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I change the font of a GtkText widget?</title>
 | |
| 
 | |
| <para>There are a couple of ways of doing this. As GTK+ allows
 | |
| the appearance of applications to be changed at run time using
 | |
| resources you can use something like the following in the
 | |
| appropriate file:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| style "text"
 | |
| {
 | |
|   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>Another way to do this is to load a font within your
 | |
| program, and then use this in the functions for adding text to
 | |
| the text widget. You can load a font using, for example:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   GdkFont *font;
 | |
|   font = gdk_font_load("-adobe-helvetica-medium-r-normal--*-140-*-*-*-*-*-*");
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I set the cursor position in a GtkText
 | |
| object?</title>
 | |
| 
 | |
| <para>Notice that the response is valid for any object that
 | |
| inherits from the GtkEditable class.</para>
 | |
| 
 | |
| <para>Are you sure that you want to move the cursor position?
 | |
| Most of the time, while the cursor position is good, the
 | |
| insertion point does not match the cursor position. If this
 | |
| apply to what you really want, then you should use the
 | |
| <literal>gtk_text_set_point()</literal> function. If you want
 | |
| to set the insertion point at the current cursor position, use
 | |
| the following:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
|   gtk_text_set_point(GTK_TEXT(text),
 | |
|   gtk_editable_get_position(GTK_EDITABLE(text)));
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you want the insertion point to follow the cursor at
 | |
| all time, you should probably catch the button press event,
 | |
| and then move the insertion point. Be careful : you'll have to
 | |
| catch it after the widget has changed the cursor position
 | |
| though. Thomas Mailund Jensen proposed the following
 | |
| code:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| static void
 | |
| insert_bar (GtkWidget *text)
 | |
| {
 | |
|   /* jump to cursor mark */
 | |
|   gtk_text_set_point (GTK_TEXT (text),
 | |
|   gtk_editable_get_position (GTK_EDITABLE  (text)));
 | |
| 
 | |
|   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL,
 | |
|      "bar", strlen ("bar"));
 | |
| }
 | |
| 
 | |
| int
 | |
| main (int argc, char *argv[])
 | |
| {
 | |
|   GtkWidget *window, *text;
 | |
| 
 | |
|   gtk_init (&argc, &argv);
 | |
| 
 | |
|   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 | |
|   text = gtk_text_new (NULL, NULL);
 | |
|   gtk_text_set_editable (GTK_TEXT (text), TRUE);
 | |
|   gtk_container_add (GTK_CONTAINER (window), text);
 | |
| 
 | |
|   /* connect after everything else */
 | |
|   gtk_signal_connect_after (GTK_OBJECT(text), "button_press_event",
 | |
|     GTK_SIGNAL_FUNC (insert_bar), NULL);
 | |
| 
 | |
|   gtk_widget_show_all(window);
 | |
|   gtk_main();
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>Now, if you really want to change the cursor position,
 | |
| you should use the
 | |
| <literal>gtk_editable_set_position()</literal>
 | |
| function.</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>About GDK</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What is GDK?</title>
 | |
| 
 | |
| <para>GDK is basically a wrapper around the standard Xlib
 | |
| function calls. If you are at all familiar with Xlib, a lot of
 | |
| the functions in GDK will require little or no getting used
 | |
| to. All functions are written to provide an way to access Xlib
 | |
| functions in an easier and slightly more intuitive manner. In
 | |
| addition, since GDK uses GLib (see below), it will be more
 | |
| portable and safer to use on multiple platforms.</para>
 | |
| 
 | |
| <!-- Examples, anybody? I've been mulling some over. NF -->
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How do I use color allocation?</title>
 | |
| 
 | |
| <para>One of the nice things about GDK is that it's based on
 | |
| top of Xlib; this is also a problem, especially in the area of
 | |
| color management. If you want  to use color in your program
 | |
| (drawing a rectangle or such, your code  should look something
 | |
| like this:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| {
 | |
|   GdkColor *color;
 | |
|   int width, height;
 | |
|   GtkWidget *widget;
 | |
|   GdkGC *gc;
 | |
| 
 | |
|   ...
 | |
|   
 | |
|   /* first, create a GC to draw on */
 | |
|   gc = gdk_gc_new(widget->window);
 | |
| 
 | |
|   /* find proper dimensions for rectangle */
 | |
|   gdk_window_get_size(widget->window, &width, &height);
 | |
| 
 | |
|   /* the color we want to use */
 | |
|   color = (GdkColor *)malloc(sizeof(GdkColor));
 | |
|   
 | |
|   /* red, green, and blue are passed values, indicating the RGB triple
 | |
|    * of the color we want to draw. Note that the values of the RGB components
 | |
|    * within the GdkColor are taken from 0 to 65535, not 0 to 255.
 | |
|    */
 | |
|   color->red = red * (65535/255);
 | |
|   color->green = green * (65535/255);
 | |
|   color->blue = blue * (65535/255);
 | |
|   
 | |
|   /* the pixel value indicates the index in the colormap of the color.
 | |
|    * it is simply a combination of the RGB values we set earlier
 | |
|    */
 | |
|   color->pixel = (gulong)(red*65536 + green*256 + blue);
 | |
| 
 | |
|   /* However, the pixel valule is only truly valid on 24-bit (TrueColor)
 | |
|    * displays. Therefore, this call is required so that GDK and X can
 | |
|    * give us the closest color available in the colormap
 | |
|    */
 | |
|   gdk_color_alloc(gtk_widget_get_colormap(widget), color);
 | |
| 
 | |
|   /* set the foreground to our color */
 | |
|   gdk_gc_set_foreground(gc, color);
 | |
|   
 | |
|   /* draw the rectangle */
 | |
|   gdk_draw_rectangle(widget->window, gc, 1, 0, 0, width, height);
 | |
| 
 | |
|   ...
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| <chapter>
 | |
| <title>About GLib</title>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What is GLib?</title>
 | |
| 
 | |
| <para>GLib is a library of useful functions and definitions
 | |
| available for use  when creating GDK and GTK applications. It
 | |
| provides replacements for some standard libc functions, such
 | |
| as malloc, which are buggy on some systems.</para>
 | |
| 
 | |
| <para>It also provides routines for handling:</para>
 | |
| 
 | |
| <itemizedlist spacing=compact>
 | |
| <listitem><simpara>Doubly Linked Lists</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>Singly Linked Lists</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>Timers</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>String Handling</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>A Lexical Scanner</simpara>
 | |
| </listitem>
 | |
| 
 | |
| <listitem><simpara>Error Functions</simpara>
 | |
| </listitem>
 | |
| </itemizedlist>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>How can I use the doubly linked lists?</title>
 | |
| 
 | |
| <para>The GList object is defined as:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| typedef struct _GList GList;
 | |
| 
 | |
| struct _GList
 | |
| {
 | |
|   gpointer data;
 | |
|   GList *next;
 | |
|   GList *prev;
 | |
| };
 | |
| </programlisting>
 | |
| 
 | |
| <para>To use the GList objects, simply:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| GList   *list = NULL;
 | |
| GList   *listrunner;
 | |
| gint    array[] = { 1, 2, 3, 4, 5, 6 };
 | |
| gint    pos;
 | |
| gint    *value;
 | |
| 
 | |
| /* add data to the list */
 | |
| for (pos=0;pos < sizeof array; pos++) {
 | |
|   list = g_list_append(list, (gpointer)&array[pos]);
 | |
| }
 | |
| 
 | |
| /* run through the list */
 | |
| listrunner = g_list_first(list);
 | |
| while (listrunner) {
 | |
|   value = (gint *)listrunner->data;
 | |
|   printf("%d\n", *value);
 | |
|   listrunner = g_list_next(listrunner);
 | |
| }
 | |
| 
 | |
| /* removing datas from the list */
 | |
| listrunner = g_list_first(list);
 | |
| list = g_list_remove_link(list, listrunner);
 | |
| list = g_list_remove(list, &array[4]);
 | |
| </programlisting>
 | |
| 
 | |
| <para>The same code is usable with singly linked lists (GSList
 | |
| objects) by replacing g_list_* functions with the relevant
 | |
| g_slist_* ones (g_slist_append,  g_slist_remove, ...). Just
 | |
| remember that since you can't go backward in a singly linked
 | |
| list, there is no g_slist_first function - you'll need to keep
 | |
| a  reference on the first node of the list.</para>
 | |
| 
 | |
| <!-- Some Examples might be useful here! NF -->
 | |
| <!-- I believe it should be better :) ED -->
 | |
| <!-- Linked lists are pretty standard data structures - don't want to
 | |
| over do it - TRG -->
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Memory does not seem to be released when I free the
 | |
| list nodes I've allocated</title>
 | |
| 
 | |
| <para>GLib tries to be "intelligent" on this special issue: it
 | |
| assumes that you are likely to reuse the objects, so caches
 | |
| the allocated memory. If you do not want to use this behavior,
 | |
| you'll probably want to set up a special allocator.</para>
 | |
| 
 | |
| <para>To quote Tim Janik:</para>
 | |
| <para><quote>If you have a certain portion of code that uses *lots*
 | |
| of GLists or GNodes, and you know you'd better want to release
 | |
| all of them after a short while, you'd want to use a
 | |
| GAllocator. Pushing an allocator into g_list will make all
 | |
| subsequent glist operations private to that allocator's memory
 | |
| pool (and thus you have to take care to pop the allocator
 | |
| again, before making any external calls): </quote></para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| GAllocator *allocator;
 | |
| GList *list = NULL;
 | |
| guint i;
 | |
| 
 | |
| /* set a new allocation pool for GList nodes */
 | |
| allocator = g_allocator_new ("list heap", 1024);
 | |
| g_list_push_allocator (allocator);
 | |
| 
 | |
| /* do some list operations */
 | |
| for (i = 0; i < 4096; i++)
 | |
|   list = g_list_prepend (list, NULL);
 | |
| list = g_list_reverse (list);
 | |
| 
 | |
| /* beware to pop allocator befor calling external functions */
 | |
| g_list_pop_allocator ();
 | |
| gtk_label_set_text (GTK_LABEL (some_label), "some text");
 | |
| 
 | |
| /* and set our private glist pool again */
 | |
| g_list_push_allocator (allocator);
 | |
| 
 | |
| /* do some list operations */
 | |
| g_list_free (list);
 | |
| list = NULL;
 | |
| for (i = 0; i < 4096; i++)
 | |
|   list = g_list_prepend (list, NULL);
 | |
|   
 | |
| /* and back out (while freeing all of the list nodes in our pool) */
 | |
| g_list_pop_allocator ();
 | |
| g_allocator_free (allocator);
 | |
| </programlisting>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>Why use g_print, g_malloc, g_strdup and fellow glib
 | |
| functions?</title>
 | |
| 
 | |
| <para>Thanks to Tim Janik who wrote to gtk-list: (slightly
 | |
| modified)</para>
 | |
| 
 | |
| <para><quote>Regarding g_malloc(), g_free() and siblings, these
 | |
| functions are much safer than their libc equivalents. For
 | |
| example, g_free() just returns if called with NULL. Also, if
 | |
| USE_DMALLOC is defined, the definition for these functions
 | |
| changes (in glib.h) to use MALLOC(), FREE() etc... If
 | |
| MEM_PROFILE or MEM_CHECK are defined, there are even small
 | |
| statistics made counting the used block sizes (shown by
 | |
| g_mem_profile() / g_mem_check()).</quote></para>
 | |
| 
 | |
| <para><quote>Considering the fact that glib provides an interface for
 | |
| memory chunks to save space if you have lots of blocks that
 | |
| are always the same size and to mark them ALLOC_ONLY if
 | |
| needed, it is just straight forward to create a small saver
 | |
| (debug able) wrapper around the normal malloc/free stuff as
 | |
| well - just like gdk covers Xlib. ;)</quote></para>
 | |
| 
 | |
| <para><quote>Using g_error() and g_warning() inside of applications
 | |
| like the GIMP that fully rely on gtk even gives the
 | |
| opportunity to pop up a window showing the messages inside of
 | |
| a gtk window with your own handler (by using
 | |
| g_set_error_handler()) along the lines of
 | |
| <literal>gtk_print()</literal> (inside of
 | |
| gtkmain.c).</quote></para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| <sect1>
 | |
| <title>What's a GScanner and how do I use one?</title>
 | |
| 
 | |
| <para>A GScanner will tokenize your text, that is, it'll return
 | |
| an integer for every word or number that appears in its input
 | |
| stream, following certain (customizable) rules to perform this
 | |
| translation. You still need to write the parsing functions on
 | |
| your own though.</para>
 | |
| 
 | |
| <para>Here's a little test program supplied by Tim Janik that
 | |
| will parse</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal><SYMBOL> = <OPTIONAL-MINUS> <NUMBER> ;</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>constructs, while skipping "#\n" and "/**/" style
 | |
| comments.</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| #include <glib.h>
 | |
| 
 | |
| /* some test text to be fed into the scanner */
 | |
| static const gchar *test_text =
 | |
| ( "ping = 5;\n"
 | |
|   "/* slide in some \n"
 | |
|   " * comments, just for the\n"
 | |
|   " * fun of it \n"
 | |
|   " */\n"
 | |
|   "pong = -6; \n"
 | |
|   "\n"
 | |
|   "# the next value is a float\n"
 | |
|   "zonk = 0.7;\n"
 | |
|   "# redefine ping\n"
 | |
|   "ping = - 0.5;\n" );
 | |
| 
 | |
| /* define enumeration values to be returned for specific symbols */
 | |
| enum {
 | |
|   SYMBOL_PING = G_TOKEN_LAST + 1,
 | |
|   SYMBOL_PONG = G_TOKEN_LAST + 2,
 | |
|   SYMBOL_ZONK = G_TOKEN_LAST + 3
 | |
| };
 | |
| 
 | |
| /* symbol array */
 | |
| static const struct {
 | |
|   gchar *symbol_name;
 | |
|   guint  symbol_token;
 | |
| } symbols[] = {
 | |
|   { "ping", SYMBOL_PING, },
 | |
|   { "pong", SYMBOL_PONG, },
 | |
|   { "zonk", SYMBOL_ZONK, },
 | |
|   { NULL, 0, },
 | |
| }, *symbol_p = symbols;
 | |
| 
 | |
| static gfloat ping = 0;
 | |
| static gfloat pong = 0;
 | |
| static gfloat zonk = 0;
 | |
| 
 | |
| static guint
 | |
| parse_symbol (GScanner *scanner)
 | |
| {
 | |
|   guint symbol;
 | |
|   gboolean negate = FALSE;
 | |
| 
 | |
|   /* expect a valid symbol */
 | |
|   g_scanner_get_next_token (scanner);
 | |
|   symbol = scanner->token;
 | |
|   if (symbol < SYMBOL_PING ||
 | |
|       symbol > SYMBOL_ZONK)
 | |
|     return G_TOKEN_SYMBOL;
 | |
| 
 | |
|   /* expect '=' */
 | |
|   g_scanner_get_next_token (scanner);
 | |
|   if (scanner->token != '=')
 | |
|     return '=';
 | |
| 
 | |
|   /* feature optional '-' */
 | |
|   g_scanner_peek_next_token (scanner);
 | |
|   if (scanner->next_token == '-')
 | |
|     {
 | |
|       g_scanner_get_next_token (scanner);
 | |
|       negate = !negate;
 | |
|     }
 | |
| 
 | |
|   /* expect a float (ints are converted to floats on the fly) */
 | |
|   g_scanner_get_next_token (scanner);
 | |
|   if (scanner->token != G_TOKEN_FLOAT)
 | |
|     return G_TOKEN_FLOAT;
 | |
| 
 | |
|   /* make sure the next token is a ';' */
 | |
|   if (g_scanner_peek_next_token (scanner) != ';')
 | |
|     {
 | |
|       /* not so, eat up the non-semicolon and error out */
 | |
|       g_scanner_get_next_token (scanner);
 | |
|       return ';';
 | |
|     }
 | |
| 
 | |
|   /* assign value, eat the semicolon and exit successfully */
 | |
|   switch (symbol)
 | |
|     {
 | |
|     case SYMBOL_PING:
 | |
|       ping = negate ? - scanner->value.v_float : scanner->value.v_float;
 | |
|       break;
 | |
|     case SYMBOL_PONG:
 | |
|       pong = negate ? - scanner->value.v_float : scanner->value.v_float;
 | |
|       break;
 | |
|     case SYMBOL_ZONK:
 | |
|       zonk = negate ? - scanner->value.v_float : scanner->value.v_float;
 | |
|       break;
 | |
|     }
 | |
|   g_scanner_get_next_token (scanner);
 | |
| 
 | |
|   return G_TOKEN_NONE;
 | |
| }
 | |
| 
 | |
| int
 | |
| main (int argc, char *argv[])
 | |
| {
 | |
|   GScanner *scanner;
 | |
|   guint expected_token;
 | |
| 
 | |
|   scanner = g_scanner_new (NULL);
 | |
| 
 | |
|   /* adjust lexing behaviour to suit our needs
 | |
|    */
 | |
|   /* convert non-floats (octal values, hex values...) to G_TOKEN_INT */
 | |
|   scanner->config->numbers_2_int = TRUE;
 | |
|   /* convert G_TOKEN_INT to G_TOKEN_FLOAT */
 | |
|   scanner->config->int_2_float = TRUE;
 | |
|   /* don't return G_TOKEN_SYMBOL, but the symbol's value */
 | |
|   scanner->config->symbol_2_token = TRUE;
 | |
| 
 | |
|   /* load symbols into the scanner */
 | |
|   while (symbol_p->symbol_name)
 | |
|     {
 | |
|       g_scanner_add_symbol (scanner,
 | |
|                             symbol_p->symbol_name,
 | |
|                             GINT_TO_POINTER (symbol_p->symbol_token));
 | |
|       symbol_p++;
 | |
|     }
 | |
| 
 | |
|   /* feed in the text */
 | |
|   g_scanner_input_text (scanner, test_text, strlen (test_text));
 | |
| 
 | |
|   /* give the error handler an idea on how the input is named */
 | |
|   scanner->input_name = "test text";
 | |
| 
 | |
|   /* scanning loop, we parse the input until its end is reached,
 | |
|    * the scanner encountered a lexing error, or our sub routine came
 | |
|    * across invalid syntax
 | |
|    */
 | |
|   do
 | |
|     {
 | |
|       expected_token = parse_symbol (scanner);
 | |
|       
 | |
|       g_scanner_peek_next_token (scanner);
 | |
|     }
 | |
|   while (expected_token == G_TOKEN_NONE &&
 | |
|          scanner->next_token != G_TOKEN_EOF &&
 | |
|          scanner->next_token != G_TOKEN_ERROR);
 | |
| 
 | |
|   /* give an error message upon syntax errors */
 | |
|   if (expected_token != G_TOKEN_NONE)
 | |
|     g_scanner_unexp_token (scanner, expected_token, NULL, "symbol", NULL, NULL, TRUE);
 | |
| 
 | |
|   /* finsish parsing */
 | |
|   g_scanner_destroy (scanner);
 | |
| 
 | |
|   /* print results */
 | |
|   g_print ("ping: %f\n", ping);
 | |
|   g_print ("pong: %f\n", pong);
 | |
|   g_print ("zonk: %f\n", zonk);
 | |
|   
 | |
|   return 0;
 | |
| }
 | |
| </programlisting>
 | |
| 
 | |
| <para>You need to understand that the scanner will parse its
 | |
| input and tokenize it, it is up to you to interpret these
 | |
| tokens, not define their types before they get parsed,
 | |
| e.g. watch gscanner parse a string:</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>"hi i am 17"</literal>
 | |
| <literal> |  | |  |</literal>
 | |
| <literal> |  | |  v</literal>
 | |
| <literal> |  | v  TOKEN_INT, value: 17</literal>
 | |
| <literal> |  v TOKEN_IDENTIFIER, value: "am"</literal>
 | |
| <literal> v  TOKEN_CHAR, value: 'i'</literal>
 | |
| <literal>TOKEN_IDENTIFIER, value: "hi"</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>If you configure the scanner with:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| scanner->config->int_2_float = TRUE;
 | |
| scanner->config->char_2_token = TRUE;
 | |
| scanner->config->scan_symbols = TRUE;
 | |
| </programlisting>
 | |
| 
 | |
| <para>and add "am" as a symbol with</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| g_scanner_add_symbol (scanner, "am", "symbol value");
 | |
| </programlisting>
 | |
| 
 | |
| <para>GScanner will parse it as</para>
 | |
| 
 | |
| <para><literallayout>
 | |
| <literal>"hi i am 17"</literal>
 | |
| <literal> |  | |  |</literal>
 | |
| <literal> |  | |  v</literal>
 | |
| <literal> |  | v  TOKEN_FLOAT, value: 17.0  (automatic int->float conversion)</literal>
 | |
| <literal> |  | TOKEN_SYMBOL, value: "symbol value"  (a successfull hash table lookup</literal>
 | |
| <literal> |  |                                       turned a TOKEN_IDENTIFIER into a</literal>
 | |
| <literal> |  |                                       TOKEN_SYMBOL and took over the</literal>
 | |
| <literal> |  v                                       symbol's value)</literal>
 | |
| <literal> v  'i'  ('i' can be a valid token as well, as all chars >0 and <256)</literal>
 | |
| <literal>TOKEN_IDENTIFIER, value: "hi"</literal>
 | |
| </literallayout></para>
 | |
| 
 | |
| <para>You need to match the token sequence with your code, and
 | |
| if you encounter something that you don't want, you error
 | |
| out:</para>
 | |
| 
 | |
| <programlisting role="C">
 | |
| /* expect an identifier ("hi") */
 | |
| g_scanner_get_next_token (scanner);
 | |
| if (scanner->token != G_TOKEN_IDENTIFIER)
 | |
|   return G_TOKEN_IDENTIFIER;
 | |
| /* expect a token 'i' */
 | |
| g_scanner_get_next_token (scanner);
 | |
| if (scanner->token != 'i')
 | |
|   return 'i';
 | |
| /* expect a symbol ("am") */
 | |
| g_scanner_get_next_token (scanner);
 | |
| if (scanner->token != G_TOKEN_SYMBOL)
 | |
|   return G_TOKEN_SYMBOL;
 | |
| /* expect a float (17.0) */
 | |
| g_scanner_get_next_token (scanner);
 | |
| if (scanner->token != G_TOKEN_FLOAT)
 | |
|   return G_TOKEN_FLOAT;
 | |
| </programlisting>
 | |
| 
 | |
| <para>If you got past here, you have parsed "hi i am 17" and
 | |
| would have accepted "dooh i am 42" and  "bah i am 0.75" as
 | |
| well, but you would have not accepted "hi 7 am 17" or "hi i hi
 | |
| 17".</para>
 | |
| 
 | |
| </sect1>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ***************************************************************** -->
 | |
| 
 | |
| <chapter>
 | |
| <title>GTK+ FAQ Contributions, Maintainers and Copyright</title>
 | |
| 
 | |
| <para>If you would like to make a contribution to the FAQ, send either one
 | |
| of us an e-mail message with the exact text you think should be
 | |
| included (question and answer). With your help, this document can grow
 | |
| and become more useful!</para>
 | |
| 
 | |
| <para>This document is maintained by
 | |
| Tony Gale
 | |
| <ulink url="mailto:gale@gtk.org"><gale@gtk.org></ulink>
 | |
| 
 | |
| This FAQ was created by Shawn T. Amundson 
 | |
| <ulink url="mailto:amundson@gimp.org">
 | |
| <amundson@gimp.org></ulink>.
 | |
| 
 | |
| Contributions should be sent to Tony Gale <ulink
 | |
| url="mailto:gale@gtk.org"><gale@gtk.org></ulink></para>
 | |
| 
 | |
| <para>The GTK+ FAQ is Copyright (C) 1997-2003 by Shawn T. Amundson, 
 | |
| Tony Gale.</para>
 | |
| 
 | |
| <para>Permission is granted to make and distribute verbatim copies of this
 | |
| manual provided the copyright notice and this permission notice are
 | |
| preserved on all copies.</para>
 | |
| 
 | |
| <para>Permission is granted to copy and distribute modified versions of this
 | |
| document under the conditions for verbatim copying, provided that this
 | |
| copyright notice is included exactly as in the original, and that the
 | |
| entire resulting derived work is distributed under the terms of a
 | |
| permission notice identical to this one.</para>
 | |
| 
 | |
| <para>Permission is granted to copy and distribute translations of this
 | |
| document into another language, under the above conditions for
 | |
| modified versions.</para>
 | |
| 
 | |
| <para>If you are intending to incorporate this document into a published
 | |
| work, please contact one of the maintainers, and we will make an
 | |
| effort to ensure that you have the most up to date information
 | |
| available.</para>
 | |
| 
 | |
| <para>There is no guarentee that this document lives up to its intended
 | |
| purpose.  This is simply provided as a free resource.  As such, the
 | |
| authors and maintainers of the information provided within can not
 | |
| make any guarentee that the information is even accurate.</para>
 | |
| 
 | |
| </chapter>
 | |
| 
 | |
| <!-- ----------------------------------------------------------------- -->
 | |
| 
 | |
| </book>
 | 
