/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2009 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "gth-script.h" #include "shortcuts.h" static void gth_script_dom_domizable_interface_init (DomDomizableInterface *iface); static void gth_script_gth_duplicable_interface_init (GthDuplicableInterface *iface); enum { PROP_0, PROP_ID, PROP_DISPLAY_NAME, PROP_COMMAND, PROP_VISIBLE, PROP_SHELL_SCRIPT, PROP_FOR_EACH_FILE, PROP_WAIT_COMMAND, PROP_ACCELERATOR }; struct _GthScriptPrivate { char *id; char *display_name; char *command; gboolean visible; gboolean shell_script; gboolean for_each_file; gboolean wait_command; char *accelerator; char *detailed_action; }; G_DEFINE_TYPE_WITH_CODE (GthScript, gth_script, G_TYPE_OBJECT, G_ADD_PRIVATE (GthScript) G_IMPLEMENT_INTERFACE (DOM_TYPE_DOMIZABLE, gth_script_dom_domizable_interface_init) G_IMPLEMENT_INTERFACE (GTH_TYPE_DUPLICABLE, gth_script_gth_duplicable_interface_init)) static DomElement* gth_script_real_create_element (DomDomizable *base, DomDocument *doc) { GthScript *self; DomElement *element; g_return_val_if_fail (DOM_IS_DOCUMENT (doc), NULL); self = GTH_SCRIPT (base); element = dom_document_create_element (doc, "script", "id", self->priv->id, "display-name", self->priv->display_name, "command", self->priv->command, "shell-script", (self->priv->shell_script ? "true" : "false"), "for-each-file", (self->priv->for_each_file ? "true" : "false"), "wait-command", (self->priv->wait_command ? "true" : "false"), NULL); if (! self->priv->visible) dom_element_set_attribute (element, "display", "none"); return element; } static void gth_script_real_load_from_element (DomDomizable *base, DomElement *element) { GthScript *self; g_return_if_fail (DOM_IS_ELEMENT (element)); self = GTH_SCRIPT (base); g_object_set (self, "id", dom_element_get_attribute (element, "id"), "display-name", dom_element_get_attribute (element, "display-name"), "command", dom_element_get_attribute (element, "command"), "visible", (g_strcmp0 (dom_element_get_attribute (element, "display"), "none") != 0), "shell-script", (g_strcmp0 (dom_element_get_attribute (element, "shell-script"), "true") == 0), "for-each-file", (g_strcmp0 (dom_element_get_attribute (element, "for-each-file"), "true") == 0), "wait-command", (g_strcmp0 (dom_element_get_attribute (element, "wait-command"), "true") == 0), "accelerator", "", NULL); } static GObject * gth_script_real_duplicate (GthDuplicable *duplicable) { GthScript *script = GTH_SCRIPT (duplicable); GthScript *new_script; new_script = gth_script_new (); g_object_set (new_script, "id", script->priv->id, "display-name", script->priv->display_name, "command", script->priv->command, "visible", script->priv->visible, "shell-script", script->priv->shell_script, "for-each-file", script->priv->for_each_file, "wait-command", script->priv->wait_command, "accelerator", script->priv->accelerator, NULL); return (GObject *) new_script; } static void gth_script_finalize (GObject *base) { GthScript *self; self = GTH_SCRIPT (base); g_free (self->priv->id); g_free (self->priv->display_name); g_free (self->priv->command); g_free (self->priv->accelerator); g_free (self->priv->detailed_action); G_OBJECT_CLASS (gth_script_parent_class)->finalize (base); } static char * detailed_action_from_id (char *id) { GVariant *param; char *detailed_action; param = g_variant_new_string (id); detailed_action = g_action_print_detailed_name ("exec-script", param); g_variant_unref (param); return detailed_action; } static void gth_script_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GthScript *self; self = GTH_SCRIPT (object); switch (property_id) { case PROP_ID: g_free (self->priv->id); self->priv->id = g_value_dup_string (value); if (self->priv->id == NULL) self->priv->id = g_strdup (""); g_free (self->priv->detailed_action); self->priv->detailed_action = detailed_action_from_id (self->priv->id); break; case PROP_DISPLAY_NAME: g_free (self->priv->display_name); self->priv->display_name = g_value_dup_string (value); if (self->priv->display_name == NULL) self->priv->display_name = g_strdup (""); break; case PROP_COMMAND: g_free (self->priv->command); self->priv->command = g_value_dup_string (value); if (self->priv->command == NULL) self->priv->command = g_strdup (""); break; case PROP_VISIBLE: self->priv->visible = g_value_get_boolean (value); break; case PROP_SHELL_SCRIPT: self->priv->shell_script = g_value_get_boolean (value); break; case PROP_FOR_EACH_FILE: self->priv->for_each_file = g_value_get_boolean (value); break; case PROP_WAIT_COMMAND: self->priv->wait_command = g_value_get_boolean (value); break; case PROP_ACCELERATOR: g_free (self->priv->accelerator); self->priv->accelerator = g_value_dup_string (value); break; default: break; } } static void gth_script_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GthScript *self; self = GTH_SCRIPT (object); switch (property_id) { case PROP_ID: g_value_set_string (value, self->priv->id); break; case PROP_DISPLAY_NAME: g_value_set_string (value, self->priv->display_name); break; case PROP_COMMAND: g_value_set_string (value, self->priv->command); break; case PROP_VISIBLE: g_value_set_boolean (value, self->priv->visible); break; case PROP_SHELL_SCRIPT: g_value_set_boolean (value, self->priv->shell_script); break; case PROP_FOR_EACH_FILE: g_value_set_boolean (value, self->priv->for_each_file); break; case PROP_WAIT_COMMAND: g_value_set_boolean (value, self->priv->wait_command); break; case PROP_ACCELERATOR: g_value_set_string (value, self->priv->accelerator); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void gth_script_class_init (GthScriptClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = gth_script_set_property; object_class->get_property = gth_script_get_property; object_class->finalize = gth_script_finalize; /* properties */ g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "ID", "The object id", NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DISPLAY_NAME, g_param_spec_string ("display-name", "Display name", "The user visible name", NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_COMMAND, g_param_spec_string ("command", "Command", "The command to execute", NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_VISIBLE, g_param_spec_boolean ("visible", "Visible", "Whether this script should be visible in the script list", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SHELL_SCRIPT, g_param_spec_boolean ("shell-script", "Shell Script", "Whether to execute the command inside a terminal (with sh)", TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_FOR_EACH_FILE, g_param_spec_boolean ("for-each-file", "Each File", "Whether to execute the command on file at a time", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_WAIT_COMMAND, g_param_spec_boolean ("wait-command", "Wait command", "Whether to wait command to finish", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_ACCELERATOR, g_param_spec_string ("accelerator", "Accelerator", "The keyboard shortcut to activate the script", "", G_PARAM_READWRITE)); } static void gth_script_dom_domizable_interface_init (DomDomizableInterface *iface) { iface->create_element = gth_script_real_create_element; iface->load_from_element = gth_script_real_load_from_element; } static void gth_script_gth_duplicable_interface_init (GthDuplicableInterface *iface) { iface->duplicate = gth_script_real_duplicate; } static void gth_script_init (GthScript *self) { self->priv = gth_script_get_instance_private (self); self->priv->id = NULL; self->priv->display_name = NULL; self->priv->command = NULL; self->priv->visible = FALSE; self->priv->shell_script = FALSE; self->priv->for_each_file = FALSE; self->priv->wait_command = FALSE; self->priv->accelerator = NULL; self->priv->detailed_action = NULL; } GthScript* gth_script_new (void) { GthScript *script; char *id; id = _g_str_random (ID_LENGTH); script = (GthScript *) g_object_new (GTH_TYPE_SCRIPT, "id", id, NULL); g_free (id); return script; } const char * gth_script_get_id (GthScript *script) { return script->priv->id; } const char * gth_script_get_display_name (GthScript *script) { return script->priv->display_name; } const char * gth_script_get_command (GthScript *script) { return script->priv->command; } const char * gth_script_get_detailed_action (GthScript *self) { return self->priv->detailed_action; } gboolean gth_script_is_visible (GthScript *script) { return script->priv->visible; } gboolean gth_script_is_shell_script (GthScript *script) { return script->priv->shell_script; } gboolean gth_script_for_each_file (GthScript *script) { return script->priv->for_each_file; } gboolean gth_script_wait_command (GthScript *script) { return script->priv->wait_command; } /* -- gth_script_get_requested_attributes -- */ static gboolean collect_attributes_cb (gunichar parent_code, gunichar code, char **args, gpointer user_data) { GString *result = user_data; if (code == GTH_SCRIPT_CODE_FILE_ATTRIBUTE) { if (result->str[0] != 0) g_string_append_c (result, ','); g_string_append (result, args[0]); } return FALSE; } char * gth_script_get_requested_attributes (GthScript *script) { GString *result; char *attributes; result = g_string_new (""); _g_template_for_each_token (script->priv->command, TEMPLATE_FLAGS_NO_ENUMERATOR, collect_attributes_cb, result); if (result->str[0] == 0) { attributes = NULL; g_string_free (result, TRUE); } else attributes = g_string_free (result, FALSE); return attributes; } /* -- gth_script_get_command_line_async -- */ typedef struct { GList *file_list; GError *error; GList *asked_values; GList *last_asked_value; } EvalData; typedef struct { EvalData eval_data; GtkWindow *parent; GthScript *script; GtkBuilder *builder; GthThumbLoader *thumb_loader; GtkCallback dialog_callback; gpointer user_data; } CommandLineData; typedef char * (*GetFileDataValueFunc) (GthFileData *file_data); typedef struct { int n_param; char *prompt; char *default_value; char *value; GtkWidget *entry; } AskedValue; static AskedValue * asked_value_new (int n_param) { AskedValue *asked_value; asked_value = g_new (AskedValue, 1); asked_value->n_param = n_param; asked_value->prompt = g_strdup (_("Enter a value:"));; asked_value->default_value = NULL; asked_value->value = NULL; asked_value->entry = NULL; return asked_value; } static void asked_value_free (AskedValue *asked_value) { g_free (asked_value->prompt); g_free (asked_value->default_value); g_free (asked_value->value); g_free (asked_value); } static void command_line_data_free (CommandLineData *command_data) { _g_object_unref (command_data->thumb_loader); _g_object_unref (command_data->builder); g_list_free_full (command_data->eval_data.asked_values, (GDestroyNotify) asked_value_free); _g_object_list_unref (command_data->eval_data.file_list); g_object_unref (command_data->script); g_free (command_data); } static void _append_file_list (GString *str, GList *file_list, GetFileDataValueFunc func, gboolean quote_value) { GList *scan; for (scan = file_list; scan; scan = scan->next) { GthFileData *file_data = scan->data; char *value; char *quoted; value = func (file_data); quoted = quote_value ? g_shell_quote (value) : g_strdup (value); g_string_append (str, quoted); if (scan->next != NULL) g_string_append_c (str, ' '); g_free (quoted); g_free (value); } } static char * get_uri_func (GthFileData *file_data) { return g_file_get_uri (file_data->file); } static char * get_filename_func (GthFileData *file_data) { return g_file_get_path (file_data->file); } static char * get_basename_func (GthFileData *file_data) { return g_file_get_basename (file_data->file); } static char * get_basename_wo_ext_func (GthFileData *file_data) { char *basename; char *basename_wo_ext; basename = g_file_get_basename (file_data->file); basename_wo_ext = _g_path_remove_extension (basename); g_free (basename); return basename_wo_ext; } static char * get_ext_func (GthFileData *file_data) { char *path; char *ext; path = g_file_get_path (file_data->file); ext = g_strdup (_g_path_get_extension (path)); g_free (path); return ext; } static char * get_parent_func (GthFileData *file_data) { GFile *parent; char *path; parent = g_file_get_parent (file_data->file); path = g_file_get_path (parent); g_object_unref (parent); return path; } static char * _get_timestamp (const char *format, gboolean quote_value) { GDateTime *now; char *str; now = g_date_time_new_now_local (); str = g_date_time_format (now, (format != NULL) ? format : DEFAULT_STRFTIME_FORMAT); if (quote_value) { char *tmp = str; str = g_shell_quote (tmp); g_free (tmp); } g_date_time_unref (now); return str; } static void _append_attribute_list (GString *str, GList *file_list, char *attribute, gboolean quote_value) { gboolean first_value; GList *scan; if (attribute == NULL) return; first_value = TRUE; for (scan = file_list; scan; scan = scan->next) { GthFileData *file_data = scan->data; char *value; char *quoted; value = gth_file_data_get_attribute_as_string (file_data, attribute); if (value == NULL) continue; if (! first_value) { g_string_append_c (str, ' '); first_value = FALSE; } if (value != NULL) { char *tmp = _g_utf8_replace_pattern (value, "[\r\n]", " "); g_free (value); value = tmp; } quoted = quote_value ? g_shell_quote (value) : g_strdup (value); g_string_append (str, quoted); g_free (quoted); g_free (value); } } static gboolean eval_template_cb (TemplateFlags flags, gunichar parent_code, gunichar code, char **args, GString *result, gpointer user_data) { EvalData *eval_data = user_data; gboolean preview; gboolean quote_values; gboolean highlight; char *text; if (parent_code == GTH_SCRIPT_CODE_TIMESTAMP) { /* strftime code, return the code itself. */ _g_string_append_template_code (result, code, args); return FALSE; } preview = (flags & TEMPLATE_FLAGS_PREVIEW) != 0; quote_values = ((flags & TEMPLATE_FLAGS_PARTIAL) == 0) && (parent_code == 0); highlight = preview && (code != 0) && (parent_code == 0); text = NULL; if (highlight) g_string_append (result, ""); switch (code) { case GTH_SCRIPT_CODE_URI: /* File URI */ _append_file_list (result, eval_data->file_list, get_uri_func, quote_values); break; case GTH_SCRIPT_CODE_PATH: /* File path */ _append_file_list (result, eval_data->file_list, get_filename_func, quote_values); break; case GTH_SCRIPT_CODE_BASENAME: /* File basename */ _append_file_list (result, eval_data->file_list, get_basename_func, quote_values); break; case GTH_SCRIPT_CODE_BASENAME_NO_EXTENSION: /* File basename, no extension */ _append_file_list (result, eval_data->file_list, get_basename_wo_ext_func, quote_values); break; case GTH_SCRIPT_CODE_EXTENSION: /* File extension */ _append_file_list (result, eval_data->file_list, get_ext_func, quote_values); break; case GTH_SCRIPT_CODE_PARENT_PATH: /* Parent path */ _append_file_list (result, eval_data->file_list, get_parent_func, quote_values); break; case GTH_SCRIPT_CODE_TIMESTAMP: /* Timestamp */ text = _get_timestamp (args[0], quote_values); break; case GTH_SCRIPT_CODE_ASK_VALUE: /* Ask value */ if (preview) { if ((args[0] != NULL) && ! _g_utf8_all_spaces (args[1])) g_string_append (result, args[1]); else if (! _g_utf8_all_spaces (args[0])) _g_string_append_markup_escaped (result, "{ %s }", args[0]); else g_string_append_unichar (result, code); } else if (eval_data->last_asked_value != NULL) { AskedValue *asked_value; asked_value = eval_data->last_asked_value->data; text = quote_values ? g_shell_quote (asked_value->value) : g_strdup (asked_value->value); eval_data->last_asked_value = eval_data->last_asked_value->next; } break; case GTH_SCRIPT_CODE_FILE_ATTRIBUTE: /* File attribute */ if (preview) g_string_append_printf (result, "{ %s }", args[0]); else _append_attribute_list (result, eval_data->file_list, args[0], quote_values); break; case GTH_SCRIPT_CODE_QUOTE: /* Quote text. */ if (args[0] != NULL) text = g_shell_quote (args[0]); break; default: /* Code not recognized, return the code itself. */ _g_string_append_template_code (result, code, args); break; } if (text != NULL) { g_string_append (result, text); g_free (text); } if (highlight) g_string_append (result, ""); return (eval_data->error != NULL); } static void _gth_script_get_command_line (GTask *task) { CommandLineData *command_data; char *result; command_data = g_task_get_task_data (task); command_data->eval_data.last_asked_value = command_data->eval_data.asked_values; command_data->eval_data.error = NULL; result = _g_template_eval (command_data->script->priv->command, TEMPLATE_FLAGS_NO_ENUMERATOR, eval_template_cb, &command_data->eval_data); if (command_data->eval_data.error != NULL) { g_free (result); g_task_return_error (task, command_data->eval_data.error); } else g_task_return_pointer (task, result, g_free); } static void ask_values_dialog_response_cb (GtkDialog *dialog, int response_id, gpointer user_data) { GTask *task = user_data; CommandLineData *command_data; command_data = g_task_get_task_data (task); if (command_data->dialog_callback) command_data->dialog_callback (NULL, command_data->user_data); if (response_id != GTK_RESPONSE_OK) { GError *error = NULL; if (response_id == GTK_RESPONSE_NO) error = g_error_new_literal (GTH_TASK_ERROR, GTH_TASK_ERROR_SKIP_TO_NEXT_FILE, ""); else error = g_error_new_literal (GTH_TASK_ERROR, GTH_TASK_ERROR_CANCELLED, ""); g_task_return_error (task, error); } else { GList *scan; for (scan = command_data->eval_data.asked_values; scan; scan = scan->next) { AskedValue *asked_value = scan->data; g_free (asked_value->value); asked_value->value = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (asked_value->entry)), -1, G_NORMALIZE_NFC); } _gth_script_get_command_line (task); } gtk_widget_destroy (GTK_WIDGET (dialog)); } static void thumb_loader_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { CommandLineData *command_data = user_data; cairo_surface_t *image; if (gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object), result, &image, NULL)) { gtk_image_set_from_surface (GTK_IMAGE (_gtk_builder_get_widget (command_data->builder, "request_image")), image); cairo_surface_destroy (image); } g_object_unref (command_data->builder); } /* -- gth_script_get_command_line_async -- */ typedef struct { CommandLineData *command_data; int n; } CollectValuesData; static gboolean collect_asked_values_cb (gunichar parent_code, gunichar code, char **args, gpointer user_data) { CollectValuesData *collect_data = user_data; CommandLineData *command_data = collect_data->command_data; AskedValue *asked_value; if (code != GTH_SCRIPT_CODE_ASK_VALUE) return FALSE; asked_value = asked_value_new (collect_data->n++); asked_value->prompt = _g_utf8_strip (args[0]); asked_value->default_value = _g_utf8_strip (args[1]); command_data->eval_data.asked_values = g_list_prepend (command_data->eval_data.asked_values, asked_value); return FALSE; } void gth_script_get_command_line_async (GthScript *script, GtkWindow *parent, GList *file_list /* GthFileData */, gboolean can_skip, GCancellable *cancellable, GtkCallback dialog_callback, GAsyncReadyCallback callback, gpointer user_data) { CommandLineData *command_data; GTask *task; CollectValuesData collect_data; GthFileData *file_data; GtkWidget *dialog; command_data = g_new0 (CommandLineData, 1); command_data->script = g_object_ref (script); command_data->parent = parent; command_data->dialog_callback = dialog_callback; command_data->user_data = user_data; command_data->eval_data.file_list = _g_object_list_ref (file_list); command_data->eval_data.error = NULL; task = g_task_new (script, cancellable, callback, user_data); g_task_set_task_data (task, command_data, (GDestroyNotify) command_line_data_free); /* collect the values to ask to the user */ collect_data.command_data = command_data; collect_data.n = 0; _g_template_for_each_token (script->priv->command, TEMPLATE_FLAGS_NO_ENUMERATOR, collect_asked_values_cb, &collect_data); if (command_data->eval_data.asked_values == NULL) { /* No values to ask to the user. */ _gth_script_get_command_line (task); return; } command_data->eval_data.asked_values = g_list_reverse (command_data->eval_data.asked_values); command_data->builder = gtk_builder_new_from_resource ("/org/x/Pix/list_tools/data/ui/ask-values.ui"); dialog = g_object_new (GTK_TYPE_DIALOG, "title", "", "transient-for", GTK_WINDOW (command_data->parent), "modal", FALSE, "destroy-with-parent", FALSE, "use-header-bar", _gtk_settings_get_dialogs_use_header (), "resizable", TRUE, NULL); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), _gtk_builder_get_widget (command_data->builder, "dialog_content")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, _GTK_LABEL_EXECUTE, GTK_RESPONSE_OK, ! can_skip ? NULL : (gth_script_for_each_file (command_data->script) ? _("_Skip") : NULL), GTK_RESPONSE_NO, NULL); _gtk_dialog_add_class_to_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_STYLE_CLASS_SUGGESTED_ACTION); gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (command_data->builder, "title_label")), gth_script_get_display_name (command_data->script)); file_data = (GthFileData *) command_data->eval_data.file_list->data; gtk_label_set_text (GTK_LABEL (_gtk_builder_get_widget (command_data->builder, "filename_label")), g_file_info_get_display_name (file_data->info)); { GtkWidget *prompts = _gtk_builder_get_widget (command_data->builder, "prompts"); GList *scan; for (scan = command_data->eval_data.asked_values; scan; scan = scan->next) { AskedValue *asked_value = scan->data; GtkWidget *label; GtkWidget *entry; GtkWidget *box; label = gtk_label_new (asked_value->prompt); gtk_label_set_xalign (GTK_LABEL (label), 0.0); entry = gtk_entry_new (); if (asked_value->default_value != NULL) gtk_entry_set_text (GTK_ENTRY (entry), asked_value->default_value); gtk_widget_set_size_request (entry, 300, -1); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (box), label, TRUE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), entry, TRUE, FALSE, 0); gtk_widget_show_all (box); gtk_box_pack_start (GTK_BOX (prompts), box, FALSE, FALSE, 0); asked_value->entry = entry; } } g_object_ref (command_data->builder); command_data->thumb_loader = gth_thumb_loader_new (128); gth_thumb_loader_load (command_data->thumb_loader, file_data, NULL, thumb_loader_ready_cb, command_data); g_signal_connect (dialog, "response", G_CALLBACK (ask_values_dialog_response_cb), task); gtk_widget_show (dialog); if (command_data->dialog_callback) command_data->dialog_callback (dialog, command_data->user_data); } char * gth_script_get_command_line_finish (GthScript *script, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, script), NULL); return g_task_propagate_pointer (G_TASK (result), error); } const char * gth_script_get_accelerator (GthScript *self) { g_return_val_if_fail (GTH_IS_SCRIPT (self), NULL); return self->priv->accelerator; } GthShortcut * gth_script_create_shortcut (GthScript *self) { GthShortcut *shortcut; shortcut = gth_shortcut_new ("exec-script", g_variant_new_string (gth_script_get_id (self))); shortcut->description = g_strdup (self->priv->display_name); shortcut->context = GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER; shortcut->category = GTH_SHORTCUT_CATEGORY_LIST_TOOLS; gth_shortcut_set_accelerator (shortcut, self->priv->accelerator); shortcut->default_accelerator = g_strdup (""); return shortcut; } /* -- gth_script_get_preview -- */ #define PREVIEW_URI "file:///home/user/images/filename.jpeg" char * gth_script_get_preview (const char *template, TemplateFlags flags) { EvalData preview_data; char *result; preview_data.file_list = g_list_append (NULL, gth_file_data_new_for_uri (PREVIEW_URI, NULL)); preview_data.error = NULL; preview_data.asked_values = NULL; preview_data.last_asked_value = NULL; result = _g_template_eval (template, flags | TEMPLATE_FLAGS_NO_ENUMERATOR | TEMPLATE_FLAGS_PREVIEW, eval_template_cb, &preview_data); _g_object_list_unref (preview_data.file_list); return result; }