#include #include #include #include #include #include #include //#include //#include //#include //#include #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; }