2 Copyright (C) 2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /******************************************************************/
21 /*linuxDSP - pluginui variant for LXVST (native Linux VST) Plugins*/
22 /******************************************************************/
24 #include <ardour/vstfx.h>
26 #include <gtk/gtksocket.h>
27 #include <ardour/processor.h>
28 #include <ardour/lxvst_plugin.h>
30 #include "ardour_ui.h"
31 #include "plugin_ui.h"
32 #include "lxvst_plugin_ui.h"
36 #define LXVST_H_FIDDLE 40
39 using namespace ARDOUR;
42 LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<LXVSTPlugin> lxvp)
46 create_preset_store ();
48 vstfx_run_editor (lxvst->vstfx());
50 if (lxvst->vstfx()->current_program != -1) {
51 lxvst_preset_combo.set_active (lxvst->vstfx()->current_program);
53 lxvst_preset_combo.set_active (0);
56 preset_box.set_spacing (6);
57 preset_box.set_border_width (6);
58 preset_box.pack_end (bypass_button, false, false, 10);
59 preset_box.pack_end (save_button, false, false);
60 preset_box.pack_end (lxvst_preset_combo, false, false);
62 lxvst_preset_combo.signal_changed().connect (mem_fun (*this, &LXVSTPluginUI::preset_chosen));
64 if (!insert->active()) {
65 bypass_button.set_active_state (Gtkmm2ext::Active);
67 bypass_button.unset_active_state ();
70 pack_start (preset_box, false, false);
71 pack_start (socket, true, true);
74 LXVSTPluginUI::~LXVSTPluginUI ()
77 _screen_update_connection.disconnect();
79 // plugin destructor destroys the custom GUI, via the vstfx engine,
80 // and then our PluginUIWindow does the rest
85 LXVSTPluginUI::start_updating (GdkEventAny* ignored)
87 _screen_update_connection.disconnect();
88 _screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
89 (mem_fun(*this, &LXVSTPluginUI::resize_callback));
94 LXVSTPluginUI::stop_updating (GdkEventAny* ignored)
96 _screen_update_connection.disconnect();
102 LXVSTPluginUI::resize_callback()
104 /*We could maybe use this to resize the plugin GTK parent window
107 if(lxvst->vstfx()->want_resize)
109 int new_height = lxvst->vstfx()->height;
110 int new_width = lxvst->vstfx()->width;
112 void* gtk_parent_window = lxvst->vstfx()->extra_data;
114 if(gtk_parent_window)
115 ((Gtk::Window*)gtk_parent_window)->resize(new_width, new_height + LXVST_H_FIDDLE);
117 lxvst->vstfx()->want_resize = 0;
122 LXVSTPluginUI::preset_selected ()
124 socket.grab_focus ();
125 PlugUIBase::preset_selected ();
129 LXVSTPluginUI::preset_chosen ()
131 // we can't dispatch directly here, too many plugins only expects one GUI thread.
133 lxvst->vstfx()->want_program = lxvst_preset_combo.get_active_row_number ();
134 socket.grab_focus ();
138 LXVSTPluginUI::get_preferred_height ()
142 /*We have to return the required height of the plugin UI window + a fiddle factor
143 because we can't know how big the preset menu bar is until the window is realised
144 and we can't realise it until we have told it how big we would like it to be
145 which we can't do until it is realised etc*/
147 return (lxvst->vstfx()->height) + LXVST_H_FIDDLE; //May not be 40 for all screen res etc
151 LXVSTPluginUI::get_preferred_width ()
153 return lxvst->vstfx()->width;
157 LXVSTPluginUI::package (Gtk::Window& win)
159 /* forward configure events to plugin window */
161 win.signal_configure_event().connect (bind (mem_fun (*this, &LXVSTPluginUI::configure_handler), &socket), false);
163 /*Map the UI start and stop updating events to 'Map' events on the Window*/
165 win.signal_map_event().connect (mem_fun (*this, &LXVSTPluginUI::start_updating));
166 win.signal_unmap_event().connect (mem_fun (*this, &LXVSTPluginUI::stop_updating));
168 /* this assumes that the window's owner understands the XEmbed protocol. */
170 socket.add_id (vstfx_get_XID (lxvst->vstfx()));
172 vstfx_move_window_into_view (lxvst->vstfx());
174 lxvst->vstfx()->extra_data = (void*)(&win);
175 lxvst->vstfx()->want_resize = 0;
181 LXVSTPluginUI::configure_handler (GdkEventConfigure* ev, Gtk::Socket *socket)
187 if (socket == 0 || ((w = socket->gobj()->plug_window) == 0)) {
191 event.xconfigure.type = ConfigureNotify;
192 event.xconfigure.event = GDK_WINDOW_XWINDOW (w);
193 event.xconfigure.window = GDK_WINDOW_XWINDOW (w);
195 /* The ICCCM says that synthetic events should have root relative
196 * coordinates. We still aren't really ICCCM compliant, since
197 * we don't send events when the real toplevel is moved.
199 gdk_error_trap_push ();
200 gdk_window_get_origin (w, &x, &y);
201 gdk_error_trap_pop ();
203 event.xconfigure.x = x;
204 event.xconfigure.y = y;
205 event.xconfigure.width = GTK_WIDGET(socket->gobj())->allocation.width;
206 event.xconfigure.height = GTK_WIDGET(socket->gobj())->allocation.height;
208 event.xconfigure.border_width = 0;
209 event.xconfigure.above = None;
210 event.xconfigure.override_redirect = False;
212 gdk_error_trap_push ();
213 XSendEvent (GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XWINDOW (w), False, StructureNotifyMask, &event);
214 gdk_error_trap_pop ();
220 LXVSTPluginUI::forward_key_event (GdkEventKey* ev)
222 std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
227 LXVSTPluginUI::create_preset_store ()
229 VSTState* vstfx = lxvst->vstfx();
231 int vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
233 preset_model = ListStore::create (preset_columns);
235 for (int i = 0; i < vstfx->plugin->numPrograms; ++i) {
237 TreeModel::Row row = *(preset_model->append());
239 snprintf (buf, 90, "preset %d", i);
241 if (vst_version >= 2) {
242 vstfx->plugin->dispatcher (vstfx->plugin, 29, i, 0, buf, 0.0);
245 row[preset_columns.name] = buf;
246 row[preset_columns.number] = i;
249 lxvst_preset_combo.set_model (preset_model);
251 CellRenderer* renderer = manage (new CellRendererText());
252 lxvst_preset_combo.pack_start (*renderer, true);
253 lxvst_preset_combo.add_attribute (*renderer, "text", 0);
256 typedef int (*error_handler_t)( Display *, XErrorEvent *);
257 static Display *the_gtk_display;
258 static error_handler_t vstfx_error_handler;
259 static error_handler_t gtk_error_handler;
262 gtk_xerror_handler( Display *disp, XErrorEvent *ev )
264 std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
270 gui_init (int *argc, char **argv[])
272 vstfx_error_handler = XSetErrorHandler (NULL);
273 gtk_init (argc, argv);
274 the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
275 gtk_error_handler = XSetErrorHandler( gtk_xerror_handler );