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