r854: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / pluginserver.C
blob9d4775735bb39bf8c157628dd57b34ebf7e9a3a2
1 #include "amodule.h"
2 #include "atrack.h"
3 #include "attachmentpoint.h"
4 #include "autoconf.h"
5 #include "bcsignals.h"
6 #include "cplayback.h"
7 #include "cwindow.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "floatautos.h"
11 #include "localsession.h"
12 #include "mainprogress.h"
13 #include "mainundo.h"
14 #include "menueffects.h"
15 #include "mwindow.h"
16 #include "mwindowgui.h"
17 #include "playbackengine.h"
18 #include "plugin.h"
19 #include "pluginaclient.h"
20 #include "pluginaclientlad.h"
21 #include "pluginclient.h"
22 #include "plugincommands.h"
23 #include "pluginserver.h"
24 #include "pluginvclient.h"
25 #include "preferences.h"
26 #include "sema.h"
27 #include "mainsession.h"
28 #include "trackcanvas.h"
29 #include "transportque.h"
30 #include "vdevicex11.h"
31 #include "vframe.h"
32 #include "videodevice.h"
33 #include "virtualanode.h"
34 #include "virtualvnode.h"
35 #include "vmodule.h"
36 #include "vtrack.h"
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <dlfcn.h>
44 PluginServer::PluginServer()
46         reset_parameters();
47         modules = new ArrayList<Module*>;
48         nodes = new ArrayList<VirtualNode*>;
51 PluginServer::PluginServer(char *path)
53         reset_parameters();
54         set_path(path);
55         modules = new ArrayList<Module*>;
56         nodes = new ArrayList<VirtualNode*>;
59 PluginServer::PluginServer(PluginServer &that)
61         reset_parameters();
63         if(that.title)
64         {
65                 title = new char[strlen(that.title) + 1];
66                 strcpy(title, that.title);
67         }
69         if(that.path)
70         {
71                 path = new char[strlen(that.path) + 1];
72                 strcpy(path, that.path);
73         }
75         modules = new ArrayList<Module*>;
76         nodes = new ArrayList<VirtualNode*>;
78         attachment = that.attachment;   
79         realtime = that.realtime;
80         multichannel = that.multichannel;
81         preferences = that.preferences;
82         synthesis = that.synthesis;
83         audio = that.audio;
84         video = that.video;
85         theme = that.theme;
86         fileio = that.fileio;
87         uses_gui = that.uses_gui;
88         mwindow = that.mwindow;
89         keyframe = that.keyframe;
90         plugin_fd = that.plugin_fd;
91         new_plugin = that.new_plugin;
93         is_lad = that.is_lad;
94         lad_descriptor = that.lad_descriptor;
95         lad_descriptor_function = that.lad_descriptor_function;
98 PluginServer::~PluginServer()
100         close_plugin();
101         if(path) delete [] path;
102         if(title) delete [] title;
103         if(modules) delete modules;
104         if(nodes) delete nodes;
105         if(picon) delete picon;
108 // Done only once at creation
109 int PluginServer::reset_parameters()
111         mwindow = 0;
112         keyframe = 0;
113         prompt = 0;
114         cleanup_plugin();
115         plugin_fd = 0;
116         autos = 0;
117         plugin = 0;
118         edl = 0;
119         preferences = 0;
120         title = 0;
121         path = 0;
122         audio = video = theme = 0;
123         uses_gui = 0;
124         realtime = multichannel = fileio = 0;
125         synthesis = 0;
126         start_auto = end_auto = 0;
127         picon = 0;
128         transition = 0;
129         new_plugin = 0;
130         client = 0;
131         use_opengl = 0;
132         vdevice = 0;
134         is_lad = 0;
135         lad_descriptor_function = 0;
136         lad_descriptor = 0;
140 // Done every time the plugin is opened or closed
141 int PluginServer::cleanup_plugin()
143         in_buffer_size = out_buffer_size = 0;
144         total_in_buffers = total_out_buffers = 0;
145         error_flag = 0;
146         written_samples = 0;
147         shared_buffers = 0;
148         new_buffers = 0;
149         written_samples = written_frames = 0;
150         gui_on = 0;
151         plugin = 0;
152         plugin_open = 0;
155 void PluginServer::set_mwindow(MWindow *mwindow)
157         this->mwindow = mwindow;
160 void PluginServer::set_attachmentpoint(AttachmentPoint *attachmentpoint)
162         this->attachmentpoint = attachmentpoint;
165 void PluginServer::set_keyframe(KeyFrame *keyframe)
167         this->keyframe = keyframe;
170 void PluginServer::set_prompt(MenuEffectPrompt *prompt)
172         this->prompt = prompt;
176 int PluginServer::set_path(char *path)
178         if(this->path) delete [] this->path;
179         this->path = new char[strlen(path) + 1];
180         strcpy(this->path, path);
183 void PluginServer::set_title(char *string)
185         if(title) delete [] title;
186         title = new char[strlen(string) + 1];
187         strcpy(title, string);
190 void PluginServer::generate_display_title(char *string)
192         if(plugin && plugin->track) 
193                 sprintf(string, "%s: %s", plugin->track->title, title);
194         else
195                 strcpy(string, title);
198 // Open plugin for signal processing
199 int PluginServer::open_plugin(int master, 
200         Preferences *preferences,
201         EDL *edl, 
202         Plugin *plugin,
203         int lad_index)
205         if(plugin_open) return 0;
207         this->preferences = preferences;
208         this->plugin = plugin;
209         this->edl = edl;
213         if(!new_plugin && !plugin_fd) plugin_fd = dlopen(path, RTLD_NOW);
215         if(!new_plugin && !plugin_fd)
216         {
217 // If the dlopen failed it may still be an executable tool for a specific
218 // file format, in which case we just store the path.
219                 set_title(path);
220                 char string[BCTEXTLEN];
221                 strcpy(string, dlerror());
223                 if(!strstr(string, "executable"))
224                         printf("PluginServer::open_plugin: %s\n", string);
225                 
226                 return 0;
227         }
230         if(!new_plugin && !lad_descriptor)
231         {
232                 new_plugin = (PluginClient* (*)(PluginServer*))dlsym(plugin_fd, "new_plugin");
234 // Probably a LAD plugin but we're not going to instantiate it here anyway.
235                 if(!new_plugin)
236                 {
237                         lad_descriptor_function = (LADSPA_Descriptor_Function)dlsym(
238                                 plugin_fd,
239                                 "ladspa_descriptor");
241                         if(!lad_descriptor_function)
242                         {
243 // Not a recognized plugin
244                                 fprintf(stderr, "PluginServer::open_plugin: new_plugin undefined in %s\n", path);
245                                 dlclose(plugin_fd);
246                                 plugin_fd = 0;
247                                 return PLUGINSERVER_NOT_RECOGNIZED;
248                         }
249                         else
250                         {
251 // LAD plugin,  Load the descriptor and get parameters.
252                                 is_lad = 1;
253                                 if(lad_index >= 0)
254                                 {
255                                         lad_descriptor = lad_descriptor_function(lad_index);
256                                 }
258 // make plugin initializer handle the subplugins in the LAD plugin or stop
259 // trying subplugins.
260                                 if(!lad_descriptor)
261                                 {
262                                         dlclose(plugin_fd);
263                                         plugin_fd = 0;
264                                         return PLUGINSERVER_IS_LAD;
265                                 }
266                         }
267                 }
268         }
271         if(is_lad)
272         {
273                 client = new PluginAClientLAD(this);
274         }
275         else
276         {
277                 client = new_plugin(this);
278         }
280         realtime = client->is_realtime();
281         audio = client->is_audio();
282         video = client->is_video();
283         theme = client->is_theme();
284         fileio = client->is_fileio();
285         uses_gui = client->uses_gui();
286         multichannel = client->is_multichannel();
287         synthesis = client->is_synthesis();
288         transition = client->is_transition();
289         set_title(client->plugin_title());
291         if(master)
292         {
293                 picon = client->new_picon();
294         }
296 //printf("PluginServer::open_plugin 2\n");
297         plugin_open = 1;
298         return PLUGINSERVER_OK;
301 int PluginServer::close_plugin()
303         if(!plugin_open) return 0;
305         int plugin_status, result;
306         if(client) delete client;
308 // shared object is persistent since plugin deletion would unlink its own object
309 //      dlclose(plugin_fd);
310         plugin_open = 0;
312         cleanup_plugin();
314         return 0;
317 void PluginServer::client_side_close()
319 // Last command executed in client thread
320         if(plugin)
321                 mwindow->hide_plugin(plugin, 1);
322         else
323         if(prompt)
324         {
325                 prompt->lock_window();
326                 prompt->set_done(1);
327                 prompt->unlock_window();
328         }
331 void PluginServer::render_stop()
333         if(client)
334                 client->render_stop();
338 int PluginServer::init_realtime(int realtime_sched,
339                 int total_in_buffers, 
340                 int buffer_size)
343         if(!plugin_open) return 0;
345 // set for realtime priority
346 // initialize plugin
347 // Call start_realtime
348         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
349         client->plugin_init_realtime(realtime_sched, 
350                 total_in_buffers, 
351                 buffer_size);
356 // Replaced by pull method but still needed for transitions
357 void PluginServer::process_transition(VFrame *input, 
358                 VFrame *output, 
359                 int64_t current_position,
360                 int64_t total_len)
362         if(!plugin_open) return;
363         PluginVClient *vclient = (PluginVClient*)client;
365         vclient->source_position = current_position;
366         vclient->source_start = 0;
367         vclient->total_len = total_len;
369         vclient->input = new VFrame*[1];
370         vclient->output = new VFrame*[1];
372         vclient->input[0] = input;
373         vclient->output[0] = output;
375         vclient->process_realtime(input, output);
376         vclient->age_temp();
377         delete [] vclient->input;
378         delete [] vclient->output;
379         use_opengl = 0;
382 void PluginServer::process_transition(double *input, 
383                 double *output,
384                 int64_t current_position, 
385                 int64_t fragment_size,
386                 int64_t total_len)
388         if(!plugin_open) return;
389         PluginAClient *aclient = (PluginAClient*)client;
391         aclient->source_position = current_position;
392         aclient->total_len = total_len;
393         aclient->source_start = 0;
394         aclient->process_realtime(fragment_size,
395                 input, 
396                 output);
400 void PluginServer::process_buffer(VFrame **frame, 
401         int64_t current_position,
402         double frame_rate,
403         int64_t total_len,
404         int direction)
406         if(!plugin_open) return;
407         PluginVClient *vclient = (PluginVClient*)client;
409         vclient->source_position = current_position;
410         vclient->total_len = total_len;
411         vclient->frame_rate = frame_rate;
412         vclient->input = new VFrame*[total_in_buffers];
413         vclient->output = new VFrame*[total_in_buffers];
414         for(int i = 0; i < total_in_buffers; i++)
415         {
416                 vclient->input[i] = frame[i];
417                 vclient->output[i] = frame[i];
418         }
419         vclient->source_start = (int64_t)(plugin ? 
420                 plugin->startproject * 
421                 frame_rate /
422                 vclient->project_frame_rate :
423                 0);
424         vclient->direction = direction;
427         if(multichannel)
428         {
429                 vclient->process_buffer(frame, current_position, frame_rate);
430         }
431         else
432         {
433                 vclient->process_buffer(frame[0], current_position, frame_rate);
434         }
436         for(int i = 0; i < total_in_buffers; i++)
437                 frame[i]->push_prev_effect(title);
439         delete [] vclient->input;
440         delete [] vclient->output;
442     vclient->age_temp();
443         use_opengl = 0;
446 void PluginServer::process_buffer(double **buffer,
447         int64_t current_position,
448         int64_t fragment_size,
449         int64_t sample_rate,
450         int64_t total_len,
451         int direction)
453         if(!plugin_open) return;
454         PluginAClient *aclient = (PluginAClient*)client;
455         aclient->source_position = current_position;
456         aclient->total_len = total_len;
457         aclient->sample_rate = sample_rate;
458         if(plugin)
459                 aclient->source_start = plugin->startproject * 
460                         sample_rate /
461                         aclient->project_sample_rate;
462         aclient->direction = direction;
463         if(multichannel)
464                 aclient->process_buffer(fragment_size, 
465                         buffer, 
466                         current_position, 
467                         sample_rate);
468         else
469         {
470                 aclient->process_buffer(fragment_size, 
471                         buffer[0], 
472                         current_position, 
473                         sample_rate);
474         }
478 void PluginServer::send_render_gui(void *data)
480 //printf("PluginServer::send_render_gui 1 %p\n", attachmentpoint);
481         if(attachmentpoint) attachmentpoint->render_gui(data);
484 void PluginServer::send_render_gui(void *data, int size)
486 //printf("PluginServer::send_render_gui 1 %p\n", attachmentpoint);
487         if(attachmentpoint) attachmentpoint->render_gui(data, size);
490 void PluginServer::render_gui(void *data)
492         if(client) client->plugin_render_gui(data);
495 void PluginServer::render_gui(void *data, int size)
497         if(client) client->plugin_render_gui(data, size);
500 MainProgressBar* PluginServer::start_progress(char *string, int64_t length)
502         mwindow->gui->lock_window();
503         MainProgressBar *result = mwindow->mainprogress->start_progress(string, length);
504         mwindow->gui->unlock_window();
505         return result;
508 int64_t PluginServer::get_written_samples()
510         if(!plugin_open) return 0;
511         return written_samples;
514 int64_t PluginServer::get_written_frames()
516         if(!plugin_open) return 0;
517         return written_frames;
529 // ======================= Non-realtime plugin
531 int PluginServer::get_parameters(int64_t start, int64_t end, int channels)      
533         if(!plugin_open) return 0;
535         client->start = start;
536         client->end = end;
537         client->source_start = start;
538         client->total_len = end - start;
539         client->total_in_buffers = channels;
540         return client->plugin_get_parameters();
543 int PluginServer::set_interactive()
545         if(!plugin_open) return 0;
546         client->set_interactive();
547         return 0;
550 void PluginServer::append_module(Module *module)
552         modules->append(module);
555 void PluginServer::append_node(VirtualNode *node)
557         nodes->append(node);
560 void PluginServer::reset_nodes()
562         nodes->remove_all();
565 int PluginServer::set_error()
567         error_flag = 1;
568         return 0;
571 int PluginServer::set_realtime_sched()
573         struct sched_param params;
574         params.sched_priority = 1;
575         return 0;
579 int PluginServer::process_loop(VFrame **buffers, int64_t &write_length)
581         if(!plugin_open) return 1;
582         return client->plugin_process_loop(buffers, write_length);
585 int PluginServer::process_loop(double **buffers, int64_t &write_length)
587         if(!plugin_open) return 1;
588         return client->plugin_process_loop(buffers, write_length);
592 int PluginServer::start_loop(int64_t start, 
593         int64_t end, 
594         int64_t buffer_size, 
595         int total_buffers)
597         if(!plugin_open) return 0;
598         client->plugin_start_loop(start, end, buffer_size, total_buffers);
599         return 0;
602 int PluginServer::stop_loop()
604         if(!plugin_open) return 0;
605         return client->plugin_stop_loop();
608 int PluginServer::read_frame(VFrame *buffer, 
609         int channel, 
610         int64_t start_position)
612         ((VModule*)modules->values[channel])->render(buffer,
613                 start_position,
614                 PLAY_FORWARD,
615                 mwindow->edl->session->frame_rate,
616                 0,
617                 0);
618         return 0;
621 int PluginServer::read_samples(double *buffer, 
622         int channel, 
623         int64_t start_position, 
624         int64_t total_samples)
626         ((AModule*)modules->values[channel])->render(buffer, 
627                 start_position,
628                 total_samples, 
629                 PLAY_FORWARD,
630                 mwindow->edl->session->sample_rate,
631                 0);
632         return 0;
635 int PluginServer::read_frame(VFrame *buffer, 
636         int channel, 
637         int64_t start_position, 
638         double frame_rate,
639         int use_opengl)
641 // Data source depends on whether we're part of a virtual console or a
642 // plugin array.
643 //     VirtualNode
644 //     Module
645 // If we're a VirtualNode, read_data in the virtual plugin node handles
646 //     backward propogation and produces the data.
647 // If we're a Module, render in the module produces the data.
649         int result = -1;
650         if(!multichannel) channel = 0;
652 // Push our name on the next effect stack
653         buffer->push_next_effect(title);
654 //printf("PluginServer::read_frame %p\n", buffer);
655 //buffer->dump_stacks();
657         if(nodes->total > channel)
658         {
659                 result = ((VirtualVNode*)nodes->values[channel])->read_data(buffer,
660                         start_position,
661                         frame_rate,
662                         use_opengl);
663         }
664         else
665         if(modules->total > channel)
666         {
667                 result = ((VModule*)modules->values[channel])->render(buffer,
668                         start_position,
669                         PLAY_FORWARD,
670                         frame_rate,
671                         0,
672                         0,
673                         use_opengl);
674         }
675         else
676         {
677                 printf("PluginServer::read_frame no object available for channel=%d\n",
678                         channel);
679         }
681 // Pop our name from the next effect stack
682         buffer->pop_next_effect();
684         return result;
687 int PluginServer::read_samples(double *buffer,
688         int channel,
689         int64_t sample_rate,
690         int64_t start_position, 
691         int64_t len)
693         if(!multichannel) channel = 0;
695         if(nodes->total > channel)
696                 return ((VirtualANode*)nodes->values[channel])->read_data(buffer,
697                         start_position,
698                         len,
699                         sample_rate);
700         else
701         if(modules->total > channel)
702                 return ((AModule*)modules->values[channel])->render(buffer,
703                         start_position,
704                         len,
705                         PLAY_FORWARD,
706                         sample_rate,
707                         0);
708         else
709         {
710                 printf("PluginServer::read_samples no object available for channel=%d\n",
711                         channel);
712         }
714         return -1;
736 // Called by client
737 int PluginServer::get_gui_status()
739         if(plugin)
740                 return plugin->show ? GUI_ON : GUI_OFF;
741         else
742                 return GUI_OFF;
745 void PluginServer::raise_window()
747         if(!plugin_open) return;
748         client->raise_window();
751 void PluginServer::show_gui()
753         if(!plugin_open) return;
754         client->smp = preferences->processors - 1;
755         if(plugin) client->total_len = plugin->length;
756         if(plugin) client->source_start = plugin->startproject;
757         if(video)
758         {
759                 client->source_position = Units::to_int64(
760                         mwindow->edl->local_session->get_selectionstart(1) * 
761                                 mwindow->edl->session->frame_rate);
762         }
763         else
764         if(audio)
765         {
766                 client->source_position = Units::to_int64(
767                         mwindow->edl->local_session->get_selectionstart(1) * 
768                                 mwindow->edl->session->sample_rate);
769         }
770         client->update_display_title();
771         client->show_gui();
774 void PluginServer::update_gui()
776         if(!plugin_open || !plugin) return;
778         client->total_len = plugin->length;
779         client->source_start = plugin->startproject;
780         if(video)
781         {
782                 client->source_position = Units::to_int64(
783                         mwindow->edl->local_session->get_selectionstart(1) * 
784                                 mwindow->edl->session->frame_rate);
785         }
786         else
787         if(audio)
788         {
789                 client->source_position = Units::to_int64(
790                         mwindow->edl->local_session->get_selectionstart(1) * 
791                                 mwindow->edl->session->sample_rate);
792         }
793         client->update_gui();
796 void PluginServer::update_title()
798         if(!plugin_open) return;
799         
800         client->update_display_title();
804 int PluginServer::set_string(char *string)
806         if(!plugin_open) return 0;
808         client->set_string_client(string);
809         return 0;
812 int PluginServer::gui_open()
814         if(attachmentpoint) return attachmentpoint->gui_open();
815         return 0;
818 void PluginServer::set_use_opengl(int value, VideoDevice *vdevice)
820         this->use_opengl = value;
821         this->vdevice = vdevice;
824 int PluginServer::get_use_opengl()
826         return use_opengl;
830 void PluginServer::run_opengl(PluginClient *plugin_client)
832         if(vdevice)
833                 ((VDeviceX11*)vdevice->get_output_base())->run_plugin(plugin_client);
836 // ============================= queries
838 int PluginServer::get_samplerate()
840         if(!plugin_open) return 0;
841         if(audio)
842         {
843                 return client->get_samplerate();
844         }
845         else
846         if(mwindow)
847                 return mwindow->edl->session->sample_rate;
848         else
849         {
850                 printf("PluginServer::get_samplerate audio and mwindow == NULL\n");
851                 return 1;
852         }
856 double PluginServer::get_framerate()
858         if(!plugin_open) return 0;
859         if(video)
860         {
861                 return client->get_framerate();
862         }
863         else
864         if(mwindow)
865                 return mwindow->edl->session->frame_rate;
866         else 
867         {
868                 printf("PluginServer::get_framerate video and mwindow == NULL\n");
869                 return 1;
870         }
873 int PluginServer::get_project_samplerate()
875         if(mwindow)
876                 return mwindow->edl->session->sample_rate;
877         else
878         if(edl)
879                 return edl->session->sample_rate;
880         else
881         {
882                 printf("PluginServer::get_project_samplerate mwindow and edl are NULL.\n");
883                 return 1;
884         }
887 double PluginServer::get_project_framerate()
889         if(mwindow)
890                 return mwindow->edl->session->frame_rate;
891         else
892         if(edl)
893                 return edl->session->frame_rate;
894         else
895         {
896                 printf("PluginServer::get_project_framerate mwindow and edl are NULL.\n");
897                 return 1;
898         }
903 int PluginServer::detach_buffers()
905         ring_buffers_out.remove_all();
906         offset_out_render.remove_all();
907         double_buffer_out_render.remove_all();
908         realtime_out_size.remove_all();
910         ring_buffers_in.remove_all();
911         offset_in_render.remove_all();
912         double_buffer_in_render.remove_all();
913         realtime_in_size.remove_all();
914         
915         out_buffer_size = 0;
916         shared_buffers = 0;
917         total_out_buffers = 0;
918         in_buffer_size = 0;
919         total_in_buffers = 0;
920         return 0;
923 int PluginServer::arm_buffer(int buffer_number, 
924                 int64_t offset_in, 
925                 int64_t offset_out,
926                 int double_buffer_in,
927                 int double_buffer_out)
929         offset_in_render.values[buffer_number] = offset_in;
930         offset_out_render.values[buffer_number] = offset_out;
931         double_buffer_in_render.values[buffer_number] = double_buffer_in;
932         double_buffer_out_render.values[buffer_number] = double_buffer_out;
936 int PluginServer::set_automation(FloatAutos *autos, FloatAuto **start_auto, FloatAuto **end_auto, int reverse)
938         this->autos = autos;
939         this->start_auto = start_auto;
940         this->end_auto = end_auto;
941         this->reverse = reverse;
946 void PluginServer::save_data(KeyFrame *keyframe)
948         if(!plugin_open) return;
949         client->save_data(keyframe);
952 KeyFrame* PluginServer::get_prev_keyframe(int64_t position)
954         KeyFrame *result = 0;
955         if(plugin)
956                 result = plugin->get_prev_keyframe(position, client->direction);
957         else
958                 result = keyframe;
959         return result;
962 KeyFrame* PluginServer::get_next_keyframe(int64_t position)
964         KeyFrame *result = 0;
965         if(plugin)
966                 result = plugin->get_next_keyframe(position, client->direction);
967         else
968                 result = keyframe;
969         return result;
972 KeyFrame* PluginServer::get_keyframe()
974         if(plugin)
975                 return plugin->get_keyframe();
976         else
977                 return keyframe;
980 void PluginServer::get_camera(float *x, float *y, float *z,
981         int64_t position, int direction)
983         plugin->track->automation->get_camera(x, y, z, position, direction);
986 void PluginServer::get_projector(float *x, float *y, float *z,
987         int64_t position, int direction)
989         plugin->track->automation->get_projector(x, y, z, position, direction);
993 int PluginServer::get_interpolation_type()
995         return plugin->edl->session->interpolation_type;
998 Theme* PluginServer::new_theme()
1000         if(theme)
1001         {
1002                 return client->new_theme();
1003         }
1004         else
1005                 return 0;
1008 Theme* PluginServer::get_theme()
1010         if(mwindow) return mwindow->theme;
1011         printf("PluginServer::get_theme mwindow not set\n");
1012         return 0;
1016 // Called when plugin interface is tweeked
1017 void PluginServer::sync_parameters()
1019         if(video) mwindow->restart_brender();
1020         mwindow->sync_parameters();
1021         if(mwindow->edl->session->auto_conf->plugins)
1022         {
1023                 mwindow->gui->lock_window("PluginServer::sync_parameters");
1024                 mwindow->gui->canvas->draw_overlays();
1025                 mwindow->gui->canvas->flash();
1026                 mwindow->gui->unlock_window();
1027         }
1032 void PluginServer::dump()
1034         printf("    PluginServer %s %s\n", path, title);