Optimize automation-event process splitting
[ardour.git] / gtk2_ardour / lxvst_plugin_ui.cc
1 /*
2     Copyright (C) 2004 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20
21 #include "gtkmm2ext/gui_thread.h"
22 #include "ardour/lxvst_plugin.h"
23 #include "ardour/linux_vst_support.h"
24 #include "lxvst_plugin_ui.h"
25
26 #include <gdk/gdkx.h> /* must come later than glibmm/object.h */
27
28 #define LXVST_H_FIDDLE 40
29
30 using namespace std;
31 using namespace Gtk;
32 using namespace ARDOUR;
33 using namespace PBD;
34
35 LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<VSTPlugin> lxvp)
36         : VSTPluginUI (pi, lxvp)
37 {
38         vstfx_run_editor (_vst->state ());
39 }
40
41 LXVSTPluginUI::~LXVSTPluginUI ()
42 {
43         _resize_connection.disconnect();
44
45         // plugin destructor destroys the custom GUI, via the vstfx engine,
46         // and then our PluginUIWindow does the rest
47 }
48
49 void
50 LXVSTPluginUI::resize_callback ()
51 {
52         void* gtk_parent_window = _vst->state()->gtk_window_parent;
53
54         if (gtk_parent_window) {
55                 int width  = _vst->state()->width;
56                 int height = _vst->state()->height;
57 #ifndef NDEBUG
58                 printf ("LXVSTPluginUI::resize_callback %d x %d\n", width, height);
59 #endif
60                 _socket.set_size_request(
61                                 width  + _vst->state()->hoffset,
62                                 height + _vst->state()->voffset);
63
64                 ((Gtk::Window*) gtk_parent_window)->resize (width, height + LXVST_H_FIDDLE);
65                 if (_vst->state()->linux_plugin_ui_window) {
66                 }
67         }
68 }
69
70 int
71 LXVSTPluginUI::get_preferred_height ()
72 {
73         /* XXX: FIXME */
74
75         /* We have to return the required height of the plugin UI window +  a fiddle factor
76            because we can't know how big the preset menu bar is until the window is realised
77            and we can't realise it until we have told it how big we would like it to be
78            which we can't do until it is realised etc
79         */
80
81         // May not be 40 for all screen res etc
82         return VSTPluginUI::get_preferred_height () + LXVST_H_FIDDLE;
83 }
84
85 int
86 LXVSTPluginUI::package (Gtk::Window& win)
87 {
88         VSTPluginUI::package (win);
89         _vst->state()->gtk_window_parent = (void*) (&win);
90
91         /* Map the UI start and stop updating events to 'Map' events on the Window */
92
93         _vst->VSTSizeWindow.connect (_resize_connection, invalidator (*this), boost::bind (&LXVSTPluginUI::resize_callback, this), gui_context());
94         return 0;
95 }
96
97 void
98 LXVSTPluginUI::forward_key_event (GdkEventKey* gdk_key)
99 {
100         if (!_vst->state()->gtk_window_parent) {
101                 return;
102         }
103
104         Glib::RefPtr<Gdk::Window> gdk_window = ((Gtk::Window*) _vst->state()->gtk_window_parent)->get_window();
105
106         if (!gdk_window) {
107                 return;
108         }
109
110         XEvent xev;
111         int mask;
112
113         switch (gdk_key->type) {
114         case GDK_KEY_PRESS:
115                 xev.xany.type = KeyPress;
116                 mask = KeyPressMask;
117                 break;
118         case GDK_KEY_RELEASE:
119                 xev.xany.type = KeyRelease;
120                 mask = KeyReleaseMask;
121                 break;
122         default:
123                 return;
124         }
125
126         /* XXX relies on GDK using X11 definitions for these fields */
127
128         xev.xkey.state = gdk_key->state;
129         xev.xkey.keycode = gdk_key->hardware_keycode; /* see gdk/x11/gdkevents-x11.c:translate_key_event() */
130
131         xev.xkey.x = 0;
132         xev.xkey.y = 0;
133         xev.xkey.x_root = 0;
134         xev.xkey.y_root = 0;
135         xev.xkey.root = gdk_x11_get_default_root_xwindow();
136         xev.xkey.window = _vst->state()->linux_plugin_ui_window ? _vst->state()->linux_plugin_ui_window : _vst->state()->xid;
137         xev.xkey.subwindow = None;
138         xev.xkey.time = gdk_key->time;
139
140         xev.xany.serial = 0; /* we don't have one */
141         xev.xany.send_event = true; /* pretend we are using XSendEvent */
142         xev.xany.display = GDK_WINDOW_XDISPLAY (gdk_window->gobj());
143
144         if (_vst->state()->eventProc) {
145                 _vst->state()->eventProc (&xev);
146         } else if (!dispatch_effeditkey (gdk_key)) {
147                 XSendEvent (xev.xany.display, xev.xany.window, TRUE, mask, &xev);
148         }
149 }
150
151 int
152 LXVSTPluginUI::get_XID ()
153 {
154         /* Wait for the lock to become free - otherwise
155            the window might be in the process of being
156            created and we get bad Window errors when trying
157            to embed it in the GTK UI
158         */
159
160         pthread_mutex_lock (&(_vst->state()->lock));
161
162         /* The Window may be scheduled for creation
163            but not actually created by the gui_event_loop yet -
164            spin here until it has been activated.  Possible
165            deadlock if the window never gets activated but
166            should not be called here if the window doesn't
167            exist or will never exist
168         */
169
170         while (!(_vst->state()->been_activated)) {
171                 Glib::usleep (1000);
172         }
173
174         int const id = _vst->state()->xid;
175
176         pthread_mutex_unlock (&(_vst->state()->lock));
177
178         /* Finally it might be safe to return the ID -
179            problems will arise if we return either a zero ID
180            and GTK tries to socket it or if we return an ID
181            which hasn't yet become real to the server
182         */
183
184         return id;
185 }
186
187 typedef int (*error_handler_t)( Display *, XErrorEvent *);
188 static Display *the_gtk_display;
189 static error_handler_t vstfx_error_handler;
190 static error_handler_t gtk_error_handler;
191
192 static int
193 gtk_xerror_handler (Display*, XErrorEvent*)
194 {
195         std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
196
197         return 0;
198 }
199
200 void
201 gui_init (int* argc, char** argv[])
202 {
203         vstfx_error_handler = XSetErrorHandler (NULL);
204         gtk_init (argc, argv);
205         the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
206         gtk_error_handler = XSetErrorHandler (gtk_xerror_handler);
207 }