Fix thinkos in cubasish theme
[ardour.git] / gtk2_ardour / vst_plugin_ui.cc
1 /*
2  * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
3  * Copyright (C) 2012-2013 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2014-2015 David Robillard <d@drobilla.net>
5  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <gtkmm.h>
23 #include "ardour/vst_plugin.h"
24 #include "ardour/vst_types.h"
25 #include "ardour/plugin_insert.h"
26 #include "vst_plugin_ui.h"
27
28 #ifdef PLATFORM_WINDOWS
29 #include <gdk/gdkwin32.h>
30 #elif defined __APPLE__
31 // TODO
32 #else
33 #include <gdk/gdkx.h>
34 #endif
35
36 VSTPluginUI::VSTPluginUI (boost::shared_ptr<ARDOUR::PluginInsert> insert, boost::shared_ptr<ARDOUR::VSTPlugin> plugin)
37         : PlugUIBase (insert)
38         , _vst (plugin)
39 {
40         Gtk::HBox* box = manage (new Gtk::HBox);
41         box->set_spacing (6);
42         box->set_border_width (6);
43         box->pack_end (focus_button, false, false);
44         box->pack_end (bypass_button, false, false, 4);
45         if (insert->controls().size() > 0) {
46                 box->pack_end (reset_button, false, false, 4);
47         }
48         if (has_descriptive_presets ()) {
49                 box->pack_end (preset_browser_button, false, false);
50         }
51         box->pack_end (delete_button, false, false);
52         box->pack_end (save_button, false, false);
53         box->pack_end (add_button, false, false);
54         box->pack_end (_preset_combo, false, false);
55         box->pack_end (_preset_modified, false, false);
56         box->pack_end (pin_management_button, false, false);
57
58         pack_start (*box, false, false);
59         box->signal_size_allocate().connect (sigc::mem_fun (*this, &VSTPluginUI::top_box_allocated));
60 #ifdef GDK_WINDOWING_X11
61         pack_start (_socket, true, true);
62         _socket.set_border_width (0);
63 #endif
64 }
65
66 VSTPluginUI::~VSTPluginUI ()
67 {
68
69 }
70
71 void
72 VSTPluginUI::preset_selected (ARDOUR::Plugin::PresetRecord preset)
73 {
74 #ifdef GDK_WINDOWING_X11
75         _socket.grab_focus ();
76 #endif
77         PlugUIBase::preset_selected (preset);
78 }
79
80 int
81 VSTPluginUI::get_preferred_height ()
82 {
83         return _vst->state()->height + _vst->state()->voffset;
84 }
85
86 int
87 VSTPluginUI::get_preferred_width ()
88 {
89         return _vst->state()->width + _vst->state()->hoffset;
90 }
91
92 int
93 VSTPluginUI::package (Gtk::Window& win)
94 {
95 #ifdef GDK_WINDOWING_X11
96         /* Forward configure events to plugin window */
97         win.signal_configure_event().connect (sigc::mem_fun (*this, &VSTPluginUI::configure_handler), false);
98
99         /* This assumes that the window's owner understands the XEmbed protocol */
100         _socket.add_id (get_XID ());
101         _socket.set_size_request(
102                         _vst->state()->width + _vst->state()->hoffset,
103                         _vst->state()->height + _vst->state()->voffset);
104 #endif
105
106         return 0;
107 }
108
109 bool
110 VSTPluginUI::on_window_show(const std::string& title)
111 {
112         _vst->state()->gui_shown = 1;
113         return PlugUIBase::on_window_show(title);
114 }
115
116 void
117 VSTPluginUI::on_window_hide()
118 {
119         _vst->state()->gui_shown = 0;
120         PlugUIBase::on_window_hide();
121 }
122
123
124 bool
125 VSTPluginUI::configure_handler (GdkEventConfigure*)
126 {
127 #ifdef GDK_WINDOWING_X11
128         XEvent event;
129         gint x, y;
130         GdkWindow* w;
131         Window xw = _vst->state()->linux_plugin_ui_window;
132
133         if ((w = _socket.gobj()->plug_window) == 0) {
134                 return false;
135         }
136
137         event.xconfigure.type = ConfigureNotify;
138         event.xconfigure.event = GDK_WINDOW_XWINDOW (w);
139         event.xconfigure.window = GDK_WINDOW_XWINDOW (w);
140
141         /* The ICCCM says that synthetic events should have root relative
142          * coordinates. We still aren't really ICCCM compliant, since
143          * we don't send events when the real toplevel is moved.
144          */
145         gdk_error_trap_push ();
146         gdk_window_get_origin (w, &x, &y);
147         gdk_error_trap_pop ();
148
149         event.xconfigure.x = x;
150         event.xconfigure.y = y;
151         event.xconfigure.width = GTK_WIDGET (_socket.gobj())->allocation.width;
152         event.xconfigure.height = GTK_WIDGET (_socket.gobj())->allocation.height;
153
154         event.xconfigure.border_width = 0;
155         event.xconfigure.above = None;
156         event.xconfigure.override_redirect = False;
157
158         gdk_error_trap_push ();
159         XSendEvent (GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XWINDOW (w), False, StructureNotifyMask, &event);
160         /* if the plugin does adds itself to the parent,
161          * but ardour re-parents it, we have a pointer to
162          * the socket's child and need to resize the
163          * child window (e.g. JUCE, u-he)
164          */
165         if (xw) {
166                 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (w), xw,
167                                 0, 0, _vst->state()->width, _vst->state()->height);
168                 XMapRaised (GDK_WINDOW_XDISPLAY (w), xw);
169                 XFlush (GDK_WINDOW_XDISPLAY (w));
170         }
171         gdk_error_trap_pop ();
172 #endif
173
174         return false;
175 }
176
177 bool
178 VSTPluginUI::dispatch_effeditkey (GdkEventKey* gdk_key)
179 {
180         int effopcode;
181         switch (gdk_key->type) {
182                 case GDK_KEY_PRESS:
183                         effopcode = 59; // effEditKeyDown
184                         break;
185                 case GDK_KEY_RELEASE:
186                         effopcode = 60; // effEditKeyUp
187                         break;
188                 default:
189                         return false;
190         }
191
192         /* see https://github.com/DISTRHO/DPF/blob/master/distrho/src/DistrhoPluginVST.cpp */
193         int special_key = 0;
194         int ascii_key = 0;
195
196         switch (gdk_key->keyval) {
197                 case GDK_BackSpace:
198                         special_key = 1;
199                         break;
200                 case GDK_Tab:
201                 case GDK_KP_Tab:
202                         special_key = 2;
203                         break;
204                 case GDK_Return:
205                 case GDK_KP_Enter:
206                         special_key = 4;
207                         break;
208                 case GDK_Escape:
209                         special_key = 6;
210                         break;
211                 case GDK_KP_Space:
212                         special_key = 7;
213                         break;
214
215                 case GDK_End:
216                 case GDK_KP_End:
217                         special_key = 9;
218                         break;
219                 case GDK_Home:
220                 case GDK_KP_Home:
221                         special_key = 10;
222                         break;
223                 case GDK_Left:
224                         special_key = 11;
225                         break;
226                 case GDK_Up:
227                         special_key = 12;
228                         break;
229                 case GDK_Right:
230                         special_key = 13;
231                         break;
232                 case GDK_Down:
233                         special_key = 14;
234                         break;
235                 case GDK_Page_Up:
236                 case GDK_KP_Page_Up:
237                         special_key = 15;
238                         break;
239                 case GDK_Page_Down:
240                         /* fallthrough */
241                 case GDK_KP_Page_Down:
242                         special_key = 16;
243                         break;
244                 case GDK_Insert:
245                         special_key = 21;
246                         break;
247                 case GDK_Delete:
248                 case GDK_KP_Delete:
249                         special_key = 22;
250                         break;
251
252                 case GDK_Shift_L:
253                 case GDK_Shift_R:
254                         special_key = 54;
255                         break;
256                 case GDK_Control_L:
257                 case GDK_Control_R:
258                         special_key = 55;
259                         break;
260                 case GDK_Alt_L:
261                 case GDK_Alt_R:
262                         special_key = 56;
263                         break;
264
265                 case GDK_F1:  special_key = 40; break;
266                 case GDK_F2:  special_key = 41; break;
267                 case GDK_F3:  special_key = 42; break;
268                 case GDK_F4:  special_key = 43; break;
269                 case GDK_F5:  special_key = 44; break;
270                 case GDK_F6:  special_key = 45; break;
271                 case GDK_F7:  special_key = 46; break;
272                 case GDK_F8:  special_key = 47; break;
273                 case GDK_F9:  special_key = 48; break;
274                 case GDK_F10: special_key = 49; break;
275                 case GDK_F11: special_key = 50; break;
276                 case GDK_F12: special_key = 51; break;
277
278                 default:
279                         ascii_key = gdk_key->keyval;
280                         break;
281         }
282
283         if (special_key > 0 || ascii_key > 0) {
284                 VSTState* vstfx = _vst->state();
285                 /* expect non-zero return if key was handled */
286                 return 0 != vstfx->plugin->dispatcher (vstfx->plugin, effopcode, (int)ascii_key, (intptr_t)special_key, NULL, 0);
287         }
288         return false;
289 }