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