File: script-fu-lib.c

package info (click to toggle)
gimp 3.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 222,880 kB
  • sloc: ansic: 870,914; python: 10,965; lisp: 10,857; cpp: 7,355; perl: 4,536; sh: 1,753; xml: 972; yacc: 609; lex: 348; javascript: 150; makefile: 42
file content (389 lines) | stat: -rw-r--r-- 10,696 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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 3 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 <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#include <libgimp/gimp.h>

#include "script-fu-lib.h"

#include "script-fu-types.h"     /* SFScript */
#include "scheme-wrapper.h"      /* tinyscheme_init etc, */
#include "script-fu-scripts.h"   /* script_fu_find_scripts */
#include "script-fu-script.h"    /* script_fu_script_get_i18n */
#include "script-fu-interface.h" /* script_fu_interface_is_active */
#include "script-fu-proc-factory.h"


/*
 * The purpose here is a small, clean API to the exported functions of the library,
 * hiding internal types of the library
 * and hiding functions not static but not exported.
 *
 * Some are simple delegation to scheme_wrapper functions,
 * but others adapt
 * and some call functions not in scheme_wrapper.c
 */

static gboolean _script_fu_report_progress = FALSE;

/**
 * script_fu_report_progress:
 *
 * Returns: whether we should report progress status automatically
 *          (normally only within the "extension-script-fu" persistent plug-in).
 */
gboolean
script_fu_report_progress (void)
{
  return _script_fu_report_progress;
}

/*
 * Return whether extension-script-fu has an open dialog.
 * extension-script-fu is a single process.
 * It cannot have concurrent dialogs open in the GIMP app.
 *
 * Other plugins implementing PLUGIN type PDB procedures
 * in their own process (e.g. gimp-scheme-interpreter) do not need this.
 */
gboolean
script_fu_extension_is_busy (void)
{
  return script_fu_interface_is_active ();
}

/*
 * Find files at given paths, load them into the interpreter,
 * and register them as PDB procs of type TEMPORARY,
 * owned by the PDB proc of type PLUGIN for the given plugin.
 */
void
script_fu_find_and_register_scripts ( GimpPlugIn     *plugin,
                                      GList          *paths)
{
  script_fu_find_scripts (plugin, paths);
}

/*
 * Init the embedded interpreter.
 *
 * allow_register:
 * TRUE: allow loaded scripts to register PDB procedures.
 * The scheme functions script-fu-register and script-fu-menu-register are
 * defined to do something.
 * FALSE:  The scheme functions script-fu-register and script-fu-menu-register are
 * defined but do nothing.
 *
 * Note that the embedded interpreter always defines scheme functions
 * for all PDB procedures already existing when the interpreter starts
 * (currently bound at startup, but its possible to lazy bind.)
 * allow_register doesn't affect that.
 */
void
script_fu_init_embedded_interpreter (GList       *paths,
                                     gboolean     allow_register,
                                     GimpRunMode  run_mode,
                                     gboolean     report_progress)
{
  g_debug ("script_fu_init_embedded_interpreter");
  _script_fu_report_progress = report_progress;
  tinyscheme_init (paths, allow_register);
  ts_set_run_mode (run_mode);
  /*
   * Ensure the embedded interpreter is running and:
   *    loaded its internal Scheme scripts e.g. init.scm
   *    defined existing PDB procs as Scheme foreign functions
   *      (is ready to interpret PDB-like function calls in scheme scripts.)
   *    has loaded other init and compat scripts in /scripts/init
   *      e.g. script-fu-compat.scm
   *
   * The .scm file(s) for plugins in /scripts are NOT loaded.
   * Any util scripts in /scripts are NOT loaded, e.g. script-fu-utils.scm.
   */
}

/* Load script files at paths.
 * Side effect: create state script_tree.
 * Requires interpreter initialized.
 */
void
script_fu_load_scripts_into_tree (GimpPlugIn *plugin,
                                  GList      *paths)
{
  script_fu_scripts_load_into_tree (plugin, paths);
}

/* Has the interpreter been initialized and a script loaded
 * i.e. interpreted for registration into interpreter state: script_tree.
 */
gboolean
script_fu_is_scripts_loaded (void)
{
  return script_fu_scripts_are_loaded ();
}

void
script_fu_set_print_flag  (gboolean should_print)
{
  ts_set_print_flag (should_print);
}

/*
 * Make tinyscheme begin writing output to given gstring.
 */
void
script_fu_redirect_output_to_gstr (GString *output)
{
  ts_register_output_func (ts_gstring_output_func, output);
}

void
script_fu_redirect_output_to_stdout (void)
{
  ts_register_output_func (ts_stdout_output_func, NULL);
}

void
script_fu_print_welcome (void)
{
  ts_print_welcome ();
}

gboolean
script_fu_interpret_string (const gchar *text)
{
  /*converting from enum to boolean */
  return (gboolean) ts_interpret_string (text);
}

void
script_fu_set_run_mode (GimpRunMode run_mode)
{
  ts_set_run_mode (run_mode);
}

const gchar *
script_fu_get_success_msg (void)
{
  return ts_get_success_msg ();
}

/* Return an error message string for recent failure of script.
 *
 * Requires an interpretation just returned an error, else returns "Unknown".
 * Should be called exactly once per error, else second calls return "Unknown".
 *
 * Transfer ownership to caller, the string must be freed.
 */
const gchar *
script_fu_get_error_msg (void)
{
  return ts_get_error_msg ();
}

/* Return a GError for recent failure of script.
 *
 * Requires an interpretation just returned an error,
 * else returns a GError with message "Unknown".
 * Should be called exactly once per error
 *
 * You should call either get_error_msg, or get_gerror, but not both.
 *
 * Transfers ownership, caller must free the GError.
 */
GError *
script_fu_get_gerror (void)
{
  const gchar *error_message;
  GError      *result;

  error_message = script_fu_get_error_msg ();
  result = g_error_new_literal (g_quark_from_string ("scriptfu"), 0, error_message);
  g_free ((gpointer) error_message);
  return result;
}

void
script_fu_run_read_eval_print_loop (void)
{
  ts_interpret_stdin ();
}

void
script_fu_register_quit_callback (void (*func) (void))
{
  ts_register_quit_callback (func);
}

void
script_fu_register_post_command_callback (void (*func) (void))
{
  ts_register_post_command_callback (func);
}

/*
 * Return list of paths to directories containing .scm and .init scripts.
 *
 * List has two elements, in this order:
 *    directory for user scripts
 *    directory for system-wide scripts, distributed with GIMP
 * The dirs usually contain: plugins, init scripts, and utility scripts.
 *
 * The returned type is GList of GFile.
 * Caller must free the returned list.
 */
GList *
script_fu_search_path (void)
{
  gchar *path_str;
  GList *path = NULL;

  path_str = gimp_gimprc_query ("script-fu-path");
  if (path_str)
    {
      GError *error = NULL;

      path = gimp_config_path_expand_to_files (path_str, &error);
      g_free (path_str);

      if (! path)
        {
          g_warning ("Can't convert script-fu-path to filesystem encoding: %s",
                     error->message);
          g_clear_error (&error);
        }
    }
  return path;
}

/* Returns path to a subdirectory of the given path,
 * the subdirectory containing init scripts.
 *
 * SF keeps init scripts segregated in a subdirectory, since 3.0.
 * This lets them have the proper suffix ".scm"
 * without being confused with plugin scripts.
 * Also lets other scripts in that directory not be loaded at startup.
 *
 * This hides the name "init".
 *
 * Caller must free the result.
 */
gchar *
script_fu_get_init_subdirectory (GFile *dir)
{
  GFile *subdirectory = g_file_get_child (dir, "scriptfu-init");
  gchar *result_path  = g_file_get_path (subdirectory);

  g_object_unref (subdirectory);

  /* result is a string path to a directory which might not exist. */
  return result_path;
}

/* The directory containing init scripts installed with GIMP.
 * Caller must free the result string.
 */
gchar *
script_fu_sys_init_directory (void)
{
  GList *paths = script_fu_search_path ();
  GList *list_element;
  gchar *result_path;

  /* The second list element is the sys scripts dir. */
  list_element = g_list_next (paths);

  result_path = script_fu_get_init_subdirectory (list_element->data);

  g_list_free_full (paths, (GDestroyNotify) g_object_unref);

  return result_path;
}

/* The directory containing user init scripts.
 * Caller must free the result string.
 */
gchar *
script_fu_user_init_directory (void)
{
  GList *paths = script_fu_search_path ();
  GList *list_element;
  gchar *result_path;

  /* The first list element is the user scripts dir. */
  list_element = paths;

  result_path = script_fu_get_init_subdirectory (list_element->data);

  g_list_free_full (paths, (GDestroyNotify) g_object_unref);

  return result_path;
}

gboolean

/* Is the given dir named like an init dir for SF?
 *
 * This is lax, and doesn't check the dir is in one of
 * the two locations for SF's init directories.
 * Users should not use the name in their own directories
 * in the tree of script directories.
 */
script_fu_is_init_directory (GFile *dir)
{
  char    *basename = g_file_get_basename (dir);
  gboolean result;

  result = g_strcmp0 (basename, "scriptfu-init") == 0;
  g_free (basename);
  return result;
}

/* Create a PDB procedure from the SFScript for the given proc name.
 * Does not register into the PDB.
 * Requires scripts already loaded i.e. SFScript exist.
 */
GimpProcedure *
script_fu_create_PDB_proc_plugin (GimpPlugIn  *plug_in,
                                  const gchar *name)
{
  /* Delegate to factory. */
  return script_fu_proc_factory_make_PLUGIN (plug_in, name);
}

GList *
script_fu_find_scripts_list_proc_names (GimpPlugIn *plug_in,
                                        GList      *paths)
{
  /* Delegate to factory. */
  return script_fu_proc_factory_list_names (plug_in, paths);
}

/* Requires scripts already loaded. */
void
script_fu_get_i18n_for_proc (const gchar *proc_name,
                             gchar      **declared_i18n_domain,
                             gchar      **declared_i18n_catalog)
{
  SFScript *script = script_fu_find_script (proc_name);

  if (script != NULL)
    script_fu_script_get_i18n (script, declared_i18n_domain,
                               declared_i18n_catalog);
}