Logo Search packages:      
Sourcecode: ardour version File versions  Download package

vstwin.c

#include <stdio.h>
#include <libgen.h>
#include <windows.h>
#include <winnt.h>
#include <wine/exception.h>
#include <pthread.h>
#include <signal.h>

//#include <x11/xlib.h>
//#include <x11/xresource.h>
//#include <x11/xutil.h>
//#include <x11/xatom.h>

#include "fst.h"


struct ERect{
    short top;
    short left;
    short bottom;
    short right;
};

static pthread_mutex_t plugin_mutex = PTHREAD_MUTEX_INITIALIZER;
static FST* fst_first = NULL;

DWORD  gui_thread_id = 0;

static char* message_name (int message)
{
      switch (message) {
      case 0x0000:
            return "WM_NULL";

      case 0x0001:
            return "WM_CREATE";

      case 0x0002:
            return "WM_DESTROY";

      case 0x0003:
            return "WM_MOVE";

      case 0x0004:
            return "WM_SIZEWAIT";

      case 0x0005:
            return "WM_SIZE";

      case 0x0006:
            return "WM_ACTIVATE";

      case 0x0007:
            return "WM_SETFOCUS";

      case 0x0008:
            return "WM_KILLFOCUS";

      case 0x0009:
            return "WM_SETVISIBLE";

      case 0x000a:
            return "WM_ENABLE";

      case 0x000b:
            return "WM_SETREDRAW";

      case 0x000c:
            return "WM_SETTEXT";

      case 0x000d:
            return "WM_GETTEXT";

      case 0x000e:
            return "WM_GETTEXTLENGTH";

      case 0x000f:
            return "WM_PAINT";

      case 0x0010:
            return "WM_CLOSE";

      case 0x0011:
            return "WM_QUERYENDSESSION";

      case 0x0012:
            return "WM_QUIT";

      case 0x0013:
            return "WM_QUERYOPEN";

      case 0x0014:
            return "WM_ERASEBKGND";

      case 0x0015:
            return "WM_SYSCOLORCHANGE";

      case 0x0016:
            return "WM_ENDSESSION";

      case 0x0017:
            return "WM_SYSTEMERROR";

      case 0x0018:
            return "WM_SHOWWINDOW";

      case 0x0019:
            return "WM_CTLCOLOR";

      case 0x001a:
            return "WM_WININICHANGE";

      case 0x001b:
            return "WM_DEVMODECHANGE";

      case 0x001c:
            return "WM_ACTIVATEAPP";

      case 0x001d:
            return "WM_FONTCHANGE";

      case 0x001e:
            return "WM_TIMECHANGE";

      case 0x001f:
            return "WM_CANCELMODE";

      case 0x0020:
            return "WM_SETCURSOR";

      case 0x0021:
            return "WM_MOUSEACTIVATE";

      case 0x0022:
            return "WM_CHILDACTIVATE";

      case 0x0023:
            return "WM_QUEUESYNC";

      case 0x0024:
            return "WM_GETMINMAXINFO";

      default:
            break;
      }
      return "--- OTHER ---";
}
      
static LRESULT WINAPI 
my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
{
      FST* fst;

//    if (msg != WM_TIMER) {
//          fst_error ("window callback handler, msg = 0x%x (%s) win=%p\n", msg, message_name (msg), w);
//    }

      switch (msg) {
      case WM_KEYUP:
      case WM_KEYDOWN:
            break;

      case WM_CLOSE:
            PostQuitMessage (0);

      case WM_DESTROY:
      case WM_NCDESTROY:
            /* we should never get these */
            //return 0;
            break;

      case WM_PAINT:
            if ((fst = GetPropA (w, "fst_ptr")) != NULL) {
                  if (fst->window && !fst->been_activated) {
                        fst->been_activated = TRUE;
                        pthread_cond_signal (&fst->window_status_change);
                        pthread_mutex_unlock (&fst->lock);
                  }
            }
            break;

      default:
            break;
      }

      return DefWindowProcA (w, msg, wp, lp );
}

static FST* 
fst_new ()
{
      FST* fst = (FST*) calloc (1, sizeof (FST));

      pthread_mutex_init (&fst->lock, NULL);
      pthread_cond_init (&fst->window_status_change, NULL);

      return fst;
}

static FSTHandle* 
fst_handle_new ()
{
      FSTHandle* fst = (FSTHandle*) calloc (1, sizeof (FSTHandle));
      return fst;
}

int
fst_create_editor (FST* fst)
{
      HMODULE hInst;
      HWND window;

      /* "guard point" to trap errors that occur during plugin loading */

      /* Note: fst->lock is held while this function is called */

      if (!(fst->plugin->flags & effFlagsHasEditor)) {
            fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
            return -1;
      }

      if ((hInst = GetModuleHandleA (NULL)) == NULL) {
            fst_error ("can't get module handle");
            return 1;
      }
      
//    if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
      if ((window = CreateWindowExA (0, "FST", fst->handle->name,
                               (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
                               0, 0, 1, 1,
                               NULL, NULL,
                               hInst,
                               NULL)) == NULL) {
            fst_error ("cannot create editor window");
            return 1;
      }

      if (!SetPropA (window, "fst_ptr", fst)) {
            fst_error ("cannot set fst_ptr on window");
      }

      fst->window = window;
      fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");

      {
            struct ERect* er;

            ShowWindow (fst->window, SW_SHOW);
      
            fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->window, 0 );
            fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
            
            fst->width =  er->right-er->left;
            fst->height =  er->bottom-er->top;
            
            SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER);
      }

      return 0;
}

void
fst_destroy_editor (FST* fst)
{
      pthread_mutex_lock (&fst->lock);
      if (fst->window) {
            fst->destroy = TRUE;
            if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
                  fst_error ("could not post message to gui thread");
            }
            pthread_cond_wait (&fst->window_status_change, &fst->lock);

      }
      pthread_mutex_unlock (&fst->lock);
}

void
fst_event_loop_remove_plugin (FST* fst)
{
      FST* p;
      FST* prev;

      for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
            if (p == fst) {
                  if (prev) {
                        prev->next = p->next;
                  }
            }
      }

      if (fst_first == fst) {
            fst_first = fst_first->next;
      }

}

void debreak( void ) { printf( "debreak\n" ); }

DWORD WINAPI gui_event_loop (LPVOID param)
{
      MSG msg;
      FST* fst;
      HMODULE hInst;
      HWND window;

      gui_thread_id = GetCurrentThreadId ();

      /* create a dummy window for timer events */

      if ((hInst = GetModuleHandleA (NULL)) == NULL) {
            fst_error ("can't get module handle");
            return 1;
      }
      
      if ((window = CreateWindowExA (0, "FST", "dummy",
                               WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               NULL, NULL,
                               hInst,
                               NULL )) == NULL) {
            fst_error ("cannot create dummy timer window");
      }

      if (!SetTimer (window, 1000, 100, NULL)) {
            fst_error ("cannot set timer on dummy window");
      }

      while (1) {

            GetMessageA (&msg, NULL, 0,0);

            if (msg.message == WM_SYSTEMERROR) {
                  /* sent when this thread is supposed to exist */
                  break;
            }
            
            if (msg.message == WM_KEYDOWN) debreak();

            TranslateMessage( &msg );
            DispatchMessageA (&msg);

            /* handle window creation requests, destroy requests, 
               and run idle callbacks 
            */
            
            if( msg.message == WM_TIMER ) {
                pthread_mutex_lock (&plugin_mutex);
again:
                for (fst = fst_first; fst; fst = fst->next) {

                  if (fst->destroy) {
                      if (fst->window) {
                        fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
                        CloseWindow (fst->window);
                        fst->window = NULL;
                        fst->destroy = FALSE;
                      }
                      fst_event_loop_remove_plugin (fst);
                      fst->been_activated = FALSE;
                      pthread_mutex_lock (&fst->lock);
                      pthread_cond_signal (&fst->window_status_change);
                      pthread_mutex_unlock (&fst->lock);
                      goto again;
                  } 

                  if (fst->window == NULL) {
                      pthread_mutex_lock (&fst->lock);
                      if (fst_create_editor (fst)) {
                        fst_error ("cannot create editor for plugin %s", fst->handle->name);
                        fst_event_loop_remove_plugin (fst);
                        pthread_cond_signal (&fst->window_status_change);
                        pthread_mutex_unlock (&fst->lock);
                        goto again;
                      }
                      /* condition/unlock handled when we receive WM_ACTIVATE */
                  }

                  fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
                }
                pthread_mutex_unlock (&plugin_mutex);
            }
      }
      fst_error ("FST GUI event loop has quit!");
      return 0;
}

int
fst_init ()
{
      WNDCLASSA wc;
      HMODULE hInst;

      if ((hInst = GetModuleHandleA (NULL)) == NULL) {
            fst_error ("can't get module handle");
            return -1;
      }
      wc.style = 0;
      wc.lpfnWndProc = my_window_proc;
      wc.cbClsExtra = 0;
      wc.cbWndExtra = 0;
      wc.hInstance = hInst;
      wc.hIcon = LoadIconA( hInst, "FST");
      wc.hCursor = LoadCursorA( NULL, IDI_APPLICATION );
      wc.hbrBackground = GetStockObject( BLACK_BRUSH );
      wc.lpszMenuName = "MENU_FST";
      wc.lpszClassName = "FST";

      if (!RegisterClassA(&wc)){
            return 1;
      }

      if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
            fst_error ("could not create new thread proxy");
            return -1;
      }

      return 0;
}

void
fst_finish ()
{
      PostThreadMessageA (gui_thread_id, WM_SYSTEMERROR, 0, 0);
}

int
fst_run_editor (FST* fst)
{
      /* Add the FST to the list of all that should be handled by the GUI thread */

      pthread_mutex_lock (&plugin_mutex);

      if (fst_first == NULL) {
            fst_first = fst;
      } else {
            FST* p = fst_first;
            while (p->next) {
                  p = p->next;
            }
            p->next = fst;
      }

      if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
            fst_error ("could not post message to gui thread");
            return -1;
      }

      pthread_mutex_unlock (&plugin_mutex);

      /* wait for the plugin editor window to be created (or not) */

      pthread_mutex_lock (&fst->lock);
      if (!fst->window) {
            pthread_cond_wait (&fst->window_status_change, &fst->lock);
      } 
      pthread_mutex_unlock (&fst->lock);

      if (!fst->window) {
            fst_error ("no window created for VST plugin editor");
            return -1;
      }

      return 0;
}

FSTHandle*
fst_load (const char *path)
{
      char* buf;
      FSTHandle* fhandle;
      char* period;

      fhandle = fst_handle_new ();
      
      // XXX: Would be nice to find the correct call for this.
      //      if the user does not configure Z: to be / we are doomed :(

      if (strstr (path, ".dll") == NULL) {

            buf = (char *) malloc (strlen (path) + 7);

            if( path[0] == '/' ) {
                sprintf (buf, "Z:%s.dll", path);
            } else {
                sprintf (buf, "%s.dll", path);
            }

            fhandle->nameptr = strdup (path);

      } else {

            buf = (char *) malloc (strlen (path) + 3);

            if( path[0] == '/' ) {
                sprintf (buf, "Z:%s", path);
            } else {
                sprintf (buf, "%s", path);
            }

            fhandle->nameptr = strdup (path);
      }
      
      fhandle->name = basename (fhandle->nameptr);

      /* strip off .dll */

      if ((period = strrchr (fhandle->name, '.')) != NULL) {
            *period = '\0';
      }

      if ((fhandle->dll = LoadLibraryA (buf)) == NULL) {
            fst_unload (fhandle);
            return NULL;
      }

      typedef AEffect* (*entryFunctionType)(audioMasterCallback);

      if ((fhandle->main_entry = (entryFunctionType) GetProcAddress (fhandle->dll, "main")) == NULL) {
            fst_unload (fhandle);
            return NULL;
      }

      return fhandle;
}

int
fst_unload (FSTHandle* fhandle)
{
      if (fhandle->plugincnt) {
            return -1;
      }

      if (fhandle->dll) {
            FreeLibrary (fhandle->dll);
            fhandle->dll = NULL;
      }

      if (fhandle->nameptr) {
            free (fhandle->nameptr);
            fhandle->name = NULL;
      }
      
      free (fhandle);
      return 0;
}

FST*
fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
{
      FST* fst = fst_new ();

      if( fhandle == NULL ) {
          fst_error( "the handle was NULL\n" );
          return NULL;
      }

      if ((fst->plugin = fhandle->main_entry (amc)) == NULL)  {
            fst_error ("%s could not be instantiated\n", fhandle->name);
            free (fst);
            return NULL;
      }
      
      fst->handle = fhandle;
      fst->plugin->user = userptr;
            
      if (fst->plugin->magic != kEffectMagic) {
            fst_error ("%s is not a VST plugin\n", fhandle->name);
            free (fst);
            return NULL;
      }
      
      fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
      //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);

      fst->handle->plugincnt++;

      return fst;
}

void
fst_close (FST* fst)
{
      fst_destroy_editor (fst);

      fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
      fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);

      if (fst->handle->plugincnt) {
            --fst->handle->plugincnt;
      }
}

int
fst_get_XID (FST* fst)
{
      return fst->xid;
}

Generated by  Doxygen 1.6.0   Back to index