add resource wdw folder expanders, fix plugin close deadlock detect
[goodguy/history.git] / cinelerra-5.1 / cinelerra / pluginclient.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "condition.h"
27 #include "edits.h"
28 #include "edit.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "file.h"
32 #include "filesystem.h"
33 #include "indexable.h"
34 #include "language.h"
35 #include "localsession.h"
36 #include "mainundo.h"
37 #include "mwindow.h"
38 #include "plugin.h"
39 #include "pluginclient.h"
40 #include "pluginserver.h"
41 #include "preferences.h"
42 #include "track.h"
43 #include "transportque.inc"
44
45
46 #include <ctype.h>
47 #include <errno.h>
48 #include <string.h>
49
50
51
52
53
54 PluginClientThread::PluginClientThread(PluginClient *client)
55  : Thread(1, 0, 0)
56 {
57         this->client = client;
58         window = 0;
59         init_complete = new Condition(0, "PluginClientThread::init_complete");
60 }
61
62 PluginClientThread::~PluginClientThread()
63 {
64         join();
65 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
66         delete window;  window = 0;
67 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
68         delete init_complete;
69 }
70
71 void PluginClientThread::run()
72 {
73         BC_DisplayInfo info;
74         int result = 0;
75         if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
76         if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
77         if(!window)
78                 window = (PluginClientWindow*)client->new_window();
79
80         if(window) {
81                 window->lock_window("PluginClientThread::run");
82                 window->create_objects();
83                 window->unlock_window();
84
85 /* Only set it here so tracking doesn't update it until everything is created. */
86                 client->thread = this;
87                 init_complete->unlock();
88
89                 result = window->run_window();
90                 window->lock_window("PluginClientThread::run");
91 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
92                 window->hide_window(1);
93                 window->unlock_window();
94                 window->done_event(result);
95 // Can't save defaults in the destructor because it's not called immediately
96 // after closing.
97                 /* if(client->defaults) */ client->save_defaults_xml();
98 /* This is needed when the GUI is closed from itself */
99                 if(result) client->client_side_close();
100         }
101         else
102 // No window
103         {
104                 client->thread = this;
105                 init_complete->unlock();
106         }
107 }
108
109 BC_WindowBase* PluginClientThread::get_window()
110 {
111         return window;
112 }
113
114 PluginClient* PluginClientThread::get_client()
115 {
116         return client;
117 }
118
119
120
121
122
123
124 PluginClientFrame::PluginClientFrame(int data_size,
125         int period_n,
126         int period_d)
127 {
128         this->data_size = data_size;
129         force = 0;
130         this->period_n = period_n;
131         this->period_d = period_d;
132 }
133
134 PluginClientFrame::~PluginClientFrame()
135 {
136
137 }
138
139
140
141
142
143 PluginClientWindow::PluginClientWindow(PluginClient *client,
144         int w, int h, int min_w, int min_h, int allow_resize)
145  : BC_Window(client->gui_string,
146         client->window_x /* - w / 2 */,
147         client->window_y /* - h / 2 */,
148         (int)(w*get_resources()->font_scale+0.5), (int)(h*get_resources()->font_scale+0.5),
149         (int)(min_w*get_resources()->font_scale+0.5), (int)(min_h*get_resources()->font_scale+0.5),
150         allow_resize, 0, 1)
151 {
152         this->client = client;
153 }
154
155 PluginClientWindow::PluginClientWindow(const char *title,
156         int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
157  : BC_Window(title, x, y,
158         (int)(w*get_resources()->font_scale+0.5), (int)(h*get_resources()->font_scale+0.5),
159         (int)(min_w*get_resources()->font_scale+0.5), (int)(min_h*get_resources()->font_scale+0.5),
160         allow_resize, 0, 1)
161 {
162         this->client = 0;
163 }
164
165 PluginClientWindow::~PluginClientWindow()
166 {
167 }
168
169
170 int PluginClientWindow::translation_event()
171 {
172         if(client)
173         {
174                 client->window_x = get_x();
175                 client->window_y = get_y();
176         }
177
178         return 1;
179 }
180
181 int PluginClientWindow::close_event()
182 {
183 /* Set result to 1 to indicate a client side close */
184         set_done(1);
185         return 1;
186 }
187
188
189
190
191
192 PluginClient::PluginClient(PluginServer *server)
193 {
194         reset();
195         this->server = server;
196         smp = server->preferences->project_smp;
197         defaults = 0;
198         update_timer = new Timer;
199 // Virtual functions don't work here.
200 }
201
202 PluginClient::~PluginClient()
203 {
204         if( thread ) {
205                 hide_gui();
206                 thread->join();
207                 delete thread;
208         }
209
210 // Virtual functions don't work here.
211         if(defaults) delete defaults;
212         frame_buffer.remove_all_objects();
213         delete update_timer;
214 }
215
216 int PluginClient::reset()
217 {
218         window_x = -1;
219         window_y = -1;
220         interactive = 0;
221         show_initially = 0;
222         wr = rd = 0;
223         master_gui_on = 0;
224         client_gui_on = 0;
225         realtime_priority = 0;
226         gui_string[0] = 0;
227         total_in_buffers = 0;
228         total_out_buffers = 0;
229         source_position = 0;
230         source_start = 0;
231         total_len = 0;
232         direction = PLAY_FORWARD;
233         thread = 0;
234         using_defaults = 0;
235         return 0;
236 }
237
238
239 void PluginClient::hide_gui()
240 {
241         if(thread && thread->window)
242         {
243 //printf("PluginClient::delete_thread %d\n", __LINE__);
244 /* This is needed when the GUI is closed from elsewhere than itself */
245 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
246 /* Thread join will wait if this was not called from the thread itself or go on if it was */
247                 thread->window->lock_window("PluginClient::hide_gui");
248                 thread->window->set_done(0);
249 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
250                 thread->window->unlock_window();
251         }
252 }
253
254 // For realtime plugins initialize buffers
255 int PluginClient::plugin_init_realtime(int realtime_priority,
256         int total_in_buffers,
257         int buffer_size)
258 {
259
260 // Get parameters for all
261         master_gui_on = get_gui_status();
262
263
264
265 // get parameters depending on video or audio
266         init_realtime_parameters();
267
268         this->realtime_priority = realtime_priority;
269         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
270         this->out_buffer_size = this->in_buffer_size = buffer_size;
271         return 0;
272 }
273
274 int PluginClient::plugin_start_loop(int64_t start,
275         int64_t end,
276         int64_t buffer_size,
277         int total_buffers)
278 {
279 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
280 // __LINE__, start, end, buffer_size, total_buffers);
281         this->source_start = start;
282         this->total_len = end - start;
283         this->start = start;
284         this->end = end;
285         this->in_buffer_size = this->out_buffer_size = buffer_size;
286         this->total_in_buffers = this->total_out_buffers = total_buffers;
287         start_loop();
288         return 0;
289 }
290
291 int PluginClient::plugin_process_loop()
292 {
293         return process_loop();
294 }
295
296 int PluginClient::plugin_stop_loop()
297 {
298         return stop_loop();
299 }
300
301 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
302 {
303         return server->start_progress(string, length);
304 }
305
306
307 // Non realtime parameters
308 int PluginClient::plugin_get_parameters()
309 {
310         int result = get_parameters();
311         if(defaults) save_defaults();
312         return result;
313 }
314
315 // ========================= main loop
316
317 int PluginClient::is_multichannel() { return 0; }
318 int PluginClient::is_synthesis() { return 0; }
319 int PluginClient::is_realtime() { return 0; }
320 int PluginClient::is_fileio() { return 0; }
321 int PluginClient::delete_buffer_ptrs() { return 0; }
322 const char* PluginClient::plugin_title() { return _("Untitled"); }
323
324 Theme* PluginClient::new_theme() { return 0; }
325
326 int PluginClient::load_configuration()
327 {
328         return 0;
329 }
330
331 Theme* PluginClient::get_theme()
332 {
333         return server->get_theme();
334 }
335
336 int PluginClient::show_gui()
337 {
338         load_configuration();
339         thread = new PluginClientThread(this);
340         thread->start();
341         thread->init_complete->lock("PluginClient::show_gui");
342 // Must wait before sending any hide_gui
343         if( !thread->window ) return 1;
344         thread->window->init_wait();
345         return 0;
346 }
347
348 void PluginClient::raise_window()
349 {
350         if(thread && thread->window)
351         {
352                 thread->window->lock_window("PluginClient::raise_window");
353                 thread->window->raise_window();
354                 thread->window->flush();
355                 thread->window->unlock_window();
356         }
357 }
358
359 int PluginClient::set_string()
360 {
361         if(thread)
362         {
363                 thread->window->lock_window("PluginClient::set_string");
364                 thread->window->put_title(gui_string);
365                 thread->window->unlock_window();
366         }
367         return 0;
368 }
369
370
371
372
373
374 void PluginClient::begin_process_buffer()
375 {
376 // Delete all unused GUI frames
377         frame_buffer.remove_all_objects();
378 }
379
380
381 void PluginClient::end_process_buffer()
382 {
383         if(frame_buffer.size())
384         {
385                 send_render_gui();
386         }
387 }
388
389
390
391 void PluginClient::plugin_update_gui()
392 {
393
394         update_gui();
395
396 // Delete unused GUI frames
397         while(frame_buffer.size() > MAX_FRAME_BUFFER)
398                 frame_buffer.remove_object_number(0);
399
400 }
401
402 void PluginClient::update_gui()
403 {
404 }
405
406 int PluginClient::get_gui_update_frames()
407 {
408         if(frame_buffer.size())
409         {
410                 PluginClientFrame *frame = frame_buffer.get(0);
411                 int total_frames = update_timer->get_difference() *
412                         frame->period_d /
413                         frame->period_n /
414                         1000;
415                 if(total_frames) update_timer->subtract(total_frames *
416                         frame->period_n *
417                         1000 /
418                         frame->period_d);
419
420 // printf("PluginClient::get_gui_update_frames %d %ld %d %d %d\n",
421 // __LINE__,
422 // update_timer->get_difference(),
423 // frame->period_n * 1000 / frame->period_d,
424 // total_frames,
425 // frame_buffer.size());
426
427 // Add forced frames
428                 for(int i = 0; i < frame_buffer.size(); i++)
429                         if(frame_buffer.get(i)->force) total_frames++;
430                 total_frames = MIN(frame_buffer.size(), total_frames);
431
432
433                 return total_frames;
434         }
435         else
436         {
437                 return 0;
438         }
439 }
440
441 PluginClientFrame* PluginClient::get_gui_frame()
442 {
443         if(frame_buffer.size())
444         {
445                 PluginClientFrame *frame = frame_buffer.get(0);
446                 frame_buffer.remove_number(0);
447                 return frame;
448         }
449         else
450         {
451                 return 0;
452         }
453 }
454
455 void PluginClient::add_gui_frame(PluginClientFrame *frame)
456 {
457         frame_buffer.append(frame);
458 }
459
460 void PluginClient::send_render_gui()
461 {
462         server->send_render_gui(&frame_buffer);
463 }
464
465 void PluginClient::send_render_gui(void *data)
466 {
467         server->send_render_gui(data);
468 }
469
470 void PluginClient::send_render_gui(void *data, int size)
471 {
472         server->send_render_gui(data, size);
473 }
474
475 void PluginClient::plugin_render_gui(void *data, int size)
476 {
477         render_gui(data, size);
478 }
479
480
481 void PluginClient::plugin_render_gui(void *data)
482 {
483         render_gui(data);
484 }
485
486 void PluginClient::render_gui(void *data)
487 {
488         if(thread)
489         {
490                 thread->get_window()->lock_window("PluginClient::render_gui");
491
492 // Set all previous frames to draw immediately
493                 for(int i = 0; i < frame_buffer.size(); i++)
494                         frame_buffer.get(i)->force = 1;
495
496                 ArrayList<PluginClientFrame*> *src =
497                         (ArrayList<PluginClientFrame*>*)data;
498
499 // Shift GUI data to GUI client
500                 while(src->size())
501                 {
502                         this->frame_buffer.append(src->get(0));
503                         src->remove_number(0);
504                 }
505
506 // Start the timer for the current buffer
507                 update_timer->update();
508                 thread->get_window()->unlock_window();
509         }
510 }
511
512 void PluginClient::render_gui(void *data, int size)
513 {
514         printf("PluginClient::render_gui %d\n", __LINE__);
515 }
516
517
518
519
520
521
522
523
524 int PluginClient::is_audio() { return 0; }
525 int PluginClient::is_video() { return 0; }
526 int PluginClient::is_theme() { return 0; }
527 int PluginClient::uses_gui() { return 1; }
528 int PluginClient::is_transition() { return 0; }
529 int PluginClient::load_defaults()
530 {
531 //      printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
532         return 0;
533 }
534
535 int PluginClient::save_defaults()
536 {
537         save_defaults_xml();
538 //      printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
539         return 0;
540 }
541
542 void PluginClient::load_defaults_xml()
543 {
544         char path[BCTEXTLEN];
545         server->get_defaults_path(path);
546         FileSystem fs;
547         fs.complete_path(path);
548         using_defaults = 1;
549 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
550
551         KeyFrame temp_keyframe;
552         FILE *fp = fopen(path, "r");
553         if( fp ) {
554                 struct stat st;  int fd = fileno(fp);
555                 int64_t sz = !fstat(fd, &st) ? st.st_size : BCTEXTLEN;
556                 char *data = temp_keyframe.get_data(sz+1);
557                 int data_size = fread(data, 1, sz, fp);
558                 if( data_size < 0 ) data_size = 0;
559                 if( data_size > 0 ) {
560 // Get window extents
561                         int state = 0;
562                         for( int i=0; i<(data_size-8) && data[i]!='<'; ++i ) {
563                                 if( !isdigit(data[i]) ) continue;
564                                 if( !state ) {
565                                         window_x = atoi(data + i);
566                                         state = 1;
567                                 }
568                                 else {
569                                         window_y = atoi(data + i);
570                                         break;
571                                 }
572                                 while( i<data_size && isdigit(data[i]) ) ++i;
573                         }
574                         data[data_size] = 0;
575                         read_data(&temp_keyframe);
576                 }
577
578                 fclose(fp);
579         }
580         using_defaults = 0;
581 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
582 }
583
584 void PluginClient::save_defaults_xml()
585 {
586         char path[BCTEXTLEN];
587         server->get_defaults_path(path);
588         FileSystem fs;
589         fs.complete_path(path);
590         using_defaults = 1;
591
592         KeyFrame temp_keyframe;
593         save_data(&temp_keyframe);
594
595         const char *data = temp_keyframe.get_data();
596         int len = strlen(data);
597         FILE *fp = fopen(path, "w");
598
599         if( fp ) {
600                 fprintf(fp, "%d\n%d\n", window_x, window_y);
601                 if( len > 0 && !fwrite(data, len, 1, fp) ) {
602                         fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
603                                 __LINE__, path, len, strerror(errno));
604                 }
605                 fclose(fp);
606         }
607
608         using_defaults = 0;
609 }
610
611 int PluginClient::is_defaults()
612 {
613         return using_defaults;
614 }
615
616 BC_Hash* PluginClient::get_defaults()
617 {
618         return defaults;
619 }
620 PluginClientThread* PluginClient::get_thread()
621 {
622         return thread;
623 }
624
625 BC_WindowBase* PluginClient::new_window()
626 {
627         printf("PluginClient::new_window undefined in %s.\n", plugin_title());
628         return 0;
629 }
630 int PluginClient::get_parameters() { return 0; }
631 int PluginClient::get_samplerate() { return get_project_samplerate(); }
632 double PluginClient::get_framerate() { return get_project_framerate(); }
633 int PluginClient::init_realtime_parameters() { return 0; }
634 int PluginClient::delete_nonrealtime_parameters() { return 0; }
635 int PluginClient::start_loop() { return 0; };
636 int PluginClient::process_loop() { return 0; };
637 int PluginClient::stop_loop() { return 0; };
638
639 void PluginClient::set_interactive()
640 {
641         interactive = 1;
642 }
643
644 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
645 {
646         return recommended_size;
647 }
648
649 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
650 {
651         return recommended_size;
652 }
653
654 int PluginClient::get_gui_status()
655 {
656         return server->get_gui_status();
657 }
658
659 // close event from client side
660 void PluginClient::client_side_close()
661 {
662 // Last command executed
663         server->client_side_close();
664 }
665
666 int PluginClient::stop_gui_client()
667 {
668         if(!client_gui_on) return 0;
669         client_gui_on = 0;
670         return 0;
671 }
672
673 int PluginClient::get_project_samplerate()
674 {
675         return server->get_project_samplerate();
676 }
677
678 double PluginClient::get_project_framerate()
679 {
680         return server->get_project_framerate();
681 }
682
683 const char *PluginClient::get_source_path()
684 {
685         int64_t source_position = server->plugin->startproject;
686         Edit *edit = server->plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
687         Indexable *indexable = edit ? edit->get_source() : 0;
688         return indexable ? indexable->path : 0;
689 }
690
691
692 void PluginClient::update_display_title()
693 {
694         server->generate_display_title(gui_string);
695         set_string();
696 }
697
698 char* PluginClient::get_gui_string()
699 {
700         return gui_string;
701 }
702
703
704 char* PluginClient::get_path()
705 {
706         return server->path;
707 }
708
709 char* PluginClient::get_plugin_dir()
710 {
711         return server->preferences->plugin_dir;
712 }
713
714 int PluginClient::set_string_client(char *string)
715 {
716         strcpy(gui_string, string);
717         set_string();
718         return 0;
719 }
720
721
722 int PluginClient::get_interpolation_type()
723 {
724         return server->get_interpolation_type();
725 }
726
727
728 float PluginClient::get_red()
729 {
730         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
731         return !edl ? 0 : edl->local_session->use_max ?
732                 edl->local_session->red_max :
733                 edl->local_session->red;
734 }
735
736 float PluginClient::get_green()
737 {
738         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
739         return !edl ? 0 : edl->local_session->use_max ?
740                 edl->local_session->green_max :
741                 edl->local_session->green;
742 }
743
744 float PluginClient::get_blue()
745 {
746         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
747         return !edl ? 0 : edl->local_session->use_max ?
748                 edl->local_session->blue_max :
749                 edl->local_session->blue;
750 }
751
752
753 int64_t PluginClient::get_source_position()
754 {
755         return source_position;
756 }
757
758 int64_t PluginClient::get_source_start()
759 {
760         return source_start;
761 }
762
763 int64_t PluginClient::get_total_len()
764 {
765         return total_len;
766 }
767
768 int PluginClient::get_direction()
769 {
770         return direction;
771 }
772
773
774 int64_t PluginClient::local_to_edl(int64_t position)
775 {
776         return position;
777 }
778
779 int64_t PluginClient::edl_to_local(int64_t position)
780 {
781         return position;
782 }
783
784 int PluginClient::get_use_opengl()
785 {
786         return server->get_use_opengl();
787 }
788
789 int PluginClient::get_total_buffers()
790 {
791         return total_in_buffers;
792 }
793
794 int PluginClient::get_buffer_size()
795 {
796         return in_buffer_size;
797 }
798
799 int PluginClient::get_project_smp()
800 {
801 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
802         return smp;
803 }
804
805 const char* PluginClient::get_defaultdir()
806 {
807         return File::get_plugin_path();
808 }
809
810
811 int PluginClient::send_hide_gui()
812 {
813 // Stop the GUI server and delete GUI messages
814         client_gui_on = 0;
815         return 0;
816 }
817
818 int PluginClient::send_configure_change()
819 {
820         if(server->mwindow)
821                 server->mwindow->undo->update_undo_before(_("tweek"), this);
822 #ifdef USE_KEYFRAME_SPANNING
823         KeyFrame keyframe;
824         save_data(&keyframe);
825         server->apply_keyframe(&keyframe);
826 #else
827         KeyFrame* keyframe = server->get_keyframe();
828 // Call save routine in plugin
829         save_data(keyframe);
830 #endif
831         if(server->mwindow)
832                 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
833         server->sync_parameters();
834         return 0;
835 }
836
837
838 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
839 {
840         if(is_local) position = local_to_edl(position);
841         return server->get_prev_keyframe(position);
842 }
843
844 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
845 {
846         if(is_local) position = local_to_edl(position);
847         return server->get_next_keyframe(position);
848 }
849
850 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
851 {
852         server->get_camera(x, y, z, position, direction);
853 }
854
855 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
856 {
857         server->get_projector(x, y, z, position, direction);
858 }
859
860
861 EDLSession* PluginClient::get_edlsession()
862 {
863         if(server->edl)
864                 return server->edl->session;
865         return 0;
866 }
867
868 int PluginClient::gui_open()
869 {
870         return server->gui_open();
871 }