diff options
author | BST 2000 Tony Gale <gale@gtk.org> | 2000-07-04 12:14:41 +0000 |
---|---|---|
committer | Tony Gale <gale@src.gnome.org> | 2000-07-04 12:14:41 +0000 |
commit | f3d8cf9252152036ac2cc776e723fea8f6335c3c (patch) | |
tree | f06d3cd4e7f1ddd0817b56898ea9169620422aac /docs/faq | |
parent | f3f6fa88a5b798e98671c2e41535f214be3b4099 (diff) | |
download | gtk+-f3d8cf9252152036ac2cc776e723fea8f6335c3c.tar.gz |
Add remaining sections. Completes initial conversion to DocBook.
Tue Jul 4 13:13:01 BST 2000 Tony Gale <gale@gtk.org>
* docs/faq/gtk-faq.sgml: Add remaining sections. Completes
initial conversion to DocBook.
Diffstat (limited to 'docs/faq')
-rw-r--r-- | docs/faq/gtk-faq.sgml | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/docs/faq/gtk-faq.sgml b/docs/faq/gtk-faq.sgml index 181e4ee15b..580541bb12 100644 --- a/docs/faq/gtk-faq.sgml +++ b/docs/faq/gtk-faq.sgml @@ -2863,6 +2863,494 @@ main (int argc, char *argv[]) </sect2> </sect1> + <!-- ***************************************************************** --> + <sect1> + <title>About GLib</title> + + <!-- ----------------------------------------------------------------- --> + + <sect2> + <title>What is GLib?</title> + + <para>GLib is a library of useful functions and definitions + available for use when creating GDK and GTK applications. It + provides replacements for some standard libc functions, such + as malloc, which are buggy on some systems.</para> + + <para>It also provides routines for handling:</para> + + <itemizedlist> + <listitem><simpara>Doubly Linked Lists</simpara> + </listitem> + <listitem><simpara>Singly Linked Lists</simpara> + </listitem> + <listitem><simpara>Timers</simpara> + </listitem> + <listitem><simpara>String Handling</simpara> + </listitem> + <listitem><simpara>A Lexical Scanner</simpara> + </listitem> + <listitem><simpara>Error Functions</simpara> + </listitem> + </itemizedlist> + </sect2> + + <!-- ----------------------------------------------------------------- --> + + <sect2> + <title>How can I use the doubly linked lists?</title> + + <para>The GList object is defined as:</para> + +<programlisting role="C"> +typedef struct _GList GList; + +struct _GList +{ + gpointer data; + GList *next; + GList *prev; +}; +</programlisting> + + <para>To use the GList objects, simply:</para> + +<programlisting role="C"> +GList *list = NULL; +GList *listrunner; +gint array[] = { 1, 2, 3, 4, 5, 6 }; +gint pos; +gint *value; + +/* add data to the list */ +for (pos=0;pos < sizeof array; pos++) { + list = g_list_append(list, (gpointer)&array[pos]); +} + +/* run through the list */ +listrunner = g_list_first(list); +while (listrunner) { + value = (gint *)listrunner->data; + printf("%d\n", *value); + listrunner = g_list_next(listrunner); +} + +/* removing datas from the list */ +listrunner = g_list_first(list); +list = g_list_remove_link(list, listrunner); +list = g_list_remove(list, &array[4]); +</programlisting> + + <para>The same code is usable with singly linked lists (GSList + objects) by replacing g_list_* functions with the relevant + g_slist_* ones (g_slist_append, g_slist_remove, ...). Just + remember that since you can't go backward in a singly linked + list, there is no g_slist_first function - you'll need to keep + a reference on the first node of the list.</para> + + <!-- Some Examples might be useful here! NF --> + <!-- I believe it should be better :) ED --> + <!-- Linked lists are pretty standard data structures - don't want to + over do it - TRG --> + + </sect2> + + <!-- ----------------------------------------------------------------- --> + + <sect2> + <title>Memory does not seem to be released when I free the + list nodes I've allocated</title> + + <para>GLib tries to be "intelligent" on this special issue: it + assumes that you are likely to reuse the objects, so caches + the allocated memory. If you do not want to use this behavior, + you'll probably want to set up a special allocator.</para> + + <para>To quote Tim Janik:</para> + <para><quote>If you have a certain portion of code that uses *lots* + of GLists or GNodes, and you know you'd better want to release + all of them after a short while, you'd want to use a + GAllocator. Pushing an allocator into g_list will make all + subsequent glist operations private to that allocator's memory + pool (and thus you have to take care to pop the allocator + again, before making any external calls): </quote></para> + +<programlisting role="C"> +GAllocator *allocator; +GList *list = NULL; +guint i; + +/* set a new allocation pool for GList nodes */ +allocator = g_allocator_new ("list heap", 1024); +g_list_push_allocator (allocator); + +/* do some list operations */ +for (i = 0; i < 4096; i++) + list = g_list_prepend (list, NULL); +list = g_list_reverse (list); + +/* beware to pop allocator befor calling external functions */ +g_list_pop_allocator (); +gtk_label_set_text (GTK_LABEL (some_label), "some text"); + +/* and set our private glist pool again */ +g_list_push_allocator (allocator); + +/* do some list operations */ +g_list_free (list); +list = NULL; +for (i = 0; i < 4096; i++) + list = g_list_prepend (list, NULL); + +/* and back out (while freeing all of the list nodes in our pool) */ +g_list_pop_allocator (); +g_allocator_free (allocator); +</programlisting> + + </sect2> + + <!-- ----------------------------------------------------------------- --> + + <sect2> + <title>Why use g_print, g_malloc, g_strdup and fellow glib + functions?</title> + + <para>Thanks to Tim Janik who wrote to gtk-list: (slightly + modified)</para> + + <para><quote>Regarding g_malloc(), g_free() and siblings, these + functions are much safer than their libc equivalents. For + example, g_free() just returns if called with NULL. Also, if + USE_DMALLOC is defined, the definition for these functions + changes (in glib.h) to use MALLOC(), FREE() etc... If + MEM_PROFILE or MEM_CHECK are defined, there are even small + statistics made counting the used block sizes (shown by + g_mem_profile() / g_mem_check()).</quote></para> + + <para><quote>Considering the fact that glib provides an interface for + memory chunks to save space if you have lots of blocks that + are always the same size and to mark them ALLOC_ONLY if + needed, it is just straight forward to create a small saver + (debug able) wrapper around the normal malloc/free stuff as + well - just like gdk covers Xlib. ;)</quote></para> + + <para><quote>Using g_error() and g_warning() inside of applications + like the GIMP that fully rely on gtk even gives the + opportunity to pop up a window showing the messages inside of + a gtk window with your own handler (by using + g_set_error_handler()) along the lines of + <literal>gtk_print()</literal> (inside of + gtkmain.c).</quote></para> + + </sect2> + + <!-- ----------------------------------------------------------------- --> + + <sect2> + <title>What's a GScanner and how do I use one?</title> + + <para>A GScanner will tokenize your text, that is, it'll return + an integer for every word or number that appears in its input + stream, following certain (customizable) rules to perform this + translation. You still need to write the parsing functions on + your own though.</para> + + <para>Here's a little test program supplied by Tim Janik that + will parse</para> + + <para><literallayout> + <literal><SYMBOL> = <OPTIONAL-MINUS> <NUMBER> ;</literal> + </literallayout></para> + + <para>constructs, while skipping "#\n" and "/**/" style + comments.</para> + +<programlisting role="C"> +#include <glib.h> + +/* some test text to be fed into the scanner */ +static const gchar *test_text = +( "ping = 5;\n" + "/* slide in some \n" + " * comments, just for the\n" + " * fun of it \n" + " */\n" + "pong = -6; \n" + "\n" + "# the next value is a float\n" + "zonk = 0.7;\n" + "# redefine ping\n" + "ping = - 0.5;\n" ); + +/* define enumeration values to be returned for specific symbols */ +enum { + SYMBOL_PING = G_TOKEN_LAST + 1, + SYMBOL_PONG = G_TOKEN_LAST + 2, + SYMBOL_ZONK = G_TOKEN_LAST + 3 +}; + +/* symbol array */ +static const struct { + gchar *symbol_name; + guint symbol_token; +} symbols[] = { + { "ping", SYMBOL_PING, }, + { "pong", SYMBOL_PONG, }, + { "zonk", SYMBOL_ZONK, }, + { NULL, 0, }, +}, *symbol_p = symbols; + +static gfloat ping = 0; +static gfloat pong = 0; +static gfloat zonk = 0; + +static guint +parse_symbol (GScanner *scanner) +{ + guint symbol; + gboolean negate = FALSE; + + /* expect a valid symbol */ + g_scanner_get_next_token (scanner); + symbol = scanner->token; + if (symbol < SYMBOL_PING || + symbol > SYMBOL_ZONK) + return G_TOKEN_SYMBOL; + + /* expect '=' */ + g_scanner_get_next_token (scanner); + if (scanner->token != '=') + return '='; + + /* feature optional '-' */ + g_scanner_peek_next_token (scanner); + if (scanner->next_token == '-') + { + g_scanner_get_next_token (scanner); + negate = !negate; + } + + /* expect a float (ints are converted to floats on the fly) */ + g_scanner_get_next_token (scanner); + if (scanner->token != G_TOKEN_FLOAT) + return G_TOKEN_FLOAT; + + /* make sure the next token is a ';' */ + if (g_scanner_peek_next_token (scanner) != ';') + { + /* not so, eat up the non-semicolon and error out */ + g_scanner_get_next_token (scanner); + return ';'; + } + + /* assign value, eat the semicolon and exit successfully */ + switch (symbol) + { + case SYMBOL_PING: + ping = negate ? - scanner->value.v_float : scanner->value.v_float; + break; + case SYMBOL_PONG: + pong = negate ? - scanner->value.v_float : scanner->value.v_float; + break; + case SYMBOL_ZONK: + zonk = negate ? - scanner->value.v_float : scanner->value.v_float; + break; + } + g_scanner_get_next_token (scanner); + + return G_TOKEN_NONE; +} + +int +main (int argc, char *argv[]) +{ + GScanner *scanner; + guint expected_token; + + scanner = g_scanner_new (NULL); + + /* adjust lexing behaviour to suit our needs + */ + /* convert non-floats (octal values, hex values...) to G_TOKEN_INT */ + scanner->config->numbers_2_int = TRUE; + /* convert G_TOKEN_INT to G_TOKEN_FLOAT */ + scanner->config->int_2_float = TRUE; + /* don't return G_TOKEN_SYMBOL, but the symbol's value */ + scanner->config->symbol_2_token = TRUE; + + /* load symbols into the scanner */ + while (symbol_p->symbol_name) + { + g_scanner_add_symbol (scanner, + symbol_p->symbol_name, + GINT_TO_POINTER (symbol_p->symbol_token)); + symbol_p++; + } + + /* feed in the text */ + g_scanner_input_text (scanner, test_text, strlen (test_text)); + + /* give the error handler an idea on how the input is named */ + scanner->input_name = "test text"; + + /* scanning loop, we parse the input until its end is reached, + * the scanner encountered a lexing error, or our sub routine came + * across invalid syntax + */ + do + { + expected_token = parse_symbol (scanner); + + g_scanner_peek_next_token (scanner); + } + while (expected_token == G_TOKEN_NONE && + scanner->next_token != G_TOKEN_EOF && + scanner->next_token != G_TOKEN_ERROR); + + /* give an error message upon syntax errors */ + if (expected_token != G_TOKEN_NONE) + g_scanner_unexp_token (scanner, expected_token, NULL, "symbol", NULL, NULL, TRUE); + + /* finsish parsing */ + g_scanner_destroy (scanner); + + /* print results */ + g_print ("ping: %f\n", ping); + g_print ("pong: %f\n", pong); + g_print ("zonk: %f\n", zonk); + + return 0; +} +</programlisting> + + <para>You need to understand that the scanner will parse its + input and tokenize it, it is up to you to interpret these + tokens, not define their types before they get parsed, + e.g. watch gscanner parse a string:</para> + + <para><literallayout> + <literal>"hi i am 17"</literal> + <literal> | | | |</literal> + <literal> | | | v</literal> + <literal> | | v TOKEN_INT, value: 17</literal> + <literal> | v TOKEN_IDENTIFIER, value: "am"</literal> + <literal> v TOKEN_CHAR, value: 'i'</literal> + <literal>TOKEN_IDENTIFIER, value: "hi"</literal> + </literallayout></para> + + <para>If you configure the scanner with:</para> + +<programlisting role="C"> +scanner->config->int_2_float = TRUE; +scanner->config->char_2_token = TRUE; +scanner->config->scan_symbols = TRUE; +</programlisting> + + <para>and add "am" as a symbol with</para> + +<programlisting role="C"> +g_scanner_add_symbol (scanner, "am", "symbol value"); +</programlisting> + + <para>GScanner will parse it as</para> + + <para><literallayout> + <literal>"hi i am 17"</literal> + <literal> | | | |</literal> + <literal> | | | v</literal> + <literal> | | v TOKEN_FLOAT, value: 17.0 (automatic int->float conversion)</literal> + <literal> | | TOKEN_SYMBOL, value: "symbol value" (a successfull hash table lookup</literal> + <literal> | | turned a TOKEN_IDENTIFIER into a</literal> + <literal> | | TOKEN_SYMBOL and took over the</literal> + <literal> | v symbol's value)</literal> + <literal> v 'i' ('i' can be a valid token as well, as all chars >0 and <256)</literal> + <literal>TOKEN_IDENTIFIER, value: "hi"</literal> + </literallayout></para> + + <para>You need to match the token sequence with your code, and + if you encounter something that you don't want, you error + out:</para> + +<programlisting role="C"> +/* expect an identifier ("hi") */ +g_scanner_get_next_token (scanner); +if (scanner->token != G_TOKEN_IDENTIFIER) + return G_TOKEN_IDENTIFIER; +/* expect a token 'i' */ +g_scanner_get_next_token (scanner); +if (scanner->token != 'i') + return 'i'; +/* expect a symbol ("am") */ +g_scanner_get_next_token (scanner); +if (scanner->token != G_TOKEN_SYMBOL) + return G_TOKEN_SYMBOL; +/* expect a float (17.0) */ +g_scanner_get_next_token (scanner); +if (scanner->token != G_TOKEN_FLOAT) + return G_TOKEN_FLOAT; +</programlisting> + + <para>If you got past here, you have parsed "hi i am 17" and + would have accepted "dooh i am 42" and "bah i am 0.75" as + well, but you would have not accepted "hi 7 am 17" or "hi i hi + 17".</para> + + </sect2> + </sect1> + <!-- ***************************************************************** --> + <sect1> + <title>GTK+ FAQ Contributions, Maintainers and Copyright</title> + +<para>If you would like to make a contribution to the FAQ, send either one +of us an e-mail message with the exact text you think should be +included (question and answer). With your help, this document can grow +and become more useful!</para> + +<para>This document is maintained by +Tony Gale <ulink + url="mailto:gale@gtk.org"><gale@gtk.org></ulink> + +Nathan Froyd <ulink url="mailto:maestrox@geocities.com"> +<maestrox@geocities.com></ulink>, +and +Emmanuel Deloget <ulink url="mailto:logout@free.fr"> +<logout@free.fr></ulink>. +This FAQ was created by Shawn T. Amundson +<ulink url="mailto:amundson@gimp.org"> +<amundson@gimp.org></ulink> who continues to provide support. + +Contributions should be sent to Tony Gale <ulink +url="mailto:gale@gtk.org"><gale@gtk.org></ulink></para> + +<para>The GTK+ FAQ is Copyright (C) 1997-2000 by Shawn T. Amundson, +Tony Gale, Emmanuel Deloget and Nathan Froyd.</para> + +<para>Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies.</para> + +<para>Permission is granted to copy and distribute modified versions of this +document under the conditions for verbatim copying, provided that this +copyright notice is included exactly as in the original, and that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one.</para> + +<para>Permission is granted to copy and distribute translations of this +document into another language, under the above conditions for +modified versions.</para> + +<para>If you are intending to incorporate this document into a published +work, please contact one of the maintainers, and we will make an +effort to ensure that you have the most up to date information +available.</para> + +<para>There is no guarentee that this document lives up to its intended +purpose. This is simply provided as a free resource. As such, the +authors and maintainers of the information provided within can not +make any guarentee that the information is even accurate.</para> + + </sect1> + </chapter> <!-- ----------------------------------------------------------------- --> |