Loading...
Searching...
No Matches
InvisibleWindow.hpp
1#pragma once
2
3/* Microscopic platform abstraction to enable showing a
4 * borderless hidden window, necessary for scanning VST plug-ins.
5 *
6 * Based on knowledge from https://github.com/zserge/fenster
7 *
8 * MIT License
9 *
10 * Copyright (c) 2022 Serge Zaitsev
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in all
20 * copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
29 */
30// macOS: -framework CoreFoundation
31// X11: -lX11
32// Win32: -luser32 -lgdi32
33
34#if defined(__APPLE__)
35#include <CoreGraphics/CoreGraphics.h>
36#include <objc/NSObjCRuntime.h>
37
38#include <unistd.h>
39
40#include <objc/objc-runtime.h>
41#define msg(r, o, s) ((r(*)(id, SEL))objc_msgSend)(o, sel_getUid(s))
42#define msg1(r, o, s, A, a) ((r(*)(id, SEL, A))objc_msgSend)(o, sel_getUid(s), a)
43#define msg4(r, o, s, A, a, B, b, C, c, D, d) \
44 ((r(*)(id, SEL, A, B, C, D))objc_msgSend)(o, sel_getUid(s), a, b, c, d)
45
46#define cls(x) ((id)objc_getClass(x))
47
48extern id const NSDefaultRunLoopMode;
49extern id const NSApp;
50
51#elif defined(_WIN32)
52#if !defined(WIN32_LEAN_AND_MEAN)
53#define WIN32_LEAN_AND_MEAN
54#endif
55#if !defined(NOMINMAX)
56#define NOMINMAX
57#endif
58#if !defined(UNICODE)
59#define UNICODE 1
60#endif
61#if !defined(_UNICODE)
62#define _UNICODE 1
63#endif
64#include <windows.h>
65#elif __has_include(<X11/Xlib.h>)
66#define _DEFAULT_SOURCE 1
67#include <X11/XKBlib.h>
68#include <X11/Xlib.h>
69#include <X11/keysym.h>
70
71#include <dlfcn.h>
72#include <unistd.h>
73
74#include <ctime>
75#endif
76
77#include <cstdint>
78#include <cstdlib>
79#include <cstring>
80
82{
83#if defined(__APPLE__)
84 id wnd{};
85#elif defined(_WIN32)
86 HWND hwnd{};
87#elif __has_include(<X11/Xlib.h>)
88 void* x11 = dlopen("libX11.so.6", RTLD_LAZY | RTLD_LOCAL);
89 Display* dpy{};
90 Window w{};
91 GC gc{};
92#endif
93
95 {
96#if defined(__APPLE__)
97 auto pool = msg(id, cls("NSAutoreleasePool"), "alloc");
98 msg(void, pool, "init");
99
100 msg(id, cls("NSApplication"), "sharedApplication");
101
102 assert(NSApp);
103 // Prevent activation
104 msg1(
105 void, NSApp, "setActivationPolicy:", NSInteger,
106 2 /* NSApplicationActivationPolicyProhibited */);
107
108 // Create the window
109 wnd = msg4(
110 id, msg(id, cls("NSWindow"), "alloc"),
111 "initWithContentRect:styleMask:backing:defer:", CGRect, CGRectMake(0, 0, 1, 1),
112 NSUInteger, 3, NSUInteger, 2, BOOL, NO);
113 assert(wnd);
114
115 // Make the window transparent
116 msg1(void, wnd, "setOpaque:", NSInteger, NO);
117 id clearColor = msg(id, cls("NSColor"), "clearColor");
118 msg1(void, wnd, "setBackgroundColor:", id, clearColor);
119
120#elif defined(_WIN32)
121 HINSTANCE hInstance = GetModuleHandle(NULL);
122 WNDCLASSEXA wc = {0};
123 wc.cbSize = sizeof(WNDCLASSEX);
124 wc.style = CS_VREDRAW | CS_HREDRAW;
125 wc.lpfnWndProc = [](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT {
126 switch(msg)
127 {
128 case WM_CLOSE:
129 DestroyWindow(hwnd);
130 break;
131 case WM_DESTROY:
132 PostQuitMessage(0);
133 break;
134 default:
135 return DefWindowProc(hwnd, msg, wParam, lParam);
136 }
137 return 0;
138 };
139 wc.hInstance = hInstance;
140 wc.lpszClassName = "window";
141 RegisterClassExA(&wc);
142
143 // Create the window
144 hwnd = CreateWindowExA(
145 WS_EX_TRANSPARENT, "window", "window", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr,
146 hInstance, nullptr);
147
148 if(hwnd)
149 UpdateWindow(hwnd);
150
151#elif __has_include(<X11/Xlib.h>)
152 if(!x11)
153 return;
154
155 if(auto sym = reinterpret_cast<int (*)()>(dlsym(x11, "XInitThreads")))
156 sym();
157
158 decltype(XOpenDisplay)* d_XOpenDisplay
159 = (decltype(XOpenDisplay)*)dlsym(x11, "XOpenDisplay");
160 decltype(XCreateWindow)* d_XCreateWindow
161 = (decltype(XCreateWindow)*)dlsym(x11, "XCreateWindow");
162 decltype(XCreateGC)* d_XCreateGC = (decltype(XCreateGC)*)dlsym(x11, "XCreateGC");
163 decltype(XSelectInput)* d_XSelectInput
164 = (decltype(XSelectInput)*)dlsym(x11, "XSelectInput");
165 decltype(XMapWindow)* d_XMapWindow = (decltype(XMapWindow)*)dlsym(x11, "XMapWindow");
166 decltype(XSync)* d_XSync = (decltype(XSync)*)dlsym(x11, "XSync");
167 decltype(XInternAtom)* d_XInternAtom
168 = (decltype(XInternAtom)*)dlsym(x11, "XInternAtom");
169 decltype(XChangeProperty)* d_XChangeProperty
170 = (decltype(XChangeProperty)*)dlsym(x11, "XChangeProperty");
171
172 dpy = d_XOpenDisplay(NULL);
173 if(!dpy)
174 throw;
175
176 XSetWindowAttributes attrs{};
177 attrs.override_redirect = True;
178
179 w = d_XCreateWindow(
180 dpy, RootWindow(dpy, DefaultScreen(dpy)), 0, 0, 1, 1, 0, CopyFromParent,
181 InputOutput, CopyFromParent, CWOverrideRedirect, &attrs);
182
183 gc = d_XCreateGC(dpy, w, 0, 0);
184 d_XSelectInput(
185 dpy, w,
186 ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask
187 | ButtonReleaseMask | PointerMotionMask);
188 d_XMapWindow(dpy, w);
189 d_XSync(dpy, w);
190
191 // Disable decorations
192 struct
193 {
194 unsigned long flags = 2;
195 unsigned long functions = 0;
196 unsigned long decorations = 0;
197 long inputMode = 0;
198 unsigned long status = 0;
199 } hints{};
200 auto property = d_XInternAtom(dpy, "_MOTIF_WM_HINTS", true);
201 d_XChangeProperty(
202 dpy, w, property, property, 32, PropModeReplace, (unsigned char*)&hints, 5);
203 d_XMapWindow(dpy, w);
204#endif
205 }
206
207 int loop()
208 {
209#if defined(__APPLE__)
210 msg1(void, msg(id, wnd, "contentView"), "setNeedsDisplay:", BOOL, YES);
211 id ev = msg4(
212 id, NSApp, "nextEventMatchingMask:untilDate:inMode:dequeue:", NSUInteger,
213 NSUIntegerMax, id, NULL, id, NSDefaultRunLoopMode, BOOL, YES);
214 if(!ev)
215 return 0;
216 msg1(void, NSApp, "sendEvent:", id, ev);
217 return 0;
218#elif defined(_WIN32)
219 MSG msg;
220 while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
221 {
222 if(msg.message == WM_QUIT)
223 return -1;
224 TranslateMessage(&msg);
225 DispatchMessage(&msg);
226 }
227 InvalidateRect(hwnd, NULL, TRUE);
228
229#elif __has_include(<X11/Xlib.h>)
230 if(x11)
231 {
232 if(decltype(XFlush)* d_XFlush = (decltype(XFlush)*)dlsym(x11, "XFlush"))
233 d_XFlush(dpy);
234 }
235#endif
236 return 0;
237 }
238
240 {
241#if defined(__APPLE__)
242 msg(void, wnd, "close");
243 msg1(void, NSApp, "terminate:", id, NSApp);
244
245#elif defined(_WIN32)
246 // nothing to do
247
248#elif __has_include(<X11/Xlib.h>)
249 if(x11)
250 {
251 if(decltype(XCloseDisplay)* d_XCloseDisplay
252 = (decltype(XCloseDisplay)*)dlsym(x11, "XCloseDisplay"))
253 d_XCloseDisplay(dpy);
254 }
255#endif
256 }
257};
Definition InvisibleWindow.hpp:82