Merge branch 'master' into cairocanvas
[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 "ardour_ui.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 = ARDOUR_UI::instance()->RapidScreenUpdate.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                 ((Gtk::Window*) gtk_parent_window)->resize (new_width, new_height + LXVST_H_FIDDLE);
82         }
83         
84         _vst->state()->want_resize = 0;
85 }
86
87 int
88 LXVSTPluginUI::get_preferred_height ()
89 {       
90         /* XXX: FIXME */
91         
92         /* We have to return the required height of the plugin UI window +  a fiddle factor
93            because we can't know how big the preset menu bar is until the window is realised
94            and we can't realise it until we have told it how big we would like it to be
95            which we can't do until it is realised etc
96         */
97
98         // May not be 40 for all screen res etc 
99         return VSTPluginUI::get_preferred_height () + LXVST_H_FIDDLE;
100 }
101
102 int
103 LXVSTPluginUI::package (Gtk::Window& win)
104 {
105         VSTPluginUI::package (win);
106         
107         /* Map the UI start and stop updating events to 'Map' events on the Window */
108         
109         win.signal_map_event().connect (mem_fun (*this, &LXVSTPluginUI::start_updating));
110         win.signal_unmap_event().connect (mem_fun (*this, &LXVSTPluginUI::stop_updating));
111
112         _vst->state()->extra_data = (void*) (&win);
113         _vst->state()->want_resize = 0;
114
115         return 0;
116 }
117
118 void
119 LXVSTPluginUI::forward_key_event (GdkEventKey*)
120 {
121         std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
122 }
123
124 int
125 LXVSTPluginUI::get_XID ()
126 {
127         /* Wait for the lock to become free - otherwise
128            the window might be in the process of being
129            created and we get bad Window errors when trying
130            to embed it in the GTK UI
131         */
132         
133         pthread_mutex_lock (&(_vst->state()->lock));
134         
135         /* The Window may be scheduled for creation
136            but not actually created by the gui_event_loop yet - 
137            spin here until it has been activated.  Possible
138            deadlock if the window never gets activated but
139            should not be called here if the window doesn't
140            exist or will never exist
141         */
142         
143         while (!(_vst->state()->been_activated)) {
144                 Glib::usleep (1000);
145         }
146         
147         int const id = _vst->state()->xid;
148         
149         pthread_mutex_unlock (&(_vst->state()->lock));
150         
151         /* Finally it might be safe to return the ID - 
152            problems will arise if we return either a zero ID
153            and GTK tries to socket it or if we return an ID
154            which hasn't yet become real to the server
155         */
156         
157         return id;
158 }
159
160 typedef int (*error_handler_t)( Display *, XErrorEvent *);
161 static Display *the_gtk_display;
162 static error_handler_t vstfx_error_handler;
163 static error_handler_t gtk_error_handler;
164
165 static int 
166 gtk_xerror_handler (Display*, XErrorEvent*)
167 {
168         std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
169         
170         return 0;
171 }
172
173 void
174 gui_init (int* argc, char** argv[])
175 {
176         vstfx_error_handler = XSetErrorHandler (NULL);
177         gtk_init (argc, argv);
178         the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
179         gtk_error_handler = XSetErrorHandler (gtk_xerror_handler);
180 }
181