relax LinuxVST GUI event loop.
[ardour.git] / gtk2_ardour / linux_vst_gui_support.cc
1 /*
2     Copyright (C) 2012 Paul Davis 
3     Based on code by Paul Davis, Torben Hohn as part of FST
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 /******************************************************************/
22 /** VSTFX - An engine based on FST for handling linuxVST plugins **/
23 /******************************************************************/
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <libgen.h>
28 #include <assert.h>
29
30 #include <pthread.h>
31 #include <signal.h>
32 #include <glib.h>
33 #include <glibmm/timer.h>
34
35 #include "ardour/linux_vst_support.h"
36
37 #include <X11/X.h>
38 #include <X11/Xlib.h>
39 #include <dlfcn.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <pthread.h>
44 #include <sys/time.h>
45
46 struct ERect{
47     short top;
48     short left;
49     short bottom;
50     short right;
51 };
52
53 static pthread_mutex_t plugin_mutex;
54
55 static VSTState * vstfx_first = NULL;
56
57 const char magic[] = "VSTFX Plugin State v002";
58
59 int  gui_thread_id = 0;
60 static int gui_quit = 0;
61
62 /*This will be our connection to X*/
63
64 Display* LXVST_XDisplay = NULL;
65
66 /*The thread handle for the GUI event loop*/
67
68 pthread_t LXVST_gui_event_thread;
69
70 /*Util functions to get the value of a property attached to an XWindow*/
71
72 bool LXVST_xerror;
73
74 int TempErrorHandler(Display *display, XErrorEvent *e)
75 {
76         LXVST_xerror = true;
77         
78         return 0;
79 }
80
81 #ifdef LXVST_32BIT
82
83 int getXWindowProperty(Window window, Atom atom)
84 {
85         int result = 0;
86         int userSize;
87         unsigned long bytes;
88         unsigned long userCount;
89         unsigned char *data;
90         Atom userType;
91         LXVST_xerror = false;
92         
93         /*Use our own Xerror handler while we're in here - in an
94         attempt to stop the brain dead default Xerror behaviour of
95         qutting the entire application because of e.g. an invalid
96         window ID*/
97         
98         XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
99         
100         XGetWindowProperty(     LXVST_XDisplay,                 //The display
101                                                 window,                                 //The Window
102                                                 atom,                                   //The property
103                                                 0,                                              //Offset into the data
104                                                 1,                                              //Number of 32Bit chunks of data
105                                                 false,                                  //false = don't delete the property
106                                                 AnyPropertyType,                //Required property type mask
107                                                 &userType,                              //Actual type returned
108                                                 &userSize,                              //Actual format returned
109                                                 &userCount,                             //Actual number of items stored in the returned data
110                                                 &bytes,                                 //Number of bytes remaining if a partial read
111                                                 &data);                                 //The actual data read
112                                                 
113         if(LXVST_xerror == false && userCount == 1)
114                 result = *(int*)data;
115                 
116         XSetErrorHandler(olderrorhandler);
117         
118         /*Hopefully this will return zero if the property is not set*/
119         
120         return result;
121 }
122
123 #endif
124
125 #ifdef LXVST_64BIT
126
127 /********************************************************************/
128 /* This is untested - have no 64Bit plugins which use this          */
129 /* system of passing an eventProc address                           */
130 /********************************************************************/
131
132 long getXWindowProperty(Window window, Atom atom)
133 {
134         long result = 0;
135         int userSize;
136         unsigned long bytes;
137         unsigned long userCount;
138         unsigned char *data;
139         Atom userType;
140         LXVST_xerror = false;
141         
142         /*Use our own Xerror handler while we're in here - in an
143         attempt to stop the brain dead default Xerror behaviour of
144         qutting the entire application because of e.g. an invalid
145         window ID*/
146         
147         XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
148         
149         XGetWindowProperty(     LXVST_XDisplay, 
150                                                 window, 
151                                                 atom,
152                                                 0,
153                                                 2,
154                                                 false,
155                                                 AnyPropertyType, 
156                                                 &userType,
157                                                 &userSize,
158                                                 &userCount,
159                                                 &bytes,
160                                                 &data);
161                                                 
162         if(LXVST_xerror == false && userCount == 1)
163                 result = *(long*)data;
164                 
165         XSetErrorHandler(olderrorhandler);
166         
167         /*Hopefully this will return zero if the property is not set*/
168         
169         return result;
170 }
171
172 #endif
173
174 /*The event handler - called from within the main GUI thread to
175 dispatch events to any VST UIs which have callbacks stuck to them*/
176
177 static void
178 dispatch_x_events (XEvent* event, VSTState* vstfx)
179 {
180         /*Handle some of the Events we might be interested in*/
181         
182         switch(event->type)
183         {
184                 /*Configure event - when the window is resized or first drawn*/
185                         
186                 case ConfigureNotify:
187                 {
188                         Window window = event->xconfigure.event;
189                         
190                         int width = event->xconfigure.width;
191                         int height = event->xconfigure.height;
192                         
193                         /*If we get a config notify on the parent window XID then we need to see
194                         if the size has been changed - some plugins re-size their UI window e.g.
195                         when opening a preset manager (you might think that should be spawned as a new window...) */
196                         
197                         /*if the size has changed, we flag this so that in lxvst_pluginui.cc we can make the
198                         change to the GTK parent window in ardour, from its UI thread*/ 
199                         
200                         if (window == (Window) (vstfx->linux_window)) {
201                                 if (width != vstfx->width || height!=vstfx->height) {
202                                         vstfx->width = width;
203                                         vstfx->height = height;
204                                         vstfx->want_resize = 1;
205                                         
206                                         /*QUIRK : Loomer plugins not only resize the UI but throw it into some random
207                                         position at the same time. We need to re-position the window at the origin of
208                                         the parent window*/
209                                         
210                                         if (vstfx->linux_plugin_ui_window) {
211                                                 XMoveWindow (LXVST_XDisplay, vstfx->linux_plugin_ui_window, 0, 0);
212                                         }
213                                 }
214                         }
215                         
216                         break;
217                         
218                 }
219                 
220                 /*Reparent Notify - when the plugin UI is reparented into
221                 our Host Window we will get an event here... probably... */
222                 
223                 case ReparentNotify:
224                 {
225                         Window ParentWindow = event->xreparent.parent;
226                         
227                         /*If the ParentWindow matches the window for the vstfx instance then
228                         the Child window must be the XID of the pluginUI window created by the
229                         plugin, so we need to see if it has a callback stuck to it, and if so
230                         set that up in the vstfx */
231                         
232                         /***********************************************************/
233                         /* 64Bit --- This mechanism is not 64Bit compatible at the */
234                         /* present time                                            */
235                         /***********************************************************/
236                         
237                         if (ParentWindow == (Window) (vstfx->linux_window)) {
238
239                                 Window PluginUIWindowID = event->xreparent.window;
240                                 
241                                 vstfx->linux_plugin_ui_window = PluginUIWindowID;
242 #ifdef LXVST_32BIT
243                                 int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
244         
245                                 if (result == 0) {
246                                         vstfx->eventProc = NULL;
247                                 } else {
248                                         vstfx->eventProc = (void (*) (void* event))result;
249                                 }
250 #endif
251 #ifdef LXVST_64BIT
252                                 long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
253         
254                                 if(result == 0)
255                                         vstfx->eventProc = NULL;
256                                 else
257                                         vstfx->eventProc = (void (*) (void* event))result;
258 #endif
259                         }
260                         break;
261                 }
262                 
263                 case ClientMessage:
264                 {
265                         Window window = event->xany.window;
266                         Atom message_type = event->xclient.message_type;
267                         
268                         /*The only client message we are interested in is to signal
269                         that the plugin parent window is now valid and can be passed
270                         to effEditOpen when the editor is launched*/
271                         
272                         if (window == (Window) (vstfx->linux_window)) {
273                                 char* message = XGetAtomName(LXVST_XDisplay, message_type);
274                                 
275                                 if (strcmp(message,"LaunchEditor") == 0) {
276                                         if (event->xclient.data.l[0] == 0x0FEEDBAC) {
277                                                 vstfx_launch_editor (vstfx);
278                                         }
279                                 }
280                                 
281                                 XFree(message);
282                         }
283                         break;
284                 }
285                 
286                 default:
287                         break;
288         }
289         
290         /* Some VSTs built with toolkits e.g. JUCE will manager their own UI
291         autonomously in the plugin, running the UI in its own thread, so once
292         we have created a parent window for the plugin, its UI takes care of
293         itself.*/
294         
295         /*Other types register a callback as an Xwindow property on the plugin
296         UI window after they create it.  If that is the case, we need to call it
297         here, passing the XEvent into it*/
298         
299         if (vstfx->eventProc == NULL) {
300                 return;
301         }
302                                 
303         vstfx->eventProc((void*)event);
304 }
305
306 static void
307 maybe_set_program (VSTState* vstfx)
308 {
309         if (vstfx->want_program != -1) {
310                 if (vstfx->vst_version >= 2) {
311                         vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
312                 }
313
314                 vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
315                 
316                 if (vstfx->vst_version >= 2) {
317                         vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
318                 }
319                 
320                 vstfx->want_program = -1; 
321         }
322
323         if (vstfx->want_chunk == 1) {
324                 vstfx->plugin->dispatcher (vstfx->plugin, 24 /* effSetChunk */, 1, vstfx->wanted_chunk_size, vstfx->wanted_chunk, 0);
325                 vstfx->want_chunk = 0;
326         }
327 }
328
329 /** This is the main gui event loop for the plugin, we also need to pass
330 any Xevents to all the UI callbacks plugins 'may' have registered on their
331 windows, that is if they don't manage their own UIs **/
332
333 void* gui_event_loop (void* ptr)
334 {
335         VSTState* vstfx;
336         int LXVST_sched_timer_interval = 40; //ms, 25fps
337         XEvent event;
338         uint64_t clock1, clock2;
339         
340         clock1 = g_get_monotonic_time();
341         /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
342         
343         while (!gui_quit)
344         {
345                 /* handle window creation requests, destroy requests, 
346                    and run idle callbacks */
347
348                 /*Look at the XEvent queue - if there are any XEvents we need to handle them,
349                 including passing them to all the plugin (eventProcs) we are currently managing*/
350                 
351                 bool may_sleep = true;
352
353                 if(LXVST_XDisplay)
354                 {
355                         /*See if there are any events in the queue*/
356                 
357                         int num_events = XPending(LXVST_XDisplay);
358
359                         if (num_events > 0) {
360                                 // keep dispatching events as fast as possible
361                                 may_sleep = false;
362                         }
363                         
364                         /*process them if there are any*/
365                 
366                         while(num_events)
367                         {
368                                 XNextEvent(LXVST_XDisplay, &event);
369                                 
370                                 /*Call dispatch events, with the event, for each plugin in the linked list*/
371                                 
372                                 for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
373                                 {       
374                                         pthread_mutex_lock(&vstfx->lock);
375                                         
376                                         dispatch_x_events(&event, vstfx);
377                                         
378                                         pthread_mutex_unlock(&vstfx->lock);
379                                 }
380                                 
381                                 num_events--;
382                         }
383                 }
384
385                 /*We don't want to use all the CPU.. */
386
387                 Glib::usleep(1000);
388                 
389                 /*See if its time for us to do a scheduled event pass on all the plugins*/
390
391                 clock2 = g_get_monotonic_time();
392                 const int64_t elapsed_time_ms = (clock2 - clock1) / 1000;
393
394                 if((LXVST_sched_timer_interval != 0) && elapsed_time_ms >= LXVST_sched_timer_interval)
395                 {
396                         //printf("elapsed %d ms ^= %.2f Hz\n", elapsed_time_ms, 1000.0/(double)elapsed_time_ms); // DEBUG
397                         pthread_mutex_lock (&plugin_mutex);
398                     
399 again:
400                         /*Parse through the linked list of plugins*/
401                         
402                         for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
403                         {       
404                                 pthread_mutex_lock (&vstfx->lock);
405
406                                 /*Window scheduled for destruction*/
407                                 
408                                 if (vstfx->destroy) {
409                                         if (vstfx->linux_window) {
410                                                 vstfx->plugin->dispatcher (vstfx->plugin, effEditClose, 0, 0, NULL, 0.0);
411                                                         
412                                                 XDestroyWindow (LXVST_XDisplay, vstfx->linux_window);
413                                                 /* FIXME - probably safe to assume we never have an XID of 0 but not explicitly true */
414                                                 vstfx->linux_window = 0;
415                                                 vstfx->destroy = FALSE;
416                                         }
417                                         
418                                         vstfx_event_loop_remove_plugin (vstfx);
419                                         vstfx->been_activated = FALSE;
420                                         pthread_cond_signal (&vstfx->window_status_change);
421                                         pthread_mutex_unlock (&vstfx->lock);
422                                         
423                                         goto again;
424                                 } 
425                                 
426                                 /*Window does not yet exist - scheduled for creation*/
427
428                                 /* FIXME - probably safe to assume 0 is not a valid XID but not explicitly true */
429                                 if (vstfx->linux_window == 0) {
430                                         if (vstfx_create_editor (vstfx)) {
431                                                 vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
432                                                 vstfx_event_loop_remove_plugin (vstfx);
433                                                 pthread_cond_signal (&vstfx->window_status_change);
434                                                 pthread_mutex_unlock (&vstfx->lock);
435                                                 goto again;
436                                         } else {
437                                                 /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
438                                         }
439                                 }
440
441                                 maybe_set_program (vstfx);
442                                 vstfx->want_program = -1;
443                                 vstfx->want_chunk = 0;
444                                 
445                                 /*scheduled call to dispatcher*/
446                                 
447                                 if (vstfx->dispatcher_wantcall) {
448                                         vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
449                                                 vstfx->plugin, 
450                                                 vstfx->dispatcher_opcode,
451                                                 vstfx->dispatcher_index,
452                                                 vstfx->dispatcher_val,
453                                                 vstfx->dispatcher_ptr,
454                                                 vstfx->dispatcher_opt
455                                                 );
456                                         
457                                         vstfx->dispatcher_wantcall = 0;
458                                         pthread_cond_signal (&vstfx->plugin_dispatcher_called);
459                                 }
460                                 
461                                 /*Call the editor Idle function in the plugin*/
462                                 
463                                 vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
464
465                                 if(vstfx->wantIdle)
466                                         vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
467                                         
468                                 pthread_mutex_unlock (&vstfx->lock);
469                         }
470                         pthread_mutex_unlock (&plugin_mutex);
471
472                         clock1 = g_get_monotonic_time();
473                 }
474
475                 if (may_sleep && elapsed_time_ms + 1 < LXVST_sched_timer_interval) {
476                         Glib::usleep(1000 * (LXVST_sched_timer_interval - elapsed_time_ms - 1));
477                 }
478         }
479
480         /*Drop out to here if we set gui_quit to 1 */
481
482         return NULL;
483 }
484
485 /*The VSTFX Init function - this needs to be called before the VSTFX engine
486 can be accessed, it gets the UI thread running, opens a connection to X etc
487 normally started in globals.cc*/
488
489 int vstfx_init (void* ptr)
490 {
491
492         int thread_create_result;
493         
494         pthread_attr_t thread_attributes;
495         
496         /*Init the attribs to defaults*/
497         
498         pthread_attr_init(&thread_attributes);
499         
500         /*Make sure the thread is joinable - this should be the default anyway - 
501         so we can join to it on vstfx_exit*/
502         
503         pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
504         
505
506         /*This is where we need to open a connection to X, and start the GUI thread*/
507         
508         /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
509         will talk to X down this connection - X cannot handle multi-threaded access via
510         the same Display* */
511         
512         if(LXVST_XDisplay==NULL)
513                 LXVST_XDisplay = XOpenDisplay(NULL);    //We might be able to make this open a specific screen etc
514
515         /*Drop out and report the error if we fail to connect to X */
516         
517         if(LXVST_XDisplay==NULL)
518         {
519                 vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
520                 
521                 return -1;
522         }
523         
524         /*We have a connection to X - so start the gui event loop*/
525         
526         /*Create the thread - use default attrs for now, don't think we need anything special*/
527         
528         thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
529         
530         if(thread_create_result!=0)
531         {
532                 /*There was a problem starting the GUI event thread*/
533                 
534                 vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
535                 
536                 XCloseDisplay(LXVST_XDisplay);
537                 
538                 return -1;
539         }
540         
541         return 0;
542 }
543
544 /*The vstfx Quit function*/
545
546 void vstfx_exit()
547 {
548         gui_quit = 1;
549         
550         /*We need to pthread_join the gui_thread here so
551         we know when it has stopped*/
552         
553         pthread_join(LXVST_gui_event_thread, NULL);
554 }
555
556 /*Adds a new plugin (VSTFX) instance to the linked list*/
557
558 int vstfx_run_editor (VSTState* vstfx)
559 {
560         pthread_mutex_lock (&plugin_mutex);
561
562         /* Add the new VSTFX instance to the linked list */
563
564         if (vstfx_first == NULL) {
565                 vstfx_first = vstfx;
566         } else {
567                 VSTState* p = vstfx_first;
568                 
569                 while (p->next) {
570                         p = p->next;
571                 }
572                 p->next = vstfx;
573                 
574                 /* Mark the new end of the list */
575                 
576                 vstfx->next = NULL;
577         }
578
579         pthread_mutex_unlock (&plugin_mutex);
580
581         /* wait for the plugin editor window to be created (or not) */
582
583         pthread_mutex_lock (&vstfx->lock);
584         
585         if (!vstfx->linux_window) {
586                 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
587         }
588         
589         pthread_mutex_unlock (&vstfx->lock);
590
591         if (!vstfx->linux_window) {
592                 return -1;
593         }
594
595         return 0;
596 }
597
598
599 /*Creates an editor for the plugin - normally called from within the gui event loop
600 after run_editor has added the plugin (editor) to the linked list*/
601
602 int vstfx_create_editor (VSTState* vstfx)
603 {
604         Window parent_window;
605         
606         int x_size = 1;
607         int y_size = 1;
608
609         /* Note: vstfx->lock is held while this function is called */
610
611         if (!(vstfx->plugin->flags & effFlagsHasEditor))
612         {
613                 vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
614                 return -1;
615         }
616         
617         
618         /*Create an XWindow for the plugin to inhabit*/
619         
620         parent_window = XCreateSimpleWindow (
621                 LXVST_XDisplay,
622                 DefaultRootWindow(LXVST_XDisplay),
623                 0,
624                 0,
625                 x_size,
626                 y_size,
627                 0,
628                 0,
629                 0
630                 );
631                                                                                 
632         /*Select the events we are interested in receiving - we need Substructure notify so that
633         if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
634         
635         XSelectInput(LXVST_XDisplay, 
636                                 parent_window,
637                                 SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
638                                                                                 
639         vstfx->linux_window = parent_window;
640                                                                                 
641         vstfx->xid = parent_window;  //vstfx->xid will be referenced to connect to GTK UI in ardour later
642         
643         /*Because the plugin may be operating on a different Display* to us, and therefore
644         the two event queues can be asynchronous, although we have created the window on
645         our display, we can't guarantee it exists in the server yet, which will
646         cause BadWindow crashes if the plugin tries to use it.
647         
648         It would be nice to use CreateNotify events here, but they don't get
649         through on all window managers, so instead we pass a client message
650         into out queue, after the XCreateWindow.  When this message pops out
651         in our event handler, it will trigger the second stage of plugin
652         Editor instantiation, and by then the Window should be valid...*/
653         
654         XClientMessageEvent event;
655         
656         /*Create an atom to identify our message (only if it doesn't already exist)*/
657         
658         Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
659         
660         event.type = ClientMessage;
661         event.send_event = true;
662         event.window = parent_window;
663         event.message_type = WindowActiveAtom;
664
665         event.format = 32;                                              //Data format
666         event.data.l[0] = 0x0FEEDBAC;                   //Something we can recognize later
667         
668         /*Push the event into the queue on our Display*/
669         
670         XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
671
672         /*Unlock - and we are done for the first part of staring the Editor...*/
673         
674         pthread_mutex_unlock (&vstfx->lock);
675         
676         return 0;
677 }
678
679 int
680 vstfx_launch_editor (VSTState* vstfx)
681 {
682         /*This is the second stage of launching the editor (see vstfx_create editor)
683         we get called here in response to receiving the ClientMessage on our Window,
684         therefore it's about as safe (as can be) to assume that the Window we created
685         is now valid in the XServer and can be passed to the plugin in effEditOpen
686         without generating BadWindow errors when the plugin reparents itself into our
687         parent window*/
688         
689         if(vstfx->been_activated)
690                 return 0;
691         
692         Window parent_window;
693         struct ERect* er;
694         
695         int x_size = 1;
696         int y_size = 1;
697         
698         parent_window = vstfx->linux_window;
699         
700         /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
701         it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
702         Display* as a long */
703         
704         /**************************************************************/
705         /* 64Bit --- parent window is an int passed as a void* so     */
706         /* that should be ok for 64Bit machines                       */
707         /*                                                            */
708         /* Display is passed in as a long - ok on arch's where sizeof */
709         /* long = 8                                                   */
710         /*                                                            */
711         /* Most linux VST plugins open a connection to X on their own */
712         /* Display anyway so it may not matter                        */
713         /*                                                            */
714         /* linuxDSP VSTs don't use the host Display* at all           */
715         /**************************************************************/
716         
717         vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
718         
719         /*QUIRK - some plugins need a slight delay after opening the editor before you can
720         ask the window size or they might return zero - specifically discoDSP */
721         
722         Glib::usleep(100000);
723         
724         /*Now we can find out how big the parent window should be (and try) to resize it*/
725         
726         vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
727
728         x_size = er->right - er->left;
729         y_size = er->bottom - er->top;
730         
731         vstfx->width =  x_size;
732         vstfx->height =  y_size;
733         
734         XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
735         
736         XFlush (LXVST_XDisplay);
737         
738         /*Not sure if we need to map the window or if the plugin will do it for us
739         it should be ok because XReparentWindow generates a Map event*/
740         
741         /*mark the editor as activated - mainly so that vstfx_get_XID
742         will know it is valid*/
743
744         vstfx->been_activated = TRUE;
745         
746         pthread_cond_signal (&vstfx->window_status_change);
747         return 0;
748 }
749
750 /** Destroy the editor window */
751 void
752 vstfx_destroy_editor (VSTState* vstfx)
753 {
754         pthread_mutex_lock (&vstfx->lock);
755         if (vstfx->linux_window) {
756                 vstfx->destroy = TRUE;
757                 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
758         }
759         pthread_mutex_unlock (&vstfx->lock);
760 }
761
762 /** Remove a vstfx instance from the linked list parsed by the
763     event loop
764 */
765 void
766 vstfx_event_loop_remove_plugin (VSTState* vstfx)
767 {
768         /* This only ever gets called from within our GUI thread
769            so we don't need to lock here - if we did there would be
770            a deadlock anyway
771         */
772         
773         VSTState* p;
774         VSTState* prev;
775         
776         for (p = vstfx_first, prev = NULL; p; prev = p, p = p->next) {
777                 if (p == vstfx) {
778                         if (prev) {
779                                 prev->next = p->next;
780                                 break;
781                         }
782                 }
783         }
784
785         // if this function is called, there must be
786         // at least one plugin in the linked list
787         assert(vstfx_first);
788
789         if (vstfx_first == vstfx) {
790                 vstfx_first = vstfx_first->next;
791         }
792 }
793