Vkeybd: use ArdourWidgets for all GUI elements
[ardour.git] / gtk2_ardour / lxvst_plugin_ui.cc
1 /*
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>
5  *
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.
10  *
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.
15  *
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.
19  */
20
21
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"
26
27 #include <gdk/gdkx.h> /* must come later than glibmm/object.h */
28
29 #define LXVST_H_FIDDLE 40
30
31 using namespace std;
32 using namespace Gtk;
33 using namespace ARDOUR;
34 using namespace PBD;
35
36 LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<VSTPlugin> lxvp)
37         : VSTPluginUI (pi, lxvp)
38 {
39         vstfx_run_editor (_vst->state ());
40 }
41
42 LXVSTPluginUI::~LXVSTPluginUI ()
43 {
44         _resize_connection.disconnect();
45
46         // plugin destructor destroys the custom GUI, via the vstfx engine,
47         // and then our PluginUIWindow does the rest
48 }
49
50 void
51 LXVSTPluginUI::resize_callback ()
52 {
53         void* gtk_parent_window = _vst->state()->gtk_window_parent;
54
55         if (gtk_parent_window) {
56                 int width  = _vst->state()->width;
57                 int height = _vst->state()->height;
58 #ifndef NDEBUG
59                 printf ("LXVSTPluginUI::resize_callback %d x %d\n", width, height);
60 #endif
61                 _socket.set_size_request(
62                                 width  + _vst->state()->hoffset,
63                                 height + _vst->state()->voffset);
64
65                 ((Gtk::Window*) gtk_parent_window)->resize (width, height + LXVST_H_FIDDLE);
66                 if (_vst->state()->linux_plugin_ui_window) {
67                 }
68         }
69 }
70
71 int
72 LXVSTPluginUI::get_preferred_height ()
73 {
74         /* XXX: FIXME */
75
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
80         */
81
82         // May not be 40 for all screen res etc
83         return VSTPluginUI::get_preferred_height () + LXVST_H_FIDDLE;
84 }
85
86 int
87 LXVSTPluginUI::package (Gtk::Window& win)
88 {
89         VSTPluginUI::package (win);
90         _vst->state()->gtk_window_parent = (void*) (&win);
91
92         /* Map the UI start and stop updating events to 'Map' events on the Window */
93
94         _vst->VSTSizeWindow.connect (_resize_connection, invalidator (*this), boost::bind (&LXVSTPluginUI::resize_callback, this), gui_context());
95         return 0;
96 }
97
98 void
99 LXVSTPluginUI::forward_key_event (GdkEventKey* gdk_key)
100 {
101         if (!_vst->state()->gtk_window_parent) {
102                 return;
103         }
104
105         Glib::RefPtr<Gdk::Window> gdk_window = ((Gtk::Window*) _vst->state()->gtk_window_parent)->get_window();
106
107         if (!gdk_window) {
108                 return;
109         }
110
111         XEvent xev;
112         int mask;
113
114         switch (gdk_key->type) {
115         case GDK_KEY_PRESS:
116                 xev.xany.type = KeyPress;
117                 mask = KeyPressMask;
118                 break;
119         case GDK_KEY_RELEASE:
120                 xev.xany.type = KeyRelease;
121                 mask = KeyReleaseMask;
122                 break;
123         default:
124                 return;
125         }
126
127         /* XXX relies on GDK using X11 definitions for these fields */
128
129         xev.xkey.state = gdk_key->state;
130         xev.xkey.keycode = gdk_key->hardware_keycode; /* see gdk/x11/gdkevents-x11.c:translate_key_event() */
131
132         xev.xkey.x = 0;
133         xev.xkey.y = 0;
134         xev.xkey.x_root = 0;
135         xev.xkey.y_root = 0;
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;
140
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());
144
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);
149         }
150 }
151
152 int
153 LXVSTPluginUI::get_XID ()
154 {
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
159         */
160
161         pthread_mutex_lock (&(_vst->state()->lock));
162
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
169         */
170
171         while (!(_vst->state()->been_activated)) {
172                 Glib::usleep (1000);
173         }
174
175         int const id = _vst->state()->xid;
176
177         pthread_mutex_unlock (&(_vst->state()->lock));
178
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
183         */
184
185         return id;
186 }
187
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;
192
193 static int
194 gtk_xerror_handler (Display*, XErrorEvent*)
195 {
196         std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
197
198         return 0;
199 }
200
201 void
202 gui_init (int* argc, char** argv[])
203 {
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);
208 }