repair selected_to_clipboard bug
[goodguy/cinelerra.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 #include <stdio.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <fcntl.h>
50 #include <string.h>
51 #include <ctype.h>
52 #include <errno.h>
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                 VFrame *picon = client->server->get_picon();
85                 if( picon ) window->set_icon(picon);
86                 window->unlock_window();
87
88 /* Only set it here so tracking doesn't update it until everything is created. */
89                 client->thread = this;
90                 init_complete->unlock();
91
92                 result = window->run_window();
93                 window->lock_window("PluginClientThread::run");
94 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
95                 window->hide_window(1);
96                 window->unlock_window();
97                 window->done_event(result);
98 // Can't save defaults in the destructor because it's not called immediately
99 // after closing.
100                 /* if(client->defaults) */ client->save_defaults_xml();
101 /* This is needed when the GUI is closed from itself */
102                 if(result) client->client_side_close();
103         }
104         else
105 // No window
106         {
107                 client->thread = this;
108                 init_complete->unlock();
109         }
110 }
111
112 BC_WindowBase* PluginClientThread::get_window()
113 {
114         return window;
115 }
116
117 PluginClient* PluginClientThread::get_client()
118 {
119         return client;
120 }
121
122
123
124
125
126
127 PluginClientFrame::PluginClientFrame(int data_size,
128         int period_n,
129         int period_d)
130 {
131         this->data_size = data_size;
132         force = 0;
133         this->period_n = period_n;
134         this->period_d = period_d;
135 }
136
137 PluginClientFrame::~PluginClientFrame()
138 {
139
140 }
141
142
143
144
145
146 PluginClientWindow::PluginClientWindow(PluginClient *client,
147         int w, int h, int min_w, int min_h, int allow_resize)
148  : BC_Window(client->gui_string,
149         client->window_x /* - w / 2 */,
150         client->window_y /* - h / 2 */,
151         (int)(w*get_resources()->font_scale+0.5), (int)(h*get_resources()->font_scale+0.5),
152         (int)(min_w*get_resources()->font_scale+0.5), (int)(min_h*get_resources()->font_scale+0.5),
153         allow_resize, 0, 1)
154 {
155         this->client = client;
156 }
157
158 PluginClientWindow::PluginClientWindow(const char *title,
159         int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
160  : BC_Window(title, x, y,
161         (int)(w*get_resources()->font_scale+0.5), (int)(h*get_resources()->font_scale+0.5),
162         (int)(min_w*get_resources()->font_scale+0.5), (int)(min_h*get_resources()->font_scale+0.5),
163         allow_resize, 0, 1)
164 {
165         this->client = 0;
166 }
167
168 PluginClientWindow::~PluginClientWindow()
169 {
170 }
171
172
173 int PluginClientWindow::translation_event()
174 {
175         if(client)
176         {
177                 client->window_x = get_x();
178                 client->window_y = get_y();
179         }
180
181         return 1;
182 }
183
184 int PluginClientWindow::close_event()
185 {
186 /* Set result to 1 to indicate a client side close */
187         set_done(1);
188         return 1;
189 }
190
191
192
193
194
195 PluginClient::PluginClient(PluginServer *server)
196 {
197         reset();
198         this->server = server;
199         smp = server->preferences->project_smp;
200         defaults = 0;
201         update_timer = new Timer;
202 // Virtual functions don't work here.
203 }
204
205 PluginClient::~PluginClient()
206 {
207         if( thread ) {
208                 hide_gui();
209                 thread->join();
210                 delete thread;
211         }
212
213 // Virtual functions don't work here.
214         if(defaults) delete defaults;
215         frame_buffer.remove_all_objects();
216         delete update_timer;
217 }
218
219 int PluginClient::reset()
220 {
221         window_x = -1;
222         window_y = -1;
223         interactive = 0;
224         show_initially = 0;
225         wr = rd = 0;
226         master_gui_on = 0;
227         client_gui_on = 0;
228         realtime_priority = 0;
229         gui_string[0] = 0;
230         total_in_buffers = 0;
231         total_out_buffers = 0;
232         source_position = 0;
233         source_start = 0;
234         total_len = 0;
235         direction = PLAY_FORWARD;
236         thread = 0;
237         using_defaults = 0;
238         return 0;
239 }
240
241
242 void PluginClient::hide_gui()
243 {
244         if(thread && thread->window)
245         {
246 //printf("PluginClient::delete_thread %d\n", __LINE__);
247 /* This is needed when the GUI is closed from elsewhere than itself */
248 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
249 /* Thread join will wait if this was not called from the thread itself or go on if it was */
250                 thread->window->lock_window("PluginClient::hide_gui");
251                 thread->window->set_done(0);
252 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
253                 thread->window->unlock_window();
254         }
255 }
256
257 // For realtime plugins initialize buffers
258 int PluginClient::plugin_init_realtime(int realtime_priority,
259         int total_in_buffers,
260         int buffer_size)
261 {
262
263 // Get parameters for all
264         master_gui_on = get_gui_status();
265
266
267
268 // get parameters depending on video or audio
269         init_realtime_parameters();
270
271         this->realtime_priority = realtime_priority;
272         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
273         this->out_buffer_size = this->in_buffer_size = buffer_size;
274         return 0;
275 }
276
277 int PluginClient::plugin_start_loop(int64_t start,
278         int64_t end,
279         int64_t buffer_size,
280         int total_buffers)
281 {
282 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
283 // __LINE__, start, end, buffer_size, total_buffers);
284         this->source_start = start;
285         this->total_len = end - start;
286         this->start = start;
287         this->end = end;
288         this->in_buffer_size = this->out_buffer_size = buffer_size;
289         this->total_in_buffers = this->total_out_buffers = total_buffers;
290         start_loop();
291         return 0;
292 }
293
294 int PluginClient::plugin_process_loop()
295 {
296         return process_loop();
297 }
298
299 int PluginClient::plugin_stop_loop()
300 {
301         return stop_loop();
302 }
303
304 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
305 {
306         return server->start_progress(string, length);
307 }
308
309
310 // Non realtime parameters
311 int PluginClient::plugin_get_parameters()
312 {
313         int result = get_parameters();
314         if(defaults) save_defaults();
315         return result;
316 }
317
318 // ========================= main loop
319
320 int PluginClient::is_multichannel() { return 0; }
321 int PluginClient::is_synthesis() { return 0; }
322 int PluginClient::is_realtime() { return 0; }
323 int PluginClient::is_fileio() { return 0; }
324 int PluginClient::delete_buffer_ptrs() { return 0; }
325 const char* PluginClient::plugin_title() { return _("Untitled"); }
326
327 Theme* PluginClient::new_theme() { return 0; }
328
329 int PluginClient::load_configuration()
330 {
331         return 0;
332 }
333
334 Theme* PluginClient::get_theme()
335 {
336         return server->get_theme();
337 }
338
339 int PluginClient::show_gui()
340 {
341         load_configuration();
342         thread = new PluginClientThread(this);
343         thread->start();
344         thread->init_complete->lock("PluginClient::show_gui");
345 // Must wait before sending any hide_gui
346         if( !thread->window ) return 1;
347         thread->window->init_wait();
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         char *data = 0;
555         int64_t len = -1;
556         struct stat st;
557         int fd = open(path, O_RDONLY);
558         if( fd >= 0 && !fstat(fd, &st) ) {
559                 int64_t sz = st.st_size;
560                 data = new char[sz+1];
561                 len = read(fd, data, sz);
562                 close(fd);
563         }
564         if( data && len >= 0 ) {
565                 data[len] = 0;
566 // Get window extents
567                 int i = 0;
568                 for( int state=0; i<len && state>=0; ++i ) {
569                         if( !data[i] || data[i] == '<' ) break;
570                         if( !isdigit(data[i]) ) continue;
571                         if( !state ) {
572                                 window_x = atoi(data+i);
573                                 state = 1;
574                         }
575                         else {
576                                 window_y = atoi(data+i);
577                                 state = -1;
578                         }
579                         while( i<len && isdigit(data[i]) ) ++i;
580                 }
581                 KeyFrame keyframe(data+i, len-i);
582                 read_data(&keyframe);
583         }
584         delete [] data;
585
586         using_defaults = 0;
587 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
588 }
589
590 void PluginClient::save_defaults_xml()
591 {
592         char path[BCTEXTLEN];
593         server->get_defaults_path(path);
594         FileSystem fs;
595         fs.complete_path(path);
596         using_defaults = 1;
597
598         KeyFrame temp_keyframe;
599         save_data(&temp_keyframe);
600
601         const char *data = temp_keyframe.get_data();
602         int len = strlen(data);
603         FILE *fp = fopen(path, "w");
604
605         if( fp ) {
606                 fprintf(fp, "%d\n%d\n", window_x, window_y);
607                 if( len > 0 && !fwrite(data, len, 1, fp) ) {
608                         fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
609                                 __LINE__, path, len, strerror(errno));
610                 }
611                 fclose(fp);
612         }
613
614         using_defaults = 0;
615 }
616
617 int PluginClient::is_defaults()
618 {
619         return using_defaults;
620 }
621
622 BC_Hash* PluginClient::get_defaults()
623 {
624         return defaults;
625 }
626 PluginClientThread* PluginClient::get_thread()
627 {
628         return thread;
629 }
630
631 BC_WindowBase* PluginClient::new_window()
632 {
633         printf("PluginClient::new_window undefined in %s.\n", plugin_title());
634         return 0;
635 }
636 int PluginClient::get_parameters() { return 0; }
637 int PluginClient::get_samplerate() { return get_project_samplerate(); }
638 double PluginClient::get_framerate() { return get_project_framerate(); }
639 int PluginClient::init_realtime_parameters() { return 0; }
640 int PluginClient::delete_nonrealtime_parameters() { return 0; }
641 int PluginClient::start_loop() { return 0; };
642 int PluginClient::process_loop() { return 0; };
643 int PluginClient::stop_loop() { return 0; };
644
645 void PluginClient::set_interactive()
646 {
647         interactive = 1;
648 }
649
650 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
651 {
652         return recommended_size;
653 }
654
655 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
656 {
657         return recommended_size;
658 }
659
660 int PluginClient::get_gui_status()
661 {
662         return server->get_gui_status();
663 }
664
665 // close event from client side
666 void PluginClient::client_side_close()
667 {
668 // Last command executed
669         server->client_side_close();
670 }
671
672 int PluginClient::stop_gui_client()
673 {
674         if(!client_gui_on) return 0;
675         client_gui_on = 0;
676         return 0;
677 }
678
679 int PluginClient::get_project_samplerate()
680 {
681         return server->get_project_samplerate();
682 }
683
684 double PluginClient::get_project_framerate()
685 {
686         return server->get_project_framerate();
687 }
688
689 const char *PluginClient::get_source_path()
690 {
691         int64_t source_position = server->plugin->startproject;
692         Edit *edit = server->plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
693         Indexable *indexable = edit ? edit->get_source() : 0;
694         return indexable ? indexable->path : 0;
695 }
696
697
698 void PluginClient::update_display_title()
699 {
700         server->generate_display_title(gui_string);
701         set_string();
702 }
703
704 char* PluginClient::get_gui_string()
705 {
706         return gui_string;
707 }
708
709
710 char* PluginClient::get_path()
711 {
712         return server->path;
713 }
714
715 char* PluginClient::get_plugin_dir()
716 {
717         return server->preferences->plugin_dir;
718 }
719
720 int PluginClient::set_string_client(char *string)
721 {
722         strcpy(gui_string, string);
723         set_string();
724         return 0;
725 }
726
727
728 int PluginClient::get_interpolation_type()
729 {
730         return server->get_interpolation_type();
731 }
732
733
734 float PluginClient::get_red()
735 {
736         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
737         return !edl ? 0 : edl->local_session->use_max ?
738                 edl->local_session->red_max :
739                 edl->local_session->red;
740 }
741
742 float PluginClient::get_green()
743 {
744         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
745         return !edl ? 0 : edl->local_session->use_max ?
746                 edl->local_session->green_max :
747                 edl->local_session->green;
748 }
749
750 float PluginClient::get_blue()
751 {
752         EDL *edl = server->mwindow ? server->mwindow->edl : server->edl;
753         return !edl ? 0 : edl->local_session->use_max ?
754                 edl->local_session->blue_max :
755                 edl->local_session->blue;
756 }
757
758
759 int64_t PluginClient::get_source_position()
760 {
761         return source_position;
762 }
763
764 int64_t PluginClient::get_source_start()
765 {
766         return source_start;
767 }
768
769 int64_t PluginClient::get_total_len()
770 {
771         return total_len;
772 }
773
774 int PluginClient::get_direction()
775 {
776         return direction;
777 }
778
779
780 int64_t PluginClient::local_to_edl(int64_t position)
781 {
782         return position;
783 }
784
785 int64_t PluginClient::edl_to_local(int64_t position)
786 {
787         return position;
788 }
789
790 int PluginClient::get_use_opengl()
791 {
792         return server->get_use_opengl();
793 }
794
795 int PluginClient::get_total_buffers()
796 {
797         return total_in_buffers;
798 }
799
800 int PluginClient::get_buffer_size()
801 {
802         return in_buffer_size;
803 }
804
805 int PluginClient::get_project_smp()
806 {
807 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
808         return smp;
809 }
810
811 const char* PluginClient::get_defaultdir()
812 {
813         return File::get_plugin_path();
814 }
815
816
817 int PluginClient::send_hide_gui()
818 {
819 // Stop the GUI server and delete GUI messages
820         client_gui_on = 0;
821         return 0;
822 }
823
824 int PluginClient::send_configure_change()
825 {
826         if(server->mwindow)
827                 server->mwindow->undo->update_undo_before(_("tweek"), this);
828 #ifdef USE_KEYFRAME_SPANNING
829         KeyFrame keyframe;
830         save_data(&keyframe);
831         server->apply_keyframe(&keyframe);
832 #else
833         KeyFrame* keyframe = server->get_keyframe();
834 // Call save routine in plugin
835         save_data(keyframe);
836 #endif
837         if(server->mwindow)
838                 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
839         server->sync_parameters();
840         return 0;
841 }
842
843
844 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
845 {
846         if(is_local) position = local_to_edl(position);
847         return server->get_prev_keyframe(position);
848 }
849
850 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
851 {
852         if(is_local) position = local_to_edl(position);
853         return server->get_next_keyframe(position);
854 }
855
856 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
857 {
858         server->get_camera(x, y, z, position, direction);
859 }
860
861 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
862 {
863         server->get_projector(x, y, z, position, direction);
864 }
865
866
867 EDLSession* PluginClient::get_edlsession()
868 {
869         if(server->edl)
870                 return server->edl->session;
871         return 0;
872 }
873
874 int PluginClient::gui_open()
875 {
876         return server->gui_open();
877 }