various fixes to MidiRegionView selection handling, key handling, drawing of ghost...
[ardour2.git] / libs / fst / vstwin.c
blobcdc9e3af07114c04d8c394050e25234358dae174
1 #include <stdio.h>
2 #include <jack/jack.h>
3 #include <jack/thread.h>
4 #include <libgen.h>
5 #include <windows.h>
6 #include <winnt.h>
7 #include <wine/exception.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <glib.h>
12 #include "fst.h"
14 #include <X11/X.h>
15 #include <X11/Xlib.h>
17 extern char * strdup (const char *);
19 struct ERect{
20 short top;
21 short left;
22 short bottom;
23 short right;
26 static pthread_mutex_t plugin_mutex;
28 /** Head of linked list of all FSTs */
29 static FST* fst_first = NULL;
31 const char magic[] = "FST Plugin State v002";
33 DWORD gui_thread_id = 0;
34 static int gui_quit = 0;
36 #define DELAYED_WINDOW 1
39 static LRESULT WINAPI
40 my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
42 #if 0
43 if (msg != WM_TIMER) {
44 fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
46 #endif
48 switch (msg) {
49 case WM_KEYUP:
50 case WM_KEYDOWN:
51 break;
53 case WM_CLOSE:
54 /* we don't care about windows closing ... */
55 return 0;
56 break;
58 case WM_DESTROY:
59 case WM_NCDESTROY:
60 /* we don't care about windows being destroyed ... */
61 return 0;
62 break;
64 default:
65 break;
68 return DefWindowProcA (w, msg, wp, lp );
71 static FST*
72 fst_new ()
74 FST* fst = (FST*) calloc (1, sizeof (FST));
75 pthread_mutex_init (&fst->lock, NULL);
76 pthread_cond_init (&fst->window_status_change, NULL);
77 pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
78 fst->want_program = -1;
79 fst->want_chunk = 0;
80 fst->current_program = -1;
81 fst->n_pending_keys = 0;
82 fst->has_editor = 0;
83 fst->program_set_without_editor = 0;
84 return fst;
87 static FSTHandle*
88 fst_handle_new ()
90 FSTHandle* fst = (FSTHandle*) calloc (1, sizeof (FSTHandle));
91 return fst;
94 void
95 maybe_set_program (FST* fst)
97 if (fst->want_program != -1) {
98 if (fst->vst_version >= 2) {
99 fst->plugin->dispatcher (fst->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
102 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
104 if (fst->vst_version >= 2) {
105 fst->plugin->dispatcher (fst->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
107 /* did it work? */
108 fst->current_program = fst->plugin->dispatcher (fst->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
109 fst->want_program = -1;
112 if (fst->want_chunk == 1) {
113 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
114 fst->want_chunk = 0;
118 DWORD WINAPI gui_event_loop (LPVOID param)
120 MSG msg;
121 FST* fst;
122 HMODULE hInst;
123 HWND window;
124 int i;
126 gui_thread_id = GetCurrentThreadId ();
128 /* create a dummy window for timer events */
130 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
131 fst_error ("can't get module handle");
132 return 1;
135 if ((window = CreateWindowExA (0, "FST", "dummy",
136 WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
137 9999, 9999,
138 1, 1,
139 NULL, NULL,
140 hInst,
141 NULL )) == NULL) {
142 fst_error ("cannot create dummy timer window");
145 if (!SetTimer (window, 1000, 20, NULL)) {
146 fst_error ("cannot set timer on dummy window");
149 while (!gui_quit) {
151 if (!GetMessageA (&msg, NULL, 0,0)) {
152 if (!gui_quit) {
153 fprintf (stderr, "QUIT message received by Windows GUI thread - ignored\n");
154 continue;
155 } else {
156 break;
160 TranslateMessage( &msg );
161 DispatchMessageA (&msg);
163 if (msg.message != WM_TIMER) {
164 continue;
167 pthread_mutex_lock (&plugin_mutex);
169 /* Do things that are appropriate for plugins which have open editor windows:
170 handle window creation requests, destroy requests,
171 and run idle callbacks
174 again:
175 for (fst = fst_first; fst; fst = fst->next) {
177 pthread_mutex_lock (&fst->lock);
179 if (fst->has_editor == 1) {
181 if (fst->destroy) {
182 fprintf (stderr, "%s scheduled for destroy\n", fst->handle->name);
183 if (fst->window) {
184 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
185 CloseWindow (fst->window);
186 fst->window = NULL;
187 fst->destroy = FALSE;
189 fst_event_loop_remove_plugin (fst);
190 fst->been_activated = FALSE;
191 pthread_cond_signal (&fst->window_status_change);
192 pthread_mutex_unlock (&fst->lock);
193 goto again;
196 if (fst->window == NULL) {
197 if (fst_create_editor (fst)) {
198 fst_error ("cannot create editor for plugin %s", fst->handle->name);
199 fst_event_loop_remove_plugin (fst);
200 pthread_cond_signal (&fst->window_status_change);
201 pthread_mutex_unlock (&fst->lock);
202 goto again;
203 } else {
204 /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
208 if (fst->dispatcher_wantcall) {
209 fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin,
210 fst->dispatcher_opcode,
211 fst->dispatcher_index,
212 fst->dispatcher_val,
213 fst->dispatcher_ptr,
214 fst->dispatcher_opt );
215 fst->dispatcher_wantcall = 0;
216 pthread_cond_signal (&fst->plugin_dispatcher_called);
219 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
221 if (fst->wantIdle) {
222 fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
225 /* Dispatch messages to send keypresses to the plugin */
227 for (i = 0; i < fst->n_pending_keys; ++i) {
228 /* I'm not quite sure what is going on here; it seems
229 `special' keys must be delivered with WM_KEYDOWN,
230 but that alphanumerics etc. must use WM_CHAR or
231 they will be ignored. Ours is not to reason why ...
233 if (fst->pending_keys[i].special != 0) {
234 msg.message = WM_KEYDOWN;
235 msg.wParam = fst->pending_keys[i].special;
236 } else {
237 msg.message = WM_CHAR;
238 msg.wParam = fst->pending_keys[i].character;
240 msg.hwnd = GetFocus ();
241 msg.lParam = 0;
242 DispatchMessageA (&msg);
245 fst->n_pending_keys = 0;
247 /* See comment for maybe_set_program call below */
248 maybe_set_program (fst);
249 fst->want_program = -1;
250 fst->want_chunk = 0;
253 /* If we don't have an editor window yet, we still need to
254 * set up the program, otherwise when we load a plugin without
255 * opening its window it will sound wrong. However, it seems
256 * that if you don't also load the program after opening the GUI,
257 * the GUI does not reflect the program properly. So we'll not
258 * mark that we've done this (ie we won't set want_program to -1)
259 * and so it will be done again if and when the GUI arrives.
261 if (fst->program_set_without_editor == 0) {
262 maybe_set_program (fst);
263 fst->program_set_without_editor = 1;
266 pthread_mutex_unlock (&fst->lock);
269 pthread_mutex_unlock (&plugin_mutex);
272 return 0;
276 fst_init (void* possible_hmodule)
278 WNDCLASSEX wclass;
279 HMODULE hInst;
281 if (possible_hmodule) {
282 hInst = (HMODULE) possible_hmodule;
283 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
284 fst_error ("can't get module handle");
285 return -1;
288 wclass.cbSize = sizeof(WNDCLASSEX);
289 wclass.style = 0;
290 wclass.lpfnWndProc = my_window_proc;
291 wclass.cbClsExtra = 0;
292 wclass.cbWndExtra = 0;
293 wclass.hInstance = hInst;
294 wclass.hIcon = LoadIcon(hInst, "FST");
295 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
296 // wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
297 wclass.lpszMenuName = "MENU_FST";
298 wclass.lpszClassName = "FST";
299 wclass.hIconSm = 0;
302 if (!RegisterClassExA(&wclass)){
303 printf( "Class register failed :(\n" );
304 return -1;
307 fst_error ("Startup win32 GUI thread\n");
309 if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
310 fst_error ("could not create new thread proxy");
311 return -1;
314 #ifdef HAVE_JACK_SET_THREAD_CREATOR
315 jack_set_thread_creator (wine_pthread_create);
316 #endif
318 return 0;
321 void
322 fst_exit ()
324 gui_quit = 1;
325 PostQuitMessage (0);
329 fst_run_editor (FST* fst)
331 /* wait for the plugin editor window to be created (or not) */
333 pthread_mutex_lock (&fst->lock);
335 fst->has_editor = 1;
337 if (!fst->window) {
338 pthread_cond_wait (&fst->window_status_change, &fst->lock);
340 pthread_mutex_unlock (&fst->lock);
342 if (!fst->window) {
343 return -1;
346 return 0;
350 fst_call_dispatcher (FST *fst, int opcode, int index, int val, void *ptr, float opt)
352 pthread_mutex_lock (&fst->lock);
353 fst->dispatcher_opcode = opcode;
354 fst->dispatcher_index = index;
355 fst->dispatcher_val = val;
356 fst->dispatcher_ptr = ptr;
357 fst->dispatcher_opt = opt;
358 fst->dispatcher_wantcall = 1;
360 pthread_cond_wait (&fst->plugin_dispatcher_called, &fst->lock);
361 pthread_mutex_unlock (&fst->lock);
363 return fst->dispatcher_retval;
367 fst_create_editor (FST* fst)
369 HMODULE hInst;
370 HWND window;
371 struct ERect* er;
373 /* "guard point" to trap errors that occur during plugin loading */
375 /* Note: fst->lock is held while this function is called */
377 if (!(fst->plugin->flags & effFlagsHasEditor)) {
378 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
379 return -1;
382 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
383 fst_error ("can't get module handle");
384 return 1;
387 // if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
388 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
389 (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
390 // (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
391 9999,9999,1,1,
392 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
393 NULL, NULL,
394 hInst,
395 NULL)) == NULL) {
396 fst_error ("cannot create editor window");
397 return 1;
400 if (!SetPropA (window, "fst_ptr", fst)) {
401 fst_error ("cannot set fst_ptr on window");
404 fst->window = window;
405 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
408 //printf( "effEditOpen......\n" );
409 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->window, 0 );
410 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
412 fst->width = er->right-er->left;
413 fst->height = er->bottom-er->top;
414 //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
416 //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
417 SetWindowPos (fst->window, 0, 9999, 9999, 2, 2, 0);
418 ShowWindow (fst->window, SW_SHOWNA);
419 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
421 fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
422 fst->been_activated = TRUE;
423 pthread_cond_signal (&fst->window_status_change);
424 pthread_mutex_unlock (&fst->lock);
426 return 0;
429 void
430 fst_move_window_into_view (FST* fst)
432 if (fst->window) {
433 SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
434 ShowWindow (fst->window, SW_SHOWNA);
438 void
439 fst_destroy_editor (FST* fst)
441 pthread_mutex_lock (&fst->lock);
442 if (fst->window) {
443 fprintf (stderr, "mark %s for destroy\n", fst->handle->name);
444 fst->destroy = TRUE;
445 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
446 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
447 // fst_error ("could not post message to gui thread");
449 pthread_cond_wait (&fst->window_status_change, &fst->lock);
450 fprintf (stderr, "%s editor destroyed\n", fst->handle->name);
451 fst->has_editor = 0;
453 pthread_mutex_unlock (&fst->lock);
456 void
457 fst_event_loop_remove_plugin (FST* fst)
459 FST* p;
460 FST* prev;
462 for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
463 if (p == fst) {
464 if (prev) {
465 prev->next = p->next;
470 if (fst_first == fst) {
471 fst_first = fst_first->next;
476 HMODULE
477 fst_load_vst_library(const char * path)
479 HMODULE dll;
480 char * full_path;
481 char * envdup;
482 char * vst_path;
483 size_t len1;
484 size_t len2;
486 if ((dll = LoadLibraryA (path)) != NULL) {
487 return dll;
490 envdup = getenv ("VST_PATH");
491 if (envdup == NULL) {
492 return NULL;
495 envdup = strdup (envdup);
496 if (envdup == NULL) {
497 fst_error ("strdup failed");
498 return NULL;
501 len2 = strlen(path);
503 vst_path = strtok (envdup, ":");
504 while (vst_path != NULL) {
505 fst_error ("\"%s\"", vst_path);
506 len1 = strlen(vst_path);
507 full_path = malloc (len1 + 1 + len2 + 1);
508 memcpy(full_path, vst_path, len1);
509 full_path[len1] = '/';
510 memcpy(full_path + len1 + 1, path, len2);
511 full_path[len1 + 1 + len2] = '\0';
513 if ((dll = LoadLibraryA (full_path)) != NULL) {
514 break;
517 vst_path = strtok (NULL, ":");
520 free(envdup);
522 return dll;
525 FSTHandle*
526 fst_load (const char *path)
528 char* buf;
529 FSTHandle* fhandle;
530 char* period;
532 fhandle = fst_handle_new ();
534 // XXX: Would be nice to find the correct call for this.
535 // if the user does not configure Z: to be / we are doomed :(
537 if (strstr (path, ".dll") == NULL) {
539 buf = (char *) malloc (strlen (path) + 7);
541 if( path[0] == '/' ) {
542 sprintf (buf, "Z:%s.dll", path);
543 } else {
544 sprintf (buf, "%s.dll", path);
547 fhandle->nameptr = strdup (path);
549 } else {
551 buf = (char *) malloc (strlen (path) + 3);
553 if( path[0] == '/' ) {
554 sprintf (buf, "Z:%s", path);
555 } else {
556 sprintf (buf, "%s", path);
559 fhandle->nameptr = strdup (path);
562 fhandle->name = basename (fhandle->nameptr);
564 /* strip off .dll */
566 if ((period = strrchr (fhandle->name, '.')) != NULL) {
567 *period = '\0';
570 if ((fhandle->dll = fst_load_vst_library (buf)) == NULL) {
571 fst_unload (fhandle);
572 return NULL;
575 if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main")) == NULL) {
576 fst_unload (fhandle);
577 return NULL;
580 return fhandle;
584 fst_unload (FSTHandle* fhandle)
586 if (fhandle->plugincnt) {
587 return -1;
590 if (fhandle->dll) {
591 FreeLibrary (fhandle->dll);
592 fhandle->dll = NULL;
595 if (fhandle->nameptr) {
596 free (fhandle->nameptr);
597 fhandle->name = NULL;
600 free (fhandle);
601 return 0;
604 FST*
605 fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
607 FST* fst = fst_new ();
609 pthread_mutex_lock (&plugin_mutex);
611 if (fst_first == NULL) {
612 fst_first = fst;
613 } else {
614 FST* p = fst_first;
615 while (p->next) {
616 p = p->next;
618 p->next = fst;
621 pthread_mutex_unlock (&plugin_mutex);
623 if( fhandle == NULL ) {
624 fst_error( "the handle was NULL\n" );
625 return NULL;
628 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
629 fst_error ("%s could not be instantiated\n", fhandle->name);
630 free (fst);
631 return NULL;
634 fst->handle = fhandle;
635 fst->plugin->user = userptr;
637 if (fst->plugin->magic != kEffectMagic) {
638 fst_error ("%s is not a VST plugin\n", fhandle->name);
639 free (fst);
640 return NULL;
643 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
644 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
646 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
648 fst->handle->plugincnt++;
649 fst->wantIdle = 0;
651 return fst;
654 void
655 fst_close (FST* fst)
657 fst_destroy_editor (fst);
659 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
660 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
662 if (fst->handle->plugincnt) {
663 --fst->handle->plugincnt;
668 fst_get_XID (FST* fst)
670 return fst->xid;
673 float htonf (float v)
675 float result;
676 char * fin = (char*)&v;
677 char * fout = (char*)&result;
678 fout[0] = fin[3];
679 fout[1] = fin[2];
680 fout[2] = fin[1];
681 fout[3] = fin[0];
682 return result;
685 #if 0
686 int fst_load_state (FST * fst, char * filename)
688 FILE * f = fopen (filename, "rb");
689 if (f) {
690 char testMagic[sizeof (magic)];
691 fread (&testMagic, sizeof (magic), 1, f);
692 if (strcmp (testMagic, magic)) {
693 printf ("File corrupt\n");
694 return FALSE;
697 char productString[64];
698 char vendorString[64];
699 char effectName[64];
700 char testString[64];
701 unsigned length;
702 int success;
704 fread (&length, sizeof (unsigned), 1, f);
705 length = htonl (length);
706 fread (productString, length, 1, f);
707 productString[length] = 0;
708 printf ("Product string: %s\n", productString);
710 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, testString, 0 );
711 if (success == 1) {
712 if (strcmp (testString, productString) != 0) {
713 printf ("Product string mismatch! Plugin has: %s\n", testString);
714 fclose (f);
715 return FALSE;
717 } else if (length != 0) {
718 printf ("Product string mismatch! Plugin has none.\n", testString);
719 fclose (f);
720 return FALSE;
723 fread (&length, sizeof (unsigned), 1, f);
724 length = htonl (length);
725 fread (effectName, length, 1, f);
726 effectName[length] = 0;
727 printf ("Effect name: %s\n", effectName);
729 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, testString, 0 );
730 if (success == 1) {
731 if (strcmp (testString, effectName) != 0) {
732 printf ("Effect name mismatch! Plugin has: %s\n", testString);
733 fclose (f);
734 return FALSE;
736 } else if (length != 0) {
737 printf ("Effect name mismatch! Plugin has none.\n", testString);
738 fclose (f);
739 return FALSE;
742 fread (&length, sizeof (unsigned), 1, f);
743 length = htonl (length);
744 fread (vendorString, length, 1, f);
745 vendorString[length] = 0;
746 printf ("Vendor string: %s\n", vendorString);
748 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, testString, 0 );
749 if (success == 1) {
750 if (strcmp (testString, vendorString) != 0) {
751 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
752 fclose (f);
753 return FALSE;
755 } else if (length != 0) {
756 printf ("Vendor string mismatch! Plugin has none.\n", testString);
757 fclose (f);
758 return FALSE;
761 int numParam;
762 unsigned i;
763 fread (&numParam, sizeof (int), 1, f);
764 numParam = htonl (numParam);
765 for (i = 0; i < numParam; ++i) {
766 float val;
767 fread (&val, sizeof (float), 1, f);
768 val = htonf (val);
770 pthread_mutex_lock( &fst->lock );
771 fst->plugin->setParameter( fst->plugin, i, val );
772 pthread_mutex_unlock( &fst->lock );
775 int bytelen;
776 fread (&bytelen, sizeof (int), 1, f);
777 bytelen = htonl (bytelen);
778 if (bytelen) {
779 char * buf = malloc (bytelen);
780 fread (buf, bytelen, 1, f);
782 fst_call_dispatcher( fst, 24, 0, bytelen, buf, 0 );
783 free (buf);
785 } else {
786 printf ("Could not open state file\n");
787 return FALSE;
789 return TRUE;
792 #endif
794 int fst_save_state (FST * fst, char * filename)
796 FILE * f = fopen (filename, "wb");
797 int j;
799 if (f) {
800 int bytelen;
801 int numParams = fst->plugin->numParams;
802 char productString[64];
803 char effectName[64];
804 char vendorString[64];
805 int success;
807 // write header
808 fprintf( f, "<plugin_state>\n" );
810 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, productString, 0 );
811 if( success == 1 ) {
812 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
813 } else {
814 printf ("No product string\n");
817 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, effectName, 0 );
818 if( success == 1 ) {
819 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
820 printf ("Effect name: %s\n", effectName);
821 } else {
822 printf ("No effect name\n");
825 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, vendorString, 0 );
826 if( success == 1 ) {
827 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
828 printf ("Vendor string: %s\n", vendorString);
829 } else {
830 printf ("No vendor string\n");
834 if( fst->plugin->flags & 32 ) {
835 numParams = 0;
838 for (j = 0; j < numParams; ++j) {
839 float val;
841 pthread_mutex_lock( &fst->lock );
842 val = fst->plugin->getParameter (fst->plugin, j);
843 pthread_mutex_unlock( &fst->lock );
844 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", j, val );
847 if( fst->plugin->flags & 32 ) {
848 printf( "getting chunk...\n" );
849 void * chunk;
850 bytelen = fst_call_dispatcher( fst, 23, 0, 0, &chunk, 0 );
851 printf( "got tha chunk..\n" );
852 if( bytelen ) {
853 if( bytelen < 0 ) {
854 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
855 } else {
856 char *encoded = g_base64_encode( chunk, bytelen );
857 fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
858 g_free( encoded );
863 fprintf( f, "</plugin_state>\n" );
864 fclose( f );
865 } else {
866 printf ("Could not open state file\n");
867 return FALSE;
869 return TRUE;