📄 gtk.c
字号:
g_static_mutex_unlock (&extractProgressM); if (stop) goto end; } end: if (timer) g_timer_destroy (timer); g_list_free (files); g_list_free (indices); g_static_mutex_lock (&extractProgressM); extractProgress.failed = failed; extractProgress.status = STATUS_DONE; g_static_mutex_unlock (&extractProgressM); return NULL;}static gbooleanwatch_extract_thread (gpointer user_data){ ExtractProgress ep; g_static_mutex_lock (&extractProgressM); memcpy (&ep, &extractProgress, sizeof (ExtractProgress)); g_static_mutex_unlock (&extractProgressM); if (ep.status != lastKnownProgress.status) { switch (ep.status) { case STATUS_INIT: break; case STATUS_MKDIR: gtk_progress_bar_set_text (GTK_PROGRESS_BAR (W(progress)), _("Creating folders...")); break; case STATUS_EXTRACT: gtk_progress_bar_set_text (GTK_PROGRESS_BAR (W(progress)), _("0%")); break; case STATUS_DONE: break; default: break; }; } if (ep.current != lastKnownProgress.current || ep.max != lastKnownProgress.max) { if (ep.max == 0) gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (W(progress)), 0.0); else gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (W(progress)), (gdouble) ep.current / (gdouble) ep.max); if (ep.status == STATUS_EXTRACT && ep.file) { char *tmp, *basename; basename = g_path_get_basename (ep.file); tmp = str_to_utf8 (basename, NULL); g_free (basename); basename = g_strdup_printf ("%.1f%%: %s", ((gdouble) ep.current / (gdouble) ep.max) * 100, tmp); g_free (tmp); gtk_progress_bar_set_text (GTK_PROGRESS_BAR (W(progress)), basename); g_free (basename); } } memcpy (&lastKnownProgress, &ep, sizeof (ExtractProgress)); return TRUE;}static gbooleanwatch_extract_thread_stop (gpointer user_data){ guint watcher; gboolean result = TRUE; g_static_mutex_lock (&extractProgressM); if (extractProgress.status == STATUS_DONE) { char *msg; watcher = GPOINTER_TO_INT (user_data); gtk_timeout_remove (watcher); result = FALSE; if (extractProgress.failed == 0) msg = g_strdup_printf (_("%ld files extracted."), extractProgress.current); else msg = g_strdup_printf (_("%ld files extracted (%ld failed)."), extractProgress.current, extractProgress.failed); set_status (msg); g_free (msg); gtk_widget_hide (W(progressBox)); gtk_widget_set_sensitive (W(open), TRUE); gtk_widget_set_sensitive (W(extract), TRUE); } g_static_mutex_unlock (&extractProgressM); if (!result) { g_thread_join (extractProgress.thread); memset (&lastKnownProgress, 0, sizeof (ExtractProgress)); } return result;}static voidextract_files (const char *savedir, GList *files, GList *indices){ GError *err = NULL; GList *args; guint watcher; /* Run extraction as background thread */ args = g_list_append (NULL, (gpointer) savedir); args = g_list_append (args, files); args = g_list_append (args, indices); memset (&extractProgress, 0, sizeof (ExtractProgress)); memset (&lastKnownProgress, 0, sizeof (ExtractProgress)); extractProgress.thread = g_thread_create (extract_thread, args, TRUE, &err); if (!extractProgress.thread) { show_error (_("A system error occured while extracting (unable to create thread).\n%s"), err->message); g_error_free (err); g_list_free (args); memset (&extractProgress, 0, sizeof (ExtractProgress)); return; } /* Update GUI in main thread */ set_status (_("Extracting files...")); gtk_widget_set_sensitive (W(open), FALSE); gtk_widget_set_sensitive (W(extract), FALSE); gtk_widget_set_sensitive (W(stop), TRUE); gtk_widget_show (W(progressBox)); watcher = gtk_timeout_add (100, watch_extract_thread, NULL); gtk_timeout_add (10, watch_extract_thread_stop, GINT_TO_POINTER (watcher)); return;}static voidsort_by_anything (GtkTreeViewColumn *column, gint sort_column, GtkSortType default_sort){ GtkTreeView *view = GTK_TREE_VIEW (W(filelist)); GtkTreeModel *model = gtk_tree_view_get_model (view); GList *list, *cols = gtk_tree_view_get_columns (view); gint sort_id; GtkSortType sort_type; for (list = cols; list; list = list->next) { GtkTreeViewColumn *col = (GtkTreeViewColumn *) list->data; gtk_tree_view_column_set_sort_indicator (col, FALSE); } g_list_free (cols); gtk_tree_view_column_set_sort_indicator (column, TRUE); gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), &sort_id, &sort_type); if (sort_id == sort_column) { sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING; gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), sort_column, sort_type); gtk_tree_view_column_set_sort_order (column, sort_type); } else { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), sort_column, default_sort); gtk_tree_view_column_set_sort_order (column, default_sort); }}static voidsort_by_column (GtkTreeViewColumn *col, gpointer column){ sort_by_anything (col, GPOINTER_TO_INT (column), GTK_SORT_ASCENDING);}/*********************** * Callbacks ***********************/voidopen_cb (){ const char *fname = NULL; gtk_file_selection_show_fileop_buttons (GTK_FILE_SELECTION (opensel)); if (gtk_dialog_run (GTK_DIALOG (opensel)) == GTK_RESPONSE_OK) fname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (opensel)); gtk_widget_hide (opensel); if (fname) open_grf_file (fname);}voidextract_cb (){ GtkTreeSelection *selection; GList *list, *l; GtkTreePath *path; GtkTreeIter iter; char *fname, *display; unsigned long size, index; void *data; if (!grf) return; if (!savesel) { gchar *tmp, *dir; /* We want the extract file selector to have the same working directory as the open one */ savesel = gtk_file_selection_new (_("Extract & save file")); dirsel = gtk_file_selection_new (_("Extract & save to folder")); gtk_widget_set_sensitive (GTK_FILE_SELECTION (dirsel)->file_list, FALSE); tmp = g_path_get_dirname (filename->str); dir = g_strdup_printf ("%s%c", tmp, G_DIR_SEPARATOR); gtk_file_selection_complete (GTK_FILE_SELECTION (savesel), dir); gtk_file_selection_complete (GTK_FILE_SELECTION (dirsel), dir); g_free (dir); g_free (tmp); } selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (W(filelist))); list = gtk_tree_selection_get_selected_rows (selection, NULL); if (list && !list->next) { /* 1 file selected */ GtkTreePath *path; const gchar *savename = NULL; gchar *basename; GrfError err; /* Get file information */ path = (GtkTreePath *) list->data; gtk_tree_model_get_iter (filelist, &iter, path); gtk_tree_model_get (filelist, &iter, INDEX_COL, &index, DISPLAY_COL, &display, -1); /* Setup save dialog */ basename = strrchr (display, '\\'); if (basename) gtk_file_selection_set_filename (GTK_FILE_SELECTION (savesel), basename + 1); if (gtk_dialog_run (GTK_DIALOG (savesel)) == GTK_RESPONSE_OK) savename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (savesel)); gtk_widget_hide (savesel); if (!savename) { g_free (display); goto end; } /* Extract */ if (grf_index_extract (grf, index, savename, &err)) { char *msg; msg = g_strdup_printf (_("%s saved"), basename + 1); set_status (msg); g_free (msg); } else { show_error (_("Unable to extract %s:\n%s"), basename + 1, grf_strerror (err)); } g_free (display); } else { /* More than 1 file selected, or nothing selected */ const gchar *savedir = NULL; GList *files = NULL, *indices = NULL; if (gtk_dialog_run (GTK_DIALOG (dirsel)) == GTK_RESPONSE_OK) savedir = gtk_file_selection_get_filename (GTK_FILE_SELECTION (dirsel)); gtk_widget_hide (dirsel); if (!savedir) goto end; if (!g_file_test (savedir, G_FILE_TEST_IS_DIR)) { if (mkdir (savedir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { show_error (_("Unable to create a new folder: %s"), g_strerror (errno)); goto end; } } if (list) { /* More than 1 file is selected */ for (l = list; l; l = l->next) { path = (GtkTreePath *) l->data; gtk_tree_model_get_iter (filelist, &iter, path); gtk_tree_model_get (filelist, &iter, INDEX_COL, &index, -1); files = g_list_prepend (files, grf->files[index].name); indices = g_list_prepend (indices, GINT_TO_POINTER (index)); } list = g_list_reverse (list); } else if (gtk_tree_model_get_iter_first (filelist, &iter)) { /* Nothing is selected */ do { gtk_tree_model_get (filelist, &iter, INDEX_COL, &index, -1); files = g_list_prepend (files, grf->files[index].name); indices = g_list_prepend (indices, GINT_TO_POINTER (index)); } while (gtk_tree_model_iter_next (filelist, &iter)); list = g_list_reverse (list); } extract_files (savedir, files, indices); } end: g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); g_list_free (list);}voidpreview_toggled_cb (){ gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (W(preview_toggle))); if (active) gtk_widget_show (W(preview_pane)); else gtk_widget_hide (W(preview_pane));}voidfilelist_activated_cb (GtkTreeView *tree, GtkTreePath *path){ extract_cb ();}voidfill_filelist_cb (){ gchar *msg; unsigned long i; if (!grf) return; set_status (_("Searching...")); while (gtk_events_pending ()) gtk_main_iteration (); i = fill_filelist (); msg = g_strdup_printf (_("%ld files found"), i); set_status (msg); g_free (msg);}static voidfilelist_selection_changed_cb (GtkTreeSelection *selection, GtkTreeView *tree){ GList *list, *l; char *title, *tmp; GtkTreeIter iter; GtkTreePath *this; unsigned long index; guint len; if (!grf || filling) return; list = gtk_tree_selection_get_selected_rows (selection, NULL); len = g_list_length (list); if (list && !list->next) { /* 1 file selected */ char *fname, *display; this = (GtkTreePath *) list->data; if (current_selection) { if (gtk_tree_path_compare (current_selection, this) == 0) /* The user selected an already selected row; don't do anything */ goto end; gtk_tree_path_free (current_selection); } current_selection = gtk_tree_path_copy (this); gtk_tree_model_get_iter (filelist, &iter, this); gtk_tree_model_get (filelist, &iter, INDEX_COL, &index, DISPLAY_COL, &display, -1); tmp = g_path_get_basename (filename->str); title = g_strdup_printf (_("%s: %ld files - file #%ld selected"), tmp, grf->nfiles, index + 1); set_status (title); g_free (tmp); g_free (title); preview_file (display, grf->files[index].name); g_free (display); } else if (!list) { /* no files selected */ tmp = g_path_get_basename (filename->str); title = g_strdup_printf (_("%s: %ld files"), tmp, grf->nfiles); set_status (title); g_free (tmp); g_free (title); } else { /* >1 files selected */ char *sizestr; unsigned long size = 0; for (l = list; l; l = l->next) { this = (GtkTreePath *) list->data; gtk_tree_model_get_iter (filelist, &iter, this); gtk_tree_model_get (filelist, &iter, INDEX_COL, &index, -1); size += grf->files[index].real_len; } sizestr = friendly_size_name (size); tmp = g_path_get_basename (filename->str); title = g_strdup_printf (_("%s: %ld files - %d files selected (%s)"), tmp, grf->nfiles, len, sizestr); set_status (title); g_free (tmp); g_free (title); g_free (sizestr); } end: g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); g_list_free (list);}voidstop_cb (){ g_static_mutex_lock (&extractProgressM); if (extractProgress.thread) extractProgress.stop = TRUE; g_static_mutex_unlock (&extractProgressM); gtk_widget_set_sensitive (W(stop), FALSE);}intmain (int argc, char *argv[]){ GtkTreeView *tree; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkTooltips *tips; g_thread_init (NULL); gtk_init (&argc, &argv); memset (&extractProgress, 0, sizeof (ExtractProgress)); g_static_mutex_init (&extractProgressM); xml = load_glade ("grftool.glade"); opensel = gtk_file_selection_new (_("Open GRF archive")); filename = g_string_new (""); /* Manually set tooltips (libglade bug??) */ tips = gtk_tooltips_new (); gtk_tooltips_set_tip (tips, W(open), _("Open GRF file"), NULL); gtk_tooltips_set_tip (tips, W(extract), _("Extract all files or selected files"), NULL); gtk_tooltips_set_tip (tips, W(preview_toggle), _("Enable/disable preview of files"), NULL); /* Setup the file list model and widget */ filelist = GTK_TREE_MODEL (gtk_list_store_new (N_COLS, G_TYPE_ULONG, /* index */ G_TYPE_STRING, /* display name (filename converted to UTF-8) */ G_TYPE_STRING, /* type */ G_TYPE_ULONG, /* decompressed file size */ G_TYPE_STRING /* file size string */ )); tree = GTK_TREE_VIEW (W(filelist)); g_object_set (tree, "model", filelist, "rules-hint", TRUE, NULL); selection = gtk_tree_view_get_selection (tree); gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (filelist_selection_changed_cb), tree); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (filelist), (GtkTreeIterCompareFunc) gtk_false, NULL, NULL); column = gtk_tree_view_column_new_with_attributes ( _("Filename"), gtk_cell_renderer_text_new (), "text", DISPLAY_COL, NULL); g_object_set (column, "reorderable", TRUE, "resizable", TRUE, "clickable", TRUE, NULL); gtk_tree_view_append_column (tree, column); g_signal_connect (G_OBJECT (column), "clicked", G_CALLBACK (sort_by_column), GINT_TO_POINTER (DISPLAY_COL)); column = gtk_tree_view_column_new_with_attributes ( _("Type"), gtk_cell_renderer_text_new (), "text", TYPE_COL, NULL); g_object_set (column, "reorderable", TRUE, "resizable", TRUE, "clickable", TRUE, NULL); gtk_tree_view_append_column (tree, column); g_signal_connect (G_OBJECT (column), "clicked", G_CALLBACK (sort_by_column), GINT_TO_POINTER (TYPE_COL)); column = gtk_tree_view_column_new_with_attributes ( _("Size"), gtk_cell_renderer_text_new (), "text", SIZE_DISPLAY_COL, NULL); g_object_set (column, "reorderable", TRUE, "resizable", TRUE, "clickable", TRUE, NULL); gtk_tree_view_append_column (tree, column); g_signal_connect (G_OBJECT (column), "clicked", G_CALLBACK (sort_by_column), GINT_TO_POINTER (SIZE_COL)); gtk_tree_view_set_headers_visible (tree, TRUE); gtk_widget_modify_bg (W(viewport1), GTK_STATE_NORMAL, &(gtk_widget_get_style (W(viewport1))->white)); /* Show the GUI */ set_status (_("Click Open to open a GRF archive.")); busy_cursor = gdk_cursor_new (GDK_WATCH); if (argv[1]) gtk_idle_add (idle_open, argv[1]); gtk_widget_realize (W(main)); gtk_widget_show (W(main)); gtk_main (); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -