File: effect_editor_vst2.cpp

package info (click to toggle)
zytrax 0%2Bgit20201215-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 2,488 kB
  • sloc: cpp: 41,800; ansic: 3,387; makefile: 8; sh: 3
file content (331 lines) | stat: -rw-r--r-- 8,712 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include "effect_editor_vst2.h"
//keep this for order
#include "audio_effect_provider_vst2.h"
#include "effect_editor_x11.h"

#ifdef WINDOWS_ENABLED
void EffectPlaceholderVST2Win32::_vst_resize(void *self, int w, int h) {
	EffectPlaceholderVST2Win32 *ph = (EffectPlaceholderVST2Win32 *)self;
	return;
}

void EffectPlaceholderVST2Win32::resize_editor(int left, int top, int right, int bottom) {

	if (vst_window) {
		RECT rc;
		rc.left = left;
		rc.right = right;
		rc.bottom = bottom;
		rc.top = top;

		const auto style = GetWindowLongPtr(vst_window, GWL_STYLE);
		const auto exStyle = GetWindowLongPtr(vst_window, GWL_EXSTYLE);
		const BOOL fMenu = GetMenu(vst_window) != nullptr;
		AdjustWindowRectEx(&rc, style, fMenu, exStyle);
		MoveWindow(vst_window, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
	}
}
void EffectPlaceholderVST2Win32::on_size_allocate(Gtk::Allocation &allocation) {
	// Do something with the space that we have actually been given:
	//(We will not be given heights or widths less than we have requested, though
	// we might get more)

	// Use the offered allocation for this container:
	set_allocation(allocation);

	if (m_refGdkWindow) {

		m_refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(),
				allocation.get_width(),
				allocation.get_height());
	}
}

bool EffectPlaceholderVST2Win32::_update_window_position() {

	bool visible = is_visible();

	if (visible) {
		//make sure it really is..
		GtkWidget *p = gobj();
		GtkWidget *w = gtk_widget_get_parent(p);
		while (w) {
			if (GTK_IS_NOTEBOOK(w)) {
				GtkNotebook *notebook = GTK_NOTEBOOK(w);
				int cpage = gtk_notebook_get_current_page(notebook);
				if (p != gtk_notebook_get_nth_page(notebook, cpage)) {
					visible = false;
					break;
				}
			}

			p = w;
			w = gtk_widget_get_parent(p);
		}
	}

	GtkWidget *toplevel = gtk_widget_get_toplevel(gobj());
	ERR_FAIL_COND_V(!GTK_IS_WINDOW(toplevel), false);
	int root_x, root_y;
	//gtk_window_get_position(GTK_WINDOW(toplevel), &root_x, &root_y);

	HWND hwnd = gdk_win32_window_get_impl_hwnd(gtk_widget_get_window(gobj()));
	/*	RECT r;
	GetWindowRect(hwnd, &r);
	root_x = r.left;
	root_y = r.top;
*/
	POINT p;
	p.x = 0;
	p.y = 0;
	ClientToScreen(hwnd, &p);
	root_x = p.x;
	root_y = p.y;

	//method below is not compatible with multiple monitors
	{
		int widget_x, widget_y;
		gdk_window_get_origin(gtk_widget_get_window(gobj()), &widget_x, &widget_y);
		int toplevel_x, toplevel_y;
		gdk_window_get_origin(gtk_widget_get_window(toplevel), &toplevel_x, &toplevel_y);
		root_x += widget_x - toplevel_x;
		root_y += widget_y - toplevel_y;
	}

	//gdk_window_get_origin(gtk_widget_get_window(gobj()), &root_x, &root_y);
	int tlx = 0, tly = 0;
	/*gtk_widget_translate_coordinates(gobj(), gtk_widget_get_toplevel(gobj()), 0, 0, &tlx, &tly);
	root_x += tlx;
	root_y += tlx;*/

	if (root_x != prev_x || root_y != prev_y || prev_w != vst_w || prev_h != vst_h) {
		resize_editor(root_x, root_y, root_x + vst_w, root_y + vst_h);
		prev_x = root_x;
		prev_y = root_y;
		prev_w = vst_w;
		prev_h = vst_h;
	}

	if (prev_visible != visible) {
		ShowWindow(vst_window, visible ? SW_SHOW : SW_HIDE);
		prev_visible = visible;
	}

	if (visible) {
		vst_effect->process_user_interface();
	}

	return true;
}

void EffectPlaceholderVST2Win32::on_realize() {
	// Do not call base class Gtk::Widget::on_realize().
	// It's intended only for widgets that set_has_window(false).

	set_realized();

	if (!m_refGdkWindow) {
		// Create the GdkWindow:

		GdkWindowAttr attributes;
		memset(&attributes, 0, sizeof(attributes));

		Gtk::Allocation allocation = get_allocation();

		// Set initial position and size of the Gdk::Window:
		attributes.x = allocation.get_x();
		attributes.y = allocation.get_y();
		attributes.width = allocation.get_width();
		attributes.height = allocation.get_height();

		attributes.event_mask = get_events() | /* Gdk::EXPOSURE_MASK |*/
								Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
								Gdk::BUTTON1_MOTION_MASK | Gdk::KEY_PRESS_MASK |
								Gdk::KEY_RELEASE_MASK;
		attributes.window_type = GDK_WINDOW_CHILD;
		attributes.wclass = GDK_INPUT_OUTPUT;

		m_refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes,
				GDK_WA_X | GDK_WA_Y);
		set_window(m_refGdkWindow);

		// make the widget receive expose events
		m_refGdkWindow->set_user_data(gobj());

		/* Set the Window Parentship and update timer */
	}

	if (m_refGdkWindow) {

		//hwnd for gtk window
		HWND hwnd = gdk_win32_window_get_impl_hwnd(m_refGdkWindow->gobj());
		//set as parent. This works, while SetParent DOES NOT.
		SetWindowLongPtr(vst_window, GWLP_HWNDPARENT, (LONG_PTR)hwnd);
		/*SetParent((HWND)vst_window, (HWND)hwnd);*/
		//turn on update timer to reposition the Window
		//sorry, this is the only way I found..
		update_timer = Glib::signal_timeout().connect(sigc::mem_fun(*this, &EffectPlaceholderVST2Win32::_update_window_position),
				50, Glib::PRIORITY_DEFAULT);
		//Show the Window
		ShowWindow(vst_window, SW_SHOW);
		prev_visible = true;
	}
}

void EffectPlaceholderVST2Win32::on_unrealize() {
	//clear the window
	if (m_refGdkWindow) {

		//clear parenthood
		SetWindowLongPtr(vst_window, GWLP_HWNDPARENT, (LONG_PTR)NULL);
		//disconnect timer
		update_timer.disconnect();
		//Hide the Window
		ShowWindow(vst_window, SW_HIDE);

		prev_visible = false;
	}
	m_refGdkWindow.reset();

	// Call base class:
	Gtk::Widget::on_unrealize();
}

bool EffectPlaceholderVST2Win32::on_visibility_notify_event(GdkEventVisibility *visibility_event) {
	/*
	if (m_refGdkWindow) {
		if (visibility_event->state == GDK_VISIBILITY_FULLY_OBSCURED) {
			ShowWindow(vst_window, SW_HIDE);
		} else {
			ShowWindow(vst_window, SW_SHOW);
		}
	}
*/
	return false;
}

bool EffectPlaceholderVST2Win32::on_draw(const Cairo::RefPtr<Cairo::Context> &cr) {
	const Gtk::Allocation allocation = get_allocation();
	return false;

	Gdk::RGBA rgba;
	rgba.set_red(0);
	rgba.set_green(0);
	rgba.set_blue(0);
	rgba.set_alpha(1);
	Gdk::Cairo::set_source_rgba(cr, rgba);

	cr->rectangle(0, 0, allocation.get_width(), allocation.get_height());
	cr->fill();
}

EffectPlaceholderVST2Win32::EffectPlaceholderVST2Win32(AudioEffectVST2 *p_vst_effect) :
		// The GType name will actually be gtkmm__CustomObject_mywidget
		Glib::ObjectBase("filler"),
		Gtk::Widget() {

	vst_effect = p_vst_effect;
	vst_w = 1;
	vst_h = 1;

	vst_window = NULL;

	//create the window, but don't use it.
	const auto style = WS_POPUP;
	vst_window = CreateWindowExW(0, L"VST_HOST", vst_effect->get_path().c_str(), style, 0, 0, 0, 0, NULL, 0, 0, 0);
	//open the user interface (it won't be visible though.

	vst_effect->open_user_interface(vst_window);

	//allocate size for this VST here
	vst_effect->get_user_interface_size(vst_w, vst_h);
	set_size_request(vst_w, vst_h);
	prev_x = prev_y = prev_w = prev_h = -1;
	prev_visible = false;
}

EffectPlaceholderVST2Win32::~EffectPlaceholderVST2Win32() {
	vst_effect->close_user_interface();

	DestroyWindow(vst_window);
}

#endif
void initialize_vst2_editor() {

#ifdef WINDOWS_ENABLED
	HMODULE hInst = GetModuleHandleA(NULL);
	ERR_FAIL_COND(!hInst);

	WNDCLASSEXW wcex{ sizeof(wcex) };
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wcex.lpfnWndProc = DefWindowProc;
	wcex.hInstance = GetModuleHandle(0);
	wcex.lpszClassName = L"VST_HOST";

	if (!RegisterClassExW(&wcex)) {
		ERR_PRINT("Error in initialize_vst2_editor(): (class registration failed");
		return;
	}
#endif

#ifdef FREEDESKTOP_ENABLED

	vstfx_init();
#endif
}

void finalize_vst2_editor() {

#ifdef FREEDESKTOP_ENABLED

	vstfx_exit();
#endif
}

bool EffectEditorVST2::initialize() {
#ifdef FREEDESKTOP_ENABLED
	socket.add_id(xid);
	int w, h;
	vstfx_get_window_size(vst_effect, &w, &h);
	socket.set_size_request(w, h);
#endif
	return false;
}

EffectEditorVST2::EffectEditorVST2(AudioEffectVST2 *p_vst, EffectEditor *p_editor) :
		effect_editor_midi(p_vst, p_editor)
#ifdef WINDOWS_ENABLED
		,
		vst_placeholder(p_vst)
#endif
{

	vst_effect = p_vst;
#ifdef WINDOWS_ENABLED
	effect_editor_midi.prepend_page(vst_placeholder, "VST2 Plugin");
#endif

	pack_start(effect_editor_midi, Gtk::PACK_EXPAND_WIDGET);

#ifdef FREEDESKTOP_ENABLED
	effect_editor_midi.prepend_page(socket, "VST2 Plugin");
	xid = vstfx_run_editor(p_vst, this);

#endif
	//need window to be mapped, so wait
	init_timer = Glib::signal_timeout().connect(sigc::mem_fun(*this, &EffectEditorVST2::initialize),
			50, Glib::PRIORITY_DEFAULT);

	show_all_children();
}

EffectEditorVST2::~EffectEditorVST2() {
#ifdef FREEDESKTOP_ENABLED
	vstfx_destroy_editor(vst_effect);
#endif
}