/** * hildon_helloworld-9.c * * This maemo code example is licensed under a MIT-style license, * that can be found in the file called "License" in the same * directory as this file. * Copyright (c) 2007-2009 Nokia Corporation. All rights reserved. * * We'll store the color that the user selects into a GConf * preference. In fact, we'll have three settings, one for each * channel of the color (red, green and blue). * * Look for lines with "NEW" or "MODIFIED" in them. */ #include #include #include #include #include #include #include /* Include the prototypes for GConf client functions (NEW). */ #include /* The application name -part of the GConf namespace (NEW). */ #define APP_NAME "hildon_hello" /* This will be the root "directory" for our preferences (NEW). */ #define GC_ROOT "/apps/Maemo/" APP_NAME "/" /* Declare the two slant styles. */ enum { STYLE_SLANT_NORMAL = 0, STYLE_SLANT_ITALIC }; /** * The application state. */ typedef struct { gboolean styleUseUnderline; gboolean styleSlant; GdkColor currentColor; GtkWidget* textLabel; gboolean fullScreen; GtkWidget* findToolbar; GtkWidget* mainToolbar; gboolean findToolbarIsVisible; gboolean mainToolbarIsVisible; HildonProgram* program; HildonWindow* window; } ApplicationState; static gboolean cbEventDelete(GtkWidget* widget, GdkEvent* event, ApplicationState* app) { return FALSE; } static void cbActionTopDestroy(GtkWidget* widget, ApplicationState* app) { gtk_main_quit(); } /** * Ask user to pick a file and return the filename to caller. */ static gchar* runFileChooser(ApplicationState* app, GtkFileChooserAction style) { GtkWidget* dialog = NULL; gchar* filename = NULL; g_assert(app != NULL); g_print("runFilechooser: invoked\n"); dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(app->window), style); gtk_widget_show_all(GTK_WIDGET(dialog)); g_print(" running dialog\n"); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); } g_print(" dialog completed\n"); gtk_widget_destroy(dialog); if (filename != NULL) { g_print(" user selected filename '%s'\n", filename); } else { g_print(" user didn't select any filename\n"); } return filename; } static void dbgFileError(GnomeVFSResult errCode, const gchar* uri) { g_printerr("Error while accessing '%s': %s\n", uri, gnome_vfs_result_to_string(errCode)); } static void cbActionOpen(GtkWidget* widget, ApplicationState* app) { gchar* filename = NULL; gchar* uri = NULL; g_assert(app != NULL); g_assert(GTK_IS_LABEL(app->textLabel)); g_assert(GTK_IS_WINDOW(app->window)); g_print("cbActionOpen invoked\n"); /* Ask the user to select a file to open. */ filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_OPEN); if (filename) { gchar* buffer = NULL; GnomeVFSHandle* fileHandle = NULL; GnomeVFSFileInfo fileInfo = {}; GnomeVFSResult result; GnomeVFSFileSize fileSize = 0; GnomeVFSFileSize readCount = 0; g_print(" you chose to load file '%s'\n", filename); /* Convert the filename into an GnomeVFS URI. */ uri = gnome_vfs_get_uri_from_local_path(filename); g_free(filename); filename = NULL; g_assert(uri != NULL); /* Attempt to get file metadata. */ result = gnome_vfs_get_file_info(uri, &fileInfo, GNOME_VFS_FILE_INFO_DEFAULT); if (result != GNOME_VFS_OK) { dbgFileError(result, uri); goto error; } if (fileInfo.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) { fileSize = fileInfo.size; } else { g_printerr("Couldn't get the size of file!\n"); goto error; } if (fileSize > 1024*100) { g_printerr("Loading over 100KiB files is not supported!\n"); goto error; } /* Refuse to load empty files. */ if (fileSize == 0) { g_printerr("Refusing to load an empty file\n"); goto error; } buffer = g_malloc0(fileSize+1); if (buffer == NULL) { g_printerr("Failed to allocate %u bytes for buffer\n", (guint)fileSize); goto error; } result = gnome_vfs_open(&fileHandle, uri, GNOME_VFS_OPEN_READ); if (result != GNOME_VFS_OK) { dbgFileError(result, uri); goto error; } result = gnome_vfs_read(fileHandle, buffer, fileSize, &readCount); if (result != GNOME_VFS_OK) { dbgFileError(result, uri); goto error; } if (fileSize != readCount) { g_printerr("Failed to load the requested amount\n"); goto error; } gtk_label_set_markup(GTK_LABEL(app->textLabel), buffer); hildon_banner_show_information(GTK_WIDGET(app->window), NULL, /* Use the default icon (info). */ "File loaded successfully"); /* Jump to the resource releasing phase. */ goto release; error: hildon_banner_show_information(GTK_WIDGET(app->window), GTK_STOCK_DIALOG_ERROR, /* Use the stock error icon. */ "Failed to load the file"); release: /* Close and free all resources that were allocated. */ 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"); } } static 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 a filename to save to\n"); } } static void cbActionQuit(GtkWidget* widget, ApplicationState* app) { g_print("cbActionQuit invoked. Terminating using gtk_main_quit\n"); gtk_main_quit(); } static void cbActionUnderlineToggled(GtkCheckMenuItem* item, ApplicationState* app) { g_assert(app != NULL); g_print("cbActionUnderlineToggled invoked\n"); app->styleUseUnderline = gtk_check_menu_item_get_active(item); g_print(" underlining is now %s\n", app->styleUseUnderline?"on":"off"); } static void cbActionStyleNormalToggled(GtkCheckMenuItem* item, ApplicationState* app) { g_assert(app != NULL); g_print("cbActionStyleNormalToggled invoked\n"); if (gtk_check_menu_item_get_active(item)) { app->styleSlant = STYLE_SLANT_NORMAL; g_print(" selected slanting for text is now Normal\n"); } } static void cbActionStyleItalicToggled(GtkCheckMenuItem* item, ApplicationState* app) { g_assert(app != NULL); g_print("cbActionStyleItalicToggled invoked\n"); if (gtk_check_menu_item_get_active(item)) { app->styleSlant = STYLE_SLANT_ITALIC; g_print(" selected slanting for text is now Italic\n"); } } /** * NEW * * Utility function to store the given color into our application * preferences. We could use a list of integers as well, but we'll * settle for three separate properties; one for each of RGB * channels. * * The config keys that will be used are 'red', 'green' and 'blue'. * * NOTE: * We're doing things very non-optimally. If our application would * have multiple preference settings, and we would like to know * when someone will change them (external program, another * instance of our program, etc), we'd have to keep a reference to * the GConf client connection. Listening for changes in * preferences would also require a callback registration, but this * is covered in the "maemo Platform Development" material. */ static void confStoreColor(const GdkColor* color) { /* We'll store the pointer to the GConf connection here. */ GConfClient* gcClient = NULL; /* Make sure that no NULLs are passed for the color. GdkColor is not a proper GObject, so there is no GDK_IS_COLOR macro. */ g_assert(color); g_print("confStoreColor: invoked\n"); /* Open a connection to gconfd-2 (via D-Bus in maemo). The GConf API doesn't say whether this function can ever return NULL or how it will behave in error conditions. */ gcClient = gconf_client_get_default(); /* We make sure that it's a valid GConf-client object. */ g_assert(GCONF_IS_CLIENT(gcClient)); /* Store the values. */ if (!gconf_client_set_int(gcClient, GC_ROOT "red", color->red, NULL)) { g_warning(" failed to set %s/red to %d\n", GC_ROOT, color->red); } if (!gconf_client_set_int(gcClient, GC_ROOT "green", color->green, NULL)) { g_warning(" failed to set %s/green to %d\n", GC_ROOT, color->green); } if (!gconf_client_set_int(gcClient, GC_ROOT "blue", color->blue, NULL)) { g_warning(" failed to set %s/blue to %d\n", GC_ROOT, color->blue); } /* Release the GConf client object (with GObject-unref). */ g_object_unref(gcClient); gcClient = NULL; } /** * NEW * * An utility function to get an integer but also return the status * whether the requested key existed or not. * * NOTE: * It's also possible to use gconf_client_get_int(), but it's not * possible to then know whether they key existed or not, because * the function will return 0 if the key doesn't exist (and if the * value is 0, how could you tell these two conditions apart?). * * Parameters: * - GConfClient: the client object to use * - const gchar*: the key * - gint*: the address to store the integer to if the key exists * * Returns: * - TRUE: if integer has been updated with a value from GConf. * FALSE: there was no such key or it wasn't an integer. */ static gboolean confGetInt(GConfClient* gcClient, const gchar* key, gint* number) { /* This will hold the type/value pair at some point. */ GConfValue* val = NULL; /* Return flag (tells the caller whether this function wrote behind the 'number' pointer or not). */ gboolean hasChanged = FALSE; /* Try to get the type/value from the GConf DB. NOTE: We're using a version of the getter that will not return any defaults (if a schema would specify one). Instead, it will return the value if one has been set (or NULL). We're not really interested in errors as this will return a NULL in case of missing keys or errors and that is quite enough for us. */ val = gconf_client_get_without_default(gcClient, key, NULL); if (val == NULL) { /* Key wasn't found, no need to touch anything. */ g_warning("confGetInt: key %s not found\n", key); return FALSE; } /* Check whether the value stored behind the key is an integer. If it is not, we issue a warning, but return normally. */ if (val->type == GCONF_VALUE_INT) { /* It's an integer, get it and store. */ *number = gconf_value_get_int(val); /* Mark that we've changed the integer behind 'number'. */ hasChanged = TRUE; } else { g_warning("confGetInt: key %s is not an integer\n", key); } /* Free the type/value-pair. */ gconf_value_free(val); val = NULL; return hasChanged; } /** * NEW * * Utility function to change the given color into the one that is * specified in application preferences. * * If some key is missing, that channel is left untouched. The * function also checks for proper values for the channels so that * invalid values are not accepted (guint16 range of GdkColor). * * Parameters: * - GdkColor*: the color structure to modify if changed from prefs. * * Returns: * - TRUE if the color was been changed by this routine. * FALSE if the color wasn't changed (there was an error or the * color was already exactly the same as in the preferences). */ static gboolean confLoadCurrentColor(GdkColor* color) { GConfClient* gcClient = NULL; /* Temporary holders for the pref values. */ gint red = -1; gint green = -1; gint blue = -1; /* Temp variable to hold whether the color has changed. */ gboolean hasChanged = FALSE; g_assert(color); g_print("confLoadCurrentColor: invoked\n"); /* Open a connection to gconfd-2 (via d-bus). */ gcClient = gconf_client_get_default(); /* Make sure that it's a valid GConf-client object. */ g_assert(GCONF_IS_CLIENT(gcClient)); if (confGetInt(gcClient, GC_ROOT "red", &red)) { /* We got the value successfully, now clamp it. */ g_print(" got red = %d, ", red); /* We got a value, so let's limit it between 0 and 65535 (the legal range for guint16). We use the CLAMP macro from GLib for this. */ red = CLAMP(red, 0, G_MAXUINT16); g_print("after clamping = %d\n", red); /* Update & mark that at least this component changed. */ color->red = (guint16)red; hasChanged = TRUE; } /* Repeat the same logic for the green component. */ if (confGetInt(gcClient, GC_ROOT "green", &green)) { g_print(" got green = %d, ", green); green = CLAMP(green, 0, G_MAXUINT16); g_print("after clamping = %d\n", green); color->green = (guint16)green; hasChanged = TRUE; } /* Repeat the same logic for the last component (blue). */ if (confGetInt(gcClient, GC_ROOT "blue", &blue)) { g_print(" got blue = %d, ", blue); blue = CLAMP(blue, 0, G_MAXUINT16); g_print("after clamping = %d\n", blue); color->blue = (guint16)blue; hasChanged = TRUE; } /* Release the client object (with GObject-unref). */ g_object_unref(gcClient); gcClient = NULL; /* Return status if the color was been changed by this routine. */ return hasChanged; } /** * MODIFIED * * Invoked when the user selects a color (or will cancel the dialog). * * Will also write the color to preferences (GConf) each time the * color changes. We'll compare whether it has really changed (to * avoid writing to GConf is nothing really changed). */ static void cbActionColorChanged(GtkColorButton* colorButton, ApplicationState* app) { /* Local variables that we'll need to handle the change (NEW). */ gboolean hasChanged = FALSE; GdkColor newColor = {}; GdkColor* curColor = NULL; g_assert(app != NULL); g_print("cbActionColorChanged invoked\n"); /* Retrieve the new color from the color button (NEW). */ gtk_color_button_get_color(colorButton, &newColor); /* Just an alias to save some typing (could also use app->currentColor) (NEW). */ curColor = &app->currentColor; /* Check whether the color really changed (NEW). */ if ((newColor.red != curColor->red) || (newColor.green != curColor->green) || (newColor.blue != curColor->blue)) { hasChanged = TRUE; } if (!hasChanged) { g_print(" color not really changed\n"); return; } /* Color really changed, store to preferences (NEW). */ g_print(" color changed, storing into preferences.. \n"); confStoreColor(&newColor); g_print(" done.\n"); /* Update the changed color into the application state. */ app->currentColor = newColor; } static void cbActionFindToolbarToggle(GtkWidget* widget, ApplicationState* app) { gboolean newVisibilityState = FALSE; g_assert(app != NULL); g_assert(GTK_IS_TOOLBAR(app->findToolbar)); g_print("cbActionFindToolbarToggle invoked\n"); /* Toggle the visibility flag. */ newVisibilityState = ~app->findToolbarIsVisible; if (newVisibilityState) { g_print(" showing find-toolbar\n"); gtk_widget_show(app->findToolbar); } else { g_print(" hiding find-toolbar\n"); gtk_widget_hide(app->findToolbar); } app->findToolbarIsVisible = newVisibilityState; } static void cbActionMainToolbarToggle(GtkCheckMenuItem* item, ApplicationState* app) { gboolean newVisibilityState = FALSE; g_assert(app != NULL); g_assert(GTK_IS_TOOLBAR(app->mainToolbar)); g_print("cbActionMainToolbarToggle invoked\n"); newVisibilityState = gtk_check_menu_item_get_active(item); if (app->mainToolbarIsVisible != newVisibilityState) { if (newVisibilityState) { gtk_widget_show(app->mainToolbar); } else { gtk_widget_hide(app->mainToolbar); } app->mainToolbarIsVisible = newVisibilityState; } } static void cbActionFindToolbarSearch(HildonFindToolbar* fToolbar, ApplicationState* app) { gchar* findText = NULL; g_assert(app != NULL); g_print("cbActionFindToolbarSearch invoked\n"); g_object_get(G_OBJECT(fToolbar), "prefix", &findText, NULL); if (findText != NULL) { g_print(" would search for '%s' if would know how to\n", findText); } } static void cbActionFindToolbarClosed(HildonFindToolbar* fToolbar, ApplicationState* app) { g_assert(app != NULL); g_print("cbActionFindToolbarClosed invoked\n"); gtk_widget_hide(GTK_WIDGET(fToolbar)); app->findToolbarIsVisible = FALSE; } /** * Utility to switch the application to fullscreen mode. */ static void cbActionGoFullscreen(GtkMenuItem* mi, ApplicationState* app) { g_assert(app != NULL); g_print("cbActionGoFullscreen invoked. Going fullscreen.\n"); gtk_window_fullscreen(GTK_WINDOW(app->window)); app->fullScreen = TRUE; } /** * Key press event handler. */ static gboolean cbKeyPressed(GtkWidget* widget, GdkEventKey* ev, ApplicationState* app) { g_assert(app != NULL); g_print("cbKeyPress invoked\n"); /* if pressed ctrl-f */ if (ev->keyval == GDK_f && (ev->state & GDK_CONTROL_MASK)) { g_print(" pressed ctrl-f (fullscreen)\n"); if (app->fullScreen) { gtk_window_unfullscreen(GTK_WINDOW(app->window)); app->fullScreen = FALSE; } else { gtk_window_fullscreen(GTK_WINDOW(app->window)); app->fullScreen = TRUE; } /* We recognized the key, do not process it any further. */ return TRUE; } else { g_print(" not ctrl-f (something else)\n"); } /* We didn't process the event. */ return FALSE; } /** * MODIFIED * * The color of the color button will be loaded from the application * preferences (or keep the default if preferences have no setting). */ static GtkWidget* buildToolbar(ApplicationState* app) { GtkToolbar* toolbar = NULL; GtkToolItem* tbOpen = NULL; GtkToolItem* tbSave = NULL; GtkToolItem* tbSep = NULL; GtkToolItem* tbFind = NULL; GtkToolItem* tbColorButton = NULL; GtkWidget* colorButton = NULL; g_assert(app != NULL); tbOpen = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN); tbSave = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE); tbSep = gtk_separator_tool_item_new(); tbFind = gtk_tool_button_new_from_stock(GTK_STOCK_FIND); tbColorButton = gtk_tool_item_new(); colorButton = gtk_color_button_new(); /* Copy the color from the color button into the application state. This is done to detect whether the color in preferences matches the default color or not (NEW). */ gtk_color_button_get_color(GTK_COLOR_BUTTON(colorButton), &app->currentColor); /* Load preferences and change the color if necessary. */ g_print("buildToolbar: loading color pref.\n"); if (confLoadCurrentColor(&app->currentColor)) { g_print(" color not same as default one\n"); gtk_color_button_set_color(GTK_COLOR_BUTTON(colorButton), &app->currentColor); } else { g_print(" loaded color same as default\n"); } gtk_container_add(GTK_CONTAINER(tbColorButton), colorButton); toolbar = GTK_TOOLBAR(gtk_toolbar_new()); gtk_toolbar_insert(toolbar, tbOpen, -1); gtk_toolbar_insert(toolbar, tbSave, -1); gtk_toolbar_insert(toolbar, tbSep, -1); gtk_toolbar_insert(toolbar, tbFind, -1); gtk_toolbar_insert(toolbar, tbColorButton, -1); gtk_widget_show_all(GTK_WIDGET(toolbar)); if (!app->mainToolbarIsVisible) { gtk_widget_hide(GTK_WIDGET(toolbar)); } g_signal_connect(G_OBJECT(tbOpen), "clicked", G_CALLBACK(cbActionOpen), app); g_signal_connect(G_OBJECT(tbSave), "clicked", G_CALLBACK(cbActionSave), app); g_signal_connect(G_OBJECT(tbFind), "clicked", G_CALLBACK(cbActionFindToolbarToggle), app); g_signal_connect(G_OBJECT(colorButton), "color-set", G_CALLBACK(cbActionColorChanged), app); /* Return the toolbar as a GtkWidget*. */ return GTK_WIDGET(toolbar); } /** * Create the Find toolbar. */ static GtkWidget* buildFindToolbar(ApplicationState* app) { GtkWidget* findToolbar = NULL; g_assert(app != NULL); findToolbar = hildon_find_toolbar_new("Find "); g_signal_connect(G_OBJECT(findToolbar), "search", G_CALLBACK(cbActionFindToolbarSearch), app); g_signal_connect(G_OBJECT(findToolbar), "close", G_CALLBACK(cbActionFindToolbarClosed), app); gtk_widget_show_all(findToolbar); if (!app->findToolbarIsVisible) { gtk_widget_hide(findToolbar); } return findToolbar; } /** * Build the Style sub menu and return it. */ static GtkWidget* buildSubMenu(ApplicationState* app) { GtkWidget* subMenu = NULL; GtkWidget* mciUnderline = NULL; GtkWidget* miSep = NULL; GtkWidget* mriNormal = NULL; GtkWidget* mriItalic = NULL; g_assert(app != NULL); mciUnderline = gtk_check_menu_item_new_with_label("Underline"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mciUnderline), app->styleUseUnderline); { GSList* group = NULL; mriItalic = gtk_radio_menu_item_new_with_label(NULL, "Italic"); group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(mriItalic)); mriNormal = gtk_radio_menu_item_new_with_label(group, "Normal"); } if (app->styleSlant == STYLE_SLANT_NORMAL) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mriNormal), TRUE); } else { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mriItalic), TRUE); } miSep = gtk_separator_menu_item_new(); subMenu = gtk_menu_new(); gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), mciUnderline); gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), miSep); gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), mriNormal); gtk_menu_shell_append(GTK_MENU_SHELL(subMenu), mriItalic); g_signal_connect(G_OBJECT(mciUnderline), "toggled", G_CALLBACK(cbActionUnderlineToggled), app); g_signal_connect(G_OBJECT(mriNormal), "toggled", G_CALLBACK(cbActionStyleNormalToggled), app); g_signal_connect(G_OBJECT(mriItalic), "toggled", G_CALLBACK(cbActionStyleItalicToggled), app); return subMenu; } /** * Build the main level menu (and submenu) and attach to the * HildonProgram. */ static void buildMenu(ApplicationState* app) { GtkMenu* menu = NULL; GtkWidget* miOpen = NULL; GtkWidget* miSave = NULL; GtkWidget* miSep1 = NULL; GtkWidget* miStyle = NULL; GtkWidget* subMenu = NULL; GtkWidget* mciShowToolbar = NULL; GtkWidget* miFullscreen = NULL; GtkWidget* miSep2 = NULL; GtkWidget* miQuit = NULL; miOpen = gtk_menu_item_new_with_label("Open"); miSave = gtk_menu_item_new_with_label("Save"); miSep1 = gtk_separator_menu_item_new(); miStyle = gtk_menu_item_new_with_label("Style"); mciShowToolbar = gtk_check_menu_item_new_with_label("Show toolbar"); miFullscreen = gtk_menu_item_new_with_label("Fullscreen"); miSep2 = gtk_separator_menu_item_new(); miQuit = gtk_menu_item_new_with_label("Quit"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mciShowToolbar), app->mainToolbarIsVisible); subMenu = buildSubMenu(app); gtk_menu_item_set_submenu(GTK_MENU_ITEM(miStyle), subMenu); menu = GTK_MENU(gtk_menu_new()); hildon_program_set_common_menu(app->program, menu); gtk_container_add(GTK_CONTAINER(menu), miOpen); gtk_container_add(GTK_CONTAINER(menu), miSave); gtk_container_add(GTK_CONTAINER(menu), miSep1); gtk_container_add(GTK_CONTAINER(menu), miStyle); gtk_container_add(GTK_CONTAINER(menu), mciShowToolbar); gtk_container_add(GTK_CONTAINER(menu), miFullscreen); gtk_container_add(GTK_CONTAINER(menu), miSep2); gtk_container_add(GTK_CONTAINER(menu), miQuit); g_signal_connect(G_OBJECT(miOpen), "activate", G_CALLBACK(cbActionOpen), app); g_signal_connect(G_OBJECT(miSave), "activate", G_CALLBACK(cbActionSave), app); g_signal_connect(G_OBJECT(miQuit), "activate", G_CALLBACK(cbActionQuit), app); g_signal_connect(G_OBJECT(mciShowToolbar), "toggled", G_CALLBACK(cbActionMainToolbarToggle), app); g_signal_connect(G_OBJECT(miFullscreen), "activate", G_CALLBACK(cbActionGoFullscreen), app); gtk_widget_show_all(GTK_WIDGET(menu)); } int main(int argc, char** argv) { ApplicationState aState = {}; GtkWidget* label = NULL; GtkWidget* vbox = NULL; GtkWidget* mainToolbar = NULL; GtkWidget* findToolbar = NULL; if(!gnome_vfs_init()) { g_error("Failed to initialize GnomeVFS-libraries, exiting\n"); } /* Initialize the GTK+ */ gtk_init(&argc, &argv); /* Setup the HildonProgram, HildonWindow and application name. */ aState.program = HILDON_PROGRAM(hildon_program_get_instance()); g_set_application_name("Hello Hildon!"); aState.window = HILDON_WINDOW(hildon_window_new()); hildon_program_add_window(aState.program, HILDON_WINDOW(aState.window)); label = gtk_label_new("Hello Hildon (GConf " "support)!\n"); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); aState.textLabel = label; buildMenu(&aState); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(aState.window), vbox); gtk_box_pack_end(GTK_BOX(vbox), label, TRUE, TRUE, 0); mainToolbar = buildToolbar(&aState); findToolbar = buildFindToolbar(&aState); aState.mainToolbar = mainToolbar; aState.findToolbar = findToolbar; /* Connect the termination signals. */ g_signal_connect(G_OBJECT(aState.window), "delete-event", G_CALLBACK(cbEventDelete), &aState); g_signal_connect(G_OBJECT(aState.window), "destroy", G_CALLBACK(cbActionTopDestroy), &aState); /* Show all widgets that are contained by the Window. */ gtk_widget_show_all(GTK_WIDGET(aState.window)); /* Add the toolbars to the Hildon Window. */ hildon_window_add_toolbar(HILDON_WINDOW(aState.window), GTK_TOOLBAR(mainToolbar)); hildon_window_add_toolbar(HILDON_WINDOW(aState.window), GTK_TOOLBAR(findToolbar)); /* Register a callback to handle key presses. */ g_signal_connect(G_OBJECT(aState.window), "key_press_event", G_CALLBACK(cbKeyPressed), &aState); g_print("main: calling gtk_main\n"); gtk_main(); g_print("main: returned from gtk_main and exiting with success\n"); return EXIT_SUCCESS; }