1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimppluginmanager-call.c
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include <gdk-pixbuf/gdk-pixbuf.h>
23 #include <gegl.h>
24 
25 #ifdef G_OS_WIN32
26 #include <windows.h>
27 #endif
28 
29 #include "libgimpbase/gimpbase.h"
30 #include "libgimpbase/gimpprotocol.h"
31 #include "libgimpbase/gimpwire.h"
32 
33 #include "plug-in-types.h"
34 
35 #include "config/gimpguiconfig.h"
36 
37 #include "core/gimp.h"
38 #include "core/gimpprogress.h"
39 
40 #include "pdb/gimppdbcontext.h"
41 
42 #include "gimpplugin.h"
43 #include "gimpplugin-message.h"
44 #include "gimpplugindef.h"
45 #include "gimppluginerror.h"
46 #include "gimppluginmanager.h"
47 #define __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__
48 #include "gimppluginmanager-call.h"
49 #include "gimppluginshm.h"
50 #include "gimptemporaryprocedure.h"
51 #include "plug-in-params.h"
52 
53 #include "gimp-intl.h"
54 
55 
56 static void
gimp_allow_set_foreground_window(GimpPlugIn * plug_in)57 gimp_allow_set_foreground_window (GimpPlugIn *plug_in)
58 {
59 #ifdef G_OS_WIN32
60   AllowSetForegroundWindow (GetProcessId (plug_in->pid));
61 #endif
62 }
63 
64 /*  public functions  */
65 
66 void
gimp_plug_in_manager_call_query(GimpPlugInManager * manager,GimpContext * context,GimpPlugInDef * plug_in_def)67 gimp_plug_in_manager_call_query (GimpPlugInManager *manager,
68                                  GimpContext       *context,
69                                  GimpPlugInDef     *plug_in_def)
70 {
71   GimpPlugIn *plug_in;
72 
73   g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager));
74   g_return_if_fail (GIMP_IS_PDB_CONTEXT (context));
75   g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def));
76 
77   plug_in = gimp_plug_in_new (manager, context, NULL,
78                               NULL, plug_in_def->file);
79 
80   if (plug_in)
81     {
82       plug_in->plug_in_def = plug_in_def;
83 
84       if (gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_QUERY, TRUE))
85         {
86           while (plug_in->open)
87             {
88               GimpWireMessage msg;
89 
90               if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in))
91                 {
92                   gimp_plug_in_close (plug_in, TRUE);
93                 }
94               else
95                 {
96                   gimp_plug_in_handle_message (plug_in, &msg);
97                   gimp_wire_destroy (&msg);
98                 }
99             }
100         }
101 
102       g_object_unref (plug_in);
103     }
104 }
105 
106 void
gimp_plug_in_manager_call_init(GimpPlugInManager * manager,GimpContext * context,GimpPlugInDef * plug_in_def)107 gimp_plug_in_manager_call_init (GimpPlugInManager *manager,
108                                 GimpContext       *context,
109                                 GimpPlugInDef     *plug_in_def)
110 {
111   GimpPlugIn *plug_in;
112 
113   g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager));
114   g_return_if_fail (GIMP_IS_PDB_CONTEXT (context));
115   g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def));
116 
117   plug_in = gimp_plug_in_new (manager, context, NULL,
118                               NULL, plug_in_def->file);
119 
120   if (plug_in)
121     {
122       plug_in->plug_in_def = plug_in_def;
123 
124       if (gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_INIT, TRUE))
125         {
126           while (plug_in->open)
127             {
128               GimpWireMessage msg;
129 
130               if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in))
131                 {
132                   gimp_plug_in_close (plug_in, TRUE);
133                 }
134               else
135                 {
136                   gimp_plug_in_handle_message (plug_in, &msg);
137                   gimp_wire_destroy (&msg);
138                 }
139             }
140         }
141 
142       g_object_unref (plug_in);
143     }
144 }
145 
146 GimpValueArray *
gimp_plug_in_manager_call_run(GimpPlugInManager * manager,GimpContext * context,GimpProgress * progress,GimpPlugInProcedure * procedure,GimpValueArray * args,gboolean synchronous,GimpObject * display)147 gimp_plug_in_manager_call_run (GimpPlugInManager   *manager,
148                                GimpContext         *context,
149                                GimpProgress        *progress,
150                                GimpPlugInProcedure *procedure,
151                                GimpValueArray      *args,
152                                gboolean             synchronous,
153                                GimpObject          *display)
154 {
155   GimpValueArray *return_vals = NULL;
156   GimpPlugIn     *plug_in;
157 
158   g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL);
159   g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL);
160   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
161   g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL);
162   g_return_val_if_fail (args != NULL, NULL);
163   g_return_val_if_fail (display == NULL || GIMP_IS_OBJECT (display), NULL);
164 
165   plug_in = gimp_plug_in_new (manager, context, progress, procedure, NULL);
166 
167   if (plug_in)
168     {
169       GimpCoreConfig    *core_config    = manager->gimp->config;
170       GimpGeglConfig    *gegl_config    = GIMP_GEGL_CONFIG (core_config);
171       GimpDisplayConfig *display_config = GIMP_DISPLAY_CONFIG (core_config);
172       GimpGuiConfig     *gui_config     = GIMP_GUI_CONFIG (core_config);
173       GPConfig           config;
174       GPProcRun          proc_run;
175       gint               display_ID;
176       GObject           *screen;
177       gint               monitor;
178       GFile             *icon_theme_dir;
179 
180       if (! gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_RUN, FALSE))
181         {
182           const gchar *name  = gimp_object_get_name (plug_in);
183           GError      *error = g_error_new (GIMP_PLUG_IN_ERROR,
184                                             GIMP_PLUG_IN_EXECUTION_FAILED,
185                                             _("Failed to run plug-in \"%s\""),
186                                             name);
187 
188           g_object_unref (plug_in);
189 
190           return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure),
191                                                           FALSE, error);
192           g_error_free (error);
193 
194           return return_vals;
195         }
196 
197       display_ID = display ? gimp_get_display_ID (manager->gimp, display) : -1;
198 
199       icon_theme_dir = gimp_get_icon_theme_dir (manager->gimp);
200 
201       config.version          = GIMP_PROTOCOL_VERSION;
202       config.tile_width       = GIMP_PLUG_IN_TILE_WIDTH;
203       config.tile_height      = GIMP_PLUG_IN_TILE_HEIGHT;
204       config.shm_ID           = (manager->shm ?
205                                  gimp_plug_in_shm_get_ID (manager->shm) : -1);
206       config.check_size       = display_config->transparency_size;
207       config.check_type       = display_config->transparency_type;
208       config.show_help_button = (gui_config->use_help &&
209                                  gui_config->show_help_button);
210       config.use_cpu_accel    = manager->gimp->use_cpu_accel;
211       config.use_opencl       = gegl_config->use_opencl;
212       config.export_profile   = core_config->export_color_profile;
213       config.export_exif      = core_config->export_metadata_exif;
214       config.export_xmp       = core_config->export_metadata_xmp;
215       config.export_iptc      = core_config->export_metadata_iptc;
216       config.show_tooltips    = gui_config->show_tooltips;
217       config.min_colors       = 144;
218       config.gdisp_ID         = display_ID;
219       config.app_name         = (gchar *) g_get_application_name ();
220       config.wm_class         = (gchar *) gimp_get_program_class (manager->gimp);
221       config.display_name     = gimp_get_display_name (manager->gimp,
222                                                        display_ID,
223                                                        &screen, &monitor);
224       config.monitor_number   = monitor;
225       config.timestamp        = gimp_get_user_time (manager->gimp);
226       config.icon_theme_dir   = icon_theme_dir ?
227                                   g_file_get_path (icon_theme_dir) :
228                                   NULL;
229       config.tile_cache_size  = gegl_config->tile_cache_size;
230       config.swap_path        = gegl_config->swap_path;
231       config.num_processors   = gegl_config->num_processors;
232       config.swap_compression = gegl_config->swap_compression;
233 
234       proc_run.name    = GIMP_PROCEDURE (procedure)->original_name;
235       proc_run.nparams = gimp_value_array_length (args);
236       proc_run.params  = plug_in_args_to_params (args, FALSE);
237 
238       if (! gp_config_write (plug_in->my_write, &config, plug_in)     ||
239           ! gp_proc_run_write (plug_in->my_write, &proc_run, plug_in) ||
240           ! gimp_wire_flush (plug_in->my_write, plug_in))
241         {
242           const gchar *name  = gimp_object_get_name (plug_in);
243           GError      *error = g_error_new (GIMP_PLUG_IN_ERROR,
244                                             GIMP_PLUG_IN_EXECUTION_FAILED,
245                                             _("Failed to run plug-in \"%s\""),
246                                             name);
247 
248           g_free (config.display_name);
249           g_free (config.icon_theme_dir);
250           g_free (proc_run.params);
251 
252           g_object_unref (plug_in);
253 
254           return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure),
255                                                           FALSE, error);
256           g_error_free (error);
257 
258           return return_vals;
259         }
260 
261       g_free (config.display_name);
262       g_free (config.icon_theme_dir);
263       g_free (proc_run.params);
264 
265       /* If this is an extension,
266        * wait for an installation-confirmation message
267        */
268       if (GIMP_PROCEDURE (procedure)->proc_type == GIMP_EXTENSION)
269         {
270           plug_in->ext_main_loop = g_main_loop_new (NULL, FALSE);
271 
272           gimp_threads_leave (manager->gimp);
273           g_main_loop_run (plug_in->ext_main_loop);
274           gimp_threads_enter (manager->gimp);
275 
276           /*  main_loop is quit in gimp_plug_in_handle_extension_ack()  */
277 
278           g_clear_pointer (&plug_in->ext_main_loop, g_main_loop_unref);
279         }
280 
281       /* If this plug-in is requested to run synchronously,
282        * wait for its return values
283        */
284       if (synchronous)
285         {
286           GimpPlugInProcFrame *proc_frame = &plug_in->main_proc_frame;
287 
288           proc_frame->main_loop = g_main_loop_new (NULL, FALSE);
289 
290           gimp_threads_leave (manager->gimp);
291           g_main_loop_run (proc_frame->main_loop);
292           gimp_threads_enter (manager->gimp);
293 
294           /*  main_loop is quit in gimp_plug_in_handle_proc_return()  */
295 
296           g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref);
297 
298           return_vals = gimp_plug_in_proc_frame_get_return_values (proc_frame);
299         }
300 
301       g_object_unref (plug_in);
302     }
303 
304   return return_vals;
305 }
306 
307 GimpValueArray *
gimp_plug_in_manager_call_run_temp(GimpPlugInManager * manager,GimpContext * context,GimpProgress * progress,GimpTemporaryProcedure * procedure,GimpValueArray * args)308 gimp_plug_in_manager_call_run_temp (GimpPlugInManager      *manager,
309                                     GimpContext            *context,
310                                     GimpProgress           *progress,
311                                     GimpTemporaryProcedure *procedure,
312                                     GimpValueArray         *args)
313 {
314   GimpValueArray *return_vals = NULL;
315   GimpPlugIn     *plug_in;
316 
317   g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL);
318   g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL);
319   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
320   g_return_val_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (procedure), NULL);
321   g_return_val_if_fail (args != NULL, NULL);
322 
323   plug_in = procedure->plug_in;
324 
325   if (plug_in)
326     {
327       GimpPlugInProcFrame *proc_frame;
328       GPProcRun            proc_run;
329 
330       proc_frame = gimp_plug_in_proc_frame_push (plug_in, context, progress,
331                                                  procedure);
332 
333       proc_run.name    = GIMP_PROCEDURE (procedure)->original_name;
334       proc_run.nparams = gimp_value_array_length (args);
335       proc_run.params  = plug_in_args_to_params (args, FALSE);
336 
337       if (! gp_temp_proc_run_write (plug_in->my_write, &proc_run, plug_in) ||
338           ! gimp_wire_flush (plug_in->my_write, plug_in))
339         {
340           const gchar *name  = gimp_object_get_name (plug_in);
341           GError      *error = g_error_new (GIMP_PLUG_IN_ERROR,
342                                             GIMP_PLUG_IN_EXECUTION_FAILED,
343                                             _("Failed to run plug-in \"%s\""),
344                                             name);
345 
346           g_free (proc_run.params);
347           gimp_plug_in_proc_frame_pop (plug_in);
348 
349           return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure),
350                                                           FALSE, error);
351           g_error_free (error);
352 
353           return return_vals;
354         }
355       gimp_allow_set_foreground_window (plug_in);
356 
357       g_free (proc_run.params);
358 
359       g_object_ref (plug_in);
360       gimp_plug_in_proc_frame_ref (proc_frame);
361 
362       gimp_plug_in_main_loop (plug_in);
363 
364       /*  main_loop is quit and proc_frame is popped in
365        *  gimp_plug_in_handle_temp_proc_return()
366        */
367 
368       return_vals = gimp_plug_in_proc_frame_get_return_values (proc_frame);
369 
370       gimp_plug_in_proc_frame_unref (proc_frame, plug_in);
371       g_object_unref (plug_in);
372     }
373 
374   return return_vals;
375 }
376