7 #include <gdk/gdkevents.h>
10 #include <glib-2.0/glib.h>
13 #include <lash/lash.h>
14 extern lash_client_t
*lash_client
;
17 gboolean g_quit
= FALSE
;
18 gboolean quit
= FALSE
;
20 static GtkWidget
* window
;
21 static GtkWidget
* gtk_socket
;
22 static GtkWidget
* vpacker
;
23 static GtkWidget
* hpacker
;
24 static GtkWidget
* bypass_button
;
25 static GtkWidget
* remove_button
;
26 static GtkWidget
* mute_button
;
27 static GtkWidget
* event_box
;
28 static GtkWidget
* preset_listbox
;
29 static GtkWidget
* midi_learn_toggle
;
30 static GtkWidget
* load_button
;
31 static GtkWidget
* save_button
;
35 learn_handler (GtkToggleButton
*but
, gboolean ptr
)
37 JackVST
* jvst
= (JackVST
*) ptr
;
39 if( gtk_toggle_button_get_active (but
) ) {
41 jvst
->midi_learn_CC
= -1;
42 jvst
->midi_learn_PARAM
= -1;
46 gtk_widget_grab_focus( gtk_socket
);
50 bypass_handler (GtkToggleButton
*but
, gboolean ptr
)
52 JackVST
* jvst
= (JackVST
*) ptr
;
54 jvst
->bypassed
= gtk_toggle_button_get_active (but
);
55 gtk_widget_grab_focus( gtk_socket
);
59 mute_handler (GtkToggleButton
*but
, gboolean ptr
)
61 JackVST
* jvst
= (JackVST
*) ptr
;
62 jvst
->muted
= gtk_toggle_button_get_active (but
);
63 gtk_widget_grab_focus( gtk_socket
);
67 save_handler (GtkToggleButton
*but
, gboolean ptr
)
72 JackVST
* jvst
= (JackVST
*) ptr
;
75 dialog
= gtk_file_chooser_dialog_new ("Save Plugin State",
77 GTK_FILE_CHOOSER_ACTION_SAVE
,
78 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
79 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
82 GtkFileFilter
* ff
= gtk_file_filter_new();
83 gtk_file_filter_set_name(ff
,"FST Plugin State");
84 gtk_file_filter_add_pattern(ff
,"*.fps");
85 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog
),ff
);
87 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
), TRUE
);
89 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
) {
92 selected
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
94 filename
= malloc (strlen (selected
) + 5);
95 strcpy (filename
, selected
);
97 if (strlen (selected
) < 5 || strcmp (".fps", selected
+ strlen (selected
) - 4)) {
98 strcat (filename
, ".fps");
101 if (!fst_save_state (jvst
->fst
, filename
)) {
102 GtkWidget
* errdialog
= gtk_message_dialog_new (GTK_WINDOW (window
),
103 GTK_DIALOG_DESTROY_WITH_PARENT
,
106 "Error saving file '%s'",
108 gtk_dialog_run (GTK_DIALOG (errdialog
));
109 gtk_widget_destroy (errdialog
);
115 gtk_widget_destroy (dialog
);
116 gtk_widget_grab_focus( gtk_socket
);
120 load_handler (GtkToggleButton
*but
, gboolean ptr
)
122 JackVST
* jvst
= (JackVST
*) ptr
;
125 dialog
= gtk_file_chooser_dialog_new ("Load Plugin State",
127 GTK_FILE_CHOOSER_ACTION_OPEN
,
128 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
129 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
132 GtkFileFilter
* ff
= gtk_file_filter_new();
133 gtk_file_filter_set_name(ff
,"FST Plugin State");
134 gtk_file_filter_add_pattern(ff
,"*.fps");
135 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog
),ff
);
137 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
) {
139 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
141 if (!fst_load_state (jvst
->fst
, filename
)) {
142 GtkWidget
* errdialog
= gtk_message_dialog_new (GTK_WINDOW (window
),
143 GTK_DIALOG_DESTROY_WITH_PARENT
,
146 "Error loading file '%s'",
148 gtk_dialog_run (GTK_DIALOG (errdialog
));
149 gtk_widget_destroy (errdialog
);
154 gtk_widget_destroy (dialog
);
155 gtk_widget_grab_focus( gtk_socket
);
159 remove_handler (GtkToggleButton
*but
, gboolean ptr
)
161 JackVST
* jvst
= (JackVST
*) ptr
;
163 jack_deactivate (jvst
->client
);
164 fst_destroy_editor (jvst
->fst
);
168 configure_handler (GtkWidget
* widget
, GdkEventConfigure
* ev
, GtkSocket
*sock
)
174 g_return_if_fail (sock
->plug_window
!= NULL
);
176 w
= sock
->plug_window
;
177 event
.xconfigure
.type
= ConfigureNotify
;
179 event
.xconfigure
.event
= GDK_WINDOW_XWINDOW (w
);
180 event
.xconfigure
.window
= GDK_WINDOW_XWINDOW (w
);
182 /* The ICCCM says that synthetic events should have root relative
183 * coordinates. We still aren't really ICCCM compliant, since
184 * we don't send events when the real toplevel is moved.
186 gdk_error_trap_push ();
187 gdk_window_get_origin (w
, &x
, &y
);
188 gdk_error_trap_pop ();
190 event
.xconfigure
.x
= x
;
191 event
.xconfigure
.y
= y
;
192 event
.xconfigure
.width
= GTK_WIDGET(sock
)->allocation
.width
;
193 event
.xconfigure
.height
= GTK_WIDGET(sock
)->allocation
.height
;
195 event
.xconfigure
.border_width
= 0;
196 event
.xconfigure
.above
= None
;
197 event
.xconfigure
.override_redirect
= False
;
199 gdk_error_trap_push ();
200 XSendEvent (gdk_x11_drawable_get_xdisplay (w
),
201 GDK_WINDOW_XWINDOW (sock
->plug_window
),
202 False
, StructureNotifyMask
, &event
);
203 //gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (sock)));
204 gdk_error_trap_pop ();
210 forward_key_event (GtkSocket
*sock
, GdkEventKey
* ev
, JackVST
* jvst
)
215 g_return_if_fail (sock
->plug_window
!= NULL
);
217 event
.type
= (ev
->type
== GDK_KEY_PRESS
? KeyPress
: KeyRelease
);
218 event
.display
= gdk_x11_drawable_get_xdisplay (sock
->plug_window
);
219 event
.window
= fst_get_XID (jvst
->fst
);
220 event
.time
= ev
->time
;
225 event
.state
= ev
->state
;
226 event
.keycode
= ev
->hardware_keycode
;
227 event
.same_screen
= True
;
229 gdk_error_trap_push ();
230 XSendEvent (event
.display
, event
.window
, False
, 0, (XEvent
*) &event
);
231 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (sock
)));
232 gdk_error_trap_pop ();
236 destroy_handler (GtkWidget
* widget
, GdkEventAny
* ev
, gpointer ptr
)
238 JackVST
* jvst
= (JackVST
*) ptr
;
239 fst_destroy_editor (jvst
->fst
);
247 focus_handler (GtkWidget
* widget
, GdkEventFocus
* ev
, gpointer ptr
)
250 fst_error ("Socket focus in");
252 fst_error ("Socket focus out");
259 program_change (GtkComboBox
*combo
, JackVST
*jvst
)
261 int program
= gtk_combo_box_get_active (combo
);
262 printf ("active: %d\n", program
);
263 // cant be done here. plugin only expects one GUI thread.
264 //jvst->fst->plugin->dispatcher( jvst->fst->plugin, effSetProgram, 0, program, NULL, 0.0 );
265 jvst
->fst
->want_program
= program
;
266 gtk_widget_grab_focus( gtk_socket
);
271 save_data( JackVST
*jvst
)
274 lash_config_t
*config
;
277 for( i
=0; i
<jvst
->fst
->plugin
->numParams
; i
++ ) {
281 snprintf( buf
, 9, "%d", i
);
283 config
= lash_config_new_with_key( buf
);
285 pthread_mutex_lock( &(jvst
->fst
->lock
) );
286 param
= jvst
->fst
->plugin
->getParameter( jvst
->fst
->plugin
, i
);
287 pthread_mutex_unlock( &(jvst
->fst
->lock
) );
289 lash_config_set_value_double(config
, param
);
290 lash_send_config(lash_client
, config
);
291 //lash_config_destroy( config );
294 for( i
=0; i
<128; i
++ ) {
297 snprintf( buf
, 15, "midi_map%d", i
);
298 config
= lash_config_new_with_key( buf
);
299 lash_config_set_value_int(config
, jvst
->midi_map
[i
]);
300 lash_send_config(lash_client
, config
);
301 //lash_config_destroy( config );
304 if( jvst
->fst
->plugin
->flags
& 32 ) {
305 // TODO: calling from this thread is wrong.
306 // is should move it to fst gui thread.
307 printf( "getting chunk...\n" );
309 // XXX: alternative. call using the fst->lock
310 //pthread_mutex_lock( &(fst->lock) );
311 //bytelen = jvst->fst->plugin->dispatcher( jvst->fst->plugin, 23, 0, 0, &chunk, 0 );
312 //pthread_mutex_unlock( &(fst->lock) );
314 bytelen
= fst_call_dispatcher( jvst
->fst
, 23, 0, 0, &chunk
, 0 );
315 printf( "got tha chunk..\n" );
318 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
320 config
= lash_config_new_with_key( "bin_chunk" );
321 lash_config_set_value(config
, chunk
, bytelen
);
322 lash_send_config(lash_client
, config
);
323 //lash_config_destroy( config );
333 restore_data(lash_config_t
* config
, JackVST
*jvst
)
337 key
= lash_config_get_key(config
);
339 if (strncmp(key
, "midi_map", strlen( "midi_map")) == 0) {
340 int cc
= atoi( key
+strlen("midi_map") );
341 int param
= lash_config_get_value_int( config
);
343 if( cc
< 0 || cc
>=128 || param
<0 || param
>=jvst
->fst
->plugin
->numParams
)
346 jvst
->midi_map
[cc
] = param
;
350 if( jvst
->fst
->plugin
->flags
& 32 ) {
351 if (strcmp(key
, "bin_chunk") == 0) {
352 fst_call_dispatcher( jvst
->fst
, 24, 0, lash_config_get_value_size( config
), (void *) lash_config_get_value( config
), 0 );
356 pthread_mutex_lock( & jvst
->fst
->lock
);
357 jvst
->fst
->plugin
->setParameter( jvst
->fst
->plugin
, atoi( key
), lash_config_get_value_double( config
) );
358 pthread_mutex_unlock( & jvst
->fst
->lock
);
365 idle_cb(JackVST
*jvst
)
368 gtk_widget_destroy( window
);
369 fst_destroy_editor( jvst
->fst
);
375 if( jvst
->fst
->want_program
== -1 && gtk_combo_box_get_active( GTK_COMBO_BOX( preset_listbox
) ) != jvst
->current_program
)
376 gtk_combo_box_set_active( GTK_COMBO_BOX( preset_listbox
), jvst
->current_program
);
378 if( jvst
->midi_learn
&& jvst
->midi_learn_CC
!= -1 && jvst
->midi_learn_PARAM
!= -1 ) {
379 if( jvst
->midi_learn_CC
< 128 ) {
380 jvst
->midi_map
[jvst
->midi_learn_CC
] = jvst
->midi_learn_PARAM
;
382 jvst
->midi_learn
= 0;
383 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( midi_learn_toggle
), 0 );
387 if (lash_enabled(lash_client
)) {
389 lash_config_t
*config
;
391 while ((event
= lash_get_event(lash_client
))) {
392 switch (lash_event_get_type(event
)) {
395 lash_event_destroy(event
);
397 case LASH_Restore_Data_Set
:
398 printf( "lash_restore... \n" );
399 lash_send_event(lash_client
, event
);
401 case LASH_Save_Data_Set
:
402 printf( "lash_save... \n" );
404 lash_send_event(lash_client
, event
);
406 case LASH_Server_Lost
:
409 printf("%s: receieved unknown LASH event of type %d",
410 __FUNCTION__
, lash_event_get_type(event
));
411 lash_event_destroy(event
);
416 while ((config
= lash_get_config(lash_client
))) {
417 restore_data(config
, jvst
);
418 lash_config_destroy(config
);
426 GtkListStore
*create_preset_store( FST
*fst
)
428 GtkListStore
*retval
= gtk_list_store_new( 2, G_TYPE_STRING
, G_TYPE_INT
);
430 int vst_version
= fst
->plugin
->dispatcher (fst
->plugin
, effGetVstVersion
, 0, 0, NULL
, 0.0f
);
431 for( i
=0; i
<fst
->plugin
->numPrograms
; i
++ )
434 GtkTreeIter new_row_iter
;
436 snprintf( buf
, 90, "preset %d", i
);
437 if( vst_version
>= 2 )
438 fst
->plugin
->dispatcher( fst
->plugin
, 29, i
, 0, buf
, 0.0 );
440 gtk_list_store_insert( retval
, &new_row_iter
, i
);
441 gtk_list_store_set( retval
, &new_row_iter
, 0, buf
, 1, i
, -1 );
444 if( fst
->plugin
->numPrograms
> 0 )
445 fst
->plugin
->dispatcher( fst
->plugin
, effSetProgram
, 0, 0, NULL
, 0.0 );
450 manage_vst_plugin (JackVST
* jvst
)
452 // create a GtkWindow containing a GtkSocket...
454 // notice the order of the functions.
455 // you can only add an id to an anchored widget.
456 GtkCellRenderer
*renderer
;
458 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
459 gtk_window_set_title (GTK_WINDOW(window
), jvst
->handle
->name
);
461 vpacker
= gtk_vbox_new (FALSE
, 7);
462 hpacker
= gtk_hbox_new (FALSE
, 7);
463 bypass_button
= gtk_toggle_button_new_with_label ("bypass");
464 mute_button
= gtk_toggle_button_new_with_label ("mute");
465 remove_button
= gtk_toggle_button_new_with_label ("remove");
466 midi_learn_toggle
= gtk_toggle_button_new_with_label ("midi Learn");
467 save_button
= gtk_button_new_with_label ("save state");
468 load_button
= gtk_button_new_with_label ("load state");
471 //----------------------------------------------------------------------------------
472 preset_listbox
= gtk_combo_box_new_with_model( GTK_TREE_MODEL(create_preset_store( jvst
->fst
)) );
474 renderer
= gtk_cell_renderer_text_new ();
475 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (preset_listbox
), renderer
, TRUE
);
476 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (preset_listbox
), renderer
, "text", 0, NULL
);
477 gtk_combo_box_set_active( GTK_COMBO_BOX(preset_listbox
), 0 );
478 g_signal_connect( G_OBJECT(preset_listbox
), "changed", G_CALLBACK( program_change
), jvst
);
479 //----------------------------------------------------------------------------------
482 g_signal_connect (G_OBJECT(bypass_button
), "toggled",
483 G_CALLBACK(bypass_handler
),
486 g_signal_connect (G_OBJECT(mute_button
), "toggled",
487 G_CALLBACK(mute_handler
),
490 g_signal_connect (G_OBJECT(midi_learn_toggle
), "toggled",
491 G_CALLBACK(learn_handler
),
494 g_signal_connect (G_OBJECT(remove_button
), "toggled",
495 G_CALLBACK(remove_handler
),
498 g_signal_connect (G_OBJECT(load_button
), "clicked",
499 G_CALLBACK(load_handler
),
502 g_signal_connect (G_OBJECT(save_button
), "clicked",
503 G_CALLBACK(save_handler
),
507 gtk_container_set_border_width (GTK_CONTAINER(hpacker
), 3);
509 g_signal_connect (G_OBJECT(window
), "delete_event",
510 G_CALLBACK(destroy_handler
),
513 gtk_socket
= gtk_socket_new ();
514 GTK_WIDGET_SET_FLAGS(gtk_socket
, GTK_CAN_FOCUS
);
516 gtk_box_pack_end (GTK_BOX(hpacker
), midi_learn_toggle
, FALSE
, FALSE
, 0);
517 gtk_box_pack_end (GTK_BOX(hpacker
), preset_listbox
, FALSE
, FALSE
, 0);
518 gtk_box_pack_end (GTK_BOX(hpacker
), bypass_button
, FALSE
, FALSE
, 0);
519 gtk_box_pack_end (GTK_BOX(hpacker
), mute_button
, FALSE
, FALSE
, 0);
520 gtk_box_pack_end (GTK_BOX(hpacker
), load_button
, FALSE
, FALSE
, 0);
521 gtk_box_pack_end (GTK_BOX(hpacker
), save_button
, FALSE
, FALSE
, 0);
522 // gtk_box_pack_end (GTK_BOX(hpacker), remove_button, FALSE, FALSE, 0);
523 gtk_box_pack_start (GTK_BOX(vpacker
), hpacker
, FALSE
, FALSE
, 0);
524 gtk_box_pack_start (GTK_BOX(vpacker
), gtk_socket
, TRUE
, FALSE
, 0);
526 gtk_container_add (GTK_CONTAINER (window
), vpacker
);
528 // normally every socket should register it self like this.
529 g_signal_connect (G_OBJECT(window
), "configure_event",
530 G_CALLBACK(configure_handler
),
534 // but you can show() a GtkSocket only with an id set.
535 gtk_socket_add_id (GTK_SOCKET (gtk_socket
), fst_get_XID (jvst
->fst
));
537 SetWindowPos (jvst
->fst
->window
, 0, 0, 0, jvst
->fst
->width
, jvst
->fst
->height
+24, 0);
538 ShowWindow (jvst
->fst
->window
, SW_SHOWNA
);
540 gtk_widget_show_all (window
);
541 gtk_widget_grab_focus( gtk_socket
);
543 g_timeout_add(500, (GSourceFunc
) idle_cb
, jvst
);
545 printf( "calling gtk_main now\n" );
552 typedef int (*error_handler_t
)( Display
*, XErrorEvent
*);
553 static Display
*the_gtk_display
;
554 error_handler_t wine_error_handler
;
555 error_handler_t gtk_error_handler
;
557 int fst_xerror_handler( Display
*disp
, XErrorEvent
*ev
)
559 if( disp
== the_gtk_display
) {
560 printf( "relaying error to gtk\n" );
561 return gtk_error_handler( disp
, ev
);
563 printf( "relaying error to wine\n" );
564 return wine_error_handler( disp
, ev
);
569 gui_init (int *argc
, char **argv
[])
571 wine_error_handler
= XSetErrorHandler( NULL
);
572 gtk_init (argc
, argv
);
573 the_gtk_display
= gdk_x11_display_get_xdisplay( gdk_display_get_default() );
574 gtk_error_handler
= XSetErrorHandler( fst_xerror_handler
);