Remove prints, now that signals work properly
[klaudia.git] / fst / gtk.c
blob8acdb7689649d0fee05439b5346c95b42fb3b56f
3 #include "jackvst.h"
5 #include <gtk/gtk.h>
6 #include <gdk/gdkx.h>
7 #include <gdk/gdkevents.h>
8 #include <X11/Xlib.h>
10 #include <glib-2.0/glib.h>
12 gboolean g_quit = FALSE;
13 gboolean quit = FALSE;
15 static GtkWidget* window;
16 static GtkWidget* gtk_socket;
17 static GtkWidget* vpacker;
18 static GtkWidget* hpacker;
19 static GtkWidget* bypass_button;
20 static GtkWidget* remove_button;
21 static GtkWidget* mute_button;
22 static GtkWidget* event_box;
23 static GtkWidget* preset_listbox;
24 static GtkWidget* midi_learn_toggle;
25 static GtkWidget* load_button;
26 static GtkWidget* save_button;
29 static void
30 learn_handler (GtkToggleButton *but, gboolean ptr)
32 JackVST* jvst = (JackVST*) ptr;
34 if( gtk_toggle_button_get_active (but) ) {
35 jvst->midi_learn = 1;
36 jvst->midi_learn_CC = -1;
37 jvst->midi_learn_PARAM = -1;
38 } else {
39 jvst->midi_learn = 0;
41 gtk_widget_grab_focus( gtk_socket );
44 static void
45 bypass_handler (GtkToggleButton *but, gboolean ptr)
47 JackVST* jvst = (JackVST*) ptr;
49 jvst->bypassed = gtk_toggle_button_get_active (but);
50 gtk_widget_grab_focus( gtk_socket );
53 static void
54 mute_handler (GtkToggleButton *but, gboolean ptr)
56 JackVST* jvst = (JackVST*) ptr;
57 jvst->muted = gtk_toggle_button_get_active (but);
58 gtk_widget_grab_focus( gtk_socket );
61 static void
62 save_handler (GtkToggleButton *but, gboolean ptr)
64 int i, bytelen = 0;
65 void *chunk;
67 JackVST* jvst = (JackVST*) ptr;
69 GtkWidget *dialog;
70 dialog = gtk_file_chooser_dialog_new ("Save Plugin State",
71 GTK_WINDOW (window),
72 GTK_FILE_CHOOSER_ACTION_SAVE,
73 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
74 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
75 NULL);
77 GtkFileFilter * ff = gtk_file_filter_new();
78 gtk_file_filter_set_name(ff,"FST Plugin State");
79 gtk_file_filter_add_pattern(ff,"*.fps");
80 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),ff);
82 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
84 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
85 char *filename;
86 char *selected;
87 selected = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
89 filename = malloc (strlen (selected) + 5);
90 strcpy (filename, selected);
92 if (strlen (selected) < 5 || strcmp (".fps", selected + strlen (selected) - 4)) {
93 strcat (filename, ".fps");
96 if (!fst_save_state (jvst->fst, filename)) {
97 GtkWidget * errdialog = gtk_message_dialog_new (GTK_WINDOW (window),
98 GTK_DIALOG_DESTROY_WITH_PARENT,
99 GTK_MESSAGE_ERROR,
100 GTK_BUTTONS_CLOSE,
101 "Error saving file '%s'",
102 filename);
103 gtk_dialog_run (GTK_DIALOG (errdialog));
104 gtk_widget_destroy (errdialog);
107 g_free (selected);
108 free (filename);
110 gtk_widget_destroy (dialog);
111 gtk_widget_grab_focus( gtk_socket );
114 static void
115 load_handler (GtkToggleButton *but, gboolean ptr)
117 JackVST* jvst = (JackVST*) ptr;
119 GtkWidget *dialog;
120 dialog = gtk_file_chooser_dialog_new ("Load Plugin State",
121 GTK_WINDOW (window),
122 GTK_FILE_CHOOSER_ACTION_OPEN,
123 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
124 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
125 NULL);
127 GtkFileFilter * ff = gtk_file_filter_new();
128 gtk_file_filter_set_name(ff,"FST Plugin State");
129 gtk_file_filter_add_pattern(ff,"*.fps");
130 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),ff);
132 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
133 char *filename;
134 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
136 if (!fst_load_state (jvst->fst, filename)) {
137 GtkWidget * errdialog = gtk_message_dialog_new (GTK_WINDOW (window),
138 GTK_DIALOG_DESTROY_WITH_PARENT,
139 GTK_MESSAGE_ERROR,
140 GTK_BUTTONS_CLOSE,
141 "Error loading file '%s'",
142 filename);
143 gtk_dialog_run (GTK_DIALOG (errdialog));
144 gtk_widget_destroy (errdialog);
147 g_free (filename);
149 gtk_widget_destroy (dialog);
150 gtk_widget_grab_focus( gtk_socket );
153 static void
154 remove_handler (GtkToggleButton *but, gboolean ptr)
156 JackVST* jvst = (JackVST*) ptr;
158 jack_deactivate (jvst->client);
159 fst_destroy_editor (jvst->fst);
162 static gboolean
163 configure_handler (GtkWidget* widget, GdkEventConfigure* ev, GtkSocket *sock)
165 XEvent event;
166 gint x, y;
167 GdkWindow *w;
169 g_return_if_fail (sock->plug_window != NULL);
171 w = sock->plug_window;
172 event.xconfigure.type = ConfigureNotify;
174 event.xconfigure.event = GDK_WINDOW_XWINDOW (w);
175 event.xconfigure.window = GDK_WINDOW_XWINDOW (w);
177 /* The ICCCM says that synthetic events should have root relative
178 * coordinates. We still aren't really ICCCM compliant, since
179 * we don't send events when the real toplevel is moved.
181 gdk_error_trap_push ();
182 gdk_window_get_origin (w, &x, &y);
183 gdk_error_trap_pop ();
185 event.xconfigure.x = x;
186 event.xconfigure.y = y;
187 event.xconfigure.width = GTK_WIDGET(sock)->allocation.width;
188 event.xconfigure.height = GTK_WIDGET(sock)->allocation.height;
190 event.xconfigure.border_width = 0;
191 event.xconfigure.above = None;
192 event.xconfigure.override_redirect = False;
194 gdk_error_trap_push ();
195 XSendEvent (gdk_x11_drawable_get_xdisplay (w),
196 GDK_WINDOW_XWINDOW (sock->plug_window),
197 False, StructureNotifyMask, &event);
198 //gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (sock)));
199 gdk_error_trap_pop ();
201 return FALSE;
204 void
205 forward_key_event (GtkSocket *sock, GdkEventKey* ev, JackVST* jvst)
207 XKeyEvent event;
208 Status status;
210 g_return_if_fail (sock->plug_window != NULL);
212 event.type = (ev->type == GDK_KEY_PRESS ? KeyPress : KeyRelease);
213 event.display = gdk_x11_drawable_get_xdisplay (sock->plug_window);
214 event.window = fst_get_XID (jvst->fst);
215 event.time = ev->time;
216 event.x = 1;
217 event.y = 1;
218 event.x_root = 1;
219 event.y_root = 1;
220 event.state = ev->state;
221 event.keycode = ev->hardware_keycode;
222 event.same_screen = True;
224 gdk_error_trap_push ();
225 XSendEvent (event.display, event.window, False, 0, (XEvent*) &event);
226 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (sock)));
227 gdk_error_trap_pop ();
230 static gboolean
231 destroy_handler (GtkWidget* widget, GdkEventAny* ev, gpointer ptr)
233 JackVST* jvst = (JackVST*) ptr;
234 fst_destroy_editor (jvst->fst);
235 //exit (0);
236 gtk_main_quit();
238 return FALSE;
242 focus_handler (GtkWidget* widget, GdkEventFocus* ev, gpointer ptr)
244 if (ev->in) {
245 fst_error ("Socket focus in");
246 } else {
247 fst_error ("Socket focus out");
250 return FALSE;
253 static void
254 program_change (GtkComboBox *combo, JackVST *jvst)
256 int program = gtk_combo_box_get_active (combo);
257 printf ("active: %d\n", program );
258 // cant be done here. plugin only expects one GUI thread.
259 //jvst->fst->plugin->dispatcher( jvst->fst->plugin, effSetProgram, 0, program, NULL, 0.0 );
260 jvst->fst->want_program = program;
261 gtk_widget_grab_focus( gtk_socket );
264 static gboolean
265 idle_cb(JackVST *jvst)
267 if (quit) {
268 gtk_widget_destroy( window );
269 fst_destroy_editor( jvst->fst);
270 gtk_main_quit();
271 //g_quit = TRUE;
272 return FALSE;
275 if( jvst->fst->want_program == -1 && gtk_combo_box_get_active( GTK_COMBO_BOX( preset_listbox ) ) != jvst->current_program )
276 gtk_combo_box_set_active( GTK_COMBO_BOX( preset_listbox ), jvst->current_program );
278 if( jvst->midi_learn && jvst->midi_learn_CC != -1 && jvst->midi_learn_PARAM != -1 ) {
279 if( jvst->midi_learn_CC < 128 ) {
280 jvst->midi_map[jvst->midi_learn_CC] = jvst->midi_learn_PARAM;
282 jvst->midi_learn = 0;
283 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( midi_learn_toggle ), 0 );
286 return TRUE;
289 GtkListStore *create_preset_store( FST *fst )
291 GtkListStore *retval = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
292 int i;
293 int vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
294 for( i=0; i<fst->plugin->numPrograms; i++ )
296 char buf[100];
297 GtkTreeIter new_row_iter;
299 snprintf( buf, 90, "preset %d", i );
300 if( vst_version >= 2 )
301 fst->plugin->dispatcher( fst->plugin, 29, i, 0, buf, 0.0 );
303 gtk_list_store_insert( retval, &new_row_iter, i );
304 gtk_list_store_set( retval, &new_row_iter, 0, buf, 1, i, -1 );
307 if( fst->plugin->numPrograms > 0 )
308 fst->plugin->dispatcher( fst->plugin, effSetProgram, 0, 0, NULL, 0.0 );
309 else
311 GtkTreeIter new_row_iter;
312 gtk_list_store_insert( retval, &new_row_iter, 0 );
313 gtk_list_store_set( retval, &new_row_iter, 0, "no programs", 1, 0, -1 );
316 return retval;
319 manage_vst_plugin (JackVST* jvst)
321 // create a GtkWindow containing a GtkSocket...
323 // notice the order of the functions.
324 // you can only add an id to an anchored widget.
325 GtkCellRenderer *renderer;
327 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
328 gtk_window_set_title (GTK_WINDOW(window), jvst->handle->name);
330 vpacker = gtk_vbox_new (FALSE, 7);
331 hpacker = gtk_hbox_new (FALSE, 7);
332 bypass_button = gtk_toggle_button_new_with_label ("bypass");
333 mute_button = gtk_toggle_button_new_with_label ("mute");
334 remove_button = gtk_toggle_button_new_with_label ("remove");
335 midi_learn_toggle = gtk_toggle_button_new_with_label ("midi Learn");
336 save_button = gtk_button_new_with_label ("save state");
337 load_button = gtk_button_new_with_label ("load state");
340 //----------------------------------------------------------------------------------
341 preset_listbox = gtk_combo_box_new_with_model( GTK_TREE_MODEL(create_preset_store( jvst->fst )) );
343 renderer = gtk_cell_renderer_text_new ();
344 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (preset_listbox), renderer, TRUE);
345 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (preset_listbox), renderer, "text", 0, NULL);
346 gtk_combo_box_set_active( GTK_COMBO_BOX(preset_listbox), 0 );
347 g_signal_connect( G_OBJECT(preset_listbox), "changed", G_CALLBACK( program_change ), jvst );
348 //----------------------------------------------------------------------------------
351 g_signal_connect (G_OBJECT(bypass_button), "toggled",
352 G_CALLBACK(bypass_handler),
353 jvst);
355 g_signal_connect (G_OBJECT(mute_button), "toggled",
356 G_CALLBACK(mute_handler),
357 jvst);
359 g_signal_connect (G_OBJECT(midi_learn_toggle), "toggled",
360 G_CALLBACK(learn_handler),
361 jvst);
363 g_signal_connect (G_OBJECT(remove_button), "toggled",
364 G_CALLBACK(remove_handler),
365 jvst);
367 g_signal_connect (G_OBJECT(load_button), "clicked",
368 G_CALLBACK(load_handler),
369 jvst);
371 g_signal_connect (G_OBJECT(save_button), "clicked",
372 G_CALLBACK(save_handler),
373 jvst);
376 gtk_container_set_border_width (GTK_CONTAINER(hpacker), 3);
378 g_signal_connect (G_OBJECT(window), "delete_event",
379 G_CALLBACK(destroy_handler),
380 jvst);
382 gtk_socket = gtk_socket_new ();
383 GTK_WIDGET_SET_FLAGS(gtk_socket, GTK_CAN_FOCUS);
385 gtk_box_pack_end (GTK_BOX(hpacker), midi_learn_toggle, FALSE, FALSE, 0);
386 gtk_box_pack_end (GTK_BOX(hpacker), preset_listbox, FALSE, FALSE, 0);
387 gtk_box_pack_end (GTK_BOX(hpacker), bypass_button, FALSE, FALSE, 0);
388 gtk_box_pack_end (GTK_BOX(hpacker), mute_button, FALSE, FALSE, 0);
389 gtk_box_pack_end (GTK_BOX(hpacker), load_button, FALSE, FALSE, 0);
390 gtk_box_pack_end (GTK_BOX(hpacker), save_button, FALSE, FALSE, 0);
391 // gtk_box_pack_end (GTK_BOX(hpacker), remove_button, FALSE, FALSE, 0);
392 gtk_box_pack_start (GTK_BOX(vpacker), hpacker, FALSE, FALSE, 0);
393 gtk_box_pack_start (GTK_BOX(vpacker), gtk_socket, TRUE, FALSE, 0);
395 gtk_container_add (GTK_CONTAINER (window), vpacker);
397 // normally every socket should register it self like this.
398 g_signal_connect (G_OBJECT(window), "configure_event",
399 G_CALLBACK(configure_handler),
400 gtk_socket);
403 // but you can show() a GtkSocket only with an id set.
404 gtk_socket_add_id (GTK_SOCKET (gtk_socket), fst_get_XID (jvst->fst));
406 SetWindowPos (jvst->fst->window, 0, 0, 0, jvst->fst->width, jvst->fst->height+24, 0);
407 ShowWindow (jvst->fst->window, SW_SHOWNA);
409 gtk_widget_show_all (window);
410 gtk_widget_grab_focus( gtk_socket );
412 g_timeout_add(500, (GSourceFunc) idle_cb, jvst);
414 printf( "calling gtk_main now\n" );
415 gtk_main ();
417 return 0;
421 typedef int (*error_handler_t)( Display *, XErrorEvent *);
422 static Display *the_gtk_display;
423 error_handler_t wine_error_handler;
424 error_handler_t gtk_error_handler;
426 int fst_xerror_handler( Display *disp, XErrorEvent *ev )
428 if( disp == the_gtk_display ) {
429 printf( "relaying error to gtk\n" );
430 return gtk_error_handler( disp, ev );
431 } else {
432 printf( "relaying error to wine\n" );
433 return wine_error_handler( disp, ev );
437 void
438 gui_init (int *argc, char **argv[])
440 wine_error_handler = XSetErrorHandler( NULL );
441 gtk_init (argc, argv);
442 the_gtk_display = gdk_x11_display_get_xdisplay( gdk_display_get_default() );
443 gtk_error_handler = XSetErrorHandler( fst_xerror_handler );