ardour
linux_vst_gui_support.cc
Go to the documentation of this file.
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 /******************************************************************/
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 
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 
69 
70 /*Util functions to get the value of a property attached to an XWindow*/
71 
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
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 
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  if(LXVST_XDisplay)
352  {
353  /*See if there are any events in the queue*/
354 
355  int num_events = XPending(LXVST_XDisplay);
356 
357  /*process them if there are any*/
358 
359  while(num_events)
360  {
361  XNextEvent(LXVST_XDisplay, &event);
362 
363  /*Call dispatch events, with the event, for each plugin in the linked list*/
364 
365  for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
366  {
367  pthread_mutex_lock(&vstfx->lock);
368 
369  dispatch_x_events(&event, vstfx);
370 
371  pthread_mutex_unlock(&vstfx->lock);
372  }
373 
374  num_events--;
375  }
376  }
377 
378  /*We don't want to use all the CPU.. */
379 
380  Glib::usleep(1000);
381 
382  /*See if its time for us to do a scheduled event pass on all the plugins*/
383 
384  clock2 = g_get_monotonic_time();
385  const int64_t elapsed_time_ms = (clock2 - clock1) / 1000;
386 
387  if((LXVST_sched_timer_interval != 0) && elapsed_time_ms >= LXVST_sched_timer_interval)
388  {
389  //printf("elapsed %d ms ^= %.2f Hz\n", elapsed_time_ms, 1000.0/(double)elapsed_time_ms); // DEBUG
390  pthread_mutex_lock (&plugin_mutex);
391 
392 again:
393  /*Parse through the linked list of plugins*/
394 
395  for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
396  {
397  pthread_mutex_lock (&vstfx->lock);
398 
399  /*Window scheduled for destruction*/
400 
401  if (vstfx->destroy) {
402  if (vstfx->linux_window) {
403  vstfx->plugin->dispatcher (vstfx->plugin, effEditClose, 0, 0, NULL, 0.0);
404 
405  XDestroyWindow (LXVST_XDisplay, vstfx->linux_window);
406  /* FIXME - probably safe to assume we never have an XID of 0 but not explicitly true */
407  vstfx->linux_window = 0;
408  vstfx->destroy = FALSE;
409  }
410 
412  vstfx->been_activated = FALSE;
413  pthread_cond_signal (&vstfx->window_status_change);
414  pthread_mutex_unlock (&vstfx->lock);
415 
416  goto again;
417  }
418 
419  /*Window does not yet exist - scheduled for creation*/
420 
421  /* FIXME - probably safe to assume 0 is not a valid XID but not explicitly true */
422  if (vstfx->linux_window == 0) {
423  if (vstfx_create_editor (vstfx)) {
424  vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
426  pthread_cond_signal (&vstfx->window_status_change);
427  pthread_mutex_unlock (&vstfx->lock);
428  goto again;
429  } else {
430  /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
431  }
432  }
433 
434  maybe_set_program (vstfx);
435  vstfx->want_program = -1;
436  vstfx->want_chunk = 0;
437 
438  /*scheduled call to dispatcher*/
439 
440  if (vstfx->dispatcher_wantcall) {
441  vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
442  vstfx->plugin,
443  vstfx->dispatcher_opcode,
444  vstfx->dispatcher_index,
445  vstfx->dispatcher_val,
446  vstfx->dispatcher_ptr,
447  vstfx->dispatcher_opt
448  );
449 
450  vstfx->dispatcher_wantcall = 0;
451  pthread_cond_signal (&vstfx->plugin_dispatcher_called);
452  }
453 
454  /*Call the editor Idle function in the plugin*/
455 
456  vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
457 
458  if(vstfx->wantIdle)
459  vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
460 
461  pthread_mutex_unlock (&vstfx->lock);
462  }
463  pthread_mutex_unlock (&plugin_mutex);
464 
465  clock1 = g_get_monotonic_time();
466  }
467  }
468 
469  /*Drop out to here if we set gui_quit to 1 */
470 
471  return NULL;
472 }
473 
474 /*The VSTFX Init function - this needs to be called before the VSTFX engine
475 can be accessed, it gets the UI thread running, opens a connection to X etc
476 normally started in globals.cc*/
477 
478 int vstfx_init (void* ptr)
479 {
480 
481  int thread_create_result;
482 
483  pthread_attr_t thread_attributes;
484 
485  /*Init the attribs to defaults*/
486 
487  pthread_attr_init(&thread_attributes);
488 
489  /*Make sure the thread is joinable - this should be the default anyway -
490  so we can join to it on vstfx_exit*/
491 
492  pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
493 
494 
495  /*This is where we need to open a connection to X, and start the GUI thread*/
496 
497  /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
498  will talk to X down this connection - X cannot handle multi-threaded access via
499  the same Display* */
500 
501  if(LXVST_XDisplay==NULL)
502  LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
503 
504  /*Drop out and report the error if we fail to connect to X */
505 
506  if(LXVST_XDisplay==NULL)
507  {
508  vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
509 
510  return -1;
511  }
512 
513  /*We have a connection to X - so start the gui event loop*/
514 
515  /*Create the thread - use default attrs for now, don't think we need anything special*/
516 
517  thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
518 
519  if(thread_create_result!=0)
520  {
521  /*There was a problem starting the GUI event thread*/
522 
523  vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
524 
525  XCloseDisplay(LXVST_XDisplay);
526 
527  return -1;
528  }
529 
530  return 0;
531 }
532 
533 /*The vstfx Quit function*/
534 
536 {
537  gui_quit = 1;
538 
539  /*We need to pthread_join the gui_thread here so
540  we know when it has stopped*/
541 
542  pthread_join(LXVST_gui_event_thread, NULL);
543 }
544 
545 /*Adds a new plugin (VSTFX) instance to the linked list*/
546 
548 {
549  pthread_mutex_lock (&plugin_mutex);
550 
551  /* Add the new VSTFX instance to the linked list */
552 
553  if (vstfx_first == NULL) {
554  vstfx_first = vstfx;
555  } else {
556  VSTState* p = vstfx_first;
557 
558  while (p->next) {
559  p = p->next;
560  }
561  p->next = vstfx;
562 
563  /* Mark the new end of the list */
564 
565  vstfx->next = NULL;
566  }
567 
568  pthread_mutex_unlock (&plugin_mutex);
569 
570  /* wait for the plugin editor window to be created (or not) */
571 
572  pthread_mutex_lock (&vstfx->lock);
573 
574  if (!vstfx->linux_window) {
575  pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
576  }
577 
578  pthread_mutex_unlock (&vstfx->lock);
579 
580  if (!vstfx->linux_window) {
581  return -1;
582  }
583 
584  return 0;
585 }
586 
587 
588 /*Creates an editor for the plugin - normally called from within the gui event loop
589 after run_editor has added the plugin (editor) to the linked list*/
590 
592 {
593  Window parent_window;
594 
595  int x_size = 1;
596  int y_size = 1;
597 
598  /* Note: vstfx->lock is held while this function is called */
599 
600  if (!(vstfx->plugin->flags & effFlagsHasEditor))
601  {
602  vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
603  return -1;
604  }
605 
606 
607  /*Create an XWindow for the plugin to inhabit*/
608 
609  parent_window = XCreateSimpleWindow (
611  DefaultRootWindow(LXVST_XDisplay),
612  0,
613  0,
614  x_size,
615  y_size,
616  0,
617  0,
618  0
619  );
620 
621  /*Select the events we are interested in receiving - we need Substructure notify so that
622  if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
623 
624  XSelectInput(LXVST_XDisplay,
625  parent_window,
626  SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
627 
628  vstfx->linux_window = parent_window;
629 
630  vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
631 
632  /*Because the plugin may be operating on a different Display* to us, and therefore
633  the two event queues can be asynchronous, although we have created the window on
634  our display, we can't guarantee it exists in the server yet, which will
635  cause BadWindow crashes if the plugin tries to use it.
636 
637  It would be nice to use CreateNotify events here, but they don't get
638  through on all window managers, so instead we pass a client message
639  into out queue, after the XCreateWindow. When this message pops out
640  in our event handler, it will trigger the second stage of plugin
641  Editor instantiation, and by then the Window should be valid...*/
642 
643  XClientMessageEvent event;
644 
645  /*Create an atom to identify our message (only if it doesn't already exist)*/
646 
647  Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
648 
649  event.type = ClientMessage;
650  event.send_event = true;
651  event.window = parent_window;
652  event.message_type = WindowActiveAtom;
653 
654  event.format = 32; //Data format
655  event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
656 
657  /*Push the event into the queue on our Display*/
658 
659  XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
660 
661  /*Unlock - and we are done for the first part of staring the Editor...*/
662 
663  pthread_mutex_unlock (&vstfx->lock);
664 
665  return 0;
666 }
667 
668 int
670 {
671  /*This is the second stage of launching the editor (see vstfx_create editor)
672  we get called here in response to receiving the ClientMessage on our Window,
673  therefore it's about as safe (as can be) to assume that the Window we created
674  is now valid in the XServer and can be passed to the plugin in effEditOpen
675  without generating BadWindow errors when the plugin reparents itself into our
676  parent window*/
677 
678  if(vstfx->been_activated)
679  return 0;
680 
681  Window parent_window;
682  struct ERect* er;
683 
684  int x_size = 1;
685  int y_size = 1;
686 
687  parent_window = vstfx->linux_window;
688 
689  /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
690  it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
691  Display* as a long */
692 
693  /**************************************************************/
694  /* 64Bit --- parent window is an int passed as a void* so */
695  /* that should be ok for 64Bit machines */
696  /* */
697  /* Display is passed in as a long - ok on arch's where sizeof */
698  /* long = 8 */
699  /* */
700  /* Most linux VST plugins open a connection to X on their own */
701  /* Display anyway so it may not matter */
702  /* */
703  /* linuxDSP VSTs don't use the host Display* at all */
704  /**************************************************************/
705 
706  vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
707 
708  /*QUIRK - some plugins need a slight delay after opening the editor before you can
709  ask the window size or they might return zero - specifically discoDSP */
710 
711  Glib::usleep(100000);
712 
713  /*Now we can find out how big the parent window should be (and try) to resize it*/
714 
715  vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
716 
717  x_size = er->right - er->left;
718  y_size = er->bottom - er->top;
719 
720  vstfx->width = x_size;
721  vstfx->height = y_size;
722 
723  XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
724 
725  XFlush (LXVST_XDisplay);
726 
727  /*Not sure if we need to map the window or if the plugin will do it for us
728  it should be ok because XReparentWindow generates a Map event*/
729 
730  /*mark the editor as activated - mainly so that vstfx_get_XID
731  will know it is valid*/
732 
733  vstfx->been_activated = TRUE;
734 
735  pthread_cond_signal (&vstfx->window_status_change);
736  return 0;
737 }
738 
740 void
742 {
743  pthread_mutex_lock (&vstfx->lock);
744  if (vstfx->linux_window) {
745  vstfx->destroy = TRUE;
746  pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
747  }
748  pthread_mutex_unlock (&vstfx->lock);
749 }
750 
754 void
756 {
757  /* This only ever gets called from within our GUI thread
758  so we don't need to lock here - if we did there would be
759  a deadlock anyway
760  */
761 
762  VSTState* p;
763  VSTState* prev;
764 
765  for (p = vstfx_first, prev = NULL; p; prev = p, p = p->next) {
766  if (p == vstfx) {
767  if (prev) {
768  prev->next = p->next;
769  break;
770  }
771  }
772  }
773 
774  // if this function is called, there must be
775  // at least one plugin in the linked list
776  assert(vstfx_first);
777 
778  if (vstfx_first == vstfx) {
779  vstfx_first = vstfx_first->next;
780  }
781 }
782 
static void dispatch_x_events(XEvent *event, VSTState *vstfx)
int vst_version
Definition: vst_types.h:103
void * dispatcher_ptr
Definition: vst_types.h:122
const char magic[]
pthread_cond_t window_status_change
Definition: vst_types.h:128
static pthread_mutex_t plugin_mutex
static void maybe_set_program(VSTState *vstfx)
LIBARDOUR_API void vstfx_error(const char *fmt,...)
static VSTState * vstfx_first
int want_resize
Set to signal the plugin resized its UI.
Definition: vst_types.h:87
void * gui_event_loop(void *ptr)
intptr_t(* dispatcher)(struct _AEffect *, int, int, intptr_t, void *, float)
Definition: aeffectx.h:270
void vstfx_exit()
int wanted_chunk_size
Definition: vst_types.h:112
bool LXVST_xerror
int linux_plugin_ui_window
The ID of the plugin UI window created by the plugin.
Definition: vst_types.h:80
pthread_cond_t plugin_dispatcher_called
Definition: vst_types.h:129
int want_chunk
Definition: vst_types.h:109
#define effEditIdle
Definition: aeffectx.h:101
int dispatcher_wantcall
Definition: vst_types.h:118
int vstfx_run_editor(VSTState *vstfx)
struct _VSTState * next
Definition: vst_types.h:126
int wantIdle
Definition: vst_types.h:97
static int gui_quit
int vstfx_create_editor(VSTState *vstfx)
pthread_mutex_t lock
Definition: vst_types.h:127
int dispatcher_opcode
Definition: vst_types.h:119
#define effSetProgram
Definition: aeffectx.h:91
pthread_t LXVST_gui_event_thread
int dispatcher_val
Definition: vst_types.h:121
int gui_thread_id
int xid
X11 XWindow.
Definition: vst_types.h:85
int dispatcher_index
Definition: vst_types.h:120
minimum disk write bytes
int height
Definition: vst_types.h:96
#define effFlagsHasEditor
Definition: aeffectx.h:85
VSTHandle * handle
Definition: vst_types.h:93
void vstfx_destroy_editor(VSTState *vstfx)
#define effEditGetRect
Definition: aeffectx.h:98
int vstfx_init(void *ptr)
int want_program
Definition: vst_types.h:108
void vstfx_event_loop_remove_plugin(VSTState *vstfx)
Display * LXVST_XDisplay
AEffect * plugin
Definition: vst_types.h:76
int width
Definition: vst_types.h:95
int TempErrorHandler(Display *display, XErrorEvent *e)
#define effEditClose
Definition: aeffectx.h:100
int flags
Definition: aeffectx.h:286
int destroy
Definition: vst_types.h:102
void(* eventProc)(void *event)
Definition: vst_types.h:91
unsigned char * wanted_chunk
Definition: vst_types.h:111
int been_activated
Definition: vst_types.h:131
int dispatcher_retval
Definition: vst_types.h:124
#define effEditOpen
Definition: aeffectx.h:99
char * name
Definition: vst_types.h:64
int pthread_create(pthread_t *__restrict thread, __const pthread_attr_t *__restrict attr, void *(*start_routine)(void *), void *__restrict arg)
Definition: gprofhelper.c:83
int vstfx_launch_editor(VSTState *vstfx)
float dispatcher_opt
Definition: vst_types.h:123
int linux_window
The plugin's parent X11 XWindow.
Definition: vst_types.h:79