29#if JUCE_DEBUG && ! defined (JUCE_DEBUG_XERRORS)
30 #define JUCE_DEBUG_XERRORS 1
32 #if ! defined (JUCE_DEBUG_XERRORS_SYNCHRONOUSLY)
33 #define JUCE_DEBUG_XERRORS_SYNCHRONOUSLY 0
37#if JUCE_MODULE_AVAILABLE_juce_gui_extra
38 #define JUCE_X11_SUPPORTS_XEMBED 1
40 #define JUCE_X11_SUPPORTS_XEMBED 0
47 void operator() (
void* ptr)
const
50 X11Symbols::getInstance()->xFree (ptr);
54 template <
typename Data>
57 template <
typename Data,
typename Deleter>
60 template <
typename XValueType>
64 : value (
std::
move (
xv)), cleanupFunc (cleanup)
78XWindowSystemUtilities::ScopedXLock::ScopedXLock()
80 if (
auto*
xWindow = XWindowSystem::getInstanceWithoutCreating())
81 if (
auto* d =
xWindow->getDisplay())
82 X11Symbols::getInstance()->xLockDisplay (d);
85XWindowSystemUtilities::ScopedXLock::~ScopedXLock()
87 if (
auto*
xWindow = XWindowSystem::getInstanceWithoutCreating())
88 if (
auto* d =
xWindow->getDisplay())
89 X11Symbols::getInstance()->xUnlockDisplay (d);
93XWindowSystemUtilities::Atoms::Atoms (::Display* display)
95 protocols = getIfExists (display,
"WM_PROTOCOLS");
96 protocolList [TAKE_FOCUS] = getIfExists (display,
"WM_TAKE_FOCUS");
97 protocolList [DELETE_WINDOW] = getIfExists (display,
"WM_DELETE_WINDOW");
98 protocolList [PING] = getIfExists (display,
"_NET_WM_PING");
99 changeState = getIfExists (display,
"WM_CHANGE_STATE");
100 state = getIfExists (display,
"WM_STATE");
101 userTime = getCreating (display,
"_NET_WM_USER_TIME");
102 activeWin = getCreating (display,
"_NET_ACTIVE_WINDOW");
103 pid = getCreating (display,
"_NET_WM_PID");
104 windowType = getIfExists (display,
"_NET_WM_WINDOW_TYPE");
105 windowState = getIfExists (display,
"_NET_WM_STATE");
106 windowStateHidden = getIfExists (display,
"_NET_WM_STATE_HIDDEN");
108 XdndAware = getCreating (display,
"XdndAware");
109 XdndEnter = getCreating (display,
"XdndEnter");
110 XdndLeave = getCreating (display,
"XdndLeave");
111 XdndPosition = getCreating (display,
"XdndPosition");
112 XdndStatus = getCreating (display,
"XdndStatus");
113 XdndDrop = getCreating (display,
"XdndDrop");
114 XdndFinished = getCreating (display,
"XdndFinished");
115 XdndSelection = getCreating (display,
"XdndSelection");
117 XdndTypeList = getCreating (display,
"XdndTypeList");
118 XdndActionList = getCreating (display,
"XdndActionList");
119 XdndActionCopy = getCreating (display,
"XdndActionCopy");
120 XdndActionPrivate = getCreating (display,
"XdndActionPrivate");
121 XdndActionDescription = getCreating (display,
"XdndActionDescription");
123 XembedMsgType = getCreating (display,
"_XEMBED");
124 XembedInfo = getCreating (display,
"_XEMBED_INFO");
126 allowedMimeTypes[0] = getCreating (display,
"UTF8_STRING");
127 allowedMimeTypes[1] = getCreating (display,
"text/plain;charset=utf-8");
128 allowedMimeTypes[2] = getCreating (display,
"text/plain");
129 allowedMimeTypes[3] = getCreating (display,
"text/uri-list");
131 allowedActions[0] = getCreating (display,
"XdndActionMove");
132 allowedActions[1] = XdndActionCopy;
133 allowedActions[2] = getCreating (display,
"XdndActionLink");
134 allowedActions[3] = getCreating (display,
"XdndActionAsk");
135 allowedActions[4] = XdndActionPrivate;
137 utf8String = getCreating (display,
"UTF8_STRING");
138 clipboard = getCreating (display,
"CLIPBOARD");
139 targets = getCreating (display,
"TARGETS");
142Atom XWindowSystemUtilities::Atoms::getIfExists (::Display* display,
const char* name)
144 return X11Symbols::getInstance()->xInternAtom (display, name, True);
147Atom XWindowSystemUtilities::Atoms::getCreating (::Display* display,
const char* name)
149 return X11Symbols::getInstance()->xInternAtom (display, name, False);
152String XWindowSystemUtilities::Atoms::getName (::Display* display, Atom atom)
157 return makeXFreePtr (X11Symbols::getInstance()->xGetAtomName (display, atom)).get();
160bool XWindowSystemUtilities::Atoms::isMimeTypeFile (::Display* display, Atom atom)
162 return getName (display, atom).equalsIgnoreCase (
"text/uri-list");
166XWindowSystemUtilities::GetXProperty::GetXProperty (::Display* display, Window window, Atom atom,
167 long offset,
long length,
bool shouldDelete, Atom
requestedType)
169 success = (X11Symbols::getInstance()->xGetWindowProperty (display, window, atom, offset, length,
171 &actualFormat, &numItems, &bytesLeft, &data) ==
Success)
175XWindowSystemUtilities::GetXProperty::~GetXProperty()
178 X11Symbols::getInstance()->xFree (data);
184 const auto settingsAtom = Atoms::getCreating (d,
"_XSETTINGS_SETTINGS");
185 const auto settingsWindow = X11Symbols::getInstance()->xGetSelectionOwner (d,
186 Atoms::getCreating (d,
"_XSETTINGS_S0"));
188 if (settingsWindow == None)
191 return rawToUniquePtr (
new XWindowSystemUtilities::XSettings (d, settingsWindow, settingsAtom));
200XWindowSystemUtilities::XSetting XWindowSystemUtilities::XSettings::getSetting (
const String& name)
const
202 const auto iter = settings.find (name);
204 if (iter != settings.end())
210void XWindowSystemUtilities::XSettings::update()
212 const GetXProperty prop { display,
221 && prop.actualType == settingsAtom
222 && prop.actualFormat == 8
223 && prop.numItems > 0)
225 const auto bytes = (
size_t) prop.numItems;
226 auto*
data = prop.data;
229 const auto increment = [&] (
size_t amount)
243 const auto* header = unalignedPointerCast<const Header*> (data);
244 const auto headerSerial = (
int) header->serial;
245 increment (
sizeof (Header));
247 const auto readCARD16 = [&]() -> CARD16
249 if (byteNum +
sizeof (CARD16) > bytes)
252 const auto value = header->byteOrder == MSBFirst ? ByteOrder::bigEndianShort (data)
253 : ByteOrder::littleEndianShort (
data);
254 increment (
sizeof (CARD16));
258 const auto readCARD32 = [&]() -> CARD32
260 if (byteNum +
sizeof (CARD32) > bytes)
263 const auto value = header->byteOrder == MSBFirst ? ByteOrder::bigEndianInt (data)
264 : ByteOrder::littleEndianInt (
data);
265 increment (
sizeof (CARD32));
269 const auto readString = [&] (
size_t nameLen) -> String
271 const auto padded = (nameLen + 3) & (~(
size_t) 3);
273 if (byteNum + padded > bytes)
276 auto* ptr =
reinterpret_cast<const char*
> (
data);
277 const String result (ptr, nameLen);
284 while (byteNum < bytes && setting < header->nSettings)
286 const auto type = *
reinterpret_cast<const char*
> (
data);
289 const auto name = readString (readCARD16());
290 const auto serial = (
int) readCARD32();
292 enum { XSettingsTypeInteger, XSettingsTypeString, XSettingsTypeColor };
294 const auto parsedSetting = [&]() -> XSetting
298 case XSettingsTypeInteger:
299 return { name, (
int) readCARD32() };
301 case XSettingsTypeString:
302 return { name, readString (readCARD32()) };
304 case XSettingsTypeColor:
306 const auto r = (uint8) readCARD16();
307 const auto g = (uint8) readCARD16();
308 const auto b = (uint8) readCARD16();
309 const auto a = (uint8) readCARD16();
310 return { name, Colour { r, g, b, a } };
316 if (serial > lastUpdateSerial)
318 settings[parsedSetting.name] = parsedSetting;
319 listeners.call ([&parsedSetting] (Listener& l) { l.settingChanged (parsedSetting); });
325 lastUpdateSerial = headerSerial;
330::Window juce_messageWindowHandle;
331XContext windowHandleXContext;
333#if JUCE_X11_SUPPORTS_XEMBED
334 bool juce_handleXEmbedEvent (ComponentPeer*,
void*);
335 unsigned long juce_getCurrentFocusWindow (ComponentPeer*);
340 unsigned long flags = 0;
341 unsigned long functions = 0;
342 unsigned long decorations = 0;
344 unsigned long status = 0;
348namespace X11ErrorHandling
350 static XErrorHandler oldErrorHandler = {};
351 static XIOErrorHandler oldIOErrorHandler = {};
354 static int ioErrorHandler (::Display*)
356 DBG (
"ERROR: connection to X server broken.. terminating.");
358 if (JUCEApplicationBase::isStandaloneApp())
359 MessageManager::getInstance()->stopDispatchLoop();
364 static int errorHandler ([[maybe_unused]] ::Display* display, [[maybe_unused]] XErrorEvent* event)
366 #if JUCE_DEBUG_XERRORS
367 char errorStr[64] = { 0 };
368 char requestStr[64] = { 0 };
370 X11Symbols::getInstance()->xGetErrorText (display, event->error_code, errorStr, 64);
371 X11Symbols::getInstance()->xGetErrorDatabaseText (display,
"XRequest", String (event->request_code).toUTF8(),
"Unknown", requestStr, 64);
373 DBG (
"ERROR: X returned " << errorStr <<
" for operation " << requestStr);
379 static void installXErrorHandlers()
381 oldIOErrorHandler = X11Symbols::getInstance()->xSetIOErrorHandler (ioErrorHandler);
382 oldErrorHandler = X11Symbols::getInstance()->xSetErrorHandler (errorHandler);
385 static void removeXErrorHandlers()
387 X11Symbols::getInstance()->xSetIOErrorHandler (oldIOErrorHandler);
388 oldIOErrorHandler = {};
390 X11Symbols::getInstance()->xSetErrorHandler (oldErrorHandler);
391 oldErrorHandler = {};
408 static int AltMask = 0;
409 static int NumLockMask = 0;
410 static bool numLock =
false;
411 static bool capsLock =
false;
412 static char keyStates [32];
413 static constexpr int extendedKeyModifier = 0x10000000;
414 static bool modifierKeysAreStale =
false;
416 static void refreshStaleModifierKeys()
418 if (modifierKeysAreStale)
420 XWindowSystem::getInstance()->getNativeRealtimeModifiers();
421 modifierKeysAreStale =
false;
427 static void refreshStaleMouseKeys()
429 if (modifierKeysAreStale)
431 const auto oldMods = ModifierKeys::currentModifiers;
432 XWindowSystem::getInstance()->getNativeRealtimeModifiers();
433 ModifierKeys::currentModifiers = oldMods.withoutMouseButtons()
434 .withFlags (ModifierKeys::currentModifiers.withOnlyMouseButtons()
436 modifierKeysAreStale =
false;
441const int KeyPress::spaceKey = XK_space & 0xff;
442const int KeyPress::returnKey = XK_Return & 0xff;
443const int KeyPress::escapeKey = XK_Escape & 0xff;
444const int KeyPress::backspaceKey = XK_BackSpace & 0xff;
445const int KeyPress::leftKey = (XK_Left & 0xff) | Keys::extendedKeyModifier;
446const int KeyPress::rightKey = (XK_Right & 0xff) | Keys::extendedKeyModifier;
447const int KeyPress::upKey = (XK_Up & 0xff) | Keys::extendedKeyModifier;
448const int KeyPress::downKey = (XK_Down & 0xff) | Keys::extendedKeyModifier;
449const int KeyPress::pageUpKey = (XK_Page_Up & 0xff) | Keys::extendedKeyModifier;
450const int KeyPress::pageDownKey = (XK_Page_Down & 0xff) | Keys::extendedKeyModifier;
451const int KeyPress::endKey = (XK_End & 0xff) | Keys::extendedKeyModifier;
452const int KeyPress::homeKey = (XK_Home & 0xff) | Keys::extendedKeyModifier;
453const int KeyPress::insertKey = (XK_Insert & 0xff) | Keys::extendedKeyModifier;
454const int KeyPress::deleteKey = (XK_Delete & 0xff) | Keys::extendedKeyModifier;
455const int KeyPress::tabKey = XK_Tab & 0xff;
456const int KeyPress::F1Key = (XK_F1 & 0xff) | Keys::extendedKeyModifier;
457const int KeyPress::F2Key = (XK_F2 & 0xff) | Keys::extendedKeyModifier;
458const int KeyPress::F3Key = (XK_F3 & 0xff) | Keys::extendedKeyModifier;
459const int KeyPress::F4Key = (XK_F4 & 0xff) | Keys::extendedKeyModifier;
460const int KeyPress::F5Key = (XK_F5 & 0xff) | Keys::extendedKeyModifier;
461const int KeyPress::F6Key = (XK_F6 & 0xff) | Keys::extendedKeyModifier;
462const int KeyPress::F7Key = (XK_F7 & 0xff) | Keys::extendedKeyModifier;
463const int KeyPress::F8Key = (XK_F8 & 0xff) | Keys::extendedKeyModifier;
464const int KeyPress::F9Key = (XK_F9 & 0xff) | Keys::extendedKeyModifier;
465const int KeyPress::F10Key = (XK_F10 & 0xff) | Keys::extendedKeyModifier;
466const int KeyPress::F11Key = (XK_F11 & 0xff) | Keys::extendedKeyModifier;
467const int KeyPress::F12Key = (XK_F12 & 0xff) | Keys::extendedKeyModifier;
468const int KeyPress::F13Key = (XK_F13 & 0xff) | Keys::extendedKeyModifier;
469const int KeyPress::F14Key = (XK_F14 & 0xff) | Keys::extendedKeyModifier;
470const int KeyPress::F15Key = (XK_F15 & 0xff) | Keys::extendedKeyModifier;
471const int KeyPress::F16Key = (XK_F16 & 0xff) | Keys::extendedKeyModifier;
472const int KeyPress::F17Key = (XK_F17 & 0xff) | Keys::extendedKeyModifier;
473const int KeyPress::F18Key = (XK_F18 & 0xff) | Keys::extendedKeyModifier;
474const int KeyPress::F19Key = (XK_F19 & 0xff) | Keys::extendedKeyModifier;
475const int KeyPress::F20Key = (XK_F20 & 0xff) | Keys::extendedKeyModifier;
476const int KeyPress::F21Key = (XK_F21 & 0xff) | Keys::extendedKeyModifier;
477const int KeyPress::F22Key = (XK_F22 & 0xff) | Keys::extendedKeyModifier;
478const int KeyPress::F23Key = (XK_F23 & 0xff) | Keys::extendedKeyModifier;
479const int KeyPress::F24Key = (XK_F24 & 0xff) | Keys::extendedKeyModifier;
480const int KeyPress::F25Key = (XK_F25 & 0xff) | Keys::extendedKeyModifier;
481const int KeyPress::F26Key = (XK_F26 & 0xff) | Keys::extendedKeyModifier;
482const int KeyPress::F27Key = (XK_F27 & 0xff) | Keys::extendedKeyModifier;
483const int KeyPress::F28Key = (XK_F28 & 0xff) | Keys::extendedKeyModifier;
484const int KeyPress::F29Key = (XK_F29 & 0xff) | Keys::extendedKeyModifier;
485const int KeyPress::F30Key = (XK_F30 & 0xff) | Keys::extendedKeyModifier;
486const int KeyPress::F31Key = (XK_F31 & 0xff) | Keys::extendedKeyModifier;
487const int KeyPress::F32Key = (XK_F32 & 0xff) | Keys::extendedKeyModifier;
488const int KeyPress::F33Key = (XK_F33 & 0xff) | Keys::extendedKeyModifier;
489const int KeyPress::F34Key = (XK_F34 & 0xff) | Keys::extendedKeyModifier;
490const int KeyPress::F35Key = (XK_F35 & 0xff) | Keys::extendedKeyModifier;
491const int KeyPress::numberPad0 = (XK_KP_0 & 0xff) | Keys::extendedKeyModifier;
492const int KeyPress::numberPad1 = (XK_KP_1 & 0xff) | Keys::extendedKeyModifier;
493const int KeyPress::numberPad2 = (XK_KP_2 & 0xff) | Keys::extendedKeyModifier;
494const int KeyPress::numberPad3 = (XK_KP_3 & 0xff) | Keys::extendedKeyModifier;
495const int KeyPress::numberPad4 = (XK_KP_4 & 0xff) | Keys::extendedKeyModifier;
496const int KeyPress::numberPad5 = (XK_KP_5 & 0xff) | Keys::extendedKeyModifier;
497const int KeyPress::numberPad6 = (XK_KP_6 & 0xff) | Keys::extendedKeyModifier;
498const int KeyPress::numberPad7 = (XK_KP_7 & 0xff) | Keys::extendedKeyModifier;
499const int KeyPress::numberPad8 = (XK_KP_8 & 0xff) | Keys::extendedKeyModifier;
500const int KeyPress::numberPad9 = (XK_KP_9 & 0xff) | Keys::extendedKeyModifier;
501const int KeyPress::numberPadAdd = (XK_KP_Add & 0xff) | Keys::extendedKeyModifier;
502const int KeyPress::numberPadSubtract = (XK_KP_Subtract & 0xff) | Keys::extendedKeyModifier;
503const int KeyPress::numberPadMultiply = (XK_KP_Multiply & 0xff) | Keys::extendedKeyModifier;
504const int KeyPress::numberPadDivide = (XK_KP_Divide & 0xff) | Keys::extendedKeyModifier;
505const int KeyPress::numberPadSeparator = (XK_KP_Separator & 0xff) | Keys::extendedKeyModifier;
506const int KeyPress::numberPadDecimalPoint = (XK_KP_Decimal & 0xff) | Keys::extendedKeyModifier;
507const int KeyPress::numberPadEquals = (XK_KP_Equal & 0xff) | Keys::extendedKeyModifier;
508const int KeyPress::numberPadDelete = (XK_KP_Delete & 0xff) | Keys::extendedKeyModifier;
509const int KeyPress::playKey = ((
int) 0xffeeff00) | Keys::extendedKeyModifier;
510const int KeyPress::stopKey = ((
int) 0xffeeff01) | Keys::extendedKeyModifier;
511const int KeyPress::fastForwardKey = ((
int) 0xffeeff02) | Keys::extendedKeyModifier;
512const int KeyPress::rewindKey = ((
int) 0xffeeff03) | Keys::extendedKeyModifier;
514static void updateKeyStates (
int keycode,
bool press)
noexcept
516 auto keybyte = keycode >> 3;
517 auto keybit = (1 << (keycode & 7));
520 Keys::keyStates [keybyte] |= keybit;
522 Keys::keyStates [keybyte] &= ~keybit;
525static void updateKeyModifiers (
int status)
noexcept
529 if ((status & ShiftMask) != 0) keyMods |= ModifierKeys::shiftModifier;
530 if ((status & ControlMask) != 0) keyMods |= ModifierKeys::ctrlModifier;
531 if ((status & Keys::AltMask) != 0) keyMods |= ModifierKeys::altModifier;
533 ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withOnlyMouseButtons().withFlags (keyMods);
535 Keys::numLock = ((
status & Keys::NumLockMask) != 0);
536 Keys::capsLock = ((
status & LockMask) != 0);
539static bool updateKeyModifiersFromSym (KeySym sym,
bool press)
noexcept
542 bool isModifier =
true;
547 case XK_Shift_R: modifier = ModifierKeys::shiftModifier;
break;
550 case XK_Control_R: modifier = ModifierKeys::ctrlModifier;
break;
553 case XK_Alt_R: modifier = ModifierKeys::altModifier;
break;
557 Keys::numLock = ! Keys::numLock;
563 Keys::capsLock = ! Keys::capsLock;
575 ModifierKeys::currentModifiers =
press ? ModifierKeys::currentModifiers.withFlags (modifier)
576 : ModifierKeys::currentModifiers.withoutFlags (modifier);
583 KeyPressEventType = 2
588 namespace XSHMHelpers
590 static int trappedErrorCode = 0;
592 extern "C" int errorTrapHandler (Display*, XErrorEvent* err);
593 extern "C" int errorTrapHandler (Display*, XErrorEvent* err)
595 trappedErrorCode = err->error_code;
599 static bool isShmAvailable (::Display* display)
601 static bool isChecked =
false;
602 static bool isAvailable =
false;
608 if (display !=
nullptr)
613 XWindowSystemUtilities::ScopedXLock xLock;
615 if (X11Symbols::getInstance()->xShmQueryVersion (display, &major, &minor, &pixmaps))
617 trappedErrorCode = 0;
618 auto oldHandler = X11Symbols::getInstance()->xSetErrorHandler (errorTrapHandler);
620 XShmSegmentInfo segmentInfo;
623 if (
auto* xImage = X11Symbols::getInstance()->xShmCreateImage (display,
624 X11Symbols::getInstance()->xDefaultVisual (display, X11Symbols::getInstance()->xDefaultScreen (display)),
625 24, ZPixmap,
nullptr, &segmentInfo, 50, 50))
627 if ((segmentInfo.shmid =
shmget (IPC_PRIVATE,
628 (
size_t) (xImage->bytes_per_line * xImage->height),
629 IPC_CREAT | 0777)) >= 0)
631 segmentInfo.shmaddr = (
char*) shmat (segmentInfo.shmid,
nullptr, 0);
633 if (segmentInfo.shmaddr != (
void*) -1)
635 segmentInfo.readOnly = False;
636 xImage->data = segmentInfo.shmaddr;
637 X11Symbols::getInstance()->xSync (display, False);
639 if (X11Symbols::getInstance()->xShmAttach (display, &segmentInfo) != 0)
641 X11Symbols::getInstance()->xShmDetach (display, &segmentInfo);
642 X11Symbols::getInstance()->xSync (display, False);
648 X11Symbols::getInstance()->xFlush (display);
649 X11Symbols::getInstance()->xDestroyImage (xImage);
651 shmdt (segmentInfo.shmaddr);
654 shmctl (segmentInfo.shmid, IPC_RMID,
nullptr);
656 X11Symbols::getInstance()->xSetErrorHandler (oldHandler);
658 if (trappedErrorCode != 0)
674 static bool isAvailable (::Display* display)
677 return X11Symbols::getInstance()->xRenderQueryVersion (display, &major, &minor);
680 static bool hasCompositingWindowManager (::Display* display)
682 return display !=
nullptr
683 && X11Symbols::getInstance()->xGetSelectionOwner (display,
684 XWindowSystemUtilities::Atoms::getCreating (display,
"_NET_WM_CM_S0")) != 0;
687 static XRenderPictFormat* findPictureFormat (::Display* display)
689 XWindowSystemUtilities::ScopedXLock xLock;
691 if (isAvailable (display))
693 if (
auto* pictFormat = X11Symbols::getInstance()->xRenderFindStandardFormat (display, PictStandardARGB32))
695 XRenderPictFormat desiredFormat;
696 desiredFormat.type = PictTypeDirect;
697 desiredFormat.depth = 32;
699 desiredFormat.direct.alphaMask = 0xff;
700 desiredFormat.direct.redMask = 0xff;
701 desiredFormat.direct.greenMask = 0xff;
702 desiredFormat.direct.blueMask = 0xff;
704 desiredFormat.direct.alpha = 24;
705 desiredFormat.direct.red = 16;
706 desiredFormat.direct.green = 8;
707 desiredFormat.direct.blue = 0;
709 pictFormat = X11Symbols::getInstance()->xRenderFindFormat (display,
710 PictFormatType | PictFormatDepth
711 | PictFormatRedMask | PictFormatRed
712 | PictFormatGreenMask | PictFormatGreen
713 | PictFormatBlueMask | PictFormatBlue
714 | PictFormatAlphaMask | PictFormatAlpha,
730 static Visual* findVisualWithDepth (::Display* display,
int desiredDepth)
732 XWindowSystemUtilities::ScopedXLock xLock;
734 Visual* visual =
nullptr;
736 auto desiredMask = VisualNoMask;
737 XVisualInfo desiredVisual;
739 desiredVisual.screen = X11Symbols::getInstance()->xDefaultScreen (display);
740 desiredVisual.depth = desiredDepth;
742 desiredMask = VisualScreenMask | VisualDepthMask;
744 if (desiredDepth == 32)
746 desiredVisual.c_class = TrueColor;
747 desiredVisual.red_mask = 0x00FF0000;
748 desiredVisual.green_mask = 0x0000FF00;
749 desiredVisual.blue_mask = 0x000000FF;
750 desiredVisual.bits_per_rgb = 8;
752 desiredMask |= VisualClassMask;
753 desiredMask |= VisualRedMaskMask;
754 desiredMask |= VisualGreenMaskMask;
755 desiredMask |= VisualBlueMaskMask;
756 desiredMask |= VisualBitsPerRGBMask;
759 if (
auto xvinfos = makeXFreePtr (X11Symbols::getInstance()->xGetVisualInfo (display, desiredMask, &desiredVisual, &numVisuals)))
761 for (
int i = 0; i < numVisuals; i++)
763 if (xvinfos.get()[i].depth == desiredDepth)
765 visual = xvinfos.get()[i].visual;
774 static Visual* findVisualFormat (::Display* display,
int desiredDepth,
int& matchedDepth)
776 Visual* visual =
nullptr;
778 if (desiredDepth == 32)
781 if (XSHMHelpers::isShmAvailable (display))
784 if (XRender::isAvailable (display))
786 if (XRender::findPictureFormat (display) !=
nullptr)
789 XVisualInfo desiredVisual;
790 desiredVisual.screen = X11Symbols::getInstance()->xDefaultScreen (display);
791 desiredVisual.depth = 32;
792 desiredVisual.bits_per_rgb = 8;
794 if (
auto xvinfos = makeXFreePtr (X11Symbols::getInstance()->xGetVisualInfo (display,
795 VisualScreenMask | VisualDepthMask | VisualBitsPerRGBMask,
796 &desiredVisual, &numVisuals)))
798 for (
int i = 0; i < numVisuals; ++i)
800 auto pictVisualFormat = X11Symbols::getInstance()->xRenderFindVisualFormat (display, xvinfos.get()[i].visual);
802 if (pictVisualFormat !=
nullptr
803 && pictVisualFormat->type == PictTypeDirect
804 && pictVisualFormat->direct.alphaMask)
806 visual = xvinfos.get()[i].visual;
815 if (visual ==
nullptr)
817 visual = findVisualWithDepth (display, 32);
819 if (visual !=
nullptr)
826 if (visual ==
nullptr && desiredDepth >= 24)
828 visual = findVisualWithDepth (display, 24);
830 if (visual !=
nullptr)
834 if (visual ==
nullptr && desiredDepth >= 16)
836 visual = findVisualWithDepth (display, 16);
838 if (visual !=
nullptr)
851 :
ImagePixelData (image->depth == 24 ? Image::RGB : Image::ARGB, image->width, image->height),
853 imageDepth ((
unsigned int) xImage->depth)
855 pixelStride = xImage->bits_per_pixel / 8;
856 lineStride = xImage->bytes_per_line;
857 imageData =
reinterpret_cast<uint8*
> (xImage->data);
861 bool clearImage,
unsigned int imageDepth_, Visual* visual)
863 imageDepth (imageDepth_)
865 jassert (format == Image::RGB || format == Image::ARGB);
867 pixelStride = (format == Image::RGB) ? 3 : 4;
868 lineStride = ((w * pixelStride + 3) & ~3);
875 if ((imageDepth > 16) && XSHMHelpers::isShmAvailable (display))
879 segmentInfo.shmid = -1;
880 segmentInfo.shmaddr = (
char *) -1;
881 segmentInfo.readOnly = False;
883 xImage.reset (X11Symbols::getInstance()->xShmCreateImage (display, visual, imageDepth, ZPixmap,
nullptr,
884 &segmentInfo, (
unsigned int) w, (
unsigned int) h));
886 if (xImage !=
nullptr)
888 if ((segmentInfo.shmid =
shmget (IPC_PRIVATE,
889 (
size_t) (xImage->bytes_per_line * xImage->height),
890 IPC_CREAT | 0777)) >= 0)
892 if (segmentInfo.shmid != -1)
894 segmentInfo.shmaddr = (
char*)
shmat (segmentInfo.shmid,
nullptr, 0);
896 if (segmentInfo.shmaddr != (
void*) -1)
898 segmentInfo.readOnly = False;
900 xImage->data = segmentInfo.shmaddr;
901 imageData = (
uint8*) segmentInfo.shmaddr;
903 if (X11Symbols::getInstance()->xShmAttach (display, &segmentInfo) != 0)
910 shmctl (segmentInfo.shmid, IPC_RMID,
nullptr);
920 imageDataAllocated.allocate ((
size_t) (lineStride * h), format == Image::ARGB && clearImage);
921 imageData = imageDataAllocated;
923 xImage.reset ((XImage*) ::calloc (1,
sizeof (XImage)));
928 xImage->format = ZPixmap;
929 xImage->data = (
char*) imageData;
930 xImage->byte_order = X11Symbols::getInstance()->xImageByteOrder (display);
931 xImage->bitmap_unit = X11Symbols::getInstance()->xBitmapUnit (display);
932 xImage->bitmap_bit_order = X11Symbols::getInstance()->xBitmapBitOrder (display);
933 xImage->bitmap_pad = 32;
934 xImage->depth = pixelStride * 8;
935 xImage->bytes_per_line = lineStride;
936 xImage->bits_per_pixel = pixelStride * 8;
937 xImage->red_mask = 0x00FF0000;
938 xImage->green_mask = 0x0000FF00;
939 xImage->blue_mask = 0x000000FF;
941 if (imageDepth == 16)
944 auto stride = ((w * pixStride + 3) & ~3);
946 imageData16Bit.malloc (stride * h);
947 xImage->data = imageData16Bit;
948 xImage->bitmap_pad = 16;
949 xImage->depth = pixStride * 8;
950 xImage->bytes_per_line = stride;
951 xImage->bits_per_pixel = pixStride * 8;
952 xImage->red_mask = visual->red_mask;
953 xImage->green_mask = visual->green_mask;
954 xImage->blue_mask = visual->blue_mask;
957 if (! X11Symbols::getInstance()->xInitImage (xImage.get()))
967 X11Symbols::getInstance()->xFreeGC (display, gc);
972 X11Symbols::getInstance()->xShmDetach (display, &segmentInfo);
974 X11Symbols::getInstance()->xFlush (display);
976 shmdt (segmentInfo.shmaddr);
977 shmctl (segmentInfo.shmid, IPC_RMID,
nullptr);
982 xImage->data =
nullptr;
988 sendDataChangeMessage();
989 return std::make_unique<LowLevelGraphicsSoftwareRenderer> (
Image (
this));
993 Image::BitmapData::ReadWriteMode mode)
override
995 const auto offset = (
size_t) (x * pixelStride + y * lineStride);
996 bitmap.
data = imageData + offset;
997 bitmap.
size = (
size_t) (lineStride * height) - offset;
1002 if (mode != Image::BitmapData::readOnly)
1003 sendDataChangeMessage();
1014 void blitToWindow (::Window window,
int dx,
int dy,
unsigned int dw,
unsigned int dh,
int sx,
int sy)
1020 XWindowSystem::getInstance()->addPendingPaintForWindow (window);
1026 gcvalues.foreground = None;
1027 gcvalues.background = None;
1028 gcvalues.function = GXcopy;
1029 gcvalues.plane_mask = AllPlanes;
1030 gcvalues.clip_mask = None;
1031 gcvalues.graphics_exposures = False;
1033 gc = X11Symbols::getInstance()->xCreateGC (display, window,
1034 GCBackground | GCForeground | GCFunction | GCPlaneMask | GCClipMask | GCGraphicsExposures,
1038 if (imageDepth == 16)
1040 auto rMask = (uint32) xImage->red_mask;
1041 auto gMask = (uint32) xImage->green_mask;
1042 auto bMask = (uint32) xImage->blue_mask;
1043 auto rShiftL = (uint32) jmax (0, getShiftNeeded (rMask));
1044 auto rShiftR = (uint32) jmax (0, -getShiftNeeded (rMask));
1045 auto gShiftL = (uint32) jmax (0, getShiftNeeded (gMask));
1046 auto gShiftR = (uint32) jmax (0, -getShiftNeeded (gMask));
1047 auto bShiftL = (uint32) jmax (0, getShiftNeeded (bMask));
1048 auto bShiftR = (uint32) jmax (0, -getShiftNeeded (bMask));
1050 Image::BitmapData srcData (Image (
this), Image::BitmapData::readOnly);
1052 for (
int y = sy; y < sy + (
int) dh; ++y)
1054 auto* p = srcData.getPixelPointer (sx, y);
1056 for (
int x = sx; x < sx + (
int) dw; ++x)
1058 auto* pixel = (PixelRGB*) p;
1059 p += srcData.pixelStride;
1061 X11Symbols::getInstance()->xPutPixel (xImage.get(), x, y,
1062 (((((uint32) pixel->getRed()) << rShiftL) >> rShiftR) & rMask)
1063 | (((((uint32) pixel->getGreen()) << gShiftL) >> gShiftR) & gMask)
1064 | (((((uint32) pixel->getBlue()) << bShiftL) >> bShiftR) & bMask));
1072 X11Symbols::getInstance()->xShmPutImage (display, (::Drawable) window, gc, xImage.get(), sx, sy, dx, dy, dw, dh, True);
1075 X11Symbols::getInstance()->xPutImage (display, (::Drawable) window, gc, xImage.get(), sx, sy, dx, dy, dw, dh);
1079 bool isUsingXShm() const noexcept {
return usingXShm; }
1086 void operator() (XImage* img)
const noexcept
1088 X11Symbols::getInstance()->xDestroyImage (img);
1093 const unsigned int imageDepth;
1094 HeapBlock<uint8> imageDataAllocated;
1095 HeapBlock<char> imageData16Bit;
1096 int pixelStride, lineStride;
1097 uint8* imageData =
nullptr;
1099 ::Display* display = XWindowSystem::getInstance()->getDisplay();
1102 XShmSegmentInfo segmentInfo;
1106 static int getShiftNeeded (
const uint32 mask)
noexcept
1108 for (
int i = 32; --i >= 0;)
1109 if (((mask >> i) & 1) != 0)
1120namespace DisplayHelpers
1122 static double getDisplayDPI (::Display* display,
int index)
1124 auto widthMM = X11Symbols::getInstance()->xDisplayWidthMM (display, index);
1125 auto heightMM = X11Symbols::getInstance()->xDisplayHeightMM (display, index);
1127 if (widthMM > 0 && heightMM > 0)
1128 return (((X11Symbols::getInstance()->xDisplayWidth (display, index) * 25.4) / widthMM)
1129 + ((X11Symbols::getInstance()->xDisplayHeight (display, index) * 25.4) / heightMM)) / 2.0;
1134 static double getDisplayScale (
const String& name,
double dpi)
1136 if (
auto* xSettings = XWindowSystem::getInstance()->getXSettings())
1138 auto windowScalingFactorSetting = xSettings->getSetting (XWindowSystem::getWindowScalingFactorSettingName());
1140 if (windowScalingFactorSetting.isValid()
1141 && windowScalingFactorSetting.integerValue > 0)
1143 return (
double) windowScalingFactorSetting.integerValue;
1147 if (name.isNotEmpty())
1153 if (File (
"/usr/bin/dconf").existsAsFile()
1154 && dconf.start (
"/usr/bin/dconf read /com/ubuntu/user-interface/scale-factor", ChildProcess::wantStdOut))
1156 if (dconf.waitForProcessToFinish (200))
1158 auto jsonOutput = dconf.readAllProcessOutput().replaceCharacter (
'\'',
'"');
1160 if (dconf.getExitCode() == 0 && jsonOutput.isNotEmpty())
1162 auto jsonVar = JSON::parse (jsonOutput);
1164 if (
auto*
object = jsonVar.getDynamicObject())
1166 auto scaleFactorVar =
object->getProperty (name);
1168 if (! scaleFactorVar.isVoid())
1170 auto scaleFactor = ((
double) scaleFactorVar) / 8.0;
1172 if (scaleFactor > 0.0)
1183 ChildProcess gsettings;
1185 if (File (
"/usr/bin/gsettings").existsAsFile()
1186 && gsettings.start (
"/usr/bin/gsettings get org.gnome.desktop.interface scaling-factor", ChildProcess::wantStdOut))
1188 if (gsettings.waitForProcessToFinish (200))
1190 auto gsettingsOutput = StringArray::fromTokens (gsettings.readAllProcessOutput(),
true);
1192 if (gsettingsOutput.size() >= 2 && gsettingsOutput[1].length() > 0)
1194 auto scaleFactor = gsettingsOutput[1].getDoubleValue();
1196 if (scaleFactor > 0.0)
1208 return round (dpi / 96.0);
1211 #if JUCE_USE_XINERAMA
1212 static Array<XineramaScreenInfo> xineramaQueryDisplays (::Display* display)
1214 int major_opcode, first_event, first_error;
1216 if (X11Symbols::getInstance()->xQueryExtension (display,
"XINERAMA", &major_opcode, &first_event, &first_error)
1217 && (X11Symbols::getInstance()->xineramaIsActive (display) != 0))
1221 if (
auto xinfo = makeXFreePtr (X11Symbols::getInstance()->xineramaQueryScreens (display, &numScreens)))
1222 return { xinfo.get(), numScreens };
1231namespace PixmapHelpers
1233 static Pixmap createColourPixmapFromImage (::Display* display,
const Image& image)
1235 XWindowSystemUtilities::ScopedXLock xLock;
1237 auto width = (
unsigned int) image.getWidth();
1238 auto height = (
unsigned int) image.getHeight();
1239 HeapBlock<uint32> colour (width * height);
1242 for (
int y = 0; y < (
int) height; ++y)
1243 for (
int x = 0; x < (
int) width; ++x)
1244 colour[index++] = image.getPixelAt (x, y).getARGB();
1246 auto ximage = makeXFreePtr (X11Symbols::getInstance()->xCreateImage (display, (Visual*) CopyFromParent, 24, ZPixmap,
1247 0,
reinterpret_cast<const char*
> (colour.getData()),
1248 width, height, 32, 0));
1250 auto pixmap = X11Symbols::getInstance()->xCreatePixmap (display,
1251 X11Symbols::getInstance()->xDefaultRootWindow (display),
1254 XValueHolder<GC> gc (X11Symbols::getInstance()->xCreateGC (display, pixmap, 0,
nullptr),
1255 [&display] (GC& g) { X11Symbols::getInstance()->xFreeGC (display, g); });
1256 X11Symbols::getInstance()->xPutImage (display, pixmap, gc.value, ximage.get(), 0, 0, 0, 0, width, height);
1261 static Pixmap createMaskPixmapFromImage (::Display* display,
const Image& image)
1263 XWindowSystemUtilities::ScopedXLock xLock;
1265 auto width = (
unsigned int) image.getWidth();
1266 auto height = (
unsigned int) image.getHeight();
1267 auto stride = (width + 7) >> 3;
1268 HeapBlock<char> mask;
1269 mask.calloc (stride * height);
1271 auto msbfirst = (X11Symbols::getInstance()->xBitmapBitOrder (display) == MSBFirst);
1273 for (
unsigned int y = 0; y < height; ++y)
1275 for (
unsigned int x = 0; x < width; ++x)
1277 auto bit = (
char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7)));
1278 auto offset = y * stride + (x >> 3);
1280 if (image.getPixelAt ((
int) x, (
int) y).getAlpha() >= 128)
1281 mask[offset] |= bit;
1285 return X11Symbols::getInstance()->xCreatePixmapFromBitmapData (display, X11Symbols::getInstance()->xDefaultRootWindow (display),
1286 mask.getData(), width, height, 1, 0, 1);
1291namespace ClipboardHelpers
1296 static String readWindowProperty (::Display* display, Window window, Atom atom)
1298 if (display !=
nullptr)
1300 XWindowSystemUtilities::GetXProperty prop (display, window, atom, 0L, 100000,
false, AnyPropertyType);
1304 if (prop.actualType == XWindowSystem::getInstance()->getAtoms().utf8String && prop.actualFormat == 8)
1305 return String::fromUTF8 ((
const char*) prop.data, (
int) prop.numItems);
1307 if (prop.actualType == XA_STRING && prop.actualFormat == 8)
1308 return String ((
const char*) prop.data, prop.numItems);
1317 static bool requestSelectionContent (::Display* display, String& selectionContent, Atom selection, Atom requestedFormat)
1319 auto property_name = X11Symbols::getInstance()->xInternAtom (display,
"JUCE_SEL",
false);
1323 X11Symbols::getInstance()->xConvertSelection (display, selection, requestedFormat, property_name,
1324 juce_messageWindowHandle, CurrentTime);
1328 while (--count >= 0)
1332 if (X11Symbols::getInstance()->xCheckTypedWindowEvent (display, juce_messageWindowHandle, SelectionNotify, &event))
1334 if (event.xselection.property == property_name)
1336 jassert (event.xselection.requestor == juce_messageWindowHandle);
1338 selectionContent = readWindowProperty (display, event.xselection.requestor, event.xselection.property);
1356 static void handleSelection (XSelectionRequestEvent& evt)
1359 XSelectionEvent reply;
1360 reply.type = SelectionNotify;
1361 reply.display = evt.display;
1362 reply.requestor = evt.requestor;
1363 reply.selection = evt.selection;
1364 reply.target = evt.target;
1365 reply.property = None;
1366 reply.time = evt.time;
1368 HeapBlock<char>
data;
1369 int propertyFormat = 0;
1370 size_t numDataItems = 0;
1372 const auto& atoms = XWindowSystem::getInstance()->getAtoms();
1374 if (evt.selection == XA_PRIMARY || evt.selection == atoms.clipboard)
1376 if (evt.target == XA_STRING || evt.target == atoms.utf8String)
1378 auto localContent = XWindowSystem::getInstance()->getLocalClipboardContent();
1381 numDataItems = localContent.getNumBytesAsUTF8();
1382 auto numBytesRequiredToStore = numDataItems + 1;
1383 data.calloc (numBytesRequiredToStore);
1384 localContent.copyToUTF8 (data, numBytesRequiredToStore);
1387 else if (evt.target == atoms.targets)
1392 data.calloc (numDataItems *
sizeof (Atom));
1395 propertyFormat = 32;
1397 auto* dataAtoms = unalignedPointerCast<Atom*> (
data.getData());
1399 dataAtoms[0] = atoms.utf8String;
1400 dataAtoms[1] = XA_STRING;
1402 evt.target = XA_ATOM;
1407 DBG (
"requested unsupported clipboard");
1410 if (data !=
nullptr)
1412 const size_t maxReasonableSelectionSize = 1000000;
1415 if (evt.property != None && numDataItems < maxReasonableSelectionSize)
1417 X11Symbols::getInstance()->xChangeProperty (evt.display, evt.requestor,
1418 evt.property, evt.target,
1419 propertyFormat, PropModeReplace,
1420 reinterpret_cast<const unsigned char*
> (
data.getData()), (
int) numDataItems);
1421 reply.property = evt.property;
1425 X11Symbols::getInstance()->xSendEvent (evt.display, evt.requestor, 0, NoEventMask, (XEvent*) &reply);
1430ComponentPeer* getPeerFor (::Window windowH)
1435 if (
auto* display = XWindowSystem::getInstance()->getDisplay())
1437 XWindowSystemUtilities::ScopedXLock xLock;
1439 if (XPointer peer =
nullptr;
1440 X11Symbols::getInstance()->xFindContext (display,
1441 static_cast<XID
> (windowH),
1442 windowHandleXContext,
1445 return unalignedPointerCast<ComponentPeer*> (peer);
1455XWindowSystem::XWindowSystem()
1457 xIsAvailable = X11Symbols::getInstance()->loadAllSymbols();
1462 if (JUCEApplicationBase::isStandaloneApp())
1465 static bool initThreadCalled =
false;
1467 if (! initThreadCalled)
1469 if (! X11Symbols::getInstance()->xInitThreads())
1472 Logger::outputDebugString (
"Failed to initialise xlib thread support.");
1473 Process::terminate();
1478 initThreadCalled =
true;
1481 X11ErrorHandling::installXErrorHandlers();
1484 if (! initialiseXDisplay())
1486 if (JUCEApplicationBase::isStandaloneApp())
1487 X11ErrorHandling::removeXErrorHandlers();
1489 X11Symbols::deleteInstance();
1490 xIsAvailable =
false;
1494XWindowSystem::~XWindowSystem()
1500 if (JUCEApplicationBase::isStandaloneApp())
1501 X11ErrorHandling::removeXErrorHandlers();
1504 X11Symbols::deleteInstance();
1505 clearSingletonInstance();
1509static int getAllEventsMask (
bool ignoresMouseClicks)
1511 return NoEventMask | KeyPressMask | KeyReleaseMask
1512 | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask
1513 | ExposureMask | StructureNotifyMask | FocusChangeMask | PropertyChangeMask
1514 | (ignoresMouseClicks ? 0 : (ButtonPressMask | ButtonReleaseMask));
1517::Window XWindowSystem::createWindow (::Window parentToAddTo, LinuxComponentPeer* peer)
const
1526 auto styleFlags = peer->getStyleFlags();
1528 XWindowSystemUtilities::ScopedXLock xLock;
1530 auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
1532 auto visualAndDepth = displayVisuals->getBestVisualForWindow ((styleFlags & ComponentPeer::windowIsSemiTransparent) != 0);
1534 auto colormap = X11Symbols::getInstance()->xCreateColormap (display, root, visualAndDepth.visual, AllocNone);
1535 X11Symbols::getInstance()->xInstallColormap (display, colormap);
1538 XSetWindowAttributes swa;
1539 swa.border_pixel = 0;
1540 swa.background_pixmap = None;
1541 swa.colormap = colormap;
1542 swa.override_redirect = ((styleFlags & ComponentPeer::windowIsTemporary) != 0) ? True : False;
1543 swa.event_mask = getAllEventsMask (styleFlags & ComponentPeer::windowIgnoresMouseClicks);
1545 auto windowH = X11Symbols::getInstance()->xCreateWindow (display, parentToAddTo != 0 ? parentToAddTo : root,
1547 0, visualAndDepth.depth, InputOutput, visualAndDepth.visual,
1548 CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask | CWOverrideRedirect,
1552 if (! peer->setWindowAssociation (windowH))
1557 Logger::outputDebugString (
"Failed to create context information for window.\n");
1558 X11Symbols::getInstance()->xDestroyWindow (display, windowH);
1564 if (
auto wmHints = makeXFreePtr (X11Symbols::getInstance()->xAllocWMHints()))
1566 wmHints->flags = InputHint | StateHint;
1567 wmHints->input = True;
1568 wmHints->initial_state = NormalState;
1569 X11Symbols::getInstance()->xSetWMHints (display, windowH, wmHints.get());
1573 if (
auto* app = JUCEApplicationBase::getInstance())
1575 if (
auto classHint = makeXFreePtr (X11Symbols::getInstance()->xAllocClassHint()))
1577 auto appName = app->getApplicationName();
1578 classHint->res_name = (
char*) appName.getCharPointer().getAddress();
1579 classHint->res_class = (
char*) appName.getCharPointer().getAddress();
1581 X11Symbols::getInstance()->xSetClassHint (display, windowH, classHint.get());
1586 setWindowType (windowH, styleFlags);
1589 if ((styleFlags & ComponentPeer::windowHasTitleBar) == 0)
1590 removeWindowDecorations (windowH);
1592 addWindowButtons (windowH, styleFlags);
1596 xchangeProperty (windowH, atoms.pid, XA_CARDINAL, 32, &pid, 1);
1599 xchangeProperty (windowH, atoms.protocols, XA_ATOM, 32, atoms.protocolList, 2);
1602 xchangeProperty (windowH, atoms.XdndTypeList, XA_ATOM, 32, atoms.allowedMimeTypes,
numElementsInArray (atoms.allowedMimeTypes));
1603 xchangeProperty (windowH, atoms.XdndActionList, XA_ATOM, 32, atoms.allowedActions,
numElementsInArray (atoms.allowedActions));
1604 xchangeProperty (windowH, atoms.XdndActionDescription, XA_STRING, 8,
"", 0);
1606 auto dndVersion = XWindowSystemUtilities::Atoms::DndVersion;
1607 xchangeProperty (windowH, atoms.XdndAware, XA_ATOM, 32, &dndVersion, 1);
1609 unsigned long info[2] = { 0, 1 };
1610 xchangeProperty (windowH, atoms.XembedInfo, atoms.XembedInfo, 32, (
unsigned char*) info, 2);
1615void XWindowSystem::destroyWindow (::Window windowH)
1617 auto* peer =
dynamic_cast<LinuxComponentPeer*
> (getPeerFor (windowH));
1619 if (peer ==
nullptr)
1625 #if JUCE_X11_SUPPORTS_XEMBED
1626 juce_handleXEmbedEvent (peer,
nullptr);
1629 deleteIconPixmaps (windowH);
1630 dragAndDropStateMap.erase (peer);
1632 XWindowSystemUtilities::ScopedXLock xLock;
1634 peer->clearWindowAssociation();
1636 X11Symbols::getInstance()->xDestroyWindow (display, windowH);
1640 X11Symbols::getInstance()->xSync (display,
false);
1643 while (X11Symbols::getInstance()->xCheckWindowEvent (display, windowH,
1644 getAllEventsMask (peer->getStyleFlags() & ComponentPeer::windowIgnoresMouseClicks),
1649 if (XSHMHelpers::isShmAvailable (display))
1650 shmPaintsPendingMap.erase (windowH);
1655void XWindowSystem::setTitle (::Window windowH,
const String& title)
const
1659 XTextProperty nameProperty{};
1660 char* strings[] = {
const_cast<char*
> (title.toRawUTF8()) };
1662 XWindowSystemUtilities::ScopedXLock xLock;
1664 if (X11Symbols::getInstance()->xutf8TextListToTextProperty (display,
1666 numElementsInArray (strings),
1668 &nameProperty) >= 0)
1670 X11Symbols::getInstance()->xSetWMName (display, windowH, &nameProperty);
1671 X11Symbols::getInstance()->xSetWMIconName (display, windowH, &nameProperty);
1673 X11Symbols::getInstance()->xFree (nameProperty.value);
1678void XWindowSystem::setIcon (::Window windowH,
const Image& newIcon)
const
1682 auto dataSize = newIcon.getWidth() * newIcon.getHeight() + 2;
1683 HeapBlock<unsigned long>
data (dataSize);
1686 data[index++] = (
unsigned long) newIcon.getWidth();
1687 data[index++] = (
unsigned long) newIcon.getHeight();
1689 for (
int y = 0; y < newIcon.getHeight(); ++y)
1690 for (
int x = 0; x < newIcon.getWidth(); ++x)
1691 data[index++] = (
unsigned long) newIcon.getPixelAt (x, y).getARGB();
1693 XWindowSystemUtilities::ScopedXLock xLock;
1694 xchangeProperty (windowH, XWindowSystemUtilities::Atoms::getCreating (display,
"_NET_WM_ICON"),
1695 XA_CARDINAL, 32,
data.getData(), dataSize);
1697 deleteIconPixmaps (windowH);
1699 auto wmHints = makeXFreePtr (X11Symbols::getInstance()->xGetWMHints (display, windowH));
1701 if (wmHints ==
nullptr)
1702 wmHints = makeXFreePtr (X11Symbols::getInstance()->xAllocWMHints());
1704 if (wmHints !=
nullptr)
1706 wmHints->flags |= IconPixmapHint | IconMaskHint;
1707 wmHints->icon_pixmap = PixmapHelpers::createColourPixmapFromImage (display, newIcon);
1708 wmHints->icon_mask = PixmapHelpers::createMaskPixmapFromImage (display, newIcon);
1710 X11Symbols::getInstance()->xSetWMHints (display, windowH, wmHints.get());
1713 X11Symbols::getInstance()->xSync (display, False);
1716void XWindowSystem::setVisible (::Window windowH,
bool shouldBeVisible)
const
1720 XWindowSystemUtilities::ScopedXLock xLock;
1722 if (shouldBeVisible)
1723 X11Symbols::getInstance()->xMapWindow (display, windowH);
1725 X11Symbols::getInstance()->xUnmapWindow (display, windowH);
1728void XWindowSystem::setBounds (::Window windowH, Rectangle<int> newBounds,
bool isFullScreen)
const
1732 if (
auto* peer = getPeerFor (windowH))
1734 if (peer->isFullScreen() && ! isFullScreen)
1738 Atom fs = XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WM_STATE_FULLSCREEN");
1742 auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
1744 XClientMessageEvent clientMsg;
1745 clientMsg.display = display;
1746 clientMsg.window = windowH;
1747 clientMsg.type = ClientMessage;
1748 clientMsg.format = 32;
1749 clientMsg.message_type = atoms.windowState;
1750 clientMsg.data.l[0] = 0;
1751 clientMsg.data.l[1] = (
long) fs;
1752 clientMsg.data.l[2] = 0;
1753 clientMsg.data.l[3] = 1;
1755 XWindowSystemUtilities::ScopedXLock xLock;
1756 X11Symbols::getInstance()->xSendEvent (display, root,
false,
1757 SubstructureRedirectMask | SubstructureNotifyMask,
1758 (XEvent*) &clientMsg);
1762 updateConstraints (windowH, *peer);
1764 XWindowSystemUtilities::ScopedXLock xLock;
1766 if (
auto hints = makeXFreePtr (X11Symbols::getInstance()->xAllocSizeHints()))
1768 hints->flags = USSize | USPosition;
1769 hints->x = newBounds.getX();
1770 hints->y = newBounds.getY();
1771 hints->width = newBounds.getWidth();
1772 hints->height = newBounds.getHeight();
1773 X11Symbols::getInstance()->xSetWMNormalHints (display, windowH, hints.get());
1776 const auto nativeWindowBorder = [&]() -> BorderSize<int>
1778 if (
const auto& frameSize = peer->getFrameSizeIfPresent())
1779 return frameSize->multipliedBy (peer->getPlatformScaleFactor());
1784 X11Symbols::getInstance()->xMoveResizeWindow (display, windowH,
1785 newBounds.getX() - nativeWindowBorder.getLeft(),
1786 newBounds.getY() - nativeWindowBorder.getTop(),
1787 (
unsigned int) newBounds.getWidth(),
1788 (
unsigned int) newBounds.getHeight());
1792void XWindowSystem::startHostManagedResize (::Window windowH,
1793 ResizableBorderComponent::Zone zone)
1795 const auto moveResize = XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WM_MOVERESIZE");
1797 if (moveResize == None)
1800 XWindowSystemUtilities::ScopedXLock xLock;
1802 X11Symbols::getInstance()->xUngrabPointer (display, CurrentTime);
1804 const auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
1805 const auto mouseDown = getCurrentMousePosition();
1807 XClientMessageEvent clientMsg;
1808 clientMsg.display = display;
1809 clientMsg.window = windowH;
1810 clientMsg.type = ClientMessage;
1811 clientMsg.format = 32;
1812 clientMsg.message_type = moveResize;
1813 clientMsg.data.l[0] = (
long) mouseDown.x;
1814 clientMsg.data.l[1] = (
long) mouseDown.y;
1815 clientMsg.data.l[2] = [&]
1818 static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
1819 static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOP = 1;
1820 static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
1821 static constexpr auto _NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
1822 static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
1823 static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
1824 static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
1825 static constexpr auto _NET_WM_MOVERESIZE_SIZE_LEFT = 7;
1826 static constexpr auto _NET_WM_MOVERESIZE_MOVE = 8;
1828 using F = ResizableBorderComponent::Zone::Zones;
1830 switch (zone.getZoneFlags())
1832 case F::top | F::left:
return _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
1833 case F::top:
return _NET_WM_MOVERESIZE_SIZE_TOP;
1834 case F::top | F::right:
return _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
1835 case F::right:
return _NET_WM_MOVERESIZE_SIZE_RIGHT;
1836 case F::bottom | F::right:
return _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
1837 case F::bottom:
return _NET_WM_MOVERESIZE_SIZE_BOTTOM;
1838 case F::bottom | F::left:
return _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
1839 case F::left:
return _NET_WM_MOVERESIZE_SIZE_LEFT;
1842 return _NET_WM_MOVERESIZE_MOVE;
1844 clientMsg.data.l[3] = 0;
1845 clientMsg.data.l[4] = 1;
1847 X11Symbols::getInstance()->xSendEvent (display,
1850 SubstructureRedirectMask | SubstructureNotifyMask,
1851 unalignedPointerCast<XEvent*> (&clientMsg));
1854void XWindowSystem::updateConstraints (::Window windowH)
const
1856 if (
auto* peer = getPeerFor (windowH))
1857 updateConstraints (windowH, *peer);
1860void XWindowSystem::updateConstraints (::Window windowH, ComponentPeer& peer)
const
1862 XWindowSystemUtilities::ScopedXLock xLock;
1864 if (
auto hints = makeXFreePtr (X11Symbols::getInstance()->xAllocSizeHints()))
1866 if ((peer.getStyleFlags() & ComponentPeer::windowIsResizable) == 0)
1868 hints->min_width = hints->max_width = peer.getBounds().getWidth();
1869 hints->min_height = hints->max_height = peer.getBounds().getHeight();
1870 hints->flags = PMinSize | PMaxSize;
1872 else if (
auto* c = peer.getConstrainer())
1874 const auto windowBorder = [&]() -> BorderSize<int>
1876 if (
const auto& frameSize = peer.getFrameSizeIfPresent())
1882 const auto factor = peer.getPlatformScaleFactor();
1883 const auto leftAndRight = windowBorder.getLeftAndRight();
1884 const auto topAndBottom = windowBorder.getTopAndBottom();
1885 hints->min_width =
jmax (1, (
int) (factor * c->getMinimumWidth()) - leftAndRight);
1886 hints->max_width =
jmax (1, (
int) (factor * c->getMaximumWidth()) - leftAndRight);
1887 hints->min_height =
jmax (1, (
int) (factor * c->getMinimumHeight()) - topAndBottom);
1888 hints->max_height =
jmax (1, (
int) (factor * c->getMaximumHeight()) - topAndBottom);
1889 hints->flags = PMinSize | PMaxSize;
1892 X11Symbols::getInstance()->xSetWMNormalHints (display, windowH, hints.get());
1896bool XWindowSystem::contains (::Window windowH, Point<int> localPos)
const
1898 ::Window root, child;
1900 unsigned int ww, wh, bw, bitDepth;
1902 XWindowSystemUtilities::ScopedXLock xLock;
1904 return X11Symbols::getInstance()->xGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth)
1905 && X11Symbols::getInstance()->xTranslateCoordinates (display, windowH, windowH, localPos.getX(), localPos.getY(), &wx, &wy, &child)
1909ComponentPeer::OptionalBorderSize XWindowSystem::getBorderSize (::Window windowH)
const
1913 XWindowSystemUtilities::ScopedXLock xLock;
1914 auto hints = XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_FRAME_EXTENTS");
1918 XWindowSystemUtilities::GetXProperty prop (display, windowH, hints, 0, 4,
false, XA_CARDINAL);
1920 if (prop.success && prop.actualFormat == 32)
1922 auto data = prop.data;
1925 for (
auto& size : sizes)
1927 memcpy (&size, data,
sizeof (
unsigned long));
1931 return ComponentPeer::OptionalBorderSize ({ (
int) sizes[2], (
int) sizes[0], (
int) sizes[3], (
int) sizes[1] });
1938Rectangle<int> XWindowSystem::getWindowBounds (::Window windowH, ::Window parentWindow)
1944 unsigned int ww = 0, wh = 0, bw, bitDepth;
1946 XWindowSystemUtilities::ScopedXLock xLock;
1948 if (X11Symbols::getInstance()->xGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth))
1950 int rootX = 0, rootY = 0;
1952 if (! X11Symbols::getInstance()->xTranslateCoordinates (display, windowH, root, 0, 0, &rootX, &rootY, &child))
1955 if (parentWindow == 0)
1964 parentScreenPosition = Point<int> (rootX - wx, rootY - wy);
1968 return { wx, wy, (
int) ww, (
int) wh };
1971Point<int> XWindowSystem::getPhysicalParentScreenPosition()
const
1973 return parentScreenPosition;
1976void XWindowSystem::setMinimised (::Window windowH,
bool shouldBeMinimised)
const
1980 if (shouldBeMinimised)
1982 auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
1984 XClientMessageEvent clientMsg;
1985 clientMsg.display = display;
1986 clientMsg.window = windowH;
1987 clientMsg.type = ClientMessage;
1988 clientMsg.format = 32;
1989 clientMsg.message_type = atoms.changeState;
1990 clientMsg.data.l[0] = IconicState;
1992 XWindowSystemUtilities::ScopedXLock xLock;
1993 X11Symbols::getInstance()->xSendEvent (display, root,
false, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &clientMsg);
1997bool XWindowSystem::isMinimised (::Window w)
const
1999 return isHidden (w);
2002void XWindowSystem::setMaximised (::Window windowH,
bool shouldBeMaximised)
const
2004 const auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
2007 ev.xclient.window = windowH;
2008 ev.xclient.type = ClientMessage;
2009 ev.xclient.format = 32;
2010 ev.xclient.message_type = XWindowSystemUtilities::Atoms::getCreating (display,
"_NET_WM_STATE");
2011 ev.xclient.data.l[0] = shouldBeMaximised;
2012 ev.xclient.data.l[1] = (
long) XWindowSystemUtilities::Atoms::getCreating (display,
"_NET_WM_STATE_MAXIMIZED_HORZ");
2013 ev.xclient.data.l[2] = (
long) XWindowSystemUtilities::Atoms::getCreating (display,
"_NET_WM_STATE_MAXIMIZED_VERT");
2014 ev.xclient.data.l[3] = 1;
2015 ev.xclient.data.l[4] = 0;
2017 XWindowSystemUtilities::ScopedXLock xLock;
2018 X11Symbols::getInstance()->xSendEvent (display, root,
false, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
2021void XWindowSystem::toFront (::Window windowH,
bool)
const
2025 XWindowSystemUtilities::ScopedXLock xLock;
2027 ev.xclient.type = ClientMessage;
2028 ev.xclient.serial = 0;
2029 ev.xclient.send_event = True;
2030 ev.xclient.message_type = atoms.activeWin;
2031 ev.xclient.window = windowH;
2032 ev.xclient.format = 32;
2033 ev.xclient.data.l[0] = 2;
2034 ev.xclient.data.l[1] = getUserTime (windowH);
2035 ev.xclient.data.l[2] = 0;
2036 ev.xclient.data.l[3] = 0;
2037 ev.xclient.data.l[4] = 0;
2039 X11Symbols::getInstance()->xSendEvent (display, X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display)),
2040 False, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
2042 X11Symbols::getInstance()->xSync (display, False);
2045void XWindowSystem::toBehind (::Window windowH, ::Window otherWindow)
const
2047 jassert (windowH != 0 && otherWindow != 0);
2049 const auto topLevelA = findTopLevelWindowOf (windowH);
2050 const auto topLevelB = findTopLevelWindowOf (otherWindow);
2052 Window newStack[] = { topLevelA, topLevelB };
2054 XWindowSystemUtilities::ScopedXLock xLock;
2055 X11Symbols::getInstance()->xRestackWindows (display, newStack, numElementsInArray (newStack));
2058bool XWindowSystem::isFocused (::Window windowH)
const
2063 Window focusedWindow = 0;
2064 XWindowSystemUtilities::ScopedXLock xLock;
2065 X11Symbols::getInstance()->xGetInputFocus (display, &focusedWindow, &revert);
2067 if (focusedWindow == PointerRoot)
2070 return isParentWindowOf (windowH, focusedWindow);
2073::Window XWindowSystem::getFocusWindow (::Window windowH)
const
2077 #if JUCE_X11_SUPPORTS_XEMBED
2078 if (
auto w = (::Window) juce_getCurrentFocusWindow (
dynamic_cast<LinuxComponentPeer*
> (getPeerFor (windowH))))
2085bool XWindowSystem::grabFocus (::Window windowH)
const
2089 XWindowAttributes atts;
2090 XWindowSystemUtilities::ScopedXLock xLock;
2093 && X11Symbols::getInstance()->xGetWindowAttributes (display, windowH, &atts)
2094 && atts.map_state == IsViewable
2095 && ! isFocused (windowH))
2097 X11Symbols::getInstance()->xSetInputFocus (display, getFocusWindow (windowH), RevertToParent, (::Time) getUserTime (windowH));
2104bool XWindowSystem::canUseSemiTransparentWindows()
const
2106 #if JUCE_USE_XRENDER
2107 if (XRender::hasCompositingWindowManager (display))
2109 int matchedDepth = 0, desiredDepth = 32;
2111 return Visuals::findVisualFormat (display, desiredDepth, matchedDepth) !=
nullptr
2112 && matchedDepth == desiredDepth;
2119bool XWindowSystem::canUseARGBImages()
const
2121 static bool canUseARGB =
false;
2124 static bool checked =
false;
2128 if (XSHMHelpers::isShmAvailable (display))
2130 XWindowSystemUtilities::ScopedXLock xLock;
2131 XShmSegmentInfo segmentinfo;
2133 auto testImage = X11Symbols::getInstance()->xShmCreateImage (display,
2134 X11Symbols::getInstance()->xDefaultVisual (display, X11Symbols::getInstance()->xDefaultScreen (display)),
2135 24, ZPixmap,
nullptr, &segmentinfo, 64, 64);
2137 canUseARGB = testImage !=
nullptr && testImage->bits_per_pixel == 32;
2138 X11Symbols::getInstance()->xDestroyImage (testImage);
2152bool XWindowSystem::isDarkModeActive()
const
2154 const auto themeName = [
this]() -> String
2156 if (xSettings !=
nullptr)
2158 const auto themeNameSetting = xSettings->getSetting (getThemeNameSettingName());
2160 if (themeNameSetting.isValid()
2161 && themeNameSetting.stringValue.isNotEmpty())
2163 return themeNameSetting.stringValue;
2167 ChildProcess gsettings;
2169 if (File (
"/usr/bin/gsettings").existsAsFile()
2170 && gsettings.start (
"/usr/bin/gsettings get org.gnome.desktop.interface gtk-theme", ChildProcess::wantStdOut))
2172 if (gsettings.waitForProcessToFinish (200))
2173 return gsettings.readAllProcessOutput();
2179 return (themeName.isNotEmpty()
2180 && (themeName.containsIgnoreCase (
"dark") || themeName.containsIgnoreCase (
"black")));
2183Image XWindowSystem::createImage (
bool isSemiTransparent,
int width,
int height,
bool argb)
const
2185 auto visualAndDepth = displayVisuals->getBestVisualForWindow (isSemiTransparent);
2188 return Image (
new XBitmapImage (argb ? Image::ARGB : Image::RGB,
2190 return Image (new XBitmapImage (Image::RGB,
2193 (height + 31) & ~31,
2194 false, (unsigned
int) visualAndDepth.depth, visualAndDepth.visual));
2197void XWindowSystem::blitToWindow (::Window windowH, Image image, Rectangle<int> destinationRect, Rectangle<int> totalRect)
const
2201 auto* xbitmap =
static_cast<XBitmapImage*
> (image.getPixelData());
2203 xbitmap->blitToWindow (windowH,
2204 destinationRect.getX(), destinationRect.getY(),
2205 (
unsigned int) destinationRect.getWidth(),
2206 (
unsigned int) destinationRect.getHeight(),
2207 destinationRect.getX() - totalRect.getX(), destinationRect.getY() - totalRect.getY());
2210void XWindowSystem::processPendingPaintsForWindow (::Window windowH)
2213 if (! XSHMHelpers::isShmAvailable (display))
2216 if (getNumPaintsPendingForWindow (windowH) > 0)
2218 XWindowSystemUtilities::ScopedXLock xLock;
2221 while (X11Symbols::getInstance()->xCheckTypedWindowEvent (display, windowH, shmCompletionEvent, &evt))
2222 removePendingPaintForWindow (windowH);
2227int XWindowSystem::getNumPaintsPendingForWindow (::Window windowH)
2230 if (XSHMHelpers::isShmAvailable (display))
2231 return shmPaintsPendingMap[windowH];
2237void XWindowSystem::addPendingPaintForWindow (::Window windowH)
2240 if (XSHMHelpers::isShmAvailable (display))
2241 ++shmPaintsPendingMap[windowH];
2245void XWindowSystem::removePendingPaintForWindow (::Window windowH)
2248 if (XSHMHelpers::isShmAvailable (display))
2249 --shmPaintsPendingMap[windowH];
2253void XWindowSystem::setScreenSaverEnabled (
bool enabled)
const
2255 using tXScreenSaverSuspend = void (*) (Display*, Bool);
2256 static tXScreenSaverSuspend xScreenSaverSuspend =
nullptr;
2258 if (xScreenSaverSuspend ==
nullptr)
2259 if (
void* h = dlopen (
"libXss.so.1", RTLD_GLOBAL | RTLD_NOW))
2260 xScreenSaverSuspend = (tXScreenSaverSuspend)
dlsym (h,
"XScreenSaverSuspend");
2262 XWindowSystemUtilities::ScopedXLock xLock;
2264 NullCheckedInvocation::invoke (xScreenSaverSuspend, display, ! enabled);
2267Point<float> XWindowSystem::getCurrentMousePosition()
const
2270 int x, y, winx, winy;
2273 XWindowSystemUtilities::ScopedXLock xLock;
2275 if (X11Symbols::getInstance()->xQueryPointer (display,
2276 X11Symbols::getInstance()->xRootWindow (display,
2277 X11Symbols::getInstance()->xDefaultScreen (display)),
2279 &x, &y, &winx, &winy, &mask) == False)
2284 return { (
float) x, (
float) y };
2287void XWindowSystem::setMousePosition (Point<float> pos)
const
2289 XWindowSystemUtilities::ScopedXLock xLock;
2291 auto root = X11Symbols::getInstance()->xRootWindow (display,
2292 X11Symbols::getInstance()->xDefaultScreen (display));
2294 X11Symbols::getInstance()->xWarpPointer (display, None, root, 0, 0, 0, 0,
2295 roundToInt (pos.getX()),
roundToInt (pos.getY()));
2298Cursor XWindowSystem::createCustomMouseCursorInfo (
const Image& image, Point<int> hotspot)
const
2300 if (display ==
nullptr)
2303 XWindowSystemUtilities::ScopedXLock xLock;
2305 auto imageW = (
unsigned int) image.getWidth();
2306 auto imageH = (
unsigned int) image.getHeight();
2307 auto hotspotX = hotspot.x;
2308 auto hotspotY = hotspot.y;
2310 #if JUCE_USE_XCURSOR
2311 if (
auto xcImage = makeDeletedPtr (X11Symbols::getInstance()->xcursorImageCreate ((
int) imageW, (
int) imageH),
2312 [] (XcursorImage* i) { X11Symbols::getInstance()->xcursorImageDestroy (i); }))
2314 xcImage->xhot = (XcursorDim) hotspotX;
2315 xcImage->yhot = (XcursorDim) hotspotY;
2316 auto* dest = xcImage->pixels;
2318 for (
int y = 0; y < (
int) imageH; ++y)
2319 for (
int x = 0; x < (
int) imageW; ++x)
2320 *dest++ = image.getPixelAt (x, y).getARGB();
2322 auto result = X11Symbols::getInstance()->xcursorImageLoadCursor (display, xcImage.get());
2324 if (result != Cursor{})
2329 auto root = X11Symbols::getInstance()->xRootWindow (display,
2330 X11Symbols::getInstance()->xDefaultScreen (display));
2332 unsigned int cursorW, cursorH;
2333 if (! X11Symbols::getInstance()->xQueryBestCursor (display, root, imageW, imageH, &cursorW, &cursorH))
2336 Image im (Image::ARGB, (
int) cursorW, (
int) cursorH,
true);
2341 if (imageW > cursorW || imageH > cursorH)
2343 hotspotX = (hotspotX * (
int) cursorW) / (
int) imageW;
2344 hotspotY = (hotspotY * (
int) cursorH) / (
int) imageH;
2346 g.drawImage (image, Rectangle<float> ((
float) imageW, (
float) imageH),
2347 RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize);
2351 g.drawImageAt (image, 0, 0);
2355 auto stride = (cursorW + 7) >> 3;
2356 HeapBlock<char> maskPlane, sourcePlane;
2357 maskPlane.calloc (stride * cursorH);
2358 sourcePlane.calloc (stride * cursorH);
2360 auto msbfirst = (X11Symbols::getInstance()->xBitmapBitOrder (display) == MSBFirst);
2362 for (
auto y = (
int) cursorH; --y >= 0;)
2364 for (
auto x = (
int) cursorW; --x >= 0;)
2366 auto mask = (
char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7)));
2367 auto offset = (
unsigned int) y * stride + ((
unsigned int) x >> 3);
2369 auto c = im.getPixelAt (x, y);
2371 if (c.getAlpha() >= 128) maskPlane[offset] |= mask;
2372 if (c.getBrightness() >= 0.5f) sourcePlane[offset] |= mask;
2376 auto xFreePixmap = [
this] (Pixmap& p) { X11Symbols::getInstance()->xFreePixmap (display, p); };
2377 XValueHolder<Pixmap> sourcePixmap (X11Symbols::getInstance()->xCreatePixmapFromBitmapData (display, root, sourcePlane.getData(), cursorW, cursorH, 0xffff, 0, 1), xFreePixmap);
2378 XValueHolder<Pixmap> maskPixmap (X11Symbols::getInstance()->xCreatePixmapFromBitmapData (display, root, maskPlane.getData(), cursorW, cursorH, 0xffff, 0, 1), xFreePixmap);
2380 XColor white, black;
2381 black.red = black.green = black.blue = 0;
2382 white.red = white.green = white.blue = 0xffff;
2384 return X11Symbols::getInstance()->xCreatePixmapCursor (display, sourcePixmap.value, maskPixmap.value, &white, &black,
2385 (
unsigned int) hotspotX, (
unsigned int) hotspotY);
2388void XWindowSystem::deleteMouseCursor (Cursor cursorHandle)
const
2390 if (cursorHandle != Cursor{} && display !=
nullptr)
2392 XWindowSystemUtilities::ScopedXLock xLock;
2393 X11Symbols::getInstance()->xFreeCursor (display, (Cursor) cursorHandle);
2397static Cursor createDraggingHandCursor()
2399 constexpr unsigned char dragHandData[] = {
2400 71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0,16,0,
2401 0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,132,117,151,116,132,146,248,60,209,138,98,22,203,
2402 114,34,236,37,52,77,217, 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59
2405 auto image = ImageFileFormat::loadFrom (dragHandData, (
size_t) numElementsInArray (dragHandData));
2406 return XWindowSystem::getInstance()->createCustomMouseCursorInfo (std::move (image), { 8, 7 });
2409Cursor XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType type)
const
2411 if (display ==
nullptr)
2418 case MouseCursor::NormalCursor:
2419 case MouseCursor::ParentCursor:
return None;
2420 case MouseCursor::NoCursor:
return XWindowSystem::createCustomMouseCursorInfo (Image (Image::ARGB, 16, 16,
true), {});
2422 case MouseCursor::WaitCursor: shape = XC_watch;
break;
2423 case MouseCursor::IBeamCursor: shape = XC_xterm;
break;
2424 case MouseCursor::PointingHandCursor: shape = XC_hand2;
break;
2425 case MouseCursor::LeftRightResizeCursor: shape = XC_sb_h_double_arrow;
break;
2426 case MouseCursor::UpDownResizeCursor: shape = XC_sb_v_double_arrow;
break;
2427 case MouseCursor::UpDownLeftRightResizeCursor: shape = XC_fleur;
break;
2428 case MouseCursor::TopEdgeResizeCursor: shape = XC_top_side;
break;
2429 case MouseCursor::BottomEdgeResizeCursor: shape = XC_bottom_side;
break;
2430 case MouseCursor::LeftEdgeResizeCursor: shape = XC_left_side;
break;
2431 case MouseCursor::RightEdgeResizeCursor: shape = XC_right_side;
break;
2432 case MouseCursor::TopLeftCornerResizeCursor: shape = XC_top_left_corner;
break;
2433 case MouseCursor::TopRightCornerResizeCursor: shape = XC_top_right_corner;
break;
2434 case MouseCursor::BottomLeftCornerResizeCursor: shape = XC_bottom_left_corner;
break;
2435 case MouseCursor::BottomRightCornerResizeCursor: shape = XC_bottom_right_corner;
break;
2436 case MouseCursor::CrosshairCursor: shape = XC_crosshair;
break;
2437 case MouseCursor::DraggingHandCursor:
return createDraggingHandCursor();
2439 case MouseCursor::CopyingCursor:
2441 constexpr unsigned char copyCursorData[] = {
2442 71,73,70,56,57,97,21,0,21,0,145,0,0,0,0,0,255,255,255,0,128,128,255,255,255,33,249,4,1,0,0,3,0,44,0,0,0,0,
2443 21,0,21,0,0,2,72,4,134,169,171,16,199,98,11,79,90,71,161,93,56,111,78,133,218,215,137,31,82,154,100,200,
2444 86,91,202,142,12,108,212,87,235,174,15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,
2445 252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0
2448 auto image = ImageFileFormat::loadFrom (copyCursorData, (
size_t) numElementsInArray (copyCursorData));
2449 return createCustomMouseCursorInfo (std::move (image), { 1, 3 });
2452 case MouseCursor::NumStandardCursorTypes:
2460 XWindowSystemUtilities::ScopedXLock xLock;
2462 return X11Symbols::getInstance()->xCreateFontCursor (display, shape);
2465void XWindowSystem::showCursor (::Window windowH, Cursor cursorHandle)
const
2469 XWindowSystemUtilities::ScopedXLock xLock;
2470 X11Symbols::getInstance()->xDefineCursor (display, windowH, (Cursor) cursorHandle);
2473bool XWindowSystem::isKeyCurrentlyDown (
int keyCode)
const
2477 if (keyCode & Keys::extendedKeyModifier)
2479 keysym = 0xff00 | (keyCode & 0xff);
2485 if (keysym == (XK_Tab & 0xff)
2486 || keysym == (XK_Return & 0xff)
2487 || keysym == (XK_Escape & 0xff)
2488 || keysym == (XK_BackSpace & 0xff))
2494 XWindowSystemUtilities::ScopedXLock xLock;
2496 auto keycode = X11Symbols::getInstance()->xKeysymToKeycode (display, (KeySym) keysym);
2497 auto keybyte = keycode >> 3;
2498 auto keybit = (1 << (keycode & 7));
2500 return (Keys::keyStates [keybyte] & keybit) != 0;
2503ModifierKeys XWindowSystem::getNativeRealtimeModifiers()
const
2505 ::Window root, child;
2506 int x, y, winx, winy;
2510 XWindowSystemUtilities::ScopedXLock xLock;
2512 if (X11Symbols::getInstance()->xQueryPointer (display,
2513 X11Symbols::getInstance()->xRootWindow (display,
2514 X11Symbols::getInstance()->xDefaultScreen (display)),
2515 &root, &child, &x, &y, &winx, &winy, &mask) != False)
2517 if ((mask & Button1Mask) != 0) mouseMods |= ModifierKeys::leftButtonModifier;
2518 if ((mask & Button2Mask) != 0) mouseMods |= ModifierKeys::middleButtonModifier;
2519 if ((mask & Button3Mask) != 0) mouseMods |= ModifierKeys::rightButtonModifier;
2522 ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (mouseMods);
2534 Keys::modifierKeysAreStale =
true;
2536 return ModifierKeys::currentModifiers;
2539static bool hasWorkAreaData (
const XWindowSystemUtilities::GetXProperty& prop)
2542 && prop.actualType == XA_CARDINAL
2543 && prop.actualFormat == 32
2544 && prop.numItems == 4
2545 && prop.data !=
nullptr;
2548static Rectangle<int> getWorkArea (
const XWindowSystemUtilities::GetXProperty& prop)
2550 if (hasWorkAreaData (prop))
2552 auto* positionData = prop.data;
2555 for (
auto& p : position)
2557 memcpy (&p, positionData,
sizeof (
long));
2558 positionData +=
sizeof (
long);
2561 return { (
int) position[0], (
int) position[1],
2562 (
int) position[2], (
int) position[3] };
2568Array<Displays::Display> XWindowSystem::findDisplays (
float masterScale)
const
2570 Array<Displays::Display> displays;
2571 auto workAreaHints = XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WORKAREA");
2574 if (workAreaHints != None)
2576 int major_opcode, first_event, first_error;
2578 if (X11Symbols::getInstance()->xQueryExtension (display,
"RANDR", &major_opcode, &first_event, &first_error))
2580 auto numMonitors = X11Symbols::getInstance()->xScreenCount (display);
2581 auto mainDisplay = X11Symbols::getInstance()->xRRGetOutputPrimary (display, X11Symbols::getInstance()->xRootWindow (display, 0));
2583 for (
int i = 0; i < numMonitors; ++i)
2585 auto rootWindow = X11Symbols::getInstance()->xRootWindow (display, i);
2586 XWindowSystemUtilities::GetXProperty prop (display, rootWindow, workAreaHints, 0, 4,
false, XA_CARDINAL);
2588 if (! hasWorkAreaData (prop))
2591 if (
auto screens = makeDeletedPtr (X11Symbols::getInstance()->xRRGetScreenResources (display, rootWindow),
2592 [] (XRRScreenResources* srs) { X11Symbols::getInstance()->xRRFreeScreenResources (srs); }))
2594 for (
int j = 0; j < screens->noutput; ++j)
2596 if (screens->outputs[j])
2601 mainDisplay = screens->outputs[j];
2603 if (
auto output = makeDeletedPtr (X11Symbols::getInstance()->xRRGetOutputInfo (display, screens.get(), screens->outputs[j]),
2604 [] (XRROutputInfo* oi) { X11Symbols::getInstance()->xRRFreeOutputInfo (oi); }))
2608 if (
auto crtc = makeDeletedPtr (X11Symbols::getInstance()->xRRGetCrtcInfo (display, screens.get(), output->crtc),
2609 [] (XRRCrtcInfo* ci) { X11Symbols::getInstance()->xRRFreeCrtcInfo (ci); }))
2611 Displays::Display d;
2612 d.totalArea = { crtc->x, crtc->y, (
int) crtc->width, (
int) crtc->height };
2613 d.isMain = (mainDisplay == screens->outputs[j]) && (i == 0);
2614 d.dpi = DisplayHelpers::getDisplayDPI (display, 0);
2618 if (crtc->mode != None)
2621 screens->modes + screens->nmode,
2622 [&crtc] (
const auto& m) { return m.id == crtc->mode; });
2623 it != screens->modes + screens->nmode)
2625 return (
double) it->dotClock / ((
double) it->hTotal * (
double) it->vTotal);
2633 if (output->mm_width > 0 && output->mm_height > 0)
2634 d.dpi = ((
static_cast<double> (crtc->width) * 25.4 * 0.5) /
static_cast<double> (output->mm_width))
2635 + ((
static_cast<double> (crtc->height) * 25.4 * 0.5) /
static_cast<double> (output->mm_height));
2637 auto scale = DisplayHelpers::getDisplayScale (output->name, d.dpi);
2638 scale = (scale <= 0.1 || ! JUCEApplicationBase::isStandaloneApp()) ? 1.0 : scale;
2640 d.scale = masterScale * scale;
2643 displays.insert (0, d);
2654 if (! displays.isEmpty() && ! displays.getReference (0).isMain)
2655 displays.getReference (0).isMain =
true;
2659 if (displays.isEmpty())
2661 #if JUCE_USE_XINERAMA
2663 auto screens = DisplayHelpers::xineramaQueryDisplays (display);
2664 auto numMonitors = screens.size();
2666 for (
int index = 0; index < numMonitors; ++index)
2668 for (
auto j = numMonitors; --j >= 0;)
2670 if (screens[j].screen_number == index)
2672 Displays::Display d;
2673 d.totalArea = { screens[j].x_org, screens[j].y_org,
2674 screens[j].width, screens[j].height };
2675 d.isMain = (index == 0);
2676 d.scale = masterScale;
2677 d.dpi = DisplayHelpers::getDisplayDPI (display, 0);
2685 if (displays.isEmpty())
2688 if (workAreaHints != None)
2690 auto numMonitors = X11Symbols::getInstance()->xScreenCount (display);
2692 for (
int i = 0; i < numMonitors; ++i)
2694 XWindowSystemUtilities::GetXProperty prop (display,
2695 X11Symbols::getInstance()->xRootWindow (display, i),
2696 workAreaHints, 0, 4,
false, XA_CARDINAL);
2698 auto workArea = getWorkArea (prop);
2700 if (! workArea.isEmpty())
2702 Displays::Display d;
2704 d.totalArea = workArea;
2705 d.isMain = displays.isEmpty();
2706 d.scale = masterScale;
2707 d.dpi = DisplayHelpers::getDisplayDPI (display, i);
2714 if (displays.isEmpty())
2716 Displays::Display d;
2717 d.totalArea = { X11Symbols::getInstance()->xDisplayWidth (display, X11Symbols::getInstance()->xDefaultScreen (display)),
2718 X11Symbols::getInstance()->xDisplayHeight (display, X11Symbols::getInstance()->xDefaultScreen (display)) };
2720 d.scale = masterScale;
2721 d.dpi = DisplayHelpers::getDisplayDPI (display, 0);
2727 for (
auto& d : displays)
2728 d.userArea = d.totalArea;
2733::Window XWindowSystem::createKeyProxy (::Window windowH)
2737 XSetWindowAttributes swa;
2738 swa.event_mask = KeyPressMask | KeyReleaseMask | FocusChangeMask;
2740 auto keyProxy = X11Symbols::getInstance()->xCreateWindow (display, windowH,
2742 InputOnly, CopyFromParent,
2746 X11Symbols::getInstance()->xMapWindow (display, keyProxy);
2751void XWindowSystem::deleteKeyProxy (::Window keyProxy)
const
2755 X11Symbols::getInstance()->xDestroyWindow (display, keyProxy);
2756 X11Symbols::getInstance()->xSync (display,
false);
2759 while (X11Symbols::getInstance()->xCheckWindowEvent (display, keyProxy, getAllEventsMask (
false), &event) == True)
2763bool XWindowSystem::externalDragFileInit (LinuxComponentPeer* peer,
const StringArray& files,
bool,
std::function<
void()>&& callback)
const
2765 auto& dragState = dragAndDropStateMap[peer];
2767 if (dragState.isDragging())
2770 StringArray uriList;
2772 for (
auto& f : files)
2774 if (f.matchesWildcard (
"?*://*",
false))
2777 uriList.add (
"file://" + f);
2780 return dragState.externalDragInit ((::Window) peer->getNativeHandle(),
false, uriList.joinIntoString (
"\r\n"), std::move (callback));
2783bool XWindowSystem::externalDragTextInit (LinuxComponentPeer* peer,
const String& text,
std::function<
void()>&& callback)
const
2785 auto& dragState = dragAndDropStateMap[peer];
2787 if (dragState.isDragging())
2790 return dragState.externalDragInit ((::Window) peer->getNativeHandle(),
true, text, std::move (callback));
2793void XWindowSystem::copyTextToClipboard (
const String& clipText)
2795 localClipboardContent = clipText;
2797 X11Symbols::getInstance()->xSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
2798 X11Symbols::getInstance()->xSetSelectionOwner (display, atoms.clipboard, juce_messageWindowHandle, CurrentTime);
2801String XWindowSystem::getTextFromClipboard()
const
2813 auto getContentForSelection = [
this] (Atom selectionAtom) -> String
2815 auto selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selectionAtom);
2817 if (selectionOwner == None)
2820 if (selectionOwner == juce_messageWindowHandle)
2821 return localClipboardContent;
2825 if (! ClipboardHelpers::requestSelectionContent (display, content, selectionAtom, atoms.utf8String))
2826 ClipboardHelpers::requestSelectionContent (display, content, selectionAtom, XA_STRING);
2831 auto content = getContentForSelection (atoms.clipboard);
2833 if (content.isEmpty())
2834 content = getContentForSelection (XA_PRIMARY);
2840::Window XWindowSystem::findTopLevelWindowOf (::Window w)
const
2845 Window* windowList =
nullptr;
2846 uint32 windowListSize = 0;
2847 Window parent, root;
2849 XWindowSystemUtilities::ScopedXLock xLock;
2850 const auto result = X11Symbols::getInstance()->xQueryTree (display, w, &root, &parent, &windowList, &windowListSize);
2851 const auto deleter = makeXFreePtr (windowList);
2859 return findTopLevelWindowOf (parent);
2862bool XWindowSystem::isParentWindowOf (::Window windowH, ::Window possibleChild)
const
2864 if (windowH == 0 || possibleChild == 0)
2867 if (possibleChild == windowH)
2870 Window* windowList =
nullptr;
2871 uint32 windowListSize = 0;
2872 Window parent, root;
2874 XWindowSystemUtilities::ScopedXLock xLock;
2875 const auto result = X11Symbols::getInstance()->xQueryTree (display, possibleChild, &root, &parent, &windowList, &windowListSize);
2876 const auto deleter = makeXFreePtr (windowList);
2878 if (result == 0 || parent == root)
2881 return isParentWindowOf (windowH, parent);
2884bool XWindowSystem::isFrontWindow (::Window windowH)
const
2888 Window* windowList =
nullptr;
2889 uint32 windowListSize = 0;
2891 XWindowSystemUtilities::ScopedXLock xLock;
2893 auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
2895 const auto queryResult = X11Symbols::getInstance()->xQueryTree (display, root, &root, &parent, &windowList, &windowListSize);
2896 const auto deleter = makeXFreePtr (windowList);
2898 if (queryResult == 0)
2901 for (
int i = (
int) windowListSize; --i >= 0;)
2903 if (
auto* peer =
dynamic_cast<LinuxComponentPeer*
> (getPeerFor (windowList[i])))
2904 return peer ==
dynamic_cast<LinuxComponentPeer*
> (getPeerFor (windowH));
2910void XWindowSystem::xchangeProperty (::Window windowH, Atom property, Atom type,
int format,
const void* data,
int numElements)
const
2914 X11Symbols::getInstance()->xChangeProperty (display, windowH, property, type, format, PropModeReplace, (
const unsigned char*) data, numElements);
2917void XWindowSystem::removeWindowDecorations (::Window windowH)
const
2921 auto hints = XWindowSystemUtilities::Atoms::getIfExists (display,
"_MOTIF_WM_HINTS");
2925 MotifWmHints motifHints;
2928 motifHints.flags = 2;
2929 motifHints.decorations = 0;
2931 XWindowSystemUtilities::ScopedXLock xLock;
2932 xchangeProperty (windowH, hints, hints, 32, &motifHints, 4);
2935 hints = XWindowSystemUtilities::Atoms::getIfExists (display,
"_WIN_HINTS");
2939 long gnomeHints = 0;
2941 XWindowSystemUtilities::ScopedXLock xLock;
2942 xchangeProperty (windowH, hints, hints, 32, &gnomeHints, 1);
2945 hints = XWindowSystemUtilities::Atoms::getIfExists (display,
"KWM_WIN_DECORATION");
2951 XWindowSystemUtilities::ScopedXLock xLock;
2952 xchangeProperty (windowH, hints, hints, 32, &kwmHints, 1);
2955 hints = XWindowSystemUtilities::Atoms::getIfExists (display,
"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
2959 XWindowSystemUtilities::ScopedXLock xLock;
2960 xchangeProperty (windowH, atoms.windowType, XA_ATOM, 32, &hints, 1);
2964static void addAtomIfExists (
bool condition,
const char* key, ::Display* display,
std::vector<Atom>& atoms)
2968 auto atom = XWindowSystemUtilities::Atoms::getIfExists (display, key);
2975void XWindowSystem::addWindowButtons (::Window windowH,
int styleFlags)
const
2979 XWindowSystemUtilities::ScopedXLock xLock;
2980 auto motifAtom = XWindowSystemUtilities::Atoms::getIfExists (display,
"_MOTIF_WM_HINTS");
2982 if (motifAtom != None)
2984 MotifWmHints motifHints;
2987 motifHints.flags = 1 | 2;
2988 motifHints.decorations = 2 | 8 | 16;
2990 motifHints.functions = 4 ;
2992 if ((styleFlags & ComponentPeer::windowHasCloseButton) != 0)
2993 motifHints.functions |= 32;
2995 if ((styleFlags & ComponentPeer::windowHasMinimiseButton) != 0)
2997 motifHints.functions |= 8;
2998 motifHints.decorations |= 0x20;
3001 if ((styleFlags & ComponentPeer::windowHasMaximiseButton) != 0)
3003 motifHints.functions |= 0x10;
3004 motifHints.decorations |= 0x40;
3007 if ((styleFlags & ComponentPeer::windowIsResizable) != 0)
3009 motifHints.functions |= 2;
3010 motifHints.decorations |= 0x4;
3013 xchangeProperty (windowH, motifAtom, motifAtom, 32, &motifHints, 5);
3016 auto actionsAtom = XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WM_ALLOWED_ACTIONS");
3018 if (actionsAtom != None)
3022 addAtomIfExists ((styleFlags & ComponentPeer::windowIsResizable) != 0,
"_NET_WM_ACTION_RESIZE", display, netHints);
3023 addAtomIfExists ((styleFlags & ComponentPeer::windowHasMaximiseButton) != 0,
"_NET_WM_ACTION_FULLSCREEN", display, netHints);
3024 addAtomIfExists ((styleFlags & ComponentPeer::windowHasMinimiseButton) != 0,
"_NET_WM_ACTION_MINIMIZE", display, netHints);
3025 addAtomIfExists ((styleFlags & ComponentPeer::windowHasCloseButton) != 0,
"_NET_WM_ACTION_CLOSE", display, netHints);
3027 auto numHints = (
int) netHints.
size();
3030 xchangeProperty (windowH, actionsAtom, XA_ATOM, 32, netHints.
data(), numHints);
3034void XWindowSystem::setWindowType (::Window windowH,
int styleFlags)
const
3038 if (atoms.windowType != None)
3040 auto hint = (styleFlags & ComponentPeer::windowIsTemporary) != 0
3041 || ((styleFlags & ComponentPeer::windowHasDropShadow) == 0 && Desktop::canUseSemiTransparentWindows())
3042 ? XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WM_WINDOW_TYPE_COMBO")
3043 : XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_WM_WINDOW_TYPE_NORMAL");
3046 xchangeProperty (windowH, atoms.windowType, XA_ATOM, 32, &hint, 1);
3049 if (atoms.windowState != None)
3053 addAtomIfExists ((styleFlags & ComponentPeer::windowAppearsOnTaskbar) == 0,
"_NET_WM_STATE_SKIP_TASKBAR", display, netStateHints);
3054 addAtomIfExists (getPeerFor (windowH)->getComponent().isAlwaysOnTop(),
"_NET_WM_STATE_ABOVE", display, netStateHints);
3056 auto numHints = (
int) netStateHints.
size();
3059 xchangeProperty (windowH, atoms.windowState, XA_ATOM, 32, netStateHints.
data(), numHints);
3063void XWindowSystem::initialisePointerMap()
3065 auto numButtons = X11Symbols::getInstance()->xGetPointerMapping (display,
nullptr, 0);
3066 pointerMap[2] = pointerMap[3] = pointerMap[4] = Keys::NoButton;
3068 if (numButtons == 2)
3070 pointerMap[0] = Keys::LeftButton;
3071 pointerMap[1] = Keys::RightButton;
3073 else if (numButtons >= 3)
3075 pointerMap[0] = Keys::LeftButton;
3076 pointerMap[1] = Keys::MiddleButton;
3077 pointerMap[2] = Keys::RightButton;
3079 if (numButtons >= 5)
3081 pointerMap[3] = Keys::WheelUp;
3082 pointerMap[4] = Keys::WheelDown;
3087void XWindowSystem::deleteIconPixmaps (::Window windowH)
const
3091 XWindowSystemUtilities::ScopedXLock xLock;
3093 if (
auto wmHints = makeXFreePtr (X11Symbols::getInstance()->xGetWMHints (display, windowH)))
3095 if ((wmHints->flags & IconPixmapHint) != 0)
3097 wmHints->flags &= ~IconPixmapHint;
3098 X11Symbols::getInstance()->xFreePixmap (display, wmHints->icon_pixmap);
3101 if ((wmHints->flags & IconMaskHint) != 0)
3103 wmHints->flags &= ~IconMaskHint;
3104 X11Symbols::getInstance()->xFreePixmap (display, wmHints->icon_mask);
3107 X11Symbols::getInstance()->xSetWMHints (display, windowH, wmHints.get());
3112void XWindowSystem::updateModifierMappings()
const
3114 XWindowSystemUtilities::ScopedXLock xLock;
3115 auto altLeftCode = X11Symbols::getInstance()->xKeysymToKeycode (display, XK_Alt_L);
3116 auto numLockCode = X11Symbols::getInstance()->xKeysymToKeycode (display, XK_Num_Lock);
3119 Keys::NumLockMask = 0;
3121 if (
auto mapping = makeDeletedPtr (X11Symbols::getInstance()->xGetModifierMapping (display),
3122 [] (XModifierKeymap* mk) { X11Symbols::getInstance()->xFreeModifiermap (mk); }))
3124 for (
int modifierIdx = 0; modifierIdx < 8; ++modifierIdx)
3126 for (
int keyIndex = 0; keyIndex < mapping->max_keypermod; ++keyIndex)
3128 auto key = mapping->modifiermap[(modifierIdx * mapping->max_keypermod) + keyIndex];
3130 if (key == altLeftCode)
3131 Keys::AltMask = 1 << modifierIdx;
3132 else if (key == numLockCode)
3133 Keys::NumLockMask = 1 << modifierIdx;
3139long XWindowSystem::getUserTime (::Window windowH)
const
3143 XWindowSystemUtilities::GetXProperty prop (display, windowH, atoms.userTime, 0, 65536,
false, XA_CARDINAL);
3154void XWindowSystem::initialiseXSettings()
3156 xSettings = XWindowSystemUtilities::XSettings::createXSettings (display);
3158 if (xSettings !=
nullptr)
3159 X11Symbols::getInstance()->xSelectInput (display,
3160 xSettings->getSettingsWindow(),
3161 StructureNotifyMask | PropertyChangeMask);
3164XWindowSystem::DisplayVisuals::DisplayVisuals (::Display* xDisplay)
3166 auto findVisualWithDepthOrNull = [&] (
int desiredDepth) -> Visual*
3168 int matchedDepth = 0;
3169 auto* visual = Visuals::findVisualFormat (xDisplay, desiredDepth, matchedDepth);
3171 if (desiredDepth == matchedDepth)
3177 visual16Bit = findVisualWithDepthOrNull (16);
3178 visual24Bit = findVisualWithDepthOrNull (24);
3179 visual32Bit = findVisualWithDepthOrNull (32);
3182XWindowSystem::VisualAndDepth XWindowSystem::DisplayVisuals::getBestVisualForWindow (
bool isSemiTransparent)
const
3184 if (isSemiTransparent && visual32Bit !=
nullptr)
3185 return { visual32Bit, 32 };
3187 if (visual24Bit !=
nullptr)
3188 return { visual24Bit, 24 };
3190 if (visual32Bit !=
nullptr)
3191 return { visual32Bit, 32 };
3194 jassert (visual16Bit !=
nullptr);
3196 return { visual16Bit, 16 };
3199bool XWindowSystem::DisplayVisuals::isValid() const noexcept
3201 return (visual32Bit !=
nullptr || visual24Bit !=
nullptr || visual16Bit !=
nullptr);
3205bool XWindowSystem::initialiseXDisplay()
3209 String displayName (getenv (
"DISPLAY"));
3211 if (displayName.isEmpty())
3212 displayName =
":0.0";
3216 for (
int retries = 2; --retries >= 0;)
3218 display = X11Symbols::getInstance()->xOpenDisplay (displayName.toUTF8());
3220 if (display !=
nullptr)
3225 if (display ==
nullptr)
3228 #if JUCE_DEBUG_XERRORS_SYNCHRONOUSLY
3229 X11Symbols::getInstance()->xSynchronize (display, True);
3233 windowHandleXContext = (XContext) X11Symbols::getInstance()->xrmUniqueQuark();
3236 auto screen = X11Symbols::getInstance()->xDefaultScreen (display);
3237 auto root = X11Symbols::getInstance()->xRootWindow (display, screen);
3238 X11Symbols::getInstance()->xSelectInput (display, root, SubstructureNotifyMask);
3241 XSetWindowAttributes swa;
3242 swa.event_mask = NoEventMask;
3243 juce_messageWindowHandle = X11Symbols::getInstance()->xCreateWindow (display, root,
3244 0, 0, 1, 1, 0, 0, InputOnly,
3245 X11Symbols::getInstance()->xDefaultVisual (display, screen),
3248 X11Symbols::getInstance()->xSync (display, False);
3250 atoms = XWindowSystemUtilities::Atoms (display);
3252 initialisePointerMap();
3253 updateModifierMappings();
3254 initialiseXSettings();
3257 if (XSHMHelpers::isShmAvailable (display))
3258 shmCompletionEvent = X11Symbols::getInstance()->xShmGetEventBase (display) + ShmCompletion;
3261 displayVisuals = std::make_unique<DisplayVisuals> (display);
3263 if (! displayVisuals->isValid())
3265 Logger::outputDebugString (
"ERROR: System doesn't support 32, 24 or 16 bit RGB display.\n");
3270 LinuxEventLoop::registerFdCallback (X11Symbols::getInstance()->xConnectionNumber (display),
3278 XWindowSystemUtilities::ScopedXLock xLock;
3280 if (! X11Symbols::getInstance()->xPending (display))
3283 X11Symbols::getInstance()->xNextEvent (display, &evt);
3286 if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle)
3288 ClipboardHelpers::handleSelection (evt.xselectionrequest);
3290 else if (evt.xany.window != juce_messageWindowHandle)
3292 windowMessageReceive (evt);
3295 }
while (display !=
nullptr);
3301void XWindowSystem::destroyXDisplay()
3308 XWindowSystemUtilities::ScopedXLock xLock;
3310 X11Symbols::getInstance()->xDestroyWindow (display, juce_messageWindowHandle);
3311 juce_messageWindowHandle = 0;
3312 X11Symbols::getInstance()->xSync (display, True);
3315 LinuxEventLoop::unregisterFdCallback (X11Symbols::getInstance()->xConnectionNumber (display));
3318 XWindowSystemUtilities::ScopedXLock xLock;
3319 X11Symbols::getInstance()->xCloseDisplay (display);
3321 displayVisuals =
nullptr;
3327::Window juce_createKeyProxyWindow (ComponentPeer* peer);
3328::Window juce_createKeyProxyWindow (ComponentPeer* peer)
3330 return XWindowSystem::getInstance()->createKeyProxy ((::Window) peer->getNativeHandle());
3333void juce_deleteKeyProxyWindow (::Window keyProxy);
3334void juce_deleteKeyProxyWindow (::Window keyProxy)
3336 XWindowSystem::getInstance()->deleteKeyProxy (keyProxy);
3340template <
typename EventType>
3341static Point<float> getLogicalMousePos (
const EventType& e,
double scaleFactor)
noexcept
3343 return Point<float> ((
float) e.x, (
float) e.y) / scaleFactor;
3346static int64 getEventTime (::Time t)
3348 static int64 eventTimeOffset = 0x12345678;
3349 auto thisMessageTime = (int64) t;
3351 if (eventTimeOffset == 0x12345678)
3352 eventTimeOffset = Time::currentTimeMillis() - thisMessageTime;
3354 return eventTimeOffset + thisMessageTime;
3357template <
typename EventType>
3358static int64 getEventTime (
const EventType& t)
3360 return getEventTime (t.time);
3363void XWindowSystem::handleWindowMessage (LinuxComponentPeer* peer, XEvent& event)
const
3365 switch (event.xany.type)
3367 case KeyPressEventType: handleKeyPressEvent (peer, event.xkey);
break;
3368 case KeyRelease: handleKeyReleaseEvent (peer, event.xkey);
break;
3369 case ButtonPress: handleButtonPressEvent (peer, event.xbutton);
break;
3370 case ButtonRelease: handleButtonReleaseEvent (peer, event.xbutton);
break;
3371 case MotionNotify: handleMotionNotifyEvent (peer, event.xmotion);
break;
3372 case EnterNotify: handleEnterNotifyEvent (peer, event.xcrossing);
break;
3373 case LeaveNotify: handleLeaveNotifyEvent (peer, event.xcrossing);
break;
3374 case FocusIn: handleFocusInEvent (peer);
break;
3375 case FocusOut: handleFocusOutEvent (peer);
break;
3376 case Expose: handleExposeEvent (peer, event.xexpose);
break;
3377 case MappingNotify: handleMappingNotify (event.xmapping);
break;
3378 case ClientMessage: handleClientMessageEvent (peer, event.xclient, event);
break;
3379 case SelectionNotify: dragAndDropStateMap[peer].handleDragAndDropSelection (event);
break;
3380 case ConfigureNotify: handleConfigureNotifyEvent (peer, event.xconfigure);
break;
3381 case ReparentNotify:
3382 case GravityNotify: handleGravityNotify (peer);
break;
3383 case SelectionClear: dragAndDropStateMap[peer].handleExternalSelectionClear();
break;
3384 case SelectionRequest: dragAndDropStateMap[peer].handleExternalSelectionRequest (event);
break;
3385 case PropertyNotify: propertyNotifyEvent (peer, event.xproperty);
break;
3387 case CirculateNotify:
3394 peer->handleBroughtToFront();
3399 if (XSHMHelpers::isShmAvailable (display))
3401 XWindowSystemUtilities::ScopedXLock xLock;
3403 if (event.xany.type == shmCompletionEvent)
3404 XWindowSystem::getInstance()->removePendingPaintForWindow ((::Window) peer->getNativeHandle());
3411void XWindowSystem::handleKeyPressEvent (LinuxComponentPeer* peer, XKeyEvent& keyEvent)
const
3413 auto oldMods = ModifierKeys::currentModifiers;
3414 Keys::refreshStaleModifierKeys();
3416 char utf8 [64] = { 0 };
3419 bool keyDownChange =
false;
3423 XWindowSystemUtilities::ScopedXLock xLock;
3424 updateKeyStates ((
int) keyEvent.keycode,
true);
3426 String oldLocale (::setlocale (LC_ALL,
nullptr));
3427 ::setlocale (LC_ALL,
"");
3428 X11Symbols::getInstance()->xLookupString (&keyEvent, utf8,
sizeof (utf8), &sym,
nullptr);
3430 if (oldLocale.isNotEmpty())
3431 ::setlocale (LC_ALL, oldLocale.toRawUTF8());
3433 unicodeChar = *CharPointer_UTF8 (utf8);
3434 keyCode = (
int) unicodeChar;
3437 keyCode = (
int) X11Symbols::getInstance()->xkbKeycodeToKeysym (display, (::KeyCode) keyEvent.keycode, 0,
3438 ModifierKeys::currentModifiers.isShiftDown() ? 1 : 0);
3440 keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym,
true);
3443 bool keyPressed =
false;
3445 if ((sym & 0xff00) == 0xff00 || keyCode == XK_ISO_Left_Tab)
3449 case XK_KP_Add: keyCode = XK_plus;
break;
3450 case XK_KP_Subtract: keyCode = XK_hyphen;
break;
3451 case XK_KP_Divide: keyCode = XK_slash;
break;
3452 case XK_KP_Multiply: keyCode = XK_asterisk;
break;
3453 case XK_KP_Enter: keyCode = XK_Return;
break;
3454 case XK_KP_Insert: keyCode = XK_Insert;
break;
3456 case XK_KP_Delete: keyCode = XK_Delete;
break;
3457 case XK_KP_Left: keyCode = XK_Left;
break;
3458 case XK_KP_Right: keyCode = XK_Right;
break;
3459 case XK_KP_Up: keyCode = XK_Up;
break;
3460 case XK_KP_Down: keyCode = XK_Down;
break;
3461 case XK_KP_Home: keyCode = XK_Home;
break;
3462 case XK_KP_End: keyCode = XK_End;
break;
3463 case XK_KP_Page_Down: keyCode = XK_Page_Down;
break;
3464 case XK_KP_Page_Up: keyCode = XK_Page_Up;
break;
3466 case XK_KP_0: keyCode = XK_0;
break;
3467 case XK_KP_1: keyCode = XK_1;
break;
3468 case XK_KP_2: keyCode = XK_2;
break;
3469 case XK_KP_3: keyCode = XK_3;
break;
3470 case XK_KP_4: keyCode = XK_4;
break;
3471 case XK_KP_5: keyCode = XK_5;
break;
3472 case XK_KP_6: keyCode = XK_6;
break;
3473 case XK_KP_7: keyCode = XK_7;
break;
3474 case XK_KP_8: keyCode = XK_8;
break;
3475 case XK_KP_9: keyCode = XK_9;
break;
3493 keyCode = (keyCode & 0xff) | Keys::extendedKeyModifier;
3504 case XK_ISO_Left_Tab:
3506 keyCode = XK_Tab & 0xff;
3510 if (sym >= XK_F1 && sym <= XK_F35)
3513 keyCode =
static_cast<int> ((sym & 0xff) | Keys::extendedKeyModifier);
3519 if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8))
3522 if (oldMods != ModifierKeys::currentModifiers)
3523 peer->handleModifierKeysChange();
3526 peer->handleKeyUpOrDown (
true);
3529 peer->handleKeyPress (keyCode, unicodeChar);
3532void XWindowSystem::handleKeyReleaseEvent (LinuxComponentPeer* peer,
const XKeyEvent& keyEvent)
const
3534 auto isKeyReleasePartOfAutoRepeat = [&]() ->
bool
3536 if (X11Symbols::getInstance()->xPending (display))
3539 X11Symbols::getInstance()->xPeekEvent (display, &e);
3542 return e.type == KeyPressEventType
3543 && e.xkey.keycode == keyEvent.keycode
3544 && e.xkey.time == keyEvent.time;
3550 if (! isKeyReleasePartOfAutoRepeat)
3552 updateKeyStates ((
int) keyEvent.keycode,
false);
3556 XWindowSystemUtilities::ScopedXLock xLock;
3557 sym = X11Symbols::getInstance()->xkbKeycodeToKeysym (display, (::KeyCode) keyEvent.keycode, 0, 0);
3560 auto oldMods = ModifierKeys::currentModifiers;
3561 auto keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym,
false);
3563 if (oldMods != ModifierKeys::currentModifiers)
3564 peer->handleModifierKeysChange();
3567 peer->handleKeyUpOrDown (
false);
3571void XWindowSystem::handleWheelEvent (LinuxComponentPeer* peer,
const XButtonPressedEvent& buttonPressEvent,
float amount)
const
3573 MouseWheelDetails wheel;
3574 wheel.deltaX = 0.0f;
3575 wheel.deltaY = amount;
3576 wheel.isReversed =
false;
3577 wheel.isSmooth =
false;
3578 wheel.isInertial =
false;
3580 peer->handleMouseWheel (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (buttonPressEvent, peer->getPlatformScaleFactor()),
3581 getEventTime (buttonPressEvent), wheel);
3584void XWindowSystem::handleButtonPressEvent (LinuxComponentPeer* peer,
const XButtonPressedEvent& buttonPressEvent,
int buttonModifierFlag)
const
3586 ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withFlags (buttonModifierFlag);
3587 peer->toFront (
true);
3588 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (buttonPressEvent, peer->getPlatformScaleFactor()),
3589 ModifierKeys::currentModifiers, MouseInputSource::defaultPressure,
3590 MouseInputSource::defaultOrientation, getEventTime (buttonPressEvent), {});
3593void XWindowSystem::handleButtonPressEvent (LinuxComponentPeer* peer,
const XButtonPressedEvent& buttonPressEvent)
const
3595 updateKeyModifiers ((
int) buttonPressEvent.state);
3597 auto mapIndex = (uint32) (buttonPressEvent.button - Button1);
3601 switch (pointerMap[mapIndex])
3603 case Keys::WheelUp: handleWheelEvent (peer, buttonPressEvent, 50.0f / 256.0f);
break;
3604 case Keys::WheelDown: handleWheelEvent (peer, buttonPressEvent, -50.0f / 256.0f);
break;
3605 case Keys::LeftButton: handleButtonPressEvent (peer, buttonPressEvent, ModifierKeys::leftButtonModifier);
break;
3606 case Keys::RightButton: handleButtonPressEvent (peer, buttonPressEvent, ModifierKeys::rightButtonModifier);
break;
3607 case Keys::MiddleButton: handleButtonPressEvent (peer, buttonPressEvent, ModifierKeys::middleButtonModifier);
break;
3613void XWindowSystem::handleButtonReleaseEvent (LinuxComponentPeer* peer,
const XButtonReleasedEvent& buttonRelEvent)
const
3615 updateKeyModifiers ((
int) buttonRelEvent.state);
3617 if (peer->getParentWindow() != 0)
3618 peer->updateWindowBounds();
3620 auto mapIndex = (uint32) (buttonRelEvent.button - Button1);
3624 switch (pointerMap[mapIndex])
3626 case Keys::LeftButton: ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier);
break;
3627 case Keys::RightButton: ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier);
break;
3628 case Keys::MiddleButton: ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier);
break;
3633 auto& dragState = dragAndDropStateMap[peer];
3635 if (dragState.isDragging())
3636 dragState.handleExternalDragButtonReleaseEvent();
3638 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (buttonRelEvent, peer->getPlatformScaleFactor()),
3639 ModifierKeys::currentModifiers, MouseInputSource::defaultPressure, MouseInputSource::defaultOrientation, getEventTime (buttonRelEvent));
3642void XWindowSystem::handleMotionNotifyEvent (LinuxComponentPeer* peer,
const XPointerMovedEvent& movedEvent)
const
3644 updateKeyModifiers ((
int) movedEvent.state);
3645 Keys::refreshStaleMouseKeys();
3647 auto& dragState = dragAndDropStateMap[peer];
3649 if (dragState.isDragging())
3650 dragState.handleExternalDragMotionNotify();
3652 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (movedEvent, peer->getPlatformScaleFactor()),
3653 ModifierKeys::currentModifiers, MouseInputSource::defaultPressure,
3654 MouseInputSource::defaultOrientation, getEventTime (movedEvent));
3657void XWindowSystem::handleEnterNotifyEvent (LinuxComponentPeer* peer,
const XEnterWindowEvent& enterEvent)
const
3659 if (peer->getParentWindow() != 0)
3660 peer->updateWindowBounds();
3662 if (! ModifierKeys::currentModifiers.isAnyMouseButtonDown())
3664 updateKeyModifiers ((
int) enterEvent.state);
3665 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (enterEvent, peer->getPlatformScaleFactor()),
3666 ModifierKeys::currentModifiers, MouseInputSource::defaultPressure,
3667 MouseInputSource::defaultOrientation, getEventTime (enterEvent));
3671void XWindowSystem::handleLeaveNotifyEvent (LinuxComponentPeer* peer,
const XLeaveWindowEvent& leaveEvent)
const
3676 if (((! ModifierKeys::currentModifiers.isAnyMouseButtonDown()) && leaveEvent.mode == NotifyNormal)
3677 || leaveEvent.mode == NotifyUngrab)
3679 updateKeyModifiers ((
int) leaveEvent.state);
3680 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, getLogicalMousePos (leaveEvent, peer->getPlatformScaleFactor()),
3681 ModifierKeys::currentModifiers, MouseInputSource::defaultPressure,
3682 MouseInputSource::defaultOrientation, getEventTime (leaveEvent));
3686void XWindowSystem::handleFocusInEvent (LinuxComponentPeer* peer)
const
3688 peer->isActiveApplication =
true;
3690 if (isFocused ((::Window) peer->getNativeHandle()) && ! peer->focused)
3692 peer->focused =
true;
3693 peer->handleFocusGain();
3697void XWindowSystem::handleFocusOutEvent (LinuxComponentPeer* peer)
const
3699 if (! isFocused ((::Window) peer->getNativeHandle()) && peer->focused)
3701 peer->focused =
false;
3702 peer->isActiveApplication =
false;
3704 peer->handleFocusLoss();
3708void XWindowSystem::handleExposeEvent (LinuxComponentPeer* peer, XExposeEvent& exposeEvent)
const
3712 XWindowSystemUtilities::ScopedXLock xLock;
3716 peer->repaintOpenGLContexts();
3718 auto windowH = (::Window) peer->getNativeHandle();
3720 if (exposeEvent.window != windowH)
3723 X11Symbols::getInstance()->xTranslateCoordinates (display, exposeEvent.window, windowH,
3724 exposeEvent.x, exposeEvent.y, &exposeEvent.x, &exposeEvent.y,
3730 auto currentScaleFactor = peer->getPlatformScaleFactor();
3732 peer->repaint (Rectangle<int> (exposeEvent.x, exposeEvent.y,
3733 exposeEvent.width, exposeEvent.height) / currentScaleFactor);
3735 while (X11Symbols::getInstance()->xEventsQueued (display, QueuedAfterFlush) > 0)
3737 X11Symbols::getInstance()->xPeekEvent (display, &nextEvent);
3739 if (nextEvent.type != Expose || nextEvent.xany.window != exposeEvent.window)
3742 X11Symbols::getInstance()->xNextEvent (display, &nextEvent);
3743 auto& nextExposeEvent = (XExposeEvent&) nextEvent.xexpose;
3745 peer->repaint (Rectangle<int> (nextExposeEvent.x, nextExposeEvent.y,
3746 nextExposeEvent.width, nextExposeEvent.height) / currentScaleFactor);
3750void XWindowSystem::dismissBlockingModals (LinuxComponentPeer* peer)
const
3752 if (peer->getComponent().isCurrentlyBlockedByAnotherModalComponent())
3753 if (
auto* currentModalComp = Component::getCurrentlyModalComponent())
3754 if (
auto* otherPeer = currentModalComp->getPeer())
3755 if ((otherPeer->getStyleFlags() & ComponentPeer::windowIsTemporary) != 0)
3756 currentModalComp->inputAttemptWhenModal();
3759void XWindowSystem::handleConfigureNotifyEvent (LinuxComponentPeer* peer, XConfigureEvent& confEvent)
const
3761 peer->updateWindowBounds();
3762 peer->updateBorderSize();
3763 peer->handleMovedOrResized();
3766 if ((peer->getStyleFlags() & ComponentPeer::windowHasTitleBar) != 0)
3767 dismissBlockingModals (peer);
3769 auto windowH = (::Window) peer->getNativeHandle();
3771 if (confEvent.window == windowH && confEvent.above != 0 && isFrontWindow (windowH))
3772 peer->handleBroughtToFront();
3775void XWindowSystem::handleGravityNotify (LinuxComponentPeer* peer)
const
3777 peer->updateWindowBounds();
3778 peer->updateBorderSize();
3779 peer->handleMovedOrResized();
3782bool XWindowSystem::isIconic (Window w)
const
3786 XWindowSystemUtilities::ScopedXLock xLock;
3787 XWindowSystemUtilities::GetXProperty prop (display, w, atoms.state, 0, 64,
false, atoms.state);
3789 if (prop.success && prop.actualType == atoms.state
3790 && prop.actualFormat == 32 && prop.numItems > 0)
3792 unsigned long state;
3793 memcpy (&state, prop.data, sizeof (
unsigned long));
3795 return state == IconicState;
3801bool XWindowSystem::isHidden (Window w)
const
3803 XWindowSystemUtilities::ScopedXLock xLock;
3804 XWindowSystemUtilities::GetXProperty prop (display, w, atoms.windowState, 0, 128,
false, XA_ATOM);
3806 if (! (prop.success && prop.actualFormat == 32 && prop.actualType == XA_ATOM))
3809 const auto*
data = unalignedPointerCast<const long*> (prop.data);
3810 const auto end =
data + prop.numItems;
3812 return std::find (data, end, atoms.windowStateHidden) !=
end;
3815void XWindowSystem::propertyNotifyEvent (LinuxComponentPeer* peer,
const XPropertyEvent& event)
const
3817 if ((event.atom == atoms.state && isIconic (event.window))
3818 || (event.atom == atoms.windowState && isHidden (event.window)))
3820 dismissBlockingModals (peer);
3823 if (event.atom == XWindowSystemUtilities::Atoms::getIfExists (display,
"_NET_FRAME_EXTENTS"))
3824 peer->updateBorderSize();
3827void XWindowSystem::handleMappingNotify (XMappingEvent& mappingEvent)
const
3829 if (mappingEvent.request != MappingPointer)
3832 XWindowSystemUtilities::ScopedXLock xLock;
3833 X11Symbols::getInstance()->xRefreshKeyboardMapping (&mappingEvent);
3834 updateModifierMappings();
3838void XWindowSystem::handleClientMessageEvent (LinuxComponentPeer* peer, XClientMessageEvent& clientMsg, XEvent& event)
const
3840 if (clientMsg.message_type == atoms.protocols && clientMsg.format == 32)
3842 auto atom = (Atom) clientMsg.data.l[0];
3844 if (atom == atoms.protocolList [XWindowSystemUtilities::Atoms::PING])
3846 auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
3848 clientMsg.window = root;
3850 X11Symbols::getInstance()->xSendEvent (display, root, False, NoEventMask, &event);
3851 X11Symbols::getInstance()->xFlush (display);
3853 else if (atom == atoms.protocolList [XWindowSystemUtilities::Atoms::TAKE_FOCUS])
3855 if ((peer->getStyleFlags() & ComponentPeer::windowIgnoresKeyPresses) == 0)
3857 XWindowAttributes atts;
3859 XWindowSystemUtilities::ScopedXLock xLock;
3860 if (clientMsg.window != 0
3861 && X11Symbols::getInstance()->xGetWindowAttributes (display, clientMsg.window, &atts))
3863 if (atts.map_state == IsViewable)
3865 auto windowH = (::Window) peer->getNativeHandle();
3867 X11Symbols::getInstance()->xSetInputFocus (display, (clientMsg.window == windowH ? getFocusWindow (windowH)
3868 : clientMsg.window),
3869 RevertToParent, (::Time) clientMsg.
data.l[1]);
3874 else if (atom == atoms.protocolList [XWindowSystemUtilities::Atoms::DELETE_WINDOW])
3876 peer->handleUserClosingWindow();
3879 else if (clientMsg.message_type == atoms.XdndEnter)
3881 dragAndDropStateMap[peer].handleDragAndDropEnter (clientMsg, peer);
3883 else if (clientMsg.message_type == atoms.XdndLeave)
3885 dragAndDropStateMap[peer].handleDragAndDropExit();
3887 else if (clientMsg.message_type == atoms.XdndPosition)
3889 dragAndDropStateMap[peer].handleDragAndDropPosition (clientMsg, peer);
3891 else if (clientMsg.message_type == atoms.XdndDrop)
3893 dragAndDropStateMap[peer].handleDragAndDropDrop (clientMsg, peer);
3895 else if (clientMsg.message_type == atoms.XdndStatus)
3897 dragAndDropStateMap[peer].handleExternalDragAndDropStatus (clientMsg);
3899 else if (clientMsg.message_type == atoms.XdndFinished)
3901 dragAndDropStateMap[peer].externalResetDragAndDrop();
3903 else if (clientMsg.message_type == atoms.XembedMsgType && clientMsg.format == 32)
3905 handleXEmbedMessage (peer, clientMsg);
3909void XWindowSystem::handleXEmbedMessage (LinuxComponentPeer* peer, XClientMessageEvent& clientMsg)
const
3911 switch (clientMsg.data.l[1])
3914 peer->setParentWindow ((::Window) clientMsg.data.l[3]);
3915 peer->updateWindowBounds();
3916 peer->getComponent().setBounds (peer->getBounds());
3919 handleFocusInEvent (peer);
3922 handleFocusOutEvent (peer);
3931void XWindowSystem::dismissBlockingModals (LinuxComponentPeer* peer,
const XConfigureEvent& configure)
const
3933 if (peer ==
nullptr)
3936 const auto peerHandle = peer->getWindowHandle();
3938 if (configure.window != peerHandle && isParentWindowOf (configure.window, peerHandle))
3939 dismissBlockingModals (peer);
3942void XWindowSystem::windowMessageReceive (XEvent& event)
3944 if (event.xany.window != None)
3946 #if JUCE_X11_SUPPORTS_XEMBED
3947 if (! juce_handleXEmbedEvent (
nullptr, &event))
3950 auto* instance = XWindowSystem::getInstance();
3952 if (
auto* xSettings = instance->getXSettings())
3954 if (event.xany.window == xSettings->getSettingsWindow())
3956 if (event.xany.type == PropertyNotify)
3957 xSettings->update();
3958 else if (event.xany.type == DestroyNotify)
3959 instance->initialiseXSettings();
3965 if (
auto* peer =
dynamic_cast<LinuxComponentPeer*
> (getPeerFor (event.xany.window)))
3967 XWindowSystem::getInstance()->handleWindowMessage (peer, event);
3971 if (event.type != ConfigureNotify)
3974 for (
auto i = ComponentPeer::getNumPeers(); --i >= 0;)
3975 instance->dismissBlockingModals (
dynamic_cast<LinuxComponentPeer*
> (ComponentPeer::getPeer (i)),
3979 else if (event.xany.type == KeymapNotify)
3981 auto& keymapEvent = (
const XKeymapEvent&) event.xkeymap;
3982 memcpy (Keys::keyStates, keymapEvent.key_vector, 32);
3989Image createSnapshotOfNativeWindow (
void* window)
3993 unsigned int ww, wh, bw, bitDepth;
3995 XWindowSystemUtilities::ScopedXLock xLock;
3997 const auto display = XWindowSystem::getInstance()->getDisplay();
3999 if (! X11Symbols::getInstance()->xGetGeometry (display, (::Drawable) window, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth))
4002 const auto scale = []
4004 if (
auto* d = Desktop::getInstance().getDisplays().getPrimaryDisplay())
4010 auto image = Image {
new XBitmapImage { X11Symbols::getInstance()->xGetImage (display,
4011 (::Drawable) window,
4018 return image.rescaled ((
int) ((
double) ww / scale), (
int) ((
double) wh / scale));
This is a base class for holding image data in implementation-specific ways.
Retrieves a section of an image as raw pixel data, so it can be read or written to.
int pixelStride
The number of bytes between each pixel.
int lineStride
The number of bytes between each line.
PixelFormat pixelFormat
The format of the data.
uint8 * data
The raw pixel data, packed according to the image's pixel format.
size_t size
The number of valid/allocated bytes after data.
Holds a fixed-size bitmap.
A smart-pointer class which points to a reference-counted object.
std::unique_ptr< LowLevelGraphicsContext > createLowLevelContext() override
Creates a context that will draw into this image.
ImagePixelData::Ptr clone() override
Creates a copy of this image.
std::unique_ptr< ImageType > createType() const override
Creates an instance of the type of this image.
void initialiseBitmapData(Image::BitmapData &bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
Initialises a BitmapData object.
#define JUCE_IMPLEMENT_SINGLETON(Classname)
This is a counterpart to the JUCE_DECLARE_SINGLETON macros.
void zerostruct(Type &structure) noexcept
Overwrites a structure or object with zeros.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
@ press
Represents a "press" action.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
std::unique_ptr< T > rawToUniquePtr(T *ptr)
Converts an owning raw pointer into a unique_ptr, deriving the type of the unique_ptr automatically.
A handy struct that uses XLockDisplay and XUnlockDisplay to lock the X server using RAII.