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: