2 * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2013-2018 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "gtkmm2ext/gui_thread.h"
23 #include "ardour/lxvst_plugin.h"
24 #include "ardour/linux_vst_support.h"
25 #include "lxvst_plugin_ui.h"
27 #include <gdk/gdkx.h> /* must come later than glibmm/object.h */
29 #define LXVST_H_FIDDLE 40
33 using namespace ARDOUR;
36 LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<VSTPlugin> lxvp)
37 : VSTPluginUI (pi, lxvp)
39 vstfx_run_editor (_vst->state ());
42 LXVSTPluginUI::~LXVSTPluginUI ()
44 _resize_connection.disconnect();
46 // plugin destructor destroys the custom GUI, via the vstfx engine,
47 // and then our PluginUIWindow does the rest
51 LXVSTPluginUI::resize_callback ()
53 void* gtk_parent_window = _vst->state()->gtk_window_parent;
55 if (gtk_parent_window) {
56 int width = _vst->state()->width;
57 int height = _vst->state()->height;
59 printf ("LXVSTPluginUI::resize_callback %d x %d\n", width, height);
61 _socket.set_size_request(
62 width + _vst->state()->hoffset,
63 height + _vst->state()->voffset);
65 ((Gtk::Window*) gtk_parent_window)->resize (width, height + LXVST_H_FIDDLE);
66 if (_vst->state()->linux_plugin_ui_window) {
72 LXVSTPluginUI::get_preferred_height ()
76 /* We have to return the required height of the plugin UI window + a fiddle factor
77 because we can't know how big the preset menu bar is until the window is realised
78 and we can't realise it until we have told it how big we would like it to be
79 which we can't do until it is realised etc
82 // May not be 40 for all screen res etc
83 return VSTPluginUI::get_preferred_height () + LXVST_H_FIDDLE;
87 LXVSTPluginUI::package (Gtk::Window& win)
89 VSTPluginUI::package (win);
90 _vst->state()->gtk_window_parent = (void*) (&win);
92 /* Map the UI start and stop updating events to 'Map' events on the Window */
94 _vst->VSTSizeWindow.connect (_resize_connection, invalidator (*this), boost::bind (&LXVSTPluginUI::resize_callback, this), gui_context());
99 LXVSTPluginUI::forward_key_event (GdkEventKey* gdk_key)
101 if (!_vst->state()->gtk_window_parent) {
105 Glib::RefPtr<Gdk::Window> gdk_window = ((Gtk::Window*) _vst->state()->gtk_window_parent)->get_window();
114 switch (gdk_key->type) {
116 xev.xany.type = KeyPress;
119 case GDK_KEY_RELEASE:
120 xev.xany.type = KeyRelease;
121 mask = KeyReleaseMask;
127 /* XXX relies on GDK using X11 definitions for these fields */
129 xev.xkey.state = gdk_key->state;
130 xev.xkey.keycode = gdk_key->hardware_keycode; /* see gdk/x11/gdkevents-x11.c:translate_key_event() */
136 xev.xkey.root = gdk_x11_get_default_root_xwindow();
137 xev.xkey.window = _vst->state()->linux_plugin_ui_window ? _vst->state()->linux_plugin_ui_window : _vst->state()->xid;
138 xev.xkey.subwindow = None;
139 xev.xkey.time = gdk_key->time;
141 xev.xany.serial = 0; /* we don't have one */
142 xev.xany.send_event = true; /* pretend we are using XSendEvent */
143 xev.xany.display = GDK_WINDOW_XDISPLAY (gdk_window->gobj());
145 if (_vst->state()->eventProc) {
146 _vst->state()->eventProc (&xev);
147 } else if (!dispatch_effeditkey (gdk_key)) {
148 XSendEvent (xev.xany.display, xev.xany.window, TRUE, mask, &xev);
153 LXVSTPluginUI::get_XID ()
155 /* Wait for the lock to become free - otherwise
156 the window might be in the process of being
157 created and we get bad Window errors when trying
158 to embed it in the GTK UI
161 pthread_mutex_lock (&(_vst->state()->lock));
163 /* The Window may be scheduled for creation
164 but not actually created by the gui_event_loop yet -
165 spin here until it has been activated. Possible
166 deadlock if the window never gets activated but
167 should not be called here if the window doesn't
168 exist or will never exist
171 while (!(_vst->state()->been_activated)) {
175 int const id = _vst->state()->xid;
177 pthread_mutex_unlock (&(_vst->state()->lock));
179 /* Finally it might be safe to return the ID -
180 problems will arise if we return either a zero ID
181 and GTK tries to socket it or if we return an ID
182 which hasn't yet become real to the server
188 typedef int (*error_handler_t)( Display *, XErrorEvent *);
189 static Display *the_gtk_display;
190 static error_handler_t vstfx_error_handler;
191 static error_handler_t gtk_error_handler;
194 gtk_xerror_handler (Display*, XErrorEvent*)
196 std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
202 gui_init (int* argc, char** argv[])
204 vstfx_error_handler = XSetErrorHandler (NULL);
205 gtk_init (argc, argv);
206 the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
207 gtk_error_handler = XSetErrorHandler (gtk_xerror_handler);