Synhilite demo page

Copyright 2005 Aleksandr Koltsoff (czr@iki.fi)

This is an XHTML 1.0/Strict + CSS2 page generated by synhilite (or rather, its composition manager). It aims to demonstrate and test the features of synhilite. This page is generated by the composition manager out of pre-written xml-files and instructions to include some parts of source code (in this case it is a simple hildon program listing which is buggy, old and shouldn't be used).

Be sure to try the API reference-links and also note that most listing have the tooltip style enabled, so hover your mouse pointer of the hyperlink a while and you'll see a prototype for the function. The information necessary for this kind of linking is gathered by a custom program that reads gtkdoc-generated html-pages and gathers prototype and id-information as well as deprecation status. This tool is independent of the generator. One could easily (depending on fluency in python) write more tools to generate API refs based on other documentation as well.

Source for the generator is not available at the moment (it's not ready and maybe never will be). I need this tool to make better training material (this tool is just one small part of a larger set of tools)

This project consists at the moment from the following components:

Splitting the API doc information generation, preprocessing and composition into separate stages allow synhilite to be used as a modular part of a larger automatic documentation generation system (docs-2000). The larger system is driven via Makefiles which means that a change in a sourcefile will trigger the regeneration of the relevant documentation files (and only them, not the ones that don't need regeneration).

Why another generator? The world is filled with straight C->HTML translators as it is, but none of them were satisfactory for my needs (unsatisfactory C tokenization, old-world HTML output, not retargettable to other output languages, lack of API reflink generation, lack of selection support, etc).


Project statistics:
Lines of Python source code: 1512 total, Total Physical Source Lines of Code (SLOC) = 798
Lines of C code: 0


Note that the shl-file is read only once at composition stage (ie there is no need to reread the source or the shl file everytime we want to include some different part of the source)

Full listing of example source code:

   1 /**
   2  * hildon_helloworld-9.c
   3  *
   4  * We'll keep the color as a setting in our preferences
   5  * (infact, three settings)
   6  *
   7  */
   8 
   9 #include <gdk/gdkkeysyms.h>
  10 #include <gtk/gtk.h>
  11 #include <hildon-widgets/hildon-app.h>
  12 #include <hildon-widgets/hildon-color-button.h>
  13 #include <hildon-widgets/hildon-find-toolbar.h>
  14 #include <hildon-widgets/hildon-file-chooser-dialog.h>
  15 #include <hildon-widgets/gtk-infoprint.h>
  16 #include <libgnomevfs/gnome-vfs.h>
  17 /* include prototypes for GConf client-part */
  18 #include <gconf/gconf-client.h>
  19 
  20 
  21 /* we'll use this as a part of GConf-key */
  22 #define APP_NAME "hildon_hello"
  23 /* this will be the root "directory" for our preferences */
  24 #define GC_ROOT  "/apps/" APP_NAME "/"
  25 
  26 enum {
  27   STYLE_SLANT_NORMAL = 0,
  28   STYLE_SLANT_ITALIC
  29 };
  30 
  31 /**
  32  * This is totally bogus code to test out deprecation support
  33  * in synhilite
  34  */
  35 void blart(void) {
  36   gtk_clist_set_column_justification(NULL, 0, blart);
  37 }
  38 
  39 /**
  40  * NEW
  41  *
  42  * Utility function to store the given color into our
  43  * application preferences.
  44  * We could decide on use a list of integers as well,
  45  * but we'll settle for three separate properties,
  46  * one for each of RGB channels.
  47  *
  48  * The config keys used are 'red', 'green' and 'blue'
  49  *
  50  * Also note that we're doing things very un-optimally.
  51  * If our application would have multiple preference
  52  * settings, and we would like to know when someone
  53  * will change them (external program, another instance
  54  * of our program, etc), we'd have to keep a reference
  55  * to the GConf client connection.
  56  *
  57  * This way, you'll see how to release the object since
  58  * we explicitly don't want to hold a reference to it
  59  * between calls.
  60  */
  61 void confStoreColor(GdkColor* color) {
  62 
  63   /* this will be a pointer to the object once we get
  64      the connection */
  65   GConfClient* gcClient = NULL;
  66 
  67   /* there is no such thing as GDK_IS_COLOR since color
  68      is just a plain structure with four elements,
  69      not a proper GObject */
  70   g_assert(color);
  71 
  72   g_print("confStoreColor: invoked\n");
  73 
  74   /* open connection to gconfd-2 (via d-bus in maemo)
  75      the GConf API doesn't say whether this function
  76      can ever return NULL or how it will behave in
  77      error conditions */
  78   gcClient = gconf_client_get_default();
  79   /* we make sure that it's a valid GConf-client object */
  80   g_assert(GCONF_IS_CLIENT(gcClient));
  81 
  82   /* set the values (these will write them out) */
  83   if (!gconf_client_set_int(gcClient, GC_ROOT "red",
  84        color->red, NULL)) {
  85     g_warning(" failed to set %s/red to %d\n", GC_ROOT,
  86       color->red);
  87   }
  88   if (!gconf_client_set_int(gcClient, GC_ROOT "green",
  89       color->green, NULL)) {
  90     g_warning(" failed to set %s/green to %d\n", GC_ROOT,
  91       color->red);
  92   }
  93   if (!gconf_client_set_int(gcClient, GC_ROOT "blue",
  94       color->blue, NULL)) {
  95     g_warning(" failed to set %s/blue to %d\n", GC_ROOT,
  96       color->red);
  97   }
  98 
  99   /* release the client object (with GObject-unref) */
 100   g_object_unref(gcClient);
 101   gcClient = NULL;
 102 }
 103 
 104 /**
 105  * NEW
 106  *
 107  * Helper function to get an integer but also return
 108  * the status whether the given key existed or not.
 109  *
 110  * Note that it's also possible to use
 111  * gconf_client_get_int() but it's not possible then
 112  * to know whether they key existed or not, because it
 113  * will return 0 if the key doesn't exist.
 114  *
 115  * Parameters:
 116  * - GConfClient: client object to use
 117  * - const gchar*: key
 118  * - gint*: address to store the integer to if the key exists
 119  *
 120  * Returns:
 121  * - TRUE: if integer has been updated with a value from GConf
 122  *   FALSE: there was no such key or it wasn't an integer
 123  */
 124 gboolean confGetInt(GConfClient* gcClient, const gchar* key,
 125   gint* number) {
 126 
 127   /* this will hold our type/value pair at some point */
 128   GConfValue* val = NULL;
 129   /* what should we return */
 130   gboolean hasChanged = FALSE;
 131 
 132   /* try to get the type/value from GConf DB.
 133      note that we're using a version that will not return
 134      any defaults (if a schema would say one) just to be sure
 135      whether the key exists or not, really.
 136 
 137      We're not really interested in errors as this will
 138      return a NULL in case of missing keys or errors and that
 139      is quite enough for us */
 140   val = gconf_client_get_without_default(gcClient, key, NULL);
 141   if (val == NULL) {
 142     /* key not found, no need to touch anything */
 143     g_warning("confGetInt: key %s not found\n", key);
 144     return FALSE;
 145   }
 146 
 147   /* check whether the value stored behind the key is an
 148      integer. If not an int, we warn, but return normally */
 149   if (val->type == GCONF_VALUE_INT) {
 150     /* it's an integer, get it and store */
 151     *number = gconf_value_get_int(val);
 152     /* mark that we've changed the int */
 153     hasChanged = TRUE;
 154   } else {
 155     g_warning("confGetInt: key %s is not an integer\n", key);
 156   }
 157 
 158   /* free the type/value-pair */
 159   gconf_value_free(val);
 160   val = NULL;
 161 
 162   return hasChanged;
 163 }
 164 
 165 /**
 166  * NEW
 167  *
 168  * Utility function to change the given color into the
 169  * one that is specified in application config.
 170  *
 171  * If some key is missing, that channel is not changed
 172  * from the color. We also check for proper ranges
 173  * since channel color is guint16.
 174  *
 175  * Parameters:
 176  * - the color object which to modify is possible
 177  *   (preferences set one by one)
 178  *
 179  * Returns:
 180  * - TRUE if color has been changed by this routine
 181  *   FALSE if color didn't change (there was an error or
 182  *         the color is already correct one)
 183  */
 184 gboolean confLoadColor(GdkColor* color) {
 185 
 186   GConfClient* gcClient = NULL;
 187   /* temporary holders for pref values */
 188   gint red = -1;
 189   gint green = -1;
 190   gint blue = -1;
 191   /* temp variable to hold whether color has changed */
 192   gboolean hasChanged = FALSE;
 193 
 194   g_assert(color);
 195 
 196   g_print("confLoadColor: invoked\n");
 197 
 198   /* open connection to gconfd-2 (via d-bus in maemo) */
 199   gcClient = gconf_client_get_default();
 200   /* we make sure that it's a valid GConf-client object */
 201   g_assert(GCONF_IS_CLIENT(gcClient));
 202 
 203   if (confGetInt(gcClient, GC_ROOT "red", &red)) {
 204     /* we got the value successfully, now clamp it */
 205     g_print(" got red = %d, ", red);
 206     /* we got some value, so let's limit it between 0 and
 207        65535 (legal values for guint16). we use the CLAMP
 208        macro from GLib for this */
 209     red = CLAMP(red, 0, 65535);
 210     g_print("after clamping = %d\n", red);
 211     /* update & mark that updating has happened */
 212     color->red = (guint16)red;
 213     hasChanged = TRUE;
 214   }
 215   if (confGetInt(gcClient, GC_ROOT "green", &green)) {
 216     g_print(" got green = %d, ", green);
 217     green = CLAMP(green, 0, 65535);
 218     g_print("after clamping = %d\n", green);
 219     color->green = (guint16)green;
 220     hasChanged = TRUE;
 221   }
 222   if (confGetInt(gcClient, GC_ROOT "blue", &blue)) {
 223     g_print(" got blue = %d, ", blue);
 224     blue = CLAMP(blue, 0, 65535);
 225     g_print("after clamping = %d\n", blue);
 226     color->blue = (guint16)blue;
 227     hasChanged = TRUE;
 228   }
 229 
 230   /* release the client object (with GObject-unref) */
 231   g_object_unref(gcClient);
 232   gcClient = NULL;
 233 
 234   /* return whether color has been changed by us */
 235   return hasChanged;
 236 }
 237 
 238 /**
 239  * This is all the data that our application needs to run
 240  * properly. Rest of the data is not needed by our
 241  * application so we can leave that for GTK+ to handle
 242  * (references and all)
 243  */
 244 typedef struct {
 245   /* should we use underlining for text? */
 246   gboolean styleUseUnderline; /* either TRUE or FALSE */
 247   /* what is the selected slant for text
 248      either STYLE_SLANT_NORMAL or _ITALIC */
 249   gboolean styleSlant;
 250   /* currently selected color
 251      this object is owned by GTK+, do not free it */
 252   GdkColor* currentColor;
 253   /**
 254    * we need access to the label so that we can replace
 255    * it with data form a file
 256    */
 257   GtkWidget* textLabel;
 258 
 259   /* we need to keep pointers to these two widgets so that
 260      we can control their visibility from callbacks */
 261   GtkWidget* findToolbar;
 262   GtkWidget* mainToolbar;
 263   gboolean findToolbarIsVisible;
 264   gboolean mainToolbarIsVisible;
 265 
 266   /* we also add these here since we'll be needing them
 267      soon. pointer to our HildonApp-widget */
 268   GtkWidget* hildonApp;
 269   /* pointer to our main Application View */
 270   GtkWidget* mainView;
 271 
 272 } ApplicationState;
 273 
 274 /**
 275  * these are still the same functions.
 276  * they've been renamed for consistancy.
 277  *
 278  * Turns the delete event from top-level window into a
 279  * window destruction signal (handled in cbActionTopDestroy
 280  */
 281 gboolean cbEventDelete(GtkWidget* widget, GdkEvent event,
 282          ApplicationState* app) {
 283 
 284   return FALSE;
 285 }
 286 
 287 /**
 288  * ditto as with cbEventDelete
 289  */
 290 void cbActionTopDestroy(GtkWidget* widget,
 291      ApplicationState* app) {
 292 
 293   gtk_main_quit();
 294 }
 295 
 296 /**
 297  * Create a file chooser dialog and return when the user
 298  * has selected a file.
 299  *
 300  * Parameters:
 301  * - application state: we need a pointer to the main
 302  *   application window and HildonApp is extended from
 303  *   GtkWindow, so we'll use that. This is because we
 304  *   want to create a modal dialog (which normally would
 305  *   be a bad idea, but not for maemo targets)
 306  * - what kind of file chooser should be displayed:
 307  *   GTK_FILE_CHOOSER_ACTION_OPEN or _SAVE
 308  *
 309  * Returns:
 310  * - newly allocated string that we need to free our
 311  *   selves or NULL on cancellation.
 312  */
 313 gchar* runFileChooser(ApplicationState* app,
 314        GtkFileChooserAction style) {
 315 
 316   GtkWidget* dialog;
 317   gchar* filename = NULL;
 318 
 319   g_assert(app != NULL);
 320 
 321   g_print("runFilechooser: invoked\n");
 322 
 323   /* create the dialog (not shown yet) */
 324   dialog = hildon_file_chooser_dialog_new(
 325     GTK_WINDOW(app->hildonApp), style);
 326   /* display */
 327   gtk_widget_show_all(dialog);
 328   /* divert the GTK+ main loop to handle events
 329      from our dialog. we'll get back here when
 330      the dialog has been exited (not destroyed yet) */
 331   g_print(" running dialog\n");
 332   if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
 333     filename = gtk_file_chooser_get_filename(
 334                  GTK_FILE_CHOOSER(dialog));
 335   }
 336   g_print(" dialog completed\n");
 337   /* destroy all resources that the dialog is taking */
 338   gtk_widget_destroy(dialog);
 339 
 340   if (filename != NULL) {
 341     g_print(" user selected filename '%s'\n", filename);
 342   } else {
 343     g_print(" user didn't select any filename\n");
 344   }
 345   return filename;
 346 }
 347 
 348 /**
 349  * Utility function to display a file I/O related error message
 350  * (not to user)
 351  */
 352 void dbgFileError(GnomeVFSResult errCode, const gchar* uri) {
 353   g_printerr("Error while accessing '%s': %s\n",
 354     uri, gnome_vfs_result_to_string(errCode));
 355 }
 356 
 357 /**
 358  * We read in the file selected if possible
 359  * and set its contents as the new Label content
 360  *
 361  * If reading file will fail, we leave the label as it is
 362  */
 363 void cbActionOpen(GtkWidget* widget, ApplicationState* app) {
 364   gchar* filename = NULL;
 365   /* we need to use URIs with GnomeVFS */
 366   gchar* uri = NULL;
 367 
 368   g_assert(app != NULL);
 369   /* we rely on these */
 370   g_assert(GTK_IS_LABEL(app->textLabel));
 371   g_assert(GTK_IS_WINDOW(app->hildonApp));
 372 
 373   g_print("cbActionOpen invoked\n");
 374 
 375   /* ask the user to select a file to open */
 376   filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_OPEN);
 377   if (filename) {
 378     /* this will point to loaded data buffer */
 379     gchar* buffer = NULL;
 380     /* pointer to a structure describing an open "file" */
 381     GnomeVFSHandle* fileHandle = NULL;
 382     /* structure to hold information about a "file",
 383        initialize it to zero */
 384     GnomeVFSFileInfo fileInfo = {};
 385     /* result code from GnomeVFS operations */
 386     GnomeVFSResult result;
 387     /* size of the file to read in */
 388     GnomeVFSFileSize fileSize = 0;
 389     /* number of octets that were read in successfully */
 390     GnomeVFSFileSize readCount = 0;
 391 
 392     g_print("  you chose to load file '%s'\n", filename);
 393     /* first convert the filename into an URI */
 394     uri = gnome_vfs_get_uri_from_local_path(filename);
 395     /* we don't need the original filename anymore */
 396     g_free(filename);
 397     filename = NULL;
 398     /* should not happen since we got a filename before */
 399     g_assert(uri != NULL);
 400     /* attempt to get filesize first
 401        for this, we need to get file information.
 402        we can help work done by GnomeVFS by selecting
 403        only the information that interests us. Mainly,
 404        the file size */
 405     result = gnome_vfs_get_file_info(uri, &fileInfo,
 406       GNOME_VFS_FILE_INFO_DEFAULT);
 407     if (result != GNOME_VFS_OK) {
 408       /* there was a failure */
 409       dbgFileError(result, uri);
 410       goto error;
 411     }
 412     /* we got the information (maybe). let's check
 413        whether it contains the data that we need */
 414     if (fileInfo.valid_fields &
 415         GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
 416       /* yes, we have size */
 417       fileSize = fileInfo.size;
 418     } else {
 419       g_printerr("Couldn't get the size of file!\n");
 420       goto error;
 421     }
 422     /* ok, by now we have the filesize to read in.
 423        let's allocate some memory and read the file in */
 424     if (fileSize > 1024*100) {
 425       g_printerr("Loading over 100KiB files is not supported!\n");
 426       goto error;
 427     }
 428     /* refuse to load empty files */
 429     if (fileSize == 0) {
 430       g_printerr("Refusing to load an empty file\n");
 431       goto error;
 432     }
 433     /* allocate memory and fill it with zeroes.
 434        Note that we leave space for the terminating zero so that
 435        we can pass this buffer as gchar to string functions */
 436     buffer = g_malloc0(fileSize+1);
 437     if (buffer == NULL) {
 438       g_printerr("Failed to allocate %d bytes for buffer\n",
 439         (guint) fileSize);
 440       goto error;
 441     }
 442     /* open file
 443        Parameters:
 444        - pointer to location where to store the address of
 445          the new handle (created internally in open)
 446        - uri: what to open
 447        - open-flags: what we want to do with the file
 448          (this will affect how permissions are checked by
 449           the kernel)
 450     */
 451     result = gnome_vfs_open(&fileHandle, uri,
 452       GNOME_VFS_OPEN_READ);
 453     if (result != GNOME_VFS_OK) {
 454       dbgFileError(result, uri);
 455       goto error;
 456     }
 457     /* file opened ok, read it in */
 458     result = gnome_vfs_read(fileHandle, buffer,
 459       fileSize, &readCount);
 460     if (result != GNOME_VFS_OK) {
 461       dbgFileError(result, uri);
 462       goto error;
 463     }
 464     /* verify that we got the amount that we wanted
 465        note that with URIs it won't be an error to get
 466        less bytes than you requested. Getting zero bytes
 467        normally signifies an End-of-File condition */
 468     if (fileSize != readCount) {
 469       g_printerr("Failed to load the requested amount\n");
 470       /* we could of course continue since our buffer
 471          is large enough, but let's flag an error anyway */
 472       goto error;
 473     }
 474 
 475     /* whew, if we got this far, it means that we actually
 476        managed to load the file into memory. let's set
 477        the buffer contents as the new label now */
 478     gtk_label_set_markup(GTK_LABEL(app->textLabel), buffer);
 479 
 480     /* that's it ! Display a message of joy
 481        For this we'll use a dialog (non-modal) designed
 482        for message display. It will linger around on
 483        the screen for a while.
 484 
 485        Note that this comes with Hildon */
 486     gtk_infoprint(GTK_WINDOW(app->hildonApp),
 487       "File loaded successfully");
 488 
 489     /* jump to the resource releasing phase */
 490     goto release;
 491 
 492   error:
 493     /* display failure message with a stock icon.
 494        please see /usr/include/gtk-2.0/gtk/gtkstock.h for
 495        a full listing */
 496     gtk_infoprint_with_icon_stock(GTK_WINDOW(app->hildonApp),
 497       "Failed to load the file", GTK_STOCK_STOP);
 498 
 499   release:
 500     /* close and free all resources */
 501     if (fileHandle) gnome_vfs_close(fileHandle);
 502     if (filename) g_free(filename);
 503     if (uri) g_free(uri);
 504     if (buffer) g_free(buffer);
 505     /* zero them all out to prevent stack-reuse-bugs */
 506     fileHandle = NULL;
 507     filename = NULL;
 508     uri = NULL;
 509     buffer = NULL;
 510 
 511     return;
 512   } else {
 513     g_print("  you didn't choose any file to open\n");
 514   }
 515 }
 516 
 517 /**
 518  * Function to save the contents of the label
 519  * This is left empty by purpose. Use
 520  * gtk_label_get_label to get a gchar pointer into the
 521  * application label contents (including current markup)
 522  * then use gnome_vfs_create and gnome_vfs_write to
 523  * create the file.
 524  */
 525 void cbActionSave(GtkWidget* widget, ApplicationState* app) {
 526   gchar* filename = NULL;
 527 
 528   g_assert(app != NULL);
 529 
 530   g_print("cbActionSave invoked\n");
 531 
 532   filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_SAVE);
 533   if (filename) {
 534     g_print("  you chose to save into '%s'\n", filename);
 535     /* process saving .. */
 536     g_free(filename);
 537     filename = NULL;
 538   } else {
 539     g_print("  you didn't choose any file to save to\n");
 540   }
 541 }
 542 
 543 void cbActionQuit(GtkWidget* widget, ApplicationState* app) {
 544   g_print("cbActionQuit invoked\n");
 545   g_print(" terminating with gtk_main_quit\n");
 546   gtk_main_quit();
 547 }
 548 
 549 
 550 /**
 551  * Update the style to used based on whether underline is
 552  * "active" or not
 553  */
 554 void cbActionUnderlineToggled(GtkCheckMenuItem* item,
 555      ApplicationState* app) {
 556 
 557   /* verify that app is not NULL by using a GLib function
 558      which checks whether the given C statement evaluates to
 559      0(false) or non-zero(true). Will terminate the program
 560      on FALSE assertions with an error message */
 561   g_assert(app != NULL);
 562   /* normally we'd also need to check that the 'item' is of
 563      the correct type with GTK_CHECK_MENU_ITEM and put that
 564      inside an if-statement which would create a protective
 565      block around us. We'll implement this in another
 566      function below. */
 567   g_print("cbActionUnderlineToggled invoked\n");
 568   app->styleUseUnderline =
 569     gtk_check_menu_item_get_active(item);
 570   g_print(" underlining is now %s\n",
 571     app->styleUseUnderline?"on":"off");
 572 }
 573 
 574 
 575 void cbActionStyleNormalToggled(GtkCheckMenuItem* item,
 576      ApplicationState* app) {
 577 
 578   g_assert(app != NULL);
 579 
 580   g_print("cbActionStyleNormalToggled invoked\n");
 581   /* we will switch slant iff item is active */
 582   if (gtk_check_menu_item_get_active(item)) {
 583     app->styleSlant = STYLE_SLANT_NORMAL;
 584     g_print(" selected slanting for text is now Normal\n");
 585   }
 586 }
 587 
 588 void cbActionStyleItalicToggled(GtkCheckMenuItem* item,
 589      ApplicationState* app) {
 590 
 591   g_assert(app != NULL);
 592 
 593   g_print("cbActionStyleItalicToggled invoked\n");
 594   /* we will switch slant iff item is active */
 595   if (gtk_check_menu_item_get_active(item)) {
 596     app->styleSlant = STYLE_SLANT_ITALIC;
 597     g_print(" selected slanting for text is now Italic\n");
 598   }
 599 }
 600 
 601 /**
 602  * MODIFIED
 603  *
 604  * We'll now write to preferences (GConf) each time the
 605  * color changes. Note that we'll compare whether it has
 606  * really changed or user just used the dialog. This is
 607  * to conserve time (GConf is not the fastest system
 608  * around, and it's not meant to be fast).
 609  *
 610  * Invoked when user selects a color (or even tries to)
 611  */
 612 void cbColorChanged(HildonColorButton* colorButton,
 613      ApplicationState* app) {
 614 
 615   gboolean hasChanged = FALSE;
 616   GdkColor* newColor = NULL;
 617   GdkColor* curColor = NULL;
 618 
 619   g_assert(app != NULL);
 620   g_assert(app->currentColor);
 621 
 622   g_print("cbColorChanged invoked\n");
 623 
 624   /* check whether the color has really changed */
 625   newColor = hildon_color_button_get_color(colorButton);
 626   /* just an alias, could use app->currentColor everywhere */
 627   curColor = app->currentColor;
 628 
 629   if ((newColor->red != curColor->red) ||
 630       (newColor->green != curColor->green) ||
 631       (newColor->blue != curColor->blue)) {
 632     hasChanged = TRUE;
 633   }
 634   if (!hasChanged) {
 635     g_print(" color not really changed\n");
 636     return;
 637   }
 638   /* color has really changed, store to preferences */
 639   g_print(" color changed, storing into preferences.. \n");
 640   confStoreColor(newColor);
 641   g_print(" done.\n");
 642 
 643   /* also update the color into application state */
 644   app->currentColor = newColor;
 645 }
 646 
 647 /* invoked via find-toolitem in the main menubar */
 648 void cbActionFindToolbarToggle(GtkWidget* widget,
 649      ApplicationState* app) {
 650 
 651   gboolean newVisibilityState = FALSE;
 652 
 653   g_assert(app != NULL);
 654   /* see the next function for explanation of this */
 655   g_assert(GTK_IS_TOOLBAR(app->findToolbar));
 656 
 657   g_print("cbActionFindToolbarToggle invoked\n");
 658 
 659   /* toggle visibility variable first
 660      Note that with the NOT-operator TRUE becomes FALSE and
 661      FALSE becomes TRUE */
 662   newVisibilityState = ~app->findToolbarIsVisible;
 663 
 664   if (newVisibilityState) {
 665     g_print(" showing find-toolbar\n");
 666     /* Note that we could also toggle visibility of all
 667        child widgets but this is unnecessary since they
 668        will only be seen if all of their parents are seen */
 669     gtk_widget_show(app->findToolbar);
 670   } else {
 671     g_print(" hiding find-toolbar\n");
 672     gtk_widget_hide(app->findToolbar);
 673   }
 674   app->findToolbarIsVisible = newVisibilityState;
 675 }
 676 
 677 void cbActionMainToolbarToggle(GtkCheckMenuItem* item,
 678   ApplicationState* app) {
 679 
 680   gboolean newVisibilityState = FALSE;
 681 
 682   g_assert(app != NULL);
 683 
 684   if (!GTK_IS_TOOLBAR(app->mainToolbar)) {
 685     /* print a warning */
 686     g_warning(G_STRLOC ": You need to have a GtkToolbar in "
 687       "application state first!");
 688     /* then terminate, not very elegant, but this is an
 689        example */
 690     g_assert(GTK_IS_TOOLBAR(app->mainToolbar));
 691   }
 692 
 693   /* one could argue that this must be displayed on function
 694      entry. but if asserts will fail, user/debugger will see
 695      what was the filename and source code file line number
 696      where there was a problem, so this is just extra */
 697   g_print("cbActionMainToolbarToggle invoked\n");
 698 
 699   newVisibilityState = gtk_check_menu_item_get_active(item);
 700 
 701   /* is state has changed, act on it */
 702   if (app->mainToolbarIsVisible != newVisibilityState) {
 703     if (newVisibilityState) {
 704       g_print(" showing main toolbar\n");
 705       gtk_widget_show(app->mainToolbar);
 706     } else {
 707       g_print(" hiding main toolbar\n");
 708       gtk_widget_hide(app->mainToolbar);
 709     }
 710     app->mainToolbarIsVisible = newVisibilityState;
 711   }
 712 }
 713 
 714 /**
 715  * this will be called by the hildon find toolbar when user
 716  * causes a search to happen
 717  */
 718 void cbActionFindToolbarSearch(HildonFindToolbar* fToolbar,
 719      ApplicationState* app) {
 720 
 721   gchar* findText = NULL;
 722 
 723   g_assert(app != NULL);
 724 
 725   g_print("cbActionFindToolbarSearch invoked\n");
 726 
 727   /* this is one of the oddities in Hildon widgets. There is
 728      no accessor function for this at all (not in the
 729      headers at least */
 730   g_object_get(G_OBJECT(fToolbar), "prefix", &findText,NULL);
 731   if (findText != NULL) {
 732     /* the above should never happen, empty search text
 733        should return a string with zero characters
 734        (terminated immediately) */
 735     g_print(" would search for '%s' if would know how to\n",
 736       findText);
 737   }
 738 }
 739 
 740 /**
 741  * this will be called when user closes the find toolbar
 742  * we'll just hide it for future reference
 743  */
 744 void cbActionFindToolbarClosed(HildonFindToolbar* fToolbar,
 745      ApplicationState* app) {
 746 
 747   g_assert(app != NULL);
 748 
 749   g_print("cbActionFindToolbarClosed invoked\n");
 750   g_print(" hiding search toolbar\n");
 751 
 752   /* it's enough to hide the toolbar and set it's visibility
 753      status. note that we don't use hide_all as it's
 754      unnecessary and the find toolbar will be faster to
 755      restore back to visibility */
 756   gtk_widget_hide(GTK_WIDGET(fToolbar));
 757   app->findToolbarIsVisible = FALSE;
 758 }
 759 
 760 /**
 761  * Switch to fullscreen mode, called from a new
 762  * menu item that we'll add just for this. While in
 763  * fullscreen, menu is not shown. It would be probably a
 764  * good idea to implement this also as a toolbar button.
 765  */
 766 void cbActionGoFullscreen(GtkMenuItem* mi,
 767      ApplicationState* app) {
 768 
 769   g_assert(app != NULL);
 770 
 771   g_print("cbActionGoFullscreen invoked\n");
 772   g_print(" going fullscreen\n");
 773 
 774   hildon_appview_set_fullscreen(HILDON_APPVIEW(app->mainView),
 775     TRUE);
 776   /* that's it! */
 777 }
 778 
 779 /**
 780  * Switch fullscreen mode on and off
 781  *
 782  * Callback function that will handle keypresses.
 783  * As the keypresses come from outside GTK+ (even GDK), this
 784  * needs to be an event handler.
 785  */
 786 gboolean cbKeyPressed(GtkWidget* widget, GdkEventKey* ev,
 787          ApplicationState* app) {
 788 
 789   g_assert(app != NULL);
 790 
 791   g_print("cbKeyPress invoked\n");
 792 
 793   /* the reason why we use a switch statement here is so
 794      that you can extend this code easily to handle other
 795      key presses. Please see the maemo tutorial for a list
 796      of defines that map to the 770 hardware keys */
 797   switch(ev->keyval) {
 798     case GDK_F6:
 799       g_print(" F6 key pressed (or fullscreen hw-button)\n");
 800 
 801       /* toggle fullscreen mode on and off and on and off.
 802          yes, this a bit convoluted, but notice the NOT
 803          operator (!) */
 804       hildon_appview_set_fullscreen(
 805         HILDON_APPVIEW(app->mainView),
 806         !hildon_appview_get_fullscreen(
 807           HILDON_APPVIEW(app->mainView)));
 808       /* we want to handle only the keys that we recognize
 809          for this reason we return TRUE at this point
 810          and return FALSE for any other key */
 811       return TRUE;
 812     default:
 813       g_print(" not a F6-key (something else)\n");
 814   }
 815   return FALSE;
 816 }
 817 
 818 /**
 819  * MODIFIED
 820  *
 821  * We now also copy the initial color from the colorbutton
 822  * to our application state. Whatever Hildon uses for
 823  * the default color is fine with us.
 824  *
 825  * Utility function that will create the toolbar for us
 826  *
 827  * Parameters:
 828  * - ApplicationState: used to do signal connection
 829  *   also used to set initial visibility of main toolbar
 830  *
 831  * Returns:
 832  * - New toolbar suitable to use
 833  */
 834 GtkWidget* buildToolbar(ApplicationState* app) {
 835   GtkToolbar* toolbar = NULL;
 836   GtkToolItem* tbOpen = NULL;
 837   GtkToolItem* tbSave = NULL;
 838   GtkToolItem* tbSep = NULL;
 839   GtkToolItem* tbFind = NULL;
 840   GtkToolItem* tbColorButton = NULL;
 841     GtkWidget*   colorButton = NULL;
 842 
 843   g_assert(app != NULL);
 844 
 845   tbOpen = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
 846   tbSave = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
 847   tbSep  = gtk_separator_tool_item_new();
 848   tbFind = gtk_tool_button_new_from_stock(GTK_STOCK_FIND);
 849 
 850   tbColorButton = gtk_tool_item_new();
 851   colorButton = hildon_color_button_new();
 852   /**
 853    * NEW
 854    *
 855    * Store the default color to our application state
 856    * so that we can check whether it will change later
 857    * on
 858    */
 859   app->currentColor = hildon_color_button_get_color(
 860     HILDON_COLOR_BUTTON(colorButton));
 861   /* load preferences and change the color if it really
 862      has changed */
 863   g_print("buildToolbar: loading color pref.\n");
 864   if (confLoadColor(app->currentColor)) {
 865     g_print(" color not same as default one\n");
 866     hildon_color_button_set_color(
 867       HILDON_COLOR_BUTTON(colorButton), app->currentColor);
 868   } else {
 869     g_print(" loaded color same as default\n");
 870   }
 871 
 872   /* add the color button into a toolitem holder */
 873   gtk_container_add(GTK_CONTAINER(tbColorButton),
 874     colorButton);
 875 
 876   /* create the toolbar, note the casting (for next steps)*/
 877   toolbar = GTK_TOOLBAR(gtk_toolbar_new());
 878 
 879   /* add the tool items to the toolbar */
 880   gtk_toolbar_insert(toolbar, tbOpen, -1);
 881   gtk_toolbar_insert(toolbar, tbSave, -1);
 882   gtk_toolbar_insert(toolbar, tbSep,  -1);
 883   gtk_toolbar_insert(toolbar, tbFind, -1);
 884   gtk_toolbar_insert(toolbar, tbColorButton, -1);
 885 
 886   /* setup toolbar visibility according to state */
 887   gtk_widget_show_all(GTK_WIDGET(toolbar));
 888   if (!app->mainToolbarIsVisible) {
 889     /* hide toplevel since toolbar is supposed to be
 890        invisible */
 891     gtk_widget_hide(GTK_WIDGET(toolbar));
 892   }
 893 
 894   /* connect the signals to the callback functions */
 895   g_signal_connect(G_OBJECT(tbOpen), "clicked",
 896     G_CALLBACK(cbActionOpen), app);
 897   g_signal_connect(G_OBJECT(tbSave), "clicked",
 898     G_CALLBACK(cbActionSave), app);
 899   g_signal_connect(G_OBJECT(tbFind), "clicked",
 900     G_CALLBACK(cbActionFindToolbarToggle), app);
 901 
 902   /* we also connect a signal from the colorbutton when
 903      a user has selected a color. note that we connect
 904      the button itself, not the toolitem that is holding
 905      it inside toolbar */
 906   g_signal_connect(G_OBJECT(colorButton), "clicked",
 907     G_CALLBACK(cbColorChanged), app);
 908 
 909   /* we have another cast here since we return GtkWidget* */
 910   return GTK_WIDGET(toolbar);
 911 }
 912 
 913 /**
 914  * Utility to create the Find toolbar (which is only missing
 915  * signal bindings)
 916  *
 917  * Parameters:
 918  * - ApplicationState: used to connect signals and set up
 919  *   initial visibility
 920  *
 921  * Returns:
 922  * - New Findtoolbar which can be used immediately
 923  */
 924 GtkWidget* buildFindToolbar(ApplicationState* app) {
 925   GtkWidget* findToolbar = NULL;
 926 
 927   g_assert(app != NULL);
 928   /* the text parameter will be displayed before the search
 929      text input box */
 930   findToolbar = hildon_find_toolbar_new("Find ");
 931   /* connect the two signals that Hildon's Find Toolbar can
 932      emit */
 933   g_signal_connect(G_OBJECT(findToolbar), "search",
 934     G_CALLBACK(cbActionFindToolbarSearch), app);
 935   g_signal_connect(G_OBJECT(findToolbar), "close",
 936     G_CALLBACK(cbActionFindToolbarClosed), app);
 937 
 938   /* setup visibility according to passed state
 939      we use the same logic as for the main toolbar */
 940   gtk_widget_show_all(findToolbar);
 941   if (!app->findToolbarIsVisible) {
 942     gtk_widget_hide(findToolbar);
 943   }
 944 
 945   return findToolbar;
 946 }
 947 
 948 
 949 /**
 950  * Create the submenu for style selection
 951  *
 952  * Parameters:
 953  * - ApplicationState: used to do signal connection
 954  *   also used to set initial state of radio/check items
 955  *
 956  * Returns:
 957  * - New submenu ready to use
 958  */
 959 GtkWidget* buildSubMenu(ApplicationState* app) {
 960   GtkWidget* subMenu = NULL;
 961 
 962   GtkWidget* mciUnderline = NULL;
 963   GtkWidget* miSep = NULL;
 964   GtkWidget* mriNormal = NULL;
 965   GtkWidget* mriItalic = NULL;
 966 
 967   g_assert(app != NULL);
 968 
 969   /* create a checkbox-menuitem */
 970   mciUnderline =
 971     gtk_check_menu_item_new_with_label("Underline");
 972   /* set underlining according to application state */
 973   gtk_check_menu_item_set_active(
 974     GTK_CHECK_MENU_ITEM(mciUnderline),
 975     app->styleUseUnderline);
 976 
 977   {
 978     GSList* group = NULL;
 979 
 980     /* create the first radio menu item (this also creates
 981        the group for them */
 982     mriItalic = gtk_radio_menu_item_new_with_label(NULL,
 983       "Italic");
 984     /* get the group so that we can add an other radio
 985        menuitem there */
 986     group = gtk_radio_menu_item_get_group(
 987       GTK_RADIO_MENU_ITEM(mriItalic));
 988     /* create another radio menu item and add it to the same
 989        group */
 990     mriNormal = gtk_radio_menu_item_new_with_label(group,
 991       "Normal");
 992   }
 993 
 994   /* update style toggle's state according to application
 995      state */
 996   if (app->styleSlant == STYLE_SLANT_NORMAL) {
 997     gtk_check_menu_item_set_active(
 998       GTK_CHECK_MENU_ITEM(mriNormal), TRUE);
 999   } else {
1000     gtk_check_menu_item_set_active(
1001       GTK_CHECK_MENU_ITEM(mriItalic), TRUE);
1002   }
1003 
1004   /* create the separator item */
1005   miSep = gtk_separator_menu_item_new();
1006 
1007   /* create the menu to hold these three items */
1008   subMenu = gtk_menu_new();
1009 
1010   /* add the items to this new menu. */
1011   gtk_menu_shell_append(GTK_MENU_SHELL(subMenu),
1012     mciUnderline);
1013   gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), miSep);
1014   gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), mriNormal);
1015   gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), mriItalic);
1016 
1017   /* connect the signals */
1018   g_signal_connect(G_OBJECT(mciUnderline), "toggled",
1019     G_CALLBACK(cbActionUnderlineToggled), app);
1020   g_signal_connect(G_OBJECT(mriNormal), "toggled",
1021     G_CALLBACK(cbActionStyleNormalToggled), app);
1022   g_signal_connect(G_OBJECT(mriItalic), "toggled",
1023     G_CALLBACK(cbActionStyleItalicToggled), app);
1024 
1025   /* submenu is ready, return to caller */
1026   return subMenu;
1027 }
1028 
1029 
1030 /**
1031  * Create the menus (top-level and one sub-menu)
1032  *
1033  * Parameters:
1034  * - ApplicationState: bound as signal parameter and
1035  *   also used to determine initial state of the
1036  *   "Show toolbar" checkmenu item
1037  *   also used to get the main application view's
1038  *   menu to add to.
1039  *
1040  * Returns:
1041  * - nothing. will update the given menu object directly
1042  */
1043 static void buildMenu(ApplicationState* app) {
1044 
1045   GtkMenu* menu = NULL;
1046 
1047   GtkWidget* miOpen = NULL;
1048   GtkWidget* miSave = NULL;
1049   GtkWidget* miSep1 = NULL;
1050   GtkWidget* miStyle = NULL;
1051   GtkWidget* subMenu = NULL;
1052   GtkWidget* mciShowToolbar = NULL;
1053   GtkWidget* miFullscreen = NULL;
1054   GtkWidget* miSep2 = NULL;
1055   GtkWidget* miQuit = NULL;
1056 
1057   /* create the menu items */
1058   miOpen = gtk_menu_item_new_with_label("Open");
1059   miSave = gtk_menu_item_new_with_label("Save");
1060   miSep1 = gtk_separator_menu_item_new();
1061   miStyle = gtk_menu_item_new_with_label("Style");
1062   mciShowToolbar = gtk_check_menu_item_new_with_label(
1063     "Show toolbar");
1064   miFullscreen = gtk_menu_item_new_with_label("Fullscreen");
1065   miSep2 = gtk_separator_menu_item_new();
1066   miQuit = gtk_menu_item_new_with_label("Quit");
1067 
1068   /* set initial state of shot-toolbar according to
1069      application state */
1070   gtk_check_menu_item_set_active(
1071     GTK_CHECK_MENU_ITEM(mciShowToolbar),
1072     app->mainToolbarIsVisible);
1073 
1074   /* build the submenu */
1075   subMenu = buildSubMenu(app);
1076 
1077   /* connect the "style" menu item so that it will
1078      pop up the submenu */
1079   gtk_menu_item_set_submenu(GTK_MENU_ITEM(miStyle),subMenu);
1080 
1081   /* get the top-level menu from application view */
1082   menu = hildon_appview_get_menu(
1083     HILDON_APPVIEW(app->mainView));
1084 
1085   /* Add the items to the container (top-level menu */
1086   gtk_container_add(GTK_CONTAINER(menu), miOpen);
1087   gtk_container_add(GTK_CONTAINER(menu), miSave);
1088   gtk_container_add(GTK_CONTAINER(menu), miSep1);
1089   gtk_container_add(GTK_CONTAINER(menu), miStyle);
1090   gtk_container_add(GTK_CONTAINER(menu), mciShowToolbar);
1091   gtk_container_add(GTK_CONTAINER(menu), miFullscreen);
1092   gtk_container_add(GTK_CONTAINER(menu), miSep2);
1093   gtk_container_add(GTK_CONTAINER(menu), miQuit);
1094 
1095   /* Connect the signals from individual menu items. */
1096   g_signal_connect(G_OBJECT(miOpen), "activate",
1097     G_CALLBACK(cbActionOpen), app);
1098   g_signal_connect(G_OBJECT(miSave), "activate",
1099     G_CALLBACK(cbActionSave), app);
1100   g_signal_connect(G_OBJECT(miQuit), "activate",
1101     G_CALLBACK(cbActionQuit), app);
1102   g_signal_connect(G_OBJECT(mciShowToolbar), "toggled",
1103     G_CALLBACK(cbActionMainToolbarToggle), app);
1104   g_signal_connect(G_OBJECT(miFullscreen), "activate",
1105     G_CALLBACK(cbActionGoFullscreen), app);
1106 
1107   /* set visibility to menu since menu is not part of the
1108     widget tree properly in HildonAppView */
1109   gtk_widget_show_all(GTK_WIDGET(menu));
1110 }
1111 
1112 int main(int argc, char** argv) {
1113 
1114   /* allocate the application state on stack of main
1115      and initialize it to zero */
1116   ApplicationState aState = {};
1117 
1118   /* couple of widgets that we add for demo purpose */
1119   GtkWidget* label = NULL;
1120   GtkWidget* vbox = NULL;
1121   /* we need temporary access to the toolbars */
1122   GtkWidget* mainToolbar = NULL;
1123   GtkWidget* findToolbar = NULL;
1124 
1125   /* Initialize the GnomeVFS */
1126   if(!gnome_vfs_init()) {
1127     g_error(
1128       "Failed to initialize GnomeVFS-libraries, exiting\n");
1129   }
1130 
1131   /* Initialize the GTK+ */
1132   gtk_init(&argc, &argv);
1133 
1134   /* Create the hildon application */
1135   aState.hildonApp = hildon_app_new();
1136   /* Set the application title
1137      We also use the proper casting macro */
1138   hildon_app_set_title(HILDON_APP(aState.hildonApp),
1139     "Hello Hildon!");
1140   /* Create a view that will handle our layout and menu
1141      Note that hildon_app_view_new always expects a
1142      gchar* which we'd use for a title for the view */
1143   aState.mainView = hildon_appview_new(NULL);
1144 
1145   /* Label that contains markup */
1146   label = gtk_label_new("<b>Hello</b> <i>Hildon</i> (with "
1147     "Hildon<sup>search</sup>"
1148     " <u>and</u> other<sub>2</sub> tricks<sup>tm</sup>)!");
1149   /* allow lines to wrap */
1150   gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1151   /* tell the GtkLabel widget to parse the text as it would
1152      be written in the Pango markup language */
1153   gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
1154   /* store its pointer into application state */
1155   aState.textLabel = label;
1156 
1157 
1158   /* build the menu */
1159   buildMenu(&aState);
1160 
1161   /* Create a layout box for the window since it can only
1162      hold one widget
1163 
1164      Using the creator function, we need to pass two
1165      parameters for it:
1166      - gboolean: all children should be given equal amount
1167        of space
1168      - gint: pixels to leave between child widgets */
1169   vbox = gtk_vbox_new(FALSE, 0);
1170 
1171   /* Add the vbox as a child to the Appview */
1172   gtk_container_add(GTK_CONTAINER(aState.mainView), vbox);
1173 
1174   /* Pack the label into the VBox. */
1175   gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1176 
1177   /* Create the main toolbar */
1178   mainToolbar = buildToolbar(&aState);
1179   /* Create the finding toolbar */
1180   findToolbar = buildFindToolbar(&aState);
1181 
1182   /* NOTE
1183    *
1184    * If you want to test how the error handling inside
1185    * cbActionMainToolbarToggled works, comment the following
1186    * code line
1187    */
1188   aState.mainToolbar = mainToolbar;
1189   aState.findToolbar = findToolbar;
1190 
1191   /* Connect the termination signals. Note how the
1192      HildonApp-object has taken the responsibilities
1193      that a GtkWindow normally has */
1194   g_signal_connect(G_OBJECT(aState.hildonApp),
1195     "delete-event", G_CALLBACK(cbEventDelete), &aState);
1196   g_signal_connect(G_OBJECT(aState.hildonApp),
1197     "destroy", G_CALLBACK(cbActionTopDestroy), &aState);
1198 
1199   /**
1200    * We need to tell HildonApp which view to show at which
1201    * time. Since we only have one at the moment, we'll show
1202    * that.
1203    */
1204   hildon_app_set_appview(HILDON_APP(aState.hildonApp),
1205                          HILDON_APPVIEW(aState.mainView));
1206 
1207   /* Show all widgets that are contained by the app.
1208      This includes the views but for some reason not the
1209      menu inside a view */
1210   gtk_widget_show_all(aState.hildonApp);
1211 
1212   /* add the toolbars to the appview->vbox.
1213      This is done last to ensure that the toolbars that
1214      should be hidden doesn't become visible in the previous
1215      code line.
1216 
1217      Other variations are surely possible */
1218   gtk_box_pack_end(
1219     GTK_BOX(HILDON_APPVIEW(aState.mainView)->vbox),
1220     mainToolbar, TRUE, TRUE, 0);
1221   gtk_box_pack_end(
1222     GTK_BOX(HILDON_APPVIEW(aState.mainView)->vbox),
1223     findToolbar, TRUE, TRUE, 0);
1224 
1225   /* register for keypresses inside GTK+ */
1226   g_signal_connect(G_OBJECT(aState.hildonApp),
1227     "key_press_event", G_CALLBACK(cbKeyPressed), &aState);
1228 
1229   g_print("main: calling gtk_main\n");
1230 
1231   /* start main event loop */
1232   gtk_main();
1233 
1234   g_print("main: returned from gtk_main\n");
1235   g_print("main: Ending program via ret(0)\n");
1236   return 0;
1237 }

This demonstrates that ranges can be selected by source line numbers

Lines 500-550:

 500     /* close and free all resources */
 501     if (fileHandle) gnome_vfs_close(fileHandle);
 502     if (filename) g_free(filename);
 503     if (uri) g_free(uri);
 504     if (buffer) g_free(buffer);
 505     /* zero them all out to prevent stack-reuse-bugs */
 506     fileHandle = NULL;
 507     filename = NULL;
 508     uri = NULL;
 509     buffer = NULL;
 510 
 511     return;
 512   } else {
 513     g_print("  you didn't choose any file to open\n");
 514   }
 515 }
 516 
 517 /**
 518  * Function to save the contents of the label
 519  * This is left empty by purpose. Use
 520  * gtk_label_get_label to get a gchar pointer into the
 521  * application label contents (including current markup)
 522  * then use gnome_vfs_create and gnome_vfs_write to
 523  * create the file.
 524  */
 525 void cbActionSave(GtkWidget* widget, ApplicationState* app) {
 526   gchar* filename = NULL;
 527 
 528   g_assert(app != NULL);
 529 
 530   g_print("cbActionSave invoked\n");
 531 
 532   filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_SAVE);
 533   if (filename) {
 534     g_print("  you chose to save into '%s'\n", filename);
 535     /* process saving .. */
 536     g_free(filename);
 537     filename = NULL;
 538   } else {
 539     g_print("  you didn't choose any file to save to\n");
 540   }
 541 }
 542 
 543 void cbActionQuit(GtkWidget* widget, ApplicationState* app) {
 544   g_print("cbActionQuit invoked\n");
 545   g_print(" terminating with gtk_main_quit\n");
 546   gtk_main_quit();
 547 }
 548 
 549 
 550 /**

The following snippets remonstrate the same range with varying style-settings

Lines 500-550, w/o linenums:

     /* close and free all resources */
     if (fileHandle) gnome_vfs_close(fileHandle);
     if (filename) g_free(filename);
     if (uri) g_free(uri);
     if (buffer) g_free(buffer);
     /* zero them all out to prevent stack-reuse-bugs */
     fileHandle = NULL;
     filename = NULL;
     uri = NULL;
     buffer = NULL;
 
     return;
   } else {
     g_print("  you didn't choose any file to open\n");
   }
 }
 
 /**
  * Function to save the contents of the label
  * This is left empty by purpose. Use
  * gtk_label_get_label to get a gchar pointer into the
  * application label contents (including current markup)
  * then use gnome_vfs_create and gnome_vfs_write to
  * create the file.
  */
 void cbActionSave(GtkWidget* widget, ApplicationState* app) {
   gchar* filename = NULL;
 
   g_assert(app != NULL);
 
   g_print("cbActionSave invoked\n");
 
   filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_SAVE);
   if (filename) {
     g_print("  you chose to save into '%s'\n", filename);
     /* process saving .. */
     g_free(filename);
     filename = NULL;
   } else {
     g_print("  you didn't choose any file to save to\n");
   }
 }
 
 void cbActionQuit(GtkWidget* widget, ApplicationState* app) {
   g_print("cbActionQuit invoked\n");
   g_print(" terminating with gtk_main_quit\n");
   gtk_main_quit();
 }
 
 
 /**

Lines 500-550, w/o tooltips w/ linenums:

 500     /* close and free all resources */
 501     if (fileHandle) gnome_vfs_close(fileHandle);
 502     if (filename) g_free(filename);
 503     if (uri) g_free(uri);
 504     if (buffer) g_free(buffer);
 505     /* zero them all out to prevent stack-reuse-bugs */
 506     fileHandle = NULL;
 507     filename = NULL;
 508     uri = NULL;
 509     buffer = NULL;
 510 
 511     return;
 512   } else {
 513     g_print("  you didn't choose any file to open\n");
 514   }
 515 }
 516 
 517 /**
 518  * Function to save the contents of the label
 519  * This is left empty by purpose. Use
 520  * gtk_label_get_label to get a gchar pointer into the
 521  * application label contents (including current markup)
 522  * then use gnome_vfs_create and gnome_vfs_write to
 523  * create the file.
 524  */
 525 void cbActionSave(GtkWidget* widget, ApplicationState* app) {
 526   gchar* filename = NULL;
 527 
 528   g_assert(app != NULL);
 529 
 530   g_print("cbActionSave invoked\n");
 531 
 532   filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_SAVE);
 533   if (filename) {
 534     g_print("  you chose to save into '%s'\n", filename);
 535     /* process saving .. */
 536     g_free(filename);
 537     filename = NULL;
 538   } else {
 539     g_print("  you didn't choose any file to save to\n");
 540   }
 541 }
 542 
 543 void cbActionQuit(GtkWidget* widget, ApplicationState* app) {
 544   g_print("cbActionQuit invoked\n");
 545   g_print(" terminating with gtk_main_quit\n");
 546   gtk_main_quit();
 547 }
 548 
 549 
 550 /**

Line 1001, w/o tooltips w/o linenums:

       GTK_CHECK_MENU_ITEM(mriItalic), TRUE);

The following demonstrate automatic and manual selection support. Automatic works by allowing one to select based on function or typedef names. No need to fix line numbers when source code changes to include just a fragment. Quite nifty IMHO.

buildFindToolbar:

 913 /**
 914  * Utility to create the Find toolbar (which is only missing
 915  * signal bindings)
 916  *
 917  * Parameters:
 918  * - ApplicationState: used to connect signals and set up
 919  *   initial visibility
 920  *
 921  * Returns:
 922  * - New Findtoolbar which can be used immediately
 923  */
 924 GtkWidget* buildFindToolbar(ApplicationState* app) {
 925   GtkWidget* findToolbar = NULL;
 926 
 927   g_assert(app != NULL);
 928   /* the text parameter will be displayed before the search
 929      text input box */
 930   findToolbar = hildon_find_toolbar_new("Find ");
 931   /* connect the two signals that Hildon's Find Toolbar can
 932      emit */
 933   g_signal_connect(G_OBJECT(findToolbar), "search",
 934     G_CALLBACK(cbActionFindToolbarSearch), app);
 935   g_signal_connect(G_OBJECT(findToolbar), "close",
 936     G_CALLBACK(cbActionFindToolbarClosed), app);
 937 
 938   /* setup visibility according to passed state
 939      we use the same logic as for the main toolbar */
 940   gtk_widget_show_all(findToolbar);
 941   if (!app->findToolbarIsVisible) {
 942     gtk_widget_hide(findToolbar);
 943   }
 944 
 945   return findToolbar;
 946 }

ApplicationState:

 238 /**
 239  * This is all the data that our application needs to run
 240  * properly. Rest of the data is not needed by our
 241  * application so we can leave that for GTK+ to handle
 242  * (references and all)
 243  */
 244 typedef struct {
 245   /* should we use underlining for text? */
 246   gboolean styleUseUnderline; /* either TRUE or FALSE */
 247   /* what is the selected slant for text
 248      either STYLE_SLANT_NORMAL or _ITALIC */
 249   gboolean styleSlant;
 250   /* currently selected color
 251      this object is owned by GTK+, do not free it */
 252   GdkColor* currentColor;
 253   /**
 254    * we need access to the label so that we can replace
 255    * it with data form a file
 256    */
 257   GtkWidget* textLabel;
 258 
 259   /* we need to keep pointers to these two widgets so that
 260      we can control their visibility from callbacks */
 261   GtkWidget* findToolbar;
 262   GtkWidget* mainToolbar;
 263   gboolean findToolbarIsVisible;
 264   gboolean mainToolbarIsVisible;
 265 
 266   /* we also add these here since we'll be needing them
 267      soon. pointer to our HildonApp-widget */
 268   GtkWidget* hildonApp;
 269   /* pointer to our main Application View */
 270   GtkWidget* mainView;
 271 
 272 } ApplicationState;

Below is an example of manual selecting. The source code includes special markup tags to delimit specific sections that can then be accessed via the selector-name (defined in the source)

Manual tags are removed from all output. Also the c-preprocessor will replace the line with an empty line if the line consists only of C-comments and this said markup. In manual selection mode the selected region is also resized so that these empty lines are not selected into the listing (meaning nice and consistant output)

include:

   9 #include <gdk/gdkkeysyms.h>
  10 #include <gtk/gtk.h>
  11 #include <hildon-widgets/hildon-app.h>
  12 #include <hildon-widgets/hildon-color-button.h>
  13 #include <hildon-widgets/hildon-find-toolbar.h>
  14 #include <hildon-widgets/hildon-file-chooser-dialog.h>
  15 #include <hildon-widgets/gtk-infoprint.h>
  16 #include <libgnomevfs/gnome-vfs.h>
  17 /* include prototypes for GConf client-part */
  18 #include <gconf/gconf-client.h>

Below a section is generated with multiple selectors (auto and manual). Note the ordering (which demonstrates that silly ordering is also possible)

Multiple selected (ApplicationState, buildFindToolbar, include):

 238 /**
 239  * This is all the data that our application needs to run
 240  * properly. Rest of the data is not needed by our
 241  * application so we can leave that for GTK+ to handle
 242  * (references and all)
 243  */
 244 typedef struct {
 245   /* should we use underlining for text? */
 246   gboolean styleUseUnderline; /* either TRUE or FALSE */
 247   /* what is the selected slant for text
 248      either STYLE_SLANT_NORMAL or _ITALIC */
 249   gboolean styleSlant;
 250   /* currently selected color
 251      this object is owned by GTK+, do not free it */
 252   GdkColor* currentColor;
 253   /**
 254    * we need access to the label so that we can replace
 255    * it with data form a file
 256    */
 257   GtkWidget* textLabel;
 258 
 259   /* we need to keep pointers to these two widgets so that
 260      we can control their visibility from callbacks */
 261   GtkWidget* findToolbar;
 262   GtkWidget* mainToolbar;
 263   gboolean findToolbarIsVisible;
 264   gboolean mainToolbarIsVisible;
 265 
 266   /* we also add these here since we'll be needing them
 267      soon. pointer to our HildonApp-widget */
 268   GtkWidget* hildonApp;
 269   /* pointer to our main Application View */
 270   GtkWidget* mainView;
 271 
 272 } ApplicationState;
---
 913 /**
 914  * Utility to create the Find toolbar (which is only missing
 915  * signal bindings)
 916  *
 917  * Parameters:
 918  * - ApplicationState: used to connect signals and set up
 919  *   initial visibility
 920  *
 921  * Returns:
 922  * - New Findtoolbar which can be used immediately
 923  */
 924 GtkWidget* buildFindToolbar(ApplicationState* app) {
 925   GtkWidget* findToolbar = NULL;
 926 
 927   g_assert(app != NULL);
 928   /* the text parameter will be displayed before the search
 929      text input box */
 930   findToolbar = hildon_find_toolbar_new("Find ");
 931   /* connect the two signals that Hildon's Find Toolbar can
 932      emit */
 933   g_signal_connect(G_OBJECT(findToolbar), "search",
 934     G_CALLBACK(cbActionFindToolbarSearch), app);
 935   g_signal_connect(G_OBJECT(findToolbar), "close",
 936     G_CALLBACK(cbActionFindToolbarClosed), app);
 937 
 938   /* setup visibility according to passed state
 939      we use the same logic as for the main toolbar */
 940   gtk_widget_show_all(findToolbar);
 941   if (!app->findToolbarIsVisible) {
 942     gtk_widget_hide(findToolbar);
 943   }
 944 
 945   return findToolbar;
 946 }
---
   9 #include <gdk/gdkkeysyms.h>
  10 #include <gtk/gtk.h>
  11 #include <hildon-widgets/hildon-app.h>
  12 #include <hildon-widgets/hildon-color-button.h>
  13 #include <hildon-widgets/hildon-find-toolbar.h>
  14 #include <hildon-widgets/hildon-file-chooser-dialog.h>
  15 #include <hildon-widgets/gtk-infoprint.h>
  16 #include <libgnomevfs/gnome-vfs.h>
  17 /* include prototypes for GConf client-part */
  18 #include <gconf/gconf-client.h>

Compressed tooltips for firefox and IE

confGetInt:

 104 /**
 105  * NEW
 106  *
 107  * Helper function to get an integer but also return
 108  * the status whether the given key existed or not.
 109  *
 110  * Note that it's also possible to use
 111  * gconf_client_get_int() but it's not possible then
 112  * to know whether they key existed or not, because it
 113  * will return 0 if the key doesn't exist.
 114  *
 115  * Parameters:
 116  * - GConfClient: client object to use
 117  * - const gchar*: key
 118  * - gint*: address to store the integer to if the key exists
 119  *
 120  * Returns:
 121  * - TRUE: if integer has been updated with a value from GConf
 122  *   FALSE: there was no such key or it wasn't an integer
 123  */
 124 gboolean confGetInt(GConfClient* gcClient, const gchar* key,
 125   gint* number) {
 126 
 127   /* this will hold our type/value pair at some point */
 128   GConfValue* val = NULL;
 129   /* what should we return */
 130   gboolean hasChanged = FALSE;
 131 
 132   /* try to get the type/value from GConf DB.
 133      note that we're using a version that will not return
 134      any defaults (if a schema would say one) just to be sure
 135      whether the key exists or not, really.
 136 
 137      We're not really interested in errors as this will
 138      return a NULL in case of missing keys or errors and that
 139      is quite enough for us */
 140   val = gconf_client_get_without_default(gcClient, key, NULL);
 141   if (val == NULL) {
 142     /* key not found, no need to touch anything */
 143     g_warning("confGetInt: key %s not found\n", key);
 144     return FALSE;
 145   }
 146 
 147   /* check whether the value stored behind the key is an
 148      integer. If not an int, we warn, but return normally */
 149   if (val->type == GCONF_VALUE_INT) {
 150     /* it's an integer, get it and store */
 151     *number = gconf_value_get_int(val);
 152     /* mark that we've changed the int */
 153     hasChanged = TRUE;
 154   } else {
 155     g_warning("confGetInt: key %s is not an integer\n", key);
 156   }
 157 
 158   /* free the type/value-pair */
 159   gconf_value_free(val);
 160   val = NULL;
 161 
 162   return hasChanged;
 163 }

Todo:


Todo docs:


Todo later:

Done:


Valid XHTML 1.0 (Strict) Valid CSS! Made with CSS