fix crash when copy'ing latent plugins
[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 #include "ardour/lxvst_plugin.h"
21 #include "ardour/linux_vst_support.h"
22 #include "lxvst_plugin_ui.h"
23 #include "timers.h"
24 #include <gdk/gdkx.h>
25
26 #define LXVST_H_FIDDLE 40
27
28 using namespace std;
29 using namespace Gtk;
30 using namespace ARDOUR;
31 using namespace PBD;
32
33 LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<VSTPlugin> lxvp)
34         : VSTPluginUI (pi, lxvp)
35 {
36         vstfx_run_editor (_vst->state ());
37 }
38
39 LXVSTPluginUI::~LXVSTPluginUI ()
40 {
41         _screen_update_connection.disconnect();
42
43         // plugin destructor destroys the custom GUI, via the vstfx engine,
44         // and then our PluginUIWindow does the rest
45 }
46
47
48 bool
49 LXVSTPluginUI::start_updating (GdkEventAny*)
50 {
51         _screen_update_connection.disconnect();
52         _screen_update_connection = Timers::rapid_connect (mem_fun(*this, &LXVSTPluginUI::resize_callback));
53         return false;
54 }
55
56 bool
57 LXVSTPluginUI::stop_updating (GdkEventAny*)
58 {
59         _screen_update_connection.disconnect();
60         return false;
61 }
62
63
64 void
65 LXVSTPluginUI::resize_callback ()
66 {
67         /* We could maybe use this to resize the plugin GTK parent window
68            if required
69         */
70
71         if (!_vst->state()->want_resize) {
72                 return;
73         }
74
75         int new_height = _vst->state()->height;
76         int new_width = _vst->state()->width;
77
78         void* gtk_parent_window = _vst->state()->extra_data;
79
80         if (gtk_parent_window) {
81                 _socket.set_size_request(
82                                 new_width + _vst->state()->hoffset,
83                                 new_height + _vst->state()->voffset);
84
85                 ((Gtk::Window*) gtk_parent_window)->resize (new_width, new_height + LXVST_H_FIDDLE);
86         }
87         _vst->state()->want_resize = 0;
88 }
89
90 int
91 LXVSTPluginUI::get_preferred_height ()
92 {
93         /* XXX: FIXME */
94
95         /* We have to return the required height of the plugin UI window +  a fiddle factor
96            because we can't know how big the preset menu bar is until the window is realised
97            and we can't realise it until we have told it how big we would like it to be
98            which we can't do until it is realised etc
99         */
100
101         // May not be 40 for all screen res etc
102         return VSTPluginUI::get_preferred_height () + LXVST_H_FIDDLE;
103 }
104
105 int
106 LXVSTPluginUI::package (Gtk::Window& win)
107 {
108         VSTPluginUI::package (win);
109
110         /* Map the UI start and stop updating events to 'Map' events on the Window */
111
112         win.signal_map_event().connect (mem_fun (*this, &LXVSTPluginUI::start_updating));
113         win.signal_unmap_event().connect (mem_fun (*this, &LXVSTPluginUI::stop_updating));
114
115         _vst->state()->extra_data = (void*) (&win);
116         _vst->state()->want_resize = 0;
117
118         return 0;
119 }
120
121 void
122 LXVSTPluginUI::forward_key_event (GdkEventKey*)
123 {
124         std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
125 }
126
127 int
128 LXVSTPluginUI::get_XID ()
129 {
130         /* Wait for the lock to become free - otherwise
131            the window might be in the process of being
132            created and we get bad Window errors when trying
133            to embed it in the GTK UI
134         */
135
136         pthread_mutex_lock (&(_vst->state()->lock));
137
138         /* The Window may be scheduled for creation
139            but not actually created by the gui_event_loop yet -
140            spin here until it has been activated.  Possible
141            deadlock if the window never gets activated but
142            should not be called here if the window doesn't
143            exist or will never exist
144         */
145
146         while (!(_vst->state()->been_activated)) {
147                 Glib::usleep (1000);
148         }
149
150         int const id = _vst->state()->xid;
151
152         pthread_mutex_unlock (&(_vst->state()->lock));
153
154         /* Finally it might be safe to return the ID -
155            problems will arise if we return either a zero ID
156            and GTK tries to socket it or if we return an ID
157            which hasn't yet become real to the server
158         */
159
160         return id;
161 }
162
163 typedef int (*error_handler_t)( Display *, XErrorEvent *);
164 static Display *the_gtk_display;
165 static error_handler_t vstfx_error_handler;
166 static error_handler_t gtk_error_handler;
167
168 static int
169 gtk_xerror_handler (Display*, XErrorEvent*)
170 {
171         std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
172
173         return 0;
174 }
175
176 void
177 gui_init (int* argc, char** argv[])
178 {
179         vstfx_error_handler = XSetErrorHandler (NULL);
180         gtk_init (argc, argv);
181         the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
182         gtk_error_handler = XSetErrorHandler (gtk_xerror_handler);
183 }
184