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