18#include "CarlaJuceUtils.hpp"
19#include "CarlaPluginUI.hpp"
23# include <sys/types.h>
24# include <X11/Xatom.h>
26# include <X11/Xutil.h>
27# include "CarlaPluginUI_X11Icon.hpp"
31# include "CarlaMacUtils.hpp"
32# import <Cocoa/Cocoa.h>
37# include "water/common.hpp"
40#ifndef CARLA_PLUGIN_UI_CLASS_PREFIX
41# error CARLA_PLUGIN_UI_CLASS_PREFIX undefined
48static constexpr const uint X11Key_Escape = 9;
50typedef void (*EventProcPtr)(XEvent* ev);
53static bool gErrorTriggered =
false;
54# if defined(__GNUC__) && (__GNUC__ >= 5) && ! defined(__clang__)
55# pragma GCC diagnostic push
56# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
58static pthread_mutex_t gErrorMutex = PTHREAD_MUTEX_INITIALIZER;
59# if defined(__GNUC__) && (__GNUC__ >= 5) && ! defined(__clang__)
60# pragma GCC diagnostic pop
63static int temporaryErrorHandler(Display*, XErrorEvent*)
65 gErrorTriggered =
true;
69class X11PluginUI :
public CarlaPluginUI
72 X11PluginUI(Callback*
const cb,
const uintptr_t parentId,
73 const bool isStandalone,
const bool isResizable,
const bool canMonitorChildren)
noexcept
74 : CarlaPluginUI(cb, isStandalone, isResizable),
78 fChildWindowConfigured(
false),
79 fChildWindowMonitoring(isResizable || canMonitorChildren),
82 fSetSizeCalledAtLeastOnce(
false),
87 fDisplay = XOpenDisplay(
nullptr);
90 const int screen = DefaultScreen(fDisplay);
92 XSetWindowAttributes attr;
93 carla_zeroStruct(attr);
95 attr.event_mask = KeyPressMask|KeyReleaseMask|FocusChangeMask;
97 if (fChildWindowMonitoring)
98 attr.event_mask |= StructureNotifyMask|SubstructureNotifyMask;
100 fHostWindow = XCreateWindow(fDisplay, RootWindow(fDisplay, screen),
102 DefaultDepth(fDisplay, screen),
104 DefaultVisual(fDisplay, screen),
105 CWBorderPixel|CWEventMask, &attr);
109 XGrabKey(fDisplay, X11Key_Escape, AnyModifier, fHostWindow, 1, GrabModeAsync, GrabModeAsync);
111 Atom wmDelete = XInternAtom(fDisplay,
"WM_DELETE_WINDOW", True);
112 XSetWMProtocols(fDisplay, fHostWindow, &wmDelete, 1);
114 const pid_t pid = getpid();
115 const Atom _nwp = XInternAtom(fDisplay,
"_NET_WM_PID", False);
116 XChangeProperty(fDisplay, fHostWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (
const uchar*)&pid, 1);
118 const Atom _nwi = XInternAtom(fDisplay,
"_NET_WM_ICON", False);
119 XChangeProperty(fDisplay, fHostWindow, _nwi, XA_CARDINAL, 32, PropModeReplace, (
const uchar*)sCarlaX11Icon, sCarlaX11IconSize);
121 const Atom _wt = XInternAtom(fDisplay,
"_NET_WM_WINDOW_TYPE", False);
125 const Atom _wts[2] = {
126 XInternAtom(fDisplay,
"_NET_WM_WINDOW_TYPE_DIALOG", False),
127 XInternAtom(fDisplay,
"_NET_WM_WINDOW_TYPE_NORMAL", False)
129 XChangeProperty(fDisplay, fHostWindow, _wt, XA_ATOM, 32, PropModeReplace, (
const uchar*)&_wts, 2);
132 setTransientWinId(parentId);
135 ~X11PluginUI()
override
139 if (fDisplay ==
nullptr)
148 if (fHostWindow != 0)
150 XDestroyWindow(fDisplay, fHostWindow);
154 XCloseDisplay(fDisplay);
165 if (
const Window childWindow = getChildWindow())
167 if (! fSetSizeCalledAtLeastOnce)
172 XWindowAttributes attrs = {};
174 pthread_mutex_lock(&gErrorMutex);
175 const XErrorHandler oldErrorHandler = XSetErrorHandler(temporaryErrorHandler);
176 gErrorTriggered =
false;
178 if (XGetWindowAttributes(fDisplay, childWindow, &attrs))
184 XSetErrorHandler(oldErrorHandler);
185 pthread_mutex_unlock(&gErrorMutex);
189 XSizeHints sizeHints = {};
191 if (XGetNormalHints(fDisplay, childWindow, &sizeHints))
193 if (sizeHints.flags & PSize)
195 width = sizeHints.width;
196 height = sizeHints.height;
198 else if (sizeHints.flags & PBaseSize)
200 width = sizeHints.base_width;
201 height = sizeHints.base_height;
210 const Atom _xevp = XInternAtom(fDisplay,
"_XEventProc", False);
212 pthread_mutex_lock(&gErrorMutex);
213 const XErrorHandler oldErrorHandler(XSetErrorHandler(temporaryErrorHandler));
214 gErrorTriggered =
false;
218 ulong nitems, bytesAfter;
221 XGetWindowProperty(fDisplay, childWindow, _xevp, 0, 1, False, AnyPropertyType,
222 &actualType, &actualFormat, &nitems, &bytesAfter, &
data);
224 XSetErrorHandler(oldErrorHandler);
225 pthread_mutex_unlock(&gErrorMutex);
227 if (nitems == 1 && ! gErrorTriggered)
229 fEventProc = *
reinterpret_cast<EventProcPtr*
>(
data);
239 XSync(fDisplay, False);
255 if (fIsIdling)
return;
257 uint nextChildWidth = 0;
258 uint nextChildHeight = 0;
260 uint nextHostWidth = 0;
261 uint nextHostHeight = 0;
265 for (XEvent event; XPending(fDisplay) > 0;)
267 XNextEvent(fDisplay, &event);
272 char*
type =
nullptr;
276 case ConfigureNotify:
281 if (event.xconfigure.window == fHostWindow && fHostWindow != 0)
283 nextHostWidth =
static_cast<uint>(
event.xconfigure.width);
284 nextHostHeight =
static_cast<uint>(
event.xconfigure.height);
286 else if (event.xconfigure.window == fChildWindow && fChildWindow != 0)
288 nextChildWidth =
static_cast<uint>(
event.xconfigure.width);
289 nextChildHeight =
static_cast<uint>(
event.xconfigure.height);
294 type = XGetAtomName(fDisplay, event.xclient.message_type);
297 if (std::strcmp(
type,
"WM_PROTOCOLS") == 0)
301 fCallback->handlePluginUIClosed();
306 if (event.xkey.keycode == X11Key_Escape)
310 fCallback->handlePluginUIClosed();
315 if (fChildWindow == 0)
316 fChildWindow = getChildWindow();
318 if (fChildWindow != 0)
320 XWindowAttributes wa;
321 carla_zeroStruct(wa);
323 if (XGetWindowAttributes(fDisplay, fChildWindow, &wa) && wa.map_state == IsViewable)
324 XSetInputFocus(fDisplay, fChildWindow, RevertToPointerRoot, CurrentTime);
331 else if (fEventProc !=
nullptr && event.type != FocusIn && event.type != FocusOut)
335 if (nextChildWidth != 0 && nextChildHeight != 0 && fChildWindow != 0)
337 applyHintsFromChildWindow();
338 XResizeWindow(fDisplay, fHostWindow, nextChildWidth, nextChildHeight);
341 else if (nextHostWidth != 0 && nextHostHeight != 0)
343 if (fChildWindow != 0 && ! fChildWindowConfigured)
345 applyHintsFromChildWindow();
346 fChildWindowConfigured =
true;
349 if (fChildWindow != 0)
350 XResizeWindow(fDisplay, fChildWindow, nextHostWidth, nextHostHeight);
352 fCallback->handlePluginUIResized(nextHostWidth, nextHostHeight);
358 void focus()
override
363 XWindowAttributes wa;
364 carla_zeroStruct(wa);
368 if (wa.map_state == IsViewable)
370 XRaiseWindow(fDisplay, fHostWindow);
371 XSetInputFocus(fDisplay, fHostWindow, RevertToPointerRoot, CurrentTime);
372 XSync(fDisplay, False);
381 fMinimumWidth =
width;
384 XSizeHints sizeHints = {};
385 if (XGetNormalHints(fDisplay, fHostWindow, &sizeHints))
387 sizeHints.flags |= PMinSize;
388 sizeHints.min_width =
static_cast<int>(
width);
389 sizeHints.min_height =
static_cast<int>(
height);
390 XSetNormalHints(fDisplay, fHostWindow, &sizeHints);
394 void setSize(
const uint width,
const uint height,
const bool forceUpdate,
const bool resizeChild)
override
399 fSetSizeCalledAtLeastOnce =
true;
400 XResizeWindow(fDisplay, fHostWindow,
width,
height);
402 if (fChildWindow != 0 && resizeChild)
403 XResizeWindow(fDisplay, fChildWindow,
width,
height);
407 XSizeHints sizeHints = {};
408 sizeHints.flags = PSize|PMinSize|PMaxSize;
409 sizeHints.width =
static_cast<int>(
width);
410 sizeHints.height =
static_cast<int>(
height);
411 sizeHints.min_width =
static_cast<int>(
width);
412 sizeHints.min_height =
static_cast<int>(
height);
413 sizeHints.max_width =
static_cast<int>(
width);
414 sizeHints.max_height =
static_cast<int>(
height);
416 XSetNormalHints(fDisplay, fHostWindow, &sizeHints);
420 XSync(fDisplay, False);
423 void setTitle(
const char*
const title)
override
428 XStoreName(fDisplay, fHostWindow,
title);
430 const Atom _nwn = XInternAtom(fDisplay,
"_NET_WM_NAME", False);
431 const Atom utf8 = XInternAtom(fDisplay,
"UTF8_STRING", True);
433 XChangeProperty(fDisplay, fHostWindow, _nwn, utf8, 8,
439 void setTransientWinId(
const uintptr_t winId)
override
444 XSetTransientForHint(fDisplay, fHostWindow,
static_cast<Window
>(winId));
447 void setChildWindow(
void*
const winId)
override
451 fChildWindow = (Window)winId;
456 return (
void*)fHostWindow;
465 void applyHintsFromChildWindow()
467 pthread_mutex_lock(&gErrorMutex);
468 const XErrorHandler oldErrorHandler = XSetErrorHandler(temporaryErrorHandler);
469 gErrorTriggered =
false;
471 XSizeHints sizeHints = {};
472 if (XGetNormalHints(fDisplay, fChildWindow, &sizeHints) && !gErrorTriggered)
474 if (fMinimumWidth != 0 && fMinimumHeight != 0)
476 sizeHints.flags |= PMinSize;
477 sizeHints.min_width = fMinimumWidth;
478 sizeHints.min_height = fMinimumHeight;
481 XSetNormalHints(fDisplay, fHostWindow, &sizeHints);
486 carla_stdout(
"Caught errors while accessing child window");
490 XSetErrorHandler(oldErrorHandler);
491 pthread_mutex_unlock(&gErrorMutex);
494 Window getChildWindow()
const
499 Window rootWindow, parentWindow, ret = 0;
500 Window* childWindows =
nullptr;
501 uint numChildren = 0;
503 XQueryTree(fDisplay, fHostWindow, &rootWindow, &parentWindow, &childWindows, &numChildren);
505 if (numChildren > 0 && childWindows !=
nullptr)
507 ret = childWindows[0];
518 bool fChildWindowConfigured;
519 bool fChildWindowMonitoring;
522 bool fSetSizeCalledAtLeastOnce;
525 EventProcPtr fEventProc;
527 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(X11PluginUI)
536#if defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
537# define CarlaPluginWindow CARLA_JOIN_MACRO3(CarlaPluginWindowBridgedArch, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
538# define CarlaPluginWindowDelegate CARLA_JOIN_MACRO3(CarlaPluginWindowDelegateBridgedArch, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
539#elif defined(BUILD_BRIDGE)
540# define CarlaPluginWindow CARLA_JOIN_MACRO3(CarlaPluginWindowBridged, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
541# define CarlaPluginWindowDelegate CARLA_JOIN_MACRO3(CarlaPluginWindowDelegateBridged, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
543# define CarlaPluginWindow CARLA_JOIN_MACRO3(CarlaPluginWindow, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
544# define CarlaPluginWindowDelegate CARLA_JOIN_MACRO3(CarlaPluginWindowDelegate, CARLA_BACKEND_NAMESPACE, CARLA_PLUGIN_UI_CLASS_PREFIX)
547@interface CarlaPluginWindow : NSWindow
548- (id) initWithContentRect:(NSRect)contentRect
549 styleMask:(
unsigned int)aStyle
550 backing:(NSBackingStoreType)bufferingType
552- (
BOOL) canBecomeKeyWindow;
553- (
BOOL) canBecomeMainWindow;
556@implementation CarlaPluginWindow
558- (id)initWithContentRect:(NSRect)contentRect
559 styleMask:(
unsigned int)aStyle
560 backing:(NSBackingStoreType)bufferingType
563 NSWindow*
result = [
super initWithContentRect:contentRect
565 backing:bufferingType
568 [result setAcceptsMouseMovedEvents:YES];
570 return (CarlaPluginWindow*)
result;
576- (
BOOL)canBecomeKeyWindow
581- (
BOOL)canBecomeMainWindow
588@interface CarlaPluginWindowDelegate : NSObject<NSWindowDelegate>
591 CarlaPluginWindow*
window;
593- (instancetype)initWithWindowAndCallback:(CarlaPluginWindow*)window
594 callback:(CarlaPluginUI::Callback*)callback2;
595- (
BOOL)windowShouldClose:(
id)sender;
596- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize;
599@implementation CarlaPluginWindowDelegate
601- (instancetype)initWithWindowAndCallback:(CarlaPluginWindow*)window2
602 callback:(CarlaPluginUI::Callback*)callback2
604 if ((self = [super
init]))
613- (
BOOL)windowShouldClose:(
id)sender
624- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize
626 for (NSView* subview
in [[window contentView] subviews])
628 const NSSize minSize = [subview fittingSize];
629 if (frameSize.width < minSize.width)
630 frameSize.width = minSize.width;
631 if (frameSize.height < minSize.height)
632 frameSize.height = minSize.height;
657class CocoaPluginUI :
public CarlaPluginUI
660 CocoaPluginUI(Callback*
const callback,
const uintptr_t parentId,
const bool isStandalone,
const bool isResizable)
noexcept
661 : CarlaPluginUI(
callback, isStandalone, isResizable),
663 fParentWindow(
nullptr),
666 carla_debug(
"CocoaPluginUI::CocoaPluginUI(%p, " P_UINTPTR,
"%s)",
callback, parentId, bool2str(isResizable));
667 const CARLA_BACKEND_NAMESPACE::AutoNSAutoreleasePool arp;
670 fView = [[
NSView new]retain];
674 uint style = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
676 uint style = NSClosableWindowMask | NSTitledWindowMask;
683 const NSRect frame = NSMakeRect(0, 0, 100, 100);
685 fWindow = [[[CarlaPluginWindow alloc]
686 initWithContentRect:frame
688 backing:NSBackingStoreBuffered
692 if (fWindow ==
nullptr)
699 ((NSWindow*)fWindow).delegate = [[[CarlaPluginWindowDelegate alloc]
700 initWithWindowAndCallback:fWindow
701 callback:callback] retain];
717 [fView setAutoresizingMask:NSViewNotSizable];
718 [fView setAutoresizesSubviews:NO];
719 [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES];
722 [fWindow setContentView:fView];
723 [fWindow makeFirstResponder:fView];
725 [fView setHidden:NO];
728 setTransientWinId(parentId);
731 ~CocoaPluginUI()
override
733 carla_debug(
"CocoaPluginUI::~CocoaPluginUI()");
734 if (fView ==
nullptr)
737 [fView setHidden:YES];
738 [fView removeFromSuperview];
746 carla_debug(
"CocoaPluginUI::show()");
749 if (fParentWindow !=
nullptr)
751 [fParentWindow addChildWindow:fWindow
752 ordered:NSWindowAbove];
756 [fWindow setIsVisible:YES];
762 carla_debug(
"CocoaPluginUI::hide()");
765 [fWindow setIsVisible:NO];
767 if (fParentWindow !=
nullptr)
768 [fParentWindow removeChildWindow:fWindow];
775 for (NSView* subview
in [fView subviews])
777 const NSSize viewSize = [fView frame].size;
778 const NSSize subviewSize = [subview frame].size;
780 if (viewSize.width != subviewSize.width || viewSize.height != subviewSize.height)
782 [fView setFrameSize:subviewSize];
783 [fWindow setContentSize:subviewSize];
789 void focus()
override
791 carla_debug(
"CocoaPluginUI::focus()");
794 [fWindow makeKeyAndOrderFront:fWindow];
795 [fWindow orderFrontRegardless];
796 [NSApp activateIgnoringOtherApps:YES];
799 void setMinimumSize(
uint,
uint)
override
804 void setSize(
const uint width,
const uint height,
const bool forceUpdate,
const bool resizeChild)
override
806 carla_debug(
"CocoaPluginUI::setSize(%u, %u, %s)",
width,
height, bool2str(forceUpdate));
812 [fView setFrameSize:size];
813 [fWindow setContentSize:size];
816 if (forceUpdate && resizeChild)
818 for (NSView* subview
in [fView subviews])
820 [subview setFrame:[fView frame]];
841 [fView setNeedsDisplay:YES];
845 void setTitle(
const char*
const title)
override
847 carla_debug(
"CocoaPluginUI::setTitle(\"%s\")",
title);
850 NSString* titleString = [[NSString alloc]
853 encoding:NSUTF8StringEncoding];
855 [fWindow setTitle:titleString];
858 void setTransientWinId(
const uintptr_t winId)
override
860 carla_debug(
"CocoaPluginUI::setTransientWinId(" P_UINTPTR ")", winId);
863 NSWindow*
const parentWindow = [NSApp windowWithWindowNumber:winId];
866 fParentWindow = parentWindow;
868 if ([fWindow isVisible])
869 [fParentWindow addChildWindow:fWindow
870 ordered:NSWindowAbove];
873 void setChildWindow(
void*
const childWindow)
override
875 carla_debug(
"CocoaPluginUI::setChildWindow(%p)", childWindow);
878 NSView*
const view = (NSView*)childWindow;
879 const NSRect frame = [view frame];
881 [fWindow setContentSize:frame.size];
882 [fView setFrame:frame];
883 [fView setNeedsDisplay:YES];
888 carla_debug(
"CocoaPluginUI::getPtr()");
894 carla_debug(
"CocoaPluginUI::getDisplay()");
895 return (
void*)fWindow;
900 NSWindow* fParentWindow;
901 CarlaPluginWindow* fWindow;
903 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI)
913#define CARLA_LOCAL_CLOSE_MSG (WM_USER + 50)
917class WindowsPluginUI :
public CarlaPluginUI
920 WindowsPluginUI(Callback*
const cb,
const uintptr_t parentId,
const bool isStandalone,
const bool isResizable)
noexcept
921 : CarlaPluginUI(cb, isStandalone, isResizable),
923 fChildWindow(
nullptr),
924 fParentWindow(
nullptr),
929 static int wc_count = 0;
930 char classNameBuf[32];
931 std::srand((std::time(
nullptr)));
932 std::snprintf(classNameBuf, 32,
"CarlaWin-%d-%d", ++wc_count, std::rand());
933 classNameBuf[31] =
'\0';
935 const HINSTANCE hInstance = water::getCurrentModuleInstanceHandle();
937 carla_zeroStruct(fWindowClass);
938 fWindowClass.style = CS_OWNDC;
939 fWindowClass.lpfnWndProc =
wndProc;
940 fWindowClass.hInstance = hInstance;
941 fWindowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
943 fWindowClass.lpszClassName = strdup(classNameBuf);
945 if (!RegisterClassA(&fWindowClass)) {
946 free((
void*)fWindowClass.lpszClassName);
953 winFlags |= WS_SIZEBOX;
955#ifdef BUILDING_CARLA_FOR_WINE
956 const uint winType = WS_EX_DLGMODALFRAME;
959 const uint winType = WS_EX_TOOLWINDOW;
963 fWindow = CreateWindowExA(winType,
964 classNameBuf,
"Carla Plugin UI", winFlags,
965 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
969 if (fWindow ==
nullptr)
971 const DWORD errorCode = ::GetLastError();
972 carla_stderr2(
"CreateWindowEx failed with error code 0x%x, class name was '%s'",
973 errorCode, fWindowClass.lpszClassName);
974 UnregisterClassA(fWindowClass.lpszClassName,
nullptr);
975 free((
void*)fWindowClass.lpszClassName);
981#ifndef BUILDING_CARLA_FOR_WINE
983 setTransientWinId(parentId);
991 ~WindowsPluginUI()
override
1005 UnregisterClassA(fWindowClass.lpszClassName,
nullptr);
1006 free((
void*)fWindowClass.lpszClassName);
1009 void show()
override
1016 RECT rectChild, rectParent;
1018 if (fChildWindow !=
nullptr &&
GetWindowRect(fChildWindow, &rectChild))
1019 setSize(rectChild.
right - rectChild.
left, rectChild.
bottom - rectChild.
top,
false,
false);
1021 if (fParentWindow !=
nullptr &&
1044 void hide()
override
1053 void idle()
override
1055 if (fIsIdling || fWindow ==
nullptr)
1061 while (::PeekMessage(&
msg, fWindow, 0, 0, PM_REMOVE))
1063 switch (
msg.message)
1066 case CARLA_LOCAL_CLOSE_MSG:
1069 fCallback->handlePluginUIClosed();
1073 DispatchMessageA(&
msg);
1081 if (fWindow ==
hwnd)
1086 if (fChildWindow !=
nullptr)
1095 case CARLA_LOCAL_CLOSE_MSG:
1098 fCallback->handlePluginUIClosed();
1103 return DefWindowProcA(
hwnd,
message, wParam, lParam);
1106 void focus()
override
1115 void setMinimumSize(
uint,
uint)
override
1124 const int winFlags = WS_POPUPWINDOW |
WS_CAPTION | (fIsResizable ? WS_SIZEBOX : 0x0);
1125 RECT wr = { 0, 0,
static_cast<long>(
width),
static_cast<long>(
height) };
1126 AdjustWindowRectEx(&wr, winFlags,
FALSE, WS_EX_TOPMOST);
1135 void setTitle(
const char*
const title)
override
1139 SetWindowTextA(fWindow,
title);
1142 void setTransientWinId(
const uintptr_t winId)
override
1146 fParentWindow = (
HWND)winId;
1150 void setChildWindow(
void*
const winId)
override
1154 fChildWindow = (
HWND)winId;
1159 return (
void*)fWindow;
1171 WNDCLASSA fWindowClass;
1176 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WindowsPluginUI)
1198 return ui->checkAndHandleMessage(
hwnd,
message, wParam, lParam);
1199 return DefWindowProcA(
hwnd,
message, wParam, lParam);
1206#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1207bool CarlaPluginUI::tryTransientWinIdMatch(
const uintptr_t pid,
const char*
const uiTitle,
const uintptr_t winId,
const bool centerUI)
1212#if defined(HAVE_X11)
1213 struct ScopedDisplay {
1215 ScopedDisplay() : display(XOpenDisplay(
nullptr)) {}
1216 ~ScopedDisplay() {
if (display!=
nullptr) XCloseDisplay(display); }
1221 struct ScopedFreeData {
1226 ScopedFreeData(
char*
d) :
data(
d) {}
1227 ScopedFreeData(
uchar*
d) : udata(
d) {}
1228 ~ScopedFreeData() { XFree(
data); }
1234 const ScopedDisplay sd;
1237 const Window rootWindow(DefaultRootWindow(sd.display));
1239 const Atom _ncl = XInternAtom(sd.display,
"_NET_CLIENT_LIST" , False);
1240 const Atom _nwn = XInternAtom(sd.display,
"_NET_WM_NAME", False);
1241 const Atom _nwp = XInternAtom(sd.display,
"_NET_WM_PID", False);
1242 const Atom utf8 = XInternAtom(sd.display,
"UTF8_STRING", True);
1246 ulong numWindows, bytesAfter;
1249 int status = XGetWindowProperty(sd.display, rootWindow, _ncl, 0L, (~0L), False, AnyPropertyType, &actualType, &actualFormat, &numWindows, &bytesAfter, &
data);
1252 const ScopedFreeData sfd(
data);
1258 Window* windows = (Window*)
data;
1259 Window lastGoodWindowPID = 0, lastGoodWindowNameSimple = 0, lastGoodWindowNameUTF8 = 0;
1261 for (
ulong i = 0;
i < numWindows;
i++)
1263 const Window
window(windows[
i]);
1272 uchar* pidData =
nullptr;
1274 status = XGetWindowProperty(sd.display, window, _nwp, 0L, (~0L), False, XA_CARDINAL, &actualType, &actualFormat, &pidSize, &bytesAfter, &pidData);
1276 if (pidData !=
nullptr)
1278 const ScopedFreeData sfd2(pidData);
1282 if (*(
ulong*)pidData ==
static_cast<ulong>(pid))
1283 lastGoodWindowPID =
window;
1291 uchar* nameData =
nullptr;
1293 status = XGetWindowProperty(sd.display, window, _nwn, 0L, (~0L), False, utf8, &actualType, &actualFormat, &nameSize, &bytesAfter, &nameData);
1295 if (nameData !=
nullptr)
1297 const ScopedFreeData sfd2(nameData);
1300 if (nameSize != 0 && std::strstr((
const char*)nameData, uiTitle) !=
nullptr)
1301 lastGoodWindowNameUTF8 =
window;
1307 char* wmName =
nullptr;
1309 status = XFetchName(sd.display, window, &wmName);
1311 if (wmName !=
nullptr)
1313 const ScopedFreeData sfd2(wmName);
1316 if (std::strstr(wmName, uiTitle) !=
nullptr)
1317 lastGoodWindowNameSimple =
window;
1321 if (lastGoodWindowPID == 0 && lastGoodWindowNameSimple == 0 && lastGoodWindowNameUTF8 == 0)
1326 if (lastGoodWindowPID != 0)
1328 if (lastGoodWindowPID == lastGoodWindowNameSimple && lastGoodWindowPID == lastGoodWindowNameUTF8)
1330 carla_stdout(
"Match found using pid, simple and UTF-8 name all at once, nice!");
1331 windowToMap = lastGoodWindowPID;
1333 else if (lastGoodWindowPID == lastGoodWindowNameUTF8)
1335 carla_stdout(
"Match found using pid and UTF-8 name");
1336 windowToMap = lastGoodWindowPID;
1338 else if (lastGoodWindowPID == lastGoodWindowNameSimple)
1340 carla_stdout(
"Match found using pid and simple name");
1341 windowToMap = lastGoodWindowPID;
1343 else if (lastGoodWindowNameUTF8 != 0)
1345 if (lastGoodWindowNameUTF8 == lastGoodWindowNameSimple)
1347 carla_stdout(
"Match found using simple and UTF-8 name (ignoring pid)");
1348 windowToMap = lastGoodWindowNameUTF8;
1352 carla_stdout(
"Match found using UTF-8 name (ignoring pid)");
1353 windowToMap = lastGoodWindowNameUTF8;
1358 carla_stdout(
"Match found using pid");
1359 windowToMap = lastGoodWindowPID;
1362 else if (lastGoodWindowNameUTF8 != 0)
1364 if (lastGoodWindowNameUTF8 == lastGoodWindowNameSimple)
1366 carla_stdout(
"Match found using simple and UTF-8 name");
1367 windowToMap = lastGoodWindowNameUTF8;
1371 carla_stdout(
"Match found using UTF-8 name");
1372 windowToMap = lastGoodWindowNameUTF8;
1377 carla_stdout(
"Match found using simple name");
1378 windowToMap = lastGoodWindowNameSimple;
1381 const Atom _nwt = XInternAtom(sd.display ,
"_NET_WM_STATE", False);
1382 const Atom _nws[2] = {
1383 XInternAtom(sd.display,
"_NET_WM_STATE_SKIP_TASKBAR", False),
1384 XInternAtom(sd.display,
"_NET_WM_STATE_SKIP_PAGER", False)
1386 XChangeProperty(sd.display, windowToMap, _nwt, XA_ATOM, 32, PropModeAppend, (
const uchar*)_nws, 2);
1388 const Atom _nwi = XInternAtom(sd.display,
"_NET_WM_ICON", False);
1389 XChangeProperty(sd.display, windowToMap, _nwi, XA_CARDINAL, 32, PropModeReplace, (
const uchar*)sCarlaX11Icon, sCarlaX11IconSize);
1391 const Window hostWinId((Window)winId);
1393 XSetTransientForHint(sd.display, windowToMap, hostWinId);
1395 if (centerUI &&
false )
1397 int hostX, hostY, pluginX, pluginY;
1398 uint hostWidth, hostHeight, pluginWidth, pluginHeight,
border, depth;
1401 if (XGetGeometry(sd.display, hostWinId, &retWindow, &hostX, &hostY, &hostWidth, &hostHeight, &
border, &depth) != 0 &&
1402 XGetGeometry(sd.display, windowToMap, &retWindow, &pluginX, &pluginY, &pluginWidth, &pluginHeight, &
border, &depth) != 0)
1404 if (XTranslateCoordinates(sd.display, hostWinId, rootWindow, hostX, hostY, &hostX, &hostY, &retWindow) == True &&
1405 XTranslateCoordinates(sd.display, windowToMap, rootWindow, pluginX, pluginY, &pluginX, &pluginY, &retWindow) == True)
1407 const int newX = hostX +
int(hostWidth/2 - pluginWidth/2);
1408 const int newY = hostY +
int(hostHeight/2 - pluginHeight/2);
1410 XMoveWindow(sd.display, windowToMap, newX, newY);
1416 XRaiseWindow(sd.display, hostWinId);
1417 XSetInputFocus(sd.display, hostWinId, RevertToPointerRoot, CurrentTime);
1419 XRaiseWindow(sd.display, windowToMap);
1420 XSetInputFocus(sd.display, windowToMap, RevertToPointerRoot, CurrentTime);
1427 uint const hints = kCGWindowListOptionOnScreenOnly|kCGWindowListExcludeDesktopElements;
1429 CFArrayRef
const windowListRef = CGWindowListCopyWindowInfo(hints, kCGNullWindowID);
1430 const NSArray*
const windowList = (
const NSArray*)windowListRef;
1432 int windowToMap, windowWithPID = 0, windowWithNameAndPID = 0;
1434 const NSDictionary* entry;
1435 for (entry
in windowList)
1438#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1439 if ([entry[(
id)kCGWindowSharingState] intValue] == kCGWindowSharingNone)
1442 NSString*
const windowName = entry[(id)kCGWindowName];
1443 int const windowNumber = [entry[(id)kCGWindowNumber] intValue];
1444 uintptr_t
const windowPID = [entry[(id)kCGWindowOwnerPID] intValue];
1446 if ([[entry objectForKey:(
id)kCGWindowSharingState] intValue] == kCGWindowSharingNone)
1449 NSString*
const windowName = [entry objectForKey:(id)kCGWindowName];
1450 int const windowNumber = [[entry objectForKey:(id)kCGWindowNumber] intValue];
1451 uintptr_t
const windowPID = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
1454 if (windowPID != pid)
1457 windowWithPID = windowNumber;
1459 if (windowName !=
nullptr && std::strcmp([windowName UTF8String], uiTitle) == 0)
1460 windowWithNameAndPID = windowNumber;
1463 CFRelease(windowListRef);
1465 if (windowWithNameAndPID != 0)
1467 carla_stdout(
"Match found using pid and name");
1468 windowToMap = windowWithNameAndPID;
1470 else if (windowWithPID != 0)
1472 carla_stdout(
"Match found using pid");
1473 windowToMap = windowWithPID;
1480 NSWindow*
const parentWindow = [NSApp windowWithWindowNumber:winId];
1483 [parentWindow orderWindow:NSWindowBelow
1484 relativeTo:windowToMap];
1489 if (
HWND const childWindow = FindWindowA(
nullptr, uiTitle))
1491 HWND const parentWindow = (
HWND)winId;
1496 RECT rectChild, rectParent;
1507 carla_stdout(
"Match found using window name");
1523CarlaPluginUI* CarlaPluginUI::newX11(Callback*
const cb,
1524 const uintptr_t parentId,
1525 const bool isStandalone,
1526 const bool isResizable,
1529 return new X11PluginUI(cb, parentId, isStandalone, isResizable, isLV2);
1534CarlaPluginUI* CarlaPluginUI::newCocoa(Callback*
const cb,
1535 const uintptr_t parentId,
1536 const bool isStandalone,
1537 const bool isResizable)
1539 return new CocoaPluginUI(cb, parentId, isStandalone, isResizable);
1544CarlaPluginUI* CarlaPluginUI::newWindows(Callback*
const cb,
1545 const uintptr_t parentId,
1546 const bool isStandalone,
1547 const bool isResizable)
1549 return new WindowsPluginUI(cb, parentId, isStandalone, isResizable);
#define CARLA_SAFE_ASSERT_CONTINUE(cond)
Definition CarlaDefines.h:189
unsigned char uchar
Definition CarlaDefines.h:325
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
unsigned int uint
Definition CarlaDefines.h:327
#define CARLA_SAFE_ASSERT_BREAK(cond)
Definition CarlaDefines.h:188
unsigned long int ulong
Definition CarlaDefines.h:328
#define CARLA_PREVENT_HEAP_ALLOCATION
Definition CarlaDefines.h:257
#define P_UINTPTR
Definition CarlaDefines.h:139
#define CARLA_SAFE_ASSERT(cond)
Definition CarlaDefines.h:182
#define CARLA_DECLARE_NON_COPYABLE(ClassName)
Definition CarlaDefines.h:242
class MasterUI * ui
Definition Connection.cpp:39
#define noexcept
Definition DistrhoDefines.h:72
#define nullptr
Definition DistrhoDefines.h:75
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
static void message(int level, const char *fmt,...)
Definition adplugdb.cpp:120
unsigned d
Definition inflate.c:940
register unsigned i
Definition inflate.c:1575
static ZCONST unsigned border[]
Definition inflate.c:749
static const char * title
Definition pugl.h:1747
static int int height
Definition pugl.h:1594
static int width
Definition pugl.h:1593
static uintptr_t parent
Definition pugl.h:1644
CARLA_PLUGIN_EXPORT int XUnmapWindow(Display *display, Window window)
Definition interposer-x11.cpp:124
CARLA_PLUGIN_EXPORT int XMapRaised(Display *display, Window window)
Definition interposer-x11.cpp:110
JSAMPIMAGE data
Definition jpeglib.h:945
float in
Definition lilv_test.c:1460
const char * msg
Definition missing_descriptor.c:20
@ focus
Definition juce_AccessibilityActions.h:54
@ window
Definition juce_AccessibilityRole.h:63
Definition swell-types.h:231
LONG bottom
Definition swell-types.h:232
LONG left
Definition swell-types.h:232
LONG top
Definition swell-types.h:232
LONG right
Definition swell-types.h:232
RECT const char void(* callback)(const char *droppath))) SWELL_API_DEFINE(BOOL
Definition swell-functions.h:1004
RECT const char void HWND hwnd
Definition swell-functions.h:1066
#define SetActiveWindow(x)
Definition swell-functions.h:225
bool GetWindowRect(HWND hwnd, RECT *r)
Definition swell-generic-headless.cpp:130
void UpdateWindow(HWND hwnd)
Definition swell-generic-headless.cpp:151
void * HINSTANCE
Definition swell-types.h:212
LONG_PTR LRESULT
Definition swell-types.h:171
unsigned int UINT
Definition swell-types.h:166
LONG_PTR LPARAM
Definition swell-types.h:170
signed char BOOL
Definition swell-types.h:160
intptr_t LONG_PTR
Definition swell-types.h:42
unsigned int DWORD
Definition swell-types.h:164
ULONG_PTR WPARAM
Definition swell-types.h:169
struct HWND__ * HWND
Definition swell-types.h:210
#define CALLBACK
Definition swell-types.h:635
void SetForegroundWindow(HWND hwnd)
Definition swell-wnd-generic.cpp:489
void DestroyWindow(HWND hwnd)
Definition swell-wnd-generic.cpp:449
void SetWindowPos(HWND hwnd, HWND zorder, int x, int y, int cx, int cy, int flags)
Definition swell-wnd-generic.cpp:637
void SetFocus(HWND hwnd)
Definition swell-wnd-generic.cpp:506
BOOL PostMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition swell-wnd-generic.cpp:7561
void GetClientRect(HWND hwnd, RECT *r)
Definition swell-wnd-generic.cpp:621
void ShowWindow(HWND hwnd, int cmd)
Definition swell-wnd-generic.cpp:1034
int result
Definition process.c:1455
int flag
Definition unix.c:754
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396
#define TRUE
Definition unzpriv.h:1295
#define FALSE
Definition unzpriv.h:1298
#define GetWindowLongPtr(a, b)
Definition wdltypes.h:63
#define SetWindowLongPtr(a, b, c)
Definition wdltypes.h:62
#define GWLP_HWNDPARENT
Definition wdltypes.h:58
#define GWLP_USERDATA
Definition win.c:30
LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition win.c:953
#define const
Definition zconf.h:137