static void audit_exit (GvaProcess *process, gint status, GvaAuditData *data) { gchar *sql; GError *error = NULL; if (process->error != NULL) return; gva_db_transaction_begin (&error); gva_error_handle (&error); sql = g_strdup_printf ("UPDATE game SET %s=NULL", data->column); gva_db_execute (sql, &error); gva_error_handle (&error); g_free (sql); g_hash_table_foreach ( data->status_index, (GHFunc) audit_exit_foreach, data); gva_db_transaction_commit (&error); gva_error_handle (&error); }
/** * gva_audit_detect_changes: * * Attempts to detect ROM and sample file changes since the last program * execution by scanning the timestamps on the directories listed in the * "rompath" and "samplepath" configuration values. It returns %TRUE if * any of those timestamps are more recent than the game database. * * Returns: %TRUE if changes were detected **/ gboolean gva_audit_detect_changes (void) { gboolean changes = FALSE; gchar **directories; struct stat st; guint length, ii; GError *error = NULL; if (g_stat (gva_db_get_filename (), &st) < 0) return FALSE; directories = gva_mame_get_search_paths ("rompath", &error); length = (directories != NULL) ? g_strv_length (directories) : 0; gva_error_handle (&error); for (ii = 0; ii < length; ii++) changes |= gva_db_is_older_than (directories[ii]); g_strfreev (directories); directories = gva_mame_get_search_paths ("samplepath", &error); length = (directories != NULL) ? g_strv_length (directories) : 0; gva_error_handle (&error); for (ii = 0; ii < length; ii++) changes |= gva_db_is_older_than (directories[ii]); g_strfreev (directories); return changes; }
static void start (void) { GSettings *settings; GError *error = NULL; settings = gva_get_settings (); if (gva_db_needs_rebuilt ()) { if (!gva_main_build_database (&error)) { gva_error_handle (&error); return; } if (!gva_main_analyze_roms (&error)) { gva_error_handle (&error); return; } if (!gva_db_mark_complete (&error)) { gva_error_handle (&error); return; } } else if (gva_audit_detect_changes ()) { if (!gva_main_analyze_roms (&error)) { gva_error_handle (&error); return; } } /* Do this after ROMs are analyzed. */ if (!gva_main_init_search_completion (&error)) { gva_error_handle (&error); return; } gva_ui_unlock (); g_settings_bind ( settings, GVA_SETTING_SELECTED_VIEW, GVA_ACTION_VIEW_AVAILABLE, "current-value", G_SETTINGS_BIND_DEFAULT); /* Present a helpful dialog if no ROMs were found. */ warn_if_no_roms (); /* Listen for changes to the 'rompath' directories. */ setup_file_monitors (); }
static gboolean wnck_window_timeout_cb (WnckWindow *window) { const gchar *game; gint x, y; gint width, height; gchar *sql; GError *error = NULL; if (wnck_window_is_fullscreen (window)) goto exit; game = wnck_window_get_game (window); wnck_window_get_geometry (window, &x, &y, &width, &height); if (wnck_window_is_maximized (window)) sql = g_strdup_printf ( "UPDATE window SET maximized = 1 " "WHERE name = '%s'", game); else sql = g_strdup_printf ( "UPDATE window SET x = %d, y = %d, width = %d, " "height = %d, maximized = 0 WHERE name = '%s'", x, y, width, height, game); gva_db_execute (sql, &error); gva_error_handle (&error); g_free (sql); exit: g_object_set_data (G_OBJECT (window), TIMEOUT_SOURCE_ID_KEY, NULL); return FALSE; }
/** * gva_mame_get_save_state_file: * @name: the name of a game * * Returns the name of the automatic save state file for @name. * * Returns: the name of the save state file **/ gchar * gva_mame_get_save_state_file (const gchar *name) { const gchar *directory; gchar *basename; gchar *filename = NULL; GError *error = NULL; directory = gva_mame_get_state_directory (&error); gva_error_handle (&error); if (directory == NULL) return NULL; /* As of 0.115, MAME stores save state files as "name/auto.sta". */ filename = g_build_filename (directory, name, "auto.sta", NULL); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return filename; else g_free (filename); /* Prior to 0.115, MAME stored save state files as "name.sta". */ basename = g_strdup_printf ("%s.sta", name); filename = g_build_filename (directory, basename, NULL); g_free (basename); if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return filename; else g_free (filename); return NULL; /* file not found */ }
/** * gva_audit_save_errors: * * Saves the results of the most recent ROM file audit to a file. **/ void gva_audit_save_errors (void) { GtkTreeView *view; GtkTreeModel *model; GString *contents; gchar *mame_version; gchar *filename; GError *error = NULL; view = GTK_TREE_VIEW (GVA_WIDGET_AUDIT_TREE_VIEW); model = gtk_tree_view_get_model (view); g_return_if_fail (model != NULL); mame_version = gva_mame_get_version (&error); gva_error_handle (&error); /* Build the contents of the file. */ contents = g_string_sized_new (4096); g_string_append_printf ( contents, "%s - ROM Audit Results\n", PACKAGE_STRING); if (mame_version != NULL) g_string_append_printf (contents, "Using %s\n", mame_version); else g_string_append (contents, "Using unknown M.A.M.E. version\n"); g_string_append_c (contents, '\n'); gtk_tree_model_foreach ( model, (GtkTreeModelForeachFunc) audit_save_errors_foreach, contents); /* Prompt the user for a filename. */ filename = audit_run_save_dialog (); if (filename != NULL) { g_file_set_contents (filename, contents->str, -1, &error); gva_error_handle (&error); g_free (filename); } g_free (mame_version); g_string_free (contents, TRUE); }
/** * gva_main_set_last_search_text: * @text: the search entry text * * Writes @text to GConf key * <filename>/apps/gnome-video-arcade/search</filename>. * * This is used to remember the search entry text from the previous session * of <emphasis>GNOME Video Arcade</emphasis> so that the same text can be * preset in the search entry at startup. **/ void gva_main_set_last_search_text (const gchar *text) { GConfClient *client; GError *error = NULL; g_return_if_fail (text != NULL); client = gconf_client_get_default (); gconf_client_set_string (client, GVA_GCONF_SEARCH_KEY, text, &error); gva_error_handle (&error); g_object_unref (client); }
static void warn_if_no_roms (void) { const gchar *sql = SQL_COUNT_ROMS; GtkWidget *dialog; gchar **result; glong n_roms; GError *error = NULL; if (!gva_db_get_table (sql, &result, NULL, NULL, &error)) { gva_error_handle (&error); return; } errno = 0; g_return_if_fail (g_strv_length (result) > 1); n_roms = strtol (result[1], NULL, 10); g_strfreev (result); if (errno != 0) { g_warning ("%s", g_strerror (errno)); return; } if (n_roms > 0) return; dialog = gtk_message_dialog_new_with_markup ( GTK_WINDOW (GVA_WIDGET_MAIN_WINDOW), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "<big><b>%s</b></big>", _("No ROM files found")); gtk_message_dialog_format_secondary_markup ( GTK_MESSAGE_DIALOG (dialog), _("GNOME Video Arcade was unable to locate any ROM files. " "It could be that MAME is misconfigured or that no ROM " "files are installed. Click <b>Help</b> for more details " "and troubleshooting tips.")); gtk_dialog_add_button ( GTK_DIALOG (dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_HELP) gva_help_display (GTK_WINDOW (dialog), "troubleshooting"); gtk_widget_destroy (dialog); }
/** * gva_main_get_last_search_text: * * Returns the most recent search entry text from either the current or * previous session of <emphasis>GNOME Video Arcade</emphasis>. * * Returns: the most recent search text **/ gchar * gva_main_get_last_search_text (void) { GConfClient *client; gchar *text; GError *error = NULL; client = gconf_client_get_default (); text = gconf_client_get_string (client, GVA_GCONF_SEARCH_KEY, &error); gva_error_handle (&error); g_object_unref (client); return (text != NULL) ? g_strstrip (text) : g_strdup (""); }
/** * gva_main_execute_search: * * Executes a game database search and configures the main window to * display the results. More precisely, the function saves the search * entry contents to GConf, switches to the Search Results view, forces * an update, ensures a row in the resulting game list is selected, and * gives focus to the main tree view. * * The SQL expression used in the database search is retrieved from * gva_main_get_search_expression(). It is applied while updating the * Search Results view. **/ void gva_main_execute_search (void) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeView *view; GtkTreeIter iter; GtkEntry *entry; gchar *text; entry = GTK_ENTRY (GVA_WIDGET_MAIN_SEARCH_ENTRY); view = GTK_TREE_VIEW (GVA_WIDGET_MAIN_TREE_VIEW); selection = gtk_tree_view_get_selection (view); /* Save the search entry text. */ text = g_strdup (gtk_entry_get_text (entry)); gtk_entry_set_text (entry, g_strstrip (text)); gva_main_set_last_search_text (text); g_free (text); /* Force a tree view update. */ if (gva_tree_view_get_selected_view () != 2) gva_tree_view_set_selected_view (2); else { GError *error = NULL; gva_tree_view_update (&error); gva_error_handle (&error); } /* Select something in the tree view. Parts of this are * copied from gva_tree_view_set_selected_game(). */ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { if (gtk_tree_model_get_iter_first (model, &iter)) { GtkTreePath *path; path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_set_cursor (view, path, NULL, FALSE); gtk_tree_view_scroll_to_cell ( view, path, NULL, TRUE, 0.5, 0.0); gtk_tree_path_free (path); } } gtk_widget_grab_focus (GTK_WIDGET (view)); }
/* Helper for audit_exit() */ static void audit_exit_foreach (gchar *status, GString *names, GvaAuditData *data) { gchar *sql; GError *error = NULL; sql = g_strdup_printf ( "UPDATE game SET %s=\"%s\" WHERE name IN (%s)", data->column, status, names->str); gva_db_execute (sql, &error); gva_error_handle (&error); g_free (sql); }
/** * gva_main_get_last_selected_match: * @column_name: return location for the column name * @search_text: return location for the search text * * Returns the most recently selected match in a search completion list * from either the current or previous session of <emphasis>GNOME Video * Arcade</emphasis>. If the completion feature was not used in the * most recent search, @column_name and @search_text are set to %NULL * and the function returns %FALSE. * * Returns: %TRUE if match values were successfully retrieved from GConf, * %FALSE otherwise **/ gboolean gva_main_get_last_selected_match (gchar **column_name, gchar **search_text) { GConfClient *client; gboolean success; GError *error = NULL; g_return_val_if_fail (column_name != NULL, FALSE); g_return_val_if_fail (search_text != NULL, FALSE); *column_name = *search_text = NULL; client = gconf_client_get_default (); success = gconf_client_get_pair ( client, GVA_GCONF_SELECTED_MATCH_KEY, GCONF_VALUE_STRING, GCONF_VALUE_STRING, column_name, search_text, &error); gva_error_handle (&error); g_object_unref (client); if (!success) return FALSE; /* The value may be unset. Treat it as a failure. */ if (*column_name == NULL || *search_text == NULL) goto fail; g_strstrip (*column_name); g_strstrip (*search_text); /* Both strings must be non-empty. */ if (**column_name == '\0' || **search_text == '\0') goto fail; return TRUE; fail: g_free (*column_name); g_free (*search_text); *column_name = *search_text = NULL; return FALSE; }
/** * gva_play_back_show: * @inpname: an input filename or %NULL * * Refreshes the contents of the Recorded Games window, attempts to * select the row corresponding to @inpname (if @inpname is not %NULL), * and finally shows the window. **/ void gva_play_back_show (const gchar *inpname) { GHashTable *hash_table; GvaGameStore *game_store; GtkTreeView *view; GError *error = NULL; view = GTK_TREE_VIEW (GVA_WIDGET_PLAY_BACK_TREE_VIEW); game_store = GVA_GAME_STORE (gtk_tree_view_get_model (view)); hash_table = gva_mame_get_input_files (&error); gva_error_handle (&error); if (hash_table != NULL) { gva_game_store_clear (game_store); g_hash_table_foreach ( hash_table, (GHFunc) play_back_add_input_file, game_store); g_hash_table_destroy (hash_table); } if (inpname != NULL) { GtkTreePath *path; path = gva_game_store_index_lookup (game_store, inpname); if (path != NULL) { gtk_tree_view_set_cursor (view, path, NULL, FALSE); gtk_tree_view_scroll_to_cell ( view, path, NULL, TRUE, 0.5, 0.0); gtk_widget_grab_focus (GTK_WIDGET (view)); gtk_tree_path_free (path); } } gtk_window_present (GTK_WINDOW (GVA_WIDGET_PLAY_BACK_WINDOW)); }
/** * gva_main_set_last_selected_match: * @column_name: the column name of the completion match * @search_text: the search text of the completion match * * Writes @column_name and @search_text to GConf key * <filename>/apps/gnome-video-arcade/sql-expression</filename> as a * string pair. * * This is used to remember whether the search results from the previous * session of <emphasis>GNOME Video Arcade</emphasis> were the result of * selecting a match from the search completion list. If so, the values * are also used to restore the contents of the Search Results view. **/ void gva_main_set_last_selected_match (const gchar *column_name, const gchar *search_text) { GConfClient *client; GError *error = NULL; if (column_name == NULL) column_name = ""; if (search_text == NULL) search_text = ""; client = gconf_client_get_default (); gconf_client_set_pair ( client, GVA_GCONF_SELECTED_MATCH_KEY, GCONF_VALUE_STRING, GCONF_VALUE_STRING, &column_name, &search_text, &error); gva_error_handle (&error); g_object_unref (client); }
/** * gva_mame_get_version_int: * * Returns the MAME version as a whole number for easy comparison. * For example, MAME version 0.123 is returned as 123. * * Returns: the MAME version as an integer **/ guint gva_mame_get_version_int (void) { static gsize regex_initialized; static GRegex *regex; GMatchInfo *match = NULL; gchar *string; guint version_int = 0; GError *error = NULL; if (g_once_init_enter (®ex_initialized)) { /* MAME versions have been 0.xxx for nearly 20 years, * so I think it's safe to disregard the leading zero. */ regex = g_regex_new ("0\\.(\\d\\d\\d)", 0, 0, NULL); g_assert (regex != NULL); g_once_init_leave (®ex_initialized, 1); } string = gva_mame_get_version (&error); gva_error_handle (&error); if (string != NULL) { if (g_regex_match (regex, string, 0, &match)) { gchar *substring; substring = g_match_info_fetch (match, 1); version_int = (guint) strtoul (substring, NULL, 10); g_free (substring); } g_free (string); } return version_int; }
/** * gva_mame_has_config_value: * @config_key: a configuration key * * Returns %TRUE if the MAME configuration has a configuration value for * @config_key. The function does not report errors that occur in the * course of spawning MAME, so false negatives are possible. * * Returns: %TRUE if a value for @config_key exists, %FALSE if no such * value exists or if an error occurred **/ gboolean gva_mame_has_config_value (const gchar *config_key) { gchar *config_value; gboolean result; GError *error = NULL; config_value = gva_mame_get_config_value (config_key, &error); result = (config_value != NULL && *config_value != '\0'); g_free (config_value); if (error != NULL) { /* Suppress warnings about unknown configuration * keys, since that's what we're testing for. */ if (error->code == GVA_ERROR_MAME) g_clear_error (&error); else gva_error_handle (&error); } return result; }
static void audit_show_dialog (GvaProcess *process, gint status, GvaAuditData *data) { GtkTreeView *view; GtkTreeModel *model; GError *error = NULL; if (process->error != NULL) return; model = audit_build_model (data, &error); gva_error_handle (&error); if (model == NULL) return; view = GTK_TREE_VIEW (GVA_WIDGET_AUDIT_TREE_VIEW); gtk_tree_view_set_model (view, model); if (gtk_tree_model_iter_n_children (model, NULL) > 0) gtk_window_present (GTK_WINDOW (GVA_WIDGET_AUDIT_WINDOW)); }
gint main (gint argc, gchar **argv) { GtkApplication *application; GApplicationFlags flags; gchar *path; GError *error = NULL; bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); gtk_init_with_args ( &argc, &argv, NULL, entries, GETTEXT_PACKAGE, &error); if (error != NULL) g_error ("%s", error->message); /* This installs handlers for our custom debug log levels. */ gva_get_debug_flags (); /* Change the working directory to that of the MAME executable. * Why? Because SDLMAME's default configuration uses relative * search paths such as "rompath = roms". The paths are relative * to the directory containing the MAME executable, so we must run * from that directory in order for SDLMAME's default configuration * to work. Annoying, but a common problem for users. */ path = g_path_get_dirname (MAME_PROGRAM); g_chdir (path); g_free (path); if (opt_inspect != NULL) { gchar *value; value = gva_mame_get_config_value (opt_inspect, &error); if (value != NULL) { g_print ("%s\n", value); g_free (value); } else { g_printerr ("%s\n", error->message); g_clear_error (&error); } exit (EXIT_SUCCESS); } if (opt_version) { g_print ("%s\n", PACKAGE_STRING); exit (EXIT_SUCCESS); } if (opt_which_emulator) { g_print ("%s\n", MAME_PROGRAM); exit (EXIT_SUCCESS); } /* Register the application with the session bus. */ flags = G_APPLICATION_FLAGS_NONE; application = gtk_application_new (APPLICATION_ID, flags); g_application_register (G_APPLICATION (application), NULL, &error); if (error != NULL) g_error ("%s", error->message); /* If another instance is running, exit now. */ if (g_application_get_is_remote (G_APPLICATION (application))) { gint exit_status; if (opt_build_database) { g_printerr ( "Cannot build database: " PACKAGE_NAME " is already running\n"); exit_status = EXIT_FAILURE; } else { g_application_activate (G_APPLICATION (application)); exit_status = EXIT_SUCCESS; } g_object_unref (application); exit (exit_status); } else { GtkWindow *window; window = GTK_WINDOW (GVA_WIDGET_MAIN_WINDOW); gtk_application_add_window (application, window); } gtk_window_set_default_icon_name (PACKAGE); if (!gva_db_init (&error)) g_error ("%s", error->message); gva_main_init (); gva_play_back_init (); gva_preferences_init (); gva_properties_init (); gva_ui_init (); gva_categories_init (&error); gva_error_handle (&error); gva_history_init (&error); gva_error_handle (&error); gva_nplayers_init (&error); gva_error_handle (&error); g_idle_add (idle_start, NULL); g_idle_add (tweak_css, NULL); gtk_main (); g_object_unref (application); return EXIT_SUCCESS; }
static gchar * audit_run_save_dialog (void) { const gchar *key = GVA_GCONF_ERROR_FILE_KEY; GtkFileChooser *file_chooser; GtkWidget *dialog; GConfClient *client; gchar *filename; gchar *folder; gchar *name; GError *error = NULL; client = gconf_client_get_default (); dialog = gtk_file_chooser_dialog_new ( _("Save As"), GTK_WINDOW (GVA_WIDGET_AUDIT_WINDOW), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); file_chooser = GTK_FILE_CHOOSER (dialog); /* Suggest the previous filename, if available. */ filename = gconf_client_get_string (client, key, &error); gva_error_handle (&error); if (filename != NULL && *filename != '\0') { name = g_path_get_basename (filename); folder = g_path_get_dirname (filename); } else { name = g_strdup ("rom-errors.txt"); folder = g_strdup (g_get_home_dir ()); } gtk_file_chooser_set_current_folder (file_chooser, folder); gtk_file_chooser_set_current_name (file_chooser, name); gtk_file_chooser_set_do_overwrite_confirmation (file_chooser, TRUE); g_free (name); g_free (folder); g_free (filename); filename = NULL; if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (file_chooser); gconf_client_set_string (client, key, filename, &error); gva_error_handle (&error); } gtk_widget_destroy (dialog); g_object_unref (client); return filename; }
static void play_back_add_input_file (const gchar *inpfile, const gchar *name, GvaGameStore *game_store) { GtkTreeIter iter; gchar *comment = NULL; gchar **result = NULL; gchar *inpname; gchar *sql; gint rows; struct stat st; time_t *time; GError *error = NULL; if (g_stat (inpfile, &st) != 0) { g_warning ("%s: %s", inpfile, g_strerror (errno)); return; } time = &st.st_ctime; /* Try to fetch the comment from the database. */ sql = g_strdup_printf ( "SELECT comment FROM playback WHERE " "name == '%s' AND inode == %" G_GINT64_FORMAT, name, (gint64) st.st_ino); if (gva_db_get_table (sql, &result, &rows, NULL, &error)) { if (rows > 0) comment = g_strdup (result[1]); g_strfreev (result); } gva_error_handle (&error); g_free (sql); /* If that fails, use the game title. */ if (comment == NULL) { sql = g_strdup_printf ( "SELECT description FROM available " "WHERE name == '%s'", name); if (gva_db_get_table (sql, &result, &rows, NULL, &error)) { if (rows > 0) comment = g_strdup (result[1]); g_strfreev (result); } gva_error_handle (&error); g_free (sql); } /* The game may not be available anymore. */ if (comment == NULL) { g_warning ("%s: Game '%s' not found", inpfile, name); return; } gtk_tree_store_append (GTK_TREE_STORE (game_store), &iter, NULL); gtk_tree_store_set ( GTK_TREE_STORE (game_store), &iter, GVA_GAME_STORE_COLUMN_NAME, name, GVA_GAME_STORE_COLUMN_COMMENT, comment, GVA_GAME_STORE_COLUMN_INODE, (gint64) st.st_ino, GVA_GAME_STORE_COLUMN_INPFILE, inpfile, GVA_GAME_STORE_COLUMN_TIME, time, -1); inpname = g_strdelimit (g_path_get_basename (inpfile), ".", '\0'); gva_game_store_index_insert (game_store, inpname, &iter); g_free (inpname); g_free (comment); }
static void wnck_window_initialize (WnckWindow *window) { const gchar *game; sqlite3_stmt *stmt; gchar *sql; gint errcode; gboolean success; GError *error = NULL; game = wnck_window_get_game (window); sql = g_strdup_printf (SQL_SELECT_GAME_WINDOW, game); success = gva_db_prepare (sql, &stmt, &error); gva_error_handle (&error); g_free (sql); if (!success) return; errcode = sqlite3_step (stmt); /* Restore the window's previous geometry. */ if (errcode == SQLITE_ROW) { gint x, y; gint width, height; gboolean maximized; x = sqlite3_column_int (stmt, COLUMN_X); y = sqlite3_column_int (stmt, COLUMN_Y); width = sqlite3_column_int (stmt, COLUMN_WIDTH); height = sqlite3_column_int (stmt, COLUMN_HEIGHT); maximized = sqlite3_column_int (stmt, COLUMN_MAXIMIZED); wnck_window_set_geometry ( window, WNCK_WINDOW_GRAVITY_CURRENT, WNCK_WINDOW_CHANGE_X | WNCK_WINDOW_CHANGE_Y | WNCK_WINDOW_CHANGE_WIDTH | WNCK_WINDOW_CHANGE_HEIGHT, x, y, width, height); if (maximized) wnck_window_maximize (window); else wnck_window_unmaximize (window); } /* Create a new record using the current geometry. */ else if (errcode == SQLITE_DONE) { gint x, y; gint width, height; gboolean maximized; maximized = wnck_window_is_maximized (window); wnck_window_get_geometry (window, &x, &y, &width, &height); sql = g_strdup_printf ( "INSERT INTO window VALUES " "('%s', %d, %d, %d, %d, %d)", game, x, y, width, height, maximized); gva_db_execute (sql, &error); gva_error_handle (&error); g_free (sql); } /* Something went wrong. */ else { gva_db_set_error (&error, 0, NULL); gva_error_handle (&error); } sqlite3_finalize (stmt); }
/** * gva_play_back_window_hide_cb: * @window: the "Recorded Games" window * * Handler for #GtkWidget::hide signals to the "Recorded Games" window. * * Saves the contents of the "Recorded Games" tree view to the game database. **/ void gva_play_back_window_hide_cb (GtkWindow *window) { GtkTreeView *view; GtkTreeModel *model; GtkTreeIter iter; sqlite3_stmt *stmt; gboolean valid; GError *error = NULL; view = GTK_TREE_VIEW (GVA_WIDGET_PLAY_BACK_TREE_VIEW); model = gtk_tree_view_get_model (view); valid = gtk_tree_model_get_iter_first (model, &iter); if (!gva_db_transaction_begin (&error)) goto exit; if (!gva_db_execute (SQL_DELETE_PLAY_BACK, &error)) goto rollback; if (!gva_db_prepare (SQL_INSERT_PLAY_BACK, &stmt, &error)) goto rollback; while (valid) { gchar *comment; gchar *name; gchar *utf8; gint64 inode; gint index; gint errcode; gtk_tree_model_get ( model, &iter, GVA_GAME_STORE_COLUMN_NAME, &name, GVA_GAME_STORE_COLUMN_INODE, &inode, GVA_GAME_STORE_COLUMN_COMMENT, &comment, -1); index = sqlite3_bind_parameter_index (stmt, "@name"); utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, &error); gva_error_handle (&error); if (utf8 == NULL) { g_free (name); g_free (comment); sqlite3_finalize (stmt); goto rollback; } errcode = sqlite3_bind_text (stmt, index, utf8, -1, g_free); if (errcode != SQLITE_OK) { g_free (name); g_free (comment); sqlite3_finalize (stmt); goto rollback; } index = sqlite3_bind_parameter_index (stmt, "@inode"); errcode = sqlite3_bind_int64 (stmt, index, inode); if (errcode != SQLITE_OK) { g_free (name); g_free (comment); sqlite3_finalize (stmt); goto rollback; } index = sqlite3_bind_parameter_index (stmt, "@comment"); utf8 = g_locale_to_utf8 (comment, -1, NULL, NULL, &error); gva_error_handle (&error); if (utf8 == NULL) { g_free (name); g_free (comment); sqlite3_finalize (stmt); goto rollback; } errcode = sqlite3_bind_text (stmt, index, utf8, -1, g_free); if (errcode != SQLITE_OK) { g_free (name); g_free (comment); sqlite3_finalize (stmt); goto rollback; } g_free (name); g_free (comment); if (sqlite3_step (stmt) != SQLITE_DONE) { gva_db_set_error (&error, 0, NULL); gva_error_handle (&error); sqlite3_finalize (stmt); goto rollback; } sqlite3_reset (stmt); sqlite3_clear_bindings (stmt); valid = gtk_tree_model_iter_next (model, &iter); } sqlite3_finalize (stmt); if (!gva_db_transaction_commit (&error)) goto rollback; goto exit; rollback: gva_error_handle (&error); gva_db_transaction_rollback (&error); exit: gva_error_handle (&error); }
static void rompath_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type) { static GtkWidget *dialog = NULL; gint response; if (dialog != NULL) return; /* Filter out events we don't care about. */ switch (event_type) { case G_FILE_MONITOR_EVENT_CHANGED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: case G_FILE_MONITOR_EVENT_DELETED: case G_FILE_MONITOR_EVENT_CREATED: break; default: return; } dialog = gtk_message_dialog_new_with_markup ( GTK_WINDOW (GVA_WIDGET_MAIN_WINDOW), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "<big><b>%s</b></big>", _("Changes detected in ROM files")); gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG (dialog), _("GNOME Video Arcade has detected changes in your " "ROM files and will need to audit them in order to " "update the game list. However the audit may take " "several minutes to complete. Would you like to " "perform the audit now?\n\nIf you skip the audit now, " "it will be performed automatically the next time you " "start GNOME Video Arcade.")); gtk_dialog_add_buttons ( GTK_DIALOG (dialog), _("_Skip Audit"), GTK_RESPONSE_NO, _("_Audit ROM Files"), GTK_RESPONSE_YES, NULL); response = gtk_dialog_run (GTK_DIALOG (dialog)); /* Don't destroy the dialog just yet. If the file monitor * trips again while we're analyzing ROMs, we want the NULL * check at the top of the function to evaluate TRUE so we * return immediately. */ gtk_widget_hide (dialog); if (response == GTK_RESPONSE_YES) { GError *error = NULL; gva_ui_lock (); gva_main_analyze_roms (&error); gva_error_handle (&error); gva_tree_view_update (&error); gva_error_handle (&error); gva_ui_unlock (); /* Present a helpful dialog if no ROMs were found. */ warn_if_no_roms (); } else { /* Don't bother the user again during this session. */ g_signal_handlers_disconnect_by_func ( monitor, rompath_changed_cb, NULL); } gtk_widget_destroy (dialog); dialog = NULL; }