1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Linux: Removed X11-specific code from LinuxComponentPeer

This commit is contained in:
ed 2019-09-05 15:37:14 +01:00
parent 1c1f74562f
commit 74ca3b44c4
17 changed files with 4904 additions and 4825 deletions

View file

@ -214,8 +214,6 @@ struct SharedMessageThread : public Thread
MessageManager::getInstance()->setCurrentThreadAsMessageThread();
ScopedXDisplay xDisplay;
while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil (250))
{}
}
@ -1088,7 +1086,7 @@ public:
#elif JUCE_LINUX
addToDesktop (0, args.ptr);
hostWindow = (Window) args.ptr;
X11Symbols::getInstance()->xReparentWindow (display.display, (Window) getWindowHandle(), hostWindow, 0, 0);
X11Symbols::getInstance()->xReparentWindow (display, (Window) getWindowHandle(), hostWindow, 0, 0);
#else
hostWindow = attachComponentToWindowRefVST (this, args.ptr, wrapper.useNSView);
#endif
@ -1197,7 +1195,7 @@ public:
if (auto* peer = ed->getPeer())
scale *= (float) peer->getPlatformScaleFactor();
X11Symbols::getInstance()->xResizeWindow (display.display, (Window) getWindowHandle(),
X11Symbols::getInstance()->xResizeWindow (display, (Window) getWindowHandle(),
static_cast<unsigned int> (roundToInt (pos.getWidth() * scale)),
static_cast<unsigned int> (roundToInt (pos.getHeight() * scale)));
#endif
@ -1366,7 +1364,7 @@ public:
#if JUCE_MAC
void* hostWindow = nullptr;
#elif JUCE_LINUX
ScopedXDisplay display;
::Display* display = XWindowSystem::getInstance()->getDisplay();
Window hostWindow = {};
#elif JUCE_WINDOWS
HWND hostWindow = {};

View file

@ -237,10 +237,8 @@ namespace
Window* childWindows;
unsigned int numChildren = 0;
{
ScopedXDisplay xDisplay;
X11Symbols::getInstance()->xQueryTree (xDisplay.display, windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
}
X11Symbols::getInstance()->xQueryTree (XWindowSystem::getInstance()->getDisplay(),
windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
if (numChildren > 0)
return childWindows [0];
@ -2743,7 +2741,6 @@ public:
{
#if JUCE_LINUX
pluginWindow = None;
display = XWindowSystem::getInstance()->displayRef();
ignoreUnused (pluginRefusesToResize, alreadyInside);
#elif JUCE_MAC
ignoreUnused (recursiveResize, pluginRefusesToResize, alreadyInside);
@ -2786,10 +2783,6 @@ public:
#endif
cocoaWrapper.reset();
#else
#if JUCE_LINUX
display = XWindowSystem::getInstance()->displayUnref();
#endif
removeScaleFactorListeners();
#endif
@ -3403,15 +3396,14 @@ private:
#if ! JUCE_MAC
bool pluginRespondsToDPIChanges = false;
float nativeScaleFactor = 1.0f;
#endif
#if JUCE_WINDOWS
HWND pluginHWND = {};
void* originalWndProc = {};
int sizeCheckCount = 0;
#elif JUCE_LINUX
::Display* display;
Window pluginWindow;
#if JUCE_WINDOWS
HWND pluginHWND = {};
void* originalWndProc = {};
int sizeCheckCount = 0;
#elif JUCE_LINUX
::Display* display = XWindowSystem::getInstance()->getDisplay();
Window pluginWindow = 0;
#endif
#endif
//==============================================================================

View file

@ -250,13 +250,13 @@ namespace juce
#include "native/juce_win32_FileChooser.cpp"
#elif JUCE_LINUX
#include "native/juce_linux_X11Symbols.cpp"
#include "native/juce_linux_X11.cpp"
#include "native/juce_linux_X11_Clipboard.cpp"
#include "native/x11/juce_linux_X11_Symbols.cpp"
#include "native/x11/juce_linux_X11_DragAndDrop.cpp"
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
#include "native/juce_linux_X11_Windowing.cpp"
#include "native/juce_linux_Windowing.cpp"
#include "native/x11/juce_linux_XWindowSystem.cpp"
JUCE_END_IGNORE_WARNINGS_GCC_LIKE

View file

@ -288,8 +288,6 @@ namespace juce
#include "mouse/juce_LassoComponent.h"
#if JUCE_LINUX
#include "native/juce_linux_X11.h"
#if JUCE_GUI_BASICS_INCLUDE_XHEADERS
// If you're missing these headers, you need to install the libx11-dev package
#include <X11/Xlib.h>
@ -332,7 +330,8 @@ namespace juce
#undef SIZEOF
#undef KeyPress
#include "native/juce_linux_X11Symbols.h"
#include "native/x11/juce_linux_XWindowSystem.h"
#include "native/x11/juce_linux_X11_Symbols.h"
#endif
#endif

View file

@ -0,0 +1,682 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
static int numAlwaysOnTopPeers = 0;
bool juce_areThereAnyAlwaysOnTopWindows() { return numAlwaysOnTopPeers > 0; }
//==============================================================================
template<typename WindowHandleType>
class LinuxComponentPeer : public ComponentPeer
{
public:
LinuxComponentPeer (Component& comp, int windowStyleFlags, WindowHandleType parentToAddTo)
: ComponentPeer (comp, windowStyleFlags),
isAlwaysOnTop (comp.isAlwaysOnTop())
{
// it's dangerous to create a window on a thread other than the message thread..
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (isAlwaysOnTop)
++numAlwaysOnTopPeers;
repainter = std::make_unique<LinuxRepaintManager> (*this);
windowH = XWindowSystem::getInstance()->createWindow (parentToAddTo, this);
parentWindow = parentToAddTo;
setTitle (component.getName());
getNativeRealtimeModifiers = []() -> ModifierKeys { return XWindowSystem::getInstance()->getNativeRealtimeModifiers(); };
}
~LinuxComponentPeer() override
{
// it's dangerous to delete a window on a thread other than the message thread..
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
repainter = nullptr;
XWindowSystem::getInstance()->destroyWindow (windowH);
if (isAlwaysOnTop)
--numAlwaysOnTopPeers;
}
//==============================================================================
void* getNativeHandle() const override
{
return (void*) windowH;
}
//==============================================================================
void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override
{
bounds = newBounds.withSize (jmax (1, newBounds.getWidth()),
jmax (1, newBounds.getHeight()));
updateScaleFactorFromNewBounds (bounds, false);
auto physicalBounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
: bounds * currentScaleFactor);
WeakReference<Component> deletionChecker (&component);
XWindowSystem::getInstance()->setBounds (windowH, physicalBounds, isNowFullScreen);
fullScreen = isNowFullScreen;
if (deletionChecker != nullptr)
{
updateBorderSize();
handleMovedOrResized();
}
}
Point<int> getScreenPosition (bool physical) const
{
auto parentPosition = XWindowSystem::getInstance()->getParentScreenPosition();
auto screenBounds = (parentWindow == 0 ? bounds
: bounds.translated (parentPosition.x, parentPosition.y));
if (physical)
return Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft());
return screenBounds.getTopLeft();
}
Rectangle<int> getBounds() const override
{
return bounds;
}
BorderSize<int> getFrameSize() const override
{
return windowBorder;
}
using ComponentPeer::localToGlobal;
Point<float> localToGlobal (Point<float> relativePosition) override
{
return relativePosition + getScreenPosition (false).toFloat();
}
using ComponentPeer::globalToLocal;
Point<float> globalToLocal (Point<float> screenPosition) override
{
return screenPosition - getScreenPosition (false).toFloat();
}
//==============================================================================
StringArray getAvailableRenderingEngines() override
{
return { "Software Renderer" };
}
void setVisible (bool shouldBeVisible) override
{
XWindowSystem::getInstance()->setVisible (windowH, shouldBeVisible);
}
void setTitle (const String& title) override
{
XWindowSystem::getInstance()->setTitle (windowH, title);
}
void setMinimised (bool shouldBeMinimised) override
{
if (shouldBeMinimised)
XWindowSystem::getInstance()->setMinimised (windowH, shouldBeMinimised);
else
setVisible (true);
}
bool isMinimised() const override
{
return XWindowSystem::getInstance()->isMinimised (windowH);
}
void setFullScreen (bool shouldBeFullScreen) override
{
auto r = lastNonFullscreenBounds; // (get a copy of this before de-minimising)
setMinimised (false);
if (fullScreen != shouldBeFullScreen)
{
if (shouldBeFullScreen)
r = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
if (! r.isEmpty())
setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, r), shouldBeFullScreen);
component.repaint();
}
}
bool isFullScreen() const override
{
return fullScreen;
}
bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
{
if (! bounds.withZeroOrigin().contains (localPos))
return false;
for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
{
auto* c = Desktop::getInstance().getComponent (i);
if (c == &component)
break;
if (! c->isVisible())
continue;
if (auto* peer = c->getPeer())
if (peer->contains (localPos + bounds.getPosition() - peer->getBounds().getPosition(), true))
return false;
}
if (trueIfInAChildWindow)
return true;
return XWindowSystem::getInstance()->contains (windowH, localPos * currentScaleFactor);
}
void toFront (bool makeActive) override
{
if (makeActive)
{
setVisible (true);
grabFocus();
}
XWindowSystem::getInstance()->toFront (windowH, makeActive);
handleBroughtToFront();
}
void toBehind (ComponentPeer* other) override
{
if (auto* otherPeer = dynamic_cast<LinuxComponentPeer*> (other))
{
if (otherPeer->styleFlags & windowIsTemporary)
return;
setMinimised (false);
XWindowSystem::getInstance()->toBehind (windowH, otherPeer->windowH);
}
else
{
jassertfalse; // wrong type of window?
}
}
bool isFocused() const override
{
return XWindowSystem::getInstance()->isFocused (windowH);
}
void grabFocus() override
{
if (XWindowSystem::getInstance()->grabFocus (windowH))
isActiveApplication = true;
}
//==============================================================================
void repaint (const Rectangle<int>& area) override
{
repainter->repaint (area.getIntersection (bounds.withZeroOrigin()));
}
void performAnyPendingRepaintsNow() override
{
repainter->performAnyPendingRepaintsNow();
}
void setIcon (const Image& newIcon) override
{
XWindowSystem::getInstance()->setIcon (windowH, newIcon);
}
double getPlatformScaleFactor() const noexcept override
{
return currentScaleFactor;
}
void setAlpha (float) override {}
bool setAlwaysOnTop (bool) override { return false; }
void textInputRequired (Point<int>, TextInputTarget&) override {}
//==============================================================================
void addOpenGLRepaintListener (Component* dummy)
{
if (dummy != nullptr)
glRepaintListeners.addIfNotAlreadyThere (dummy);
}
void removeOpenGLRepaintListener (Component* dummy)
{
if (dummy != nullptr)
glRepaintListeners.removeAllInstancesOf (dummy);
}
void repaintOpenGLContexts()
{
for (auto* c : glRepaintListeners)
c->handleCommandMessage (0);
}
//==============================================================================
WindowHandleType getParentWindow() { return parentWindow; }
void setParentWindow (WindowHandleType newParent) { parentWindow = newParent; }
//==============================================================================
void updateWindowBounds()
{
jassert (windowH != 0);
if (windowH != 0)
{
auto physicalBounds = XWindowSystem::getInstance()->getWindowBounds (windowH, parentWindow);
updateScaleFactorFromNewBounds (physicalBounds, true);
bounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
: physicalBounds / currentScaleFactor);
}
}
void updateBorderSize()
{
if ((styleFlags & windowHasTitleBar) == 0)
windowBorder = {};
else if (windowBorder.getTopAndBottom() == 0 && windowBorder.getLeftAndRight() == 0)
windowBorder = XWindowSystem::getInstance()->getBorderSize (windowH);
}
//==============================================================================
static bool isActiveApplication;
bool focused = false;
private:
//==============================================================================
class LinuxRepaintManager : public Timer
{
public:
LinuxRepaintManager (LinuxComponentPeer& p) : peer (p) {}
void timerCallback() override
{
if (XWindowSystem::getInstance()->getNumPaintsPending (peer.windowH) > 0)
return;
if (! regionsNeedingRepaint.isEmpty())
{
stopTimer();
performAnyPendingRepaintsNow();
}
else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000)
{
stopTimer();
image = Image();
}
}
void repaint (Rectangle<int> area)
{
if (! isTimerRunning())
startTimer (repaintTimerPeriod);
regionsNeedingRepaint.add (area * peer.currentScaleFactor);
}
void performAnyPendingRepaintsNow()
{
if (XWindowSystem::getInstance()->getNumPaintsPending (peer.windowH) > 0)
{
startTimer (repaintTimerPeriod);
return;
}
auto originalRepaintRegion = regionsNeedingRepaint;
regionsNeedingRepaint.clear();
auto totalArea = originalRepaintRegion.getBounds();
if (! totalArea.isEmpty())
{
if (image.isNull() || image.getWidth() < totalArea.getWidth()
|| image.getHeight() < totalArea.getHeight())
{
image = XWindowSystem::getInstance()->createImage (totalArea.getWidth(), totalArea.getHeight(),
useARGBImagesForRendering);
}
startTimer (repaintTimerPeriod);
RectangleList<int> adjustedList (originalRepaintRegion);
adjustedList.offsetAll (-totalArea.getX(), -totalArea.getY());
if (XWindowSystem::getInstance()->canUseARGBImages())
for (auto& i : originalRepaintRegion)
image.clear (i - totalArea.getPosition());
{
auto context = peer.getComponent().getLookAndFeel()
.createGraphicsContext (image, -totalArea.getPosition(), adjustedList);
context->addTransform (AffineTransform::scale ((float) peer.currentScaleFactor));
peer.handlePaint (*context);
}
for (auto& i : originalRepaintRegion)
XWindowSystem::getInstance()->blitToWindow (peer.windowH, image, i, totalArea);
}
lastTimeImageUsed = Time::getApproximateMillisecondCounter();
startTimer (repaintTimerPeriod);
}
private:
enum { repaintTimerPeriod = 1000 / 100 };
LinuxComponentPeer& peer;
Image image;
uint32 lastTimeImageUsed = 0;
RectangleList<int> regionsNeedingRepaint;
bool useARGBImagesForRendering = XWindowSystem::getInstance()->canUseARGBImages();
JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager)
};
//==============================================================================
void updateScaleFactorFromNewBounds (const Rectangle<int>& newBounds, bool isPhysical)
{
Point<int> translation = (parentWindow != 0 ? getScreenPosition (isPhysical) : Point<int>());
auto newScaleFactor = Desktop::getInstance().getDisplays().findDisplayForRect (newBounds.translated (translation.x, translation.y), isPhysical).scale
/ Desktop::getInstance().getGlobalScaleFactor();
if (! approximatelyEqual (newScaleFactor, currentScaleFactor))
{
currentScaleFactor = newScaleFactor;
scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (currentScaleFactor); });
}
}
//==============================================================================
std::unique_ptr<LinuxRepaintManager> repainter;
WindowHandleType windowH = {}, parentWindow = {}, keyProxy = {};
Rectangle<int> bounds;
BorderSize<int> windowBorder;
bool fullScreen = false, isAlwaysOnTop = false;
double currentScaleFactor = 1.0;
Array<Component*> glRepaintListeners;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxComponentPeer)
};
template<typename WindowHandleType>
bool LinuxComponentPeer<WindowHandleType>::isActiveApplication = false;
//==============================================================================
ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindowToAttachTo)
{
return new LinuxComponentPeer<::Window> (*this, styleFlags, (::Window) nativeWindowToAttachTo);
}
//==============================================================================
JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return LinuxComponentPeer<::Window>::isActiveApplication; }
JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}
JUCE_API void JUCE_CALLTYPE Process::hide() {}
//==============================================================================
void Desktop::setKioskComponent (Component* comp, bool enableOrDisable, bool)
{
if (enableOrDisable)
comp->setBounds (getDisplays().findDisplayForRect (comp->getScreenBounds()).totalArea);
}
void Displays::findDisplays (float masterScale)
{
displays = XWindowSystem::getInstance()->findDisplays (masterScale);
if (! displays.isEmpty())
updateToLogical();
}
bool Desktop::canUseSemiTransparentWindows() noexcept
{
return XWindowSystem::getInstance()->canUseSemiTransparentWindows();
}
static bool screenSaverAllowed = true;
void Desktop::setScreenSaverEnabled (bool isEnabled)
{
if (screenSaverAllowed != isEnabled)
{
screenSaverAllowed = isEnabled;
XWindowSystem::getInstance()->setScreenSaverEnabled (screenSaverAllowed);
}
}
bool Desktop::isScreenSaverEnabled()
{
return screenSaverAllowed;
}
double Desktop::getDefaultMasterScale() { return 1.0; }
Desktop::DisplayOrientation Desktop::getCurrentOrientation() const { return upright; }
void Desktop::allowedOrientationsChanged() {}
//==============================================================================
bool MouseInputSource::SourceList::addSource()
{
if (sources.isEmpty())
{
addSource (0, MouseInputSource::InputSourceType::mouse);
return true;
}
return false;
}
bool MouseInputSource::SourceList::canUseTouch()
{
return false;
}
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
return Desktop::getInstance().getDisplays().physicalToLogical (XWindowSystem::getInstance()->getCurrentMousePosition());
}
void MouseInputSource::setRawMousePosition (Point<float> newPosition)
{
XWindowSystem::getInstance()->setMousePosition (Desktop::getInstance().getDisplays().logicalToPhysical (newPosition));
}
//==============================================================================
void* CustomMouseCursorInfo::create() const
{
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (image, hotspot);
}
void MouseCursor::deleteMouseCursor (void* cursorHandle, bool)
{
if (cursorHandle != nullptr)
XWindowSystem::getInstance()->deleteMouseCursor (cursorHandle);
}
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type)
{
return XWindowSystem::getInstance()->createStandardMouseCursor (type);
}
void MouseCursor::showInWindow (ComponentPeer* peer) const
{
if (peer != nullptr)
XWindowSystem::getInstance()->showCursor ((::Window) peer->getNativeHandle(), getHandle());
}
//==============================================================================
template<typename WindowHandleType>
static LinuxComponentPeer<WindowHandleType>* getPeerForDragEvent (Component* sourceComp)
{
if (sourceComp == nullptr)
if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource (0))
sourceComp = draggingSource->getComponentUnderMouse();
if (sourceComp != nullptr)
if (auto* lp = dynamic_cast<LinuxComponentPeer<::Window>*> (sourceComp->getPeer()))
return lp;
jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
return nullptr;
}
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles,
Component* sourceComp, std::function<void()> callback)
{
if (files.isEmpty())
return false;
if (auto* peer = getPeerForDragEvent<::Window> (sourceComp))
return XWindowSystem::getInstance()->externalDragFileInit (peer, files, canMoveFiles, std::move (callback));
// This method must be called in response to a component's mouseDown or mouseDrag event!
jassertfalse;
return false;
}
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component* sourceComp,
std::function<void()> callback)
{
if (text.isEmpty())
return false;
if (auto* peer = getPeerForDragEvent<::Window> (sourceComp))
return XWindowSystem::getInstance()->externalDragTextInit (peer, text, std::move (callback));
// This method must be called in response to a component's mouseDown or mouseDrag event!
jassertfalse;
return false;
}
//==============================================================================
void SystemClipboard::copyTextToClipboard (const String& clipText)
{
XWindowSystem::getInstance()->copyTextToClipboard (clipText);
}
String SystemClipboard::getTextFromClipboard()
{
return XWindowSystem::getInstance()->getTextFromClipboard();
}
//==============================================================================
bool KeyPress::isKeyCurrentlyDown (int keyCode)
{
return XWindowSystem::getInstance()->isKeyCurrentlyDown (keyCode);
}
void LookAndFeel::playAlertSound()
{
std::cout << "\a" << std::flush;
}
//==============================================================================
#if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
const String& title, const String& message,
Component*)
{
AlertWindow::showMessageBox (iconType, title, message);
}
#endif
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
{
AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback);
}
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
{
return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback);
}
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
{
return AlertWindow::showYesNoCancelBox (iconType, title, message, {}, {}, {},
associatedComponent, callback);
}
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (AlertWindow::AlertIconType iconType,
const String& title, const String& message,
Component* associatedComponent,
ModalComponentManager::Callback* callback)
{
return AlertWindow::showOkCancelBox (iconType, title, message, TRANS ("Yes"), TRANS ("No"),
associatedComponent, callback);
}
//==============================================================================
Image juce_createIconForFile (const File&)
{
return {};
}
void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy)
{
if (auto* linuxPeer = dynamic_cast<LinuxComponentPeer<::Window>*> (peer))
linuxPeer->addOpenGLRepaintListener (dummy);
}
void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy)
{
if (auto* linuxPeer = dynamic_cast<LinuxComponentPeer<::Window>*> (peer))
linuxPeer->removeOpenGLRepaintListener (dummy);
}
} // namespace juce

View file

@ -1,349 +0,0 @@
/*
==============================================================================
This file is part of the JUCE 6 technical preview.
Copyright (c) 2017 - ROLI Ltd.
You may use this code under the terms of the GPL v3
(see www.gnu.org/licenses).
For this technical preview, this file is not subject to commercial licensing.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
using WindowMessageReceiveCallback = void (*) (XEvent&);
WindowMessageReceiveCallback dispatchWindowMessage = nullptr;
using SelectionRequestCallback = void (*) (XSelectionRequestEvent&);
SelectionRequestCallback handleSelectionRequest = nullptr;
::Window juce_messageWindowHandle;
XContext windowHandleXContext;
//==============================================================================
namespace X11ErrorHandling
{
static XErrorHandler oldErrorHandler = {};
static XIOErrorHandler oldIOErrorHandler = {};
//==============================================================================
// Usually happens when client-server connection is broken
int ioErrorHandler (::Display*)
{
DBG ("ERROR: connection to X server broken.. terminating.");
if (JUCEApplicationBase::isStandaloneApp())
MessageManager::getInstance()->stopDispatchLoop();
return 0;
}
int errorHandler (::Display* display, XErrorEvent* event)
{
ignoreUnused (display, event);
#if JUCE_DEBUG_XERRORS
char errorStr[64] = { 0 };
char requestStr[64] = { 0 };
X11Symbols::getInstance()->xGetErrorText (display, event->error_code, errorStr, 64);
X11Symbols::getInstance()->xGetErrorDatabaseText (display, "XRequest", String (event->request_code).toUTF8(), "Unknown", requestStr, 64);
DBG ("ERROR: X returned " << errorStr << " for operation " << requestStr);
#endif
return 0;
}
void installXErrorHandlers()
{
oldIOErrorHandler = X11Symbols::getInstance()->xSetIOErrorHandler (ioErrorHandler);
oldErrorHandler = X11Symbols::getInstance()->xSetErrorHandler (errorHandler);
}
void removeXErrorHandlers()
{
X11Symbols::getInstance()->xSetIOErrorHandler (oldIOErrorHandler);
oldIOErrorHandler = {};
X11Symbols::getInstance()->xSetErrorHandler (oldErrorHandler);
oldErrorHandler = {};
}
}
XWindowSystem::XWindowSystem() noexcept
{
xIsAvailable = X11Symbols::getInstance()->areXFunctionsAvailable();
if (JUCEApplicationBase::isStandaloneApp() && xIsAvailable)
{
// Initialise xlib for multiple thread support
static bool initThreadCalled = false;
if (! initThreadCalled)
{
if (! X11Symbols::getInstance()->xInitThreads())
{
// This is fatal! Print error and closedown
Logger::outputDebugString ("Failed to initialise xlib thread support.");
Process::terminate();
return;
}
initThreadCalled = true;
}
X11ErrorHandling::installXErrorHandlers();
}
}
XWindowSystem::~XWindowSystem() noexcept
{
if (JUCEApplicationBase::isStandaloneApp() && xIsAvailable)
{
X11ErrorHandling::removeXErrorHandlers();
X11Symbols::deleteInstance();
}
clearSingletonInstance();
}
::Display* XWindowSystem::displayRef() noexcept
{
if (xIsAvailable && ++displayCount == 1)
{
jassert (display == nullptr);
String displayName (getenv ("DISPLAY"));
if (displayName.isEmpty())
displayName = ":0.0";
// it seems that on some systems XOpenDisplay will occasionally
// fail the first time, but succeed on a second attempt..
for (int retries = 2; --retries >= 0;)
{
display = X11Symbols::getInstance()->xOpenDisplay (displayName.toUTF8());
if (display != nullptr)
break;
}
initialiseXDisplay();
}
return display;
}
::Display* XWindowSystem::displayUnref() noexcept
{
if (xIsAvailable)
{
jassert (display != nullptr);
jassert (displayCount.get() > 0);
if (--displayCount == 0)
{
destroyXDisplay();
X11Symbols::getInstance()->xCloseDisplay (display);
display = nullptr;
}
}
return display;
}
void XWindowSystem::initialiseXDisplay() noexcept
{
if (xIsAvailable)
{
// This is fatal! Print error and closedown
if (display == nullptr)
{
Logger::outputDebugString ("Failed to connect to the X Server.");
Process::terminate();
}
// Create a context to store user data associated with Windows we create
windowHandleXContext = (XContext) X11Symbols::getInstance()->xrmUniqueQuark();
// We're only interested in client messages for this window, which are always sent
XSetWindowAttributes swa;
swa.event_mask = NoEventMask;
// Create our message window (this will never be mapped)
auto screen = X11Symbols::getInstance()->xDefaultScreen (display);
juce_messageWindowHandle = X11Symbols::getInstance()->xCreateWindow (display, X11Symbols::getInstance()->xRootWindow (display, screen),
0, 0, 1, 1, 0, 0, InputOnly,
X11Symbols::getInstance()->xDefaultVisual (display, screen),
CWEventMask, &swa);
X11Symbols::getInstance()->xSync (display, False);
// Setup input event handler
LinuxEventLoop::registerFdCallback (X11Symbols::getInstance()->xConnectionNumber (display),
[this](int)
{
do
{
XEvent evt;
{
ScopedXLock xlock (display);
if (! X11Symbols::getInstance()->xPending (display))
return;
X11Symbols::getInstance()->xNextEvent (display, &evt);
}
if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle
&& handleSelectionRequest != nullptr)
{
handleSelectionRequest (evt.xselectionrequest);
}
else if (evt.xany.window != juce_messageWindowHandle
&& dispatchWindowMessage != nullptr)
{
dispatchWindowMessage (evt);
}
} while (display != nullptr);
});
}
}
void XWindowSystem::destroyXDisplay() noexcept
{
if (xIsAvailable)
{
ScopedXLock xlock (display);
X11Symbols::getInstance()->xDestroyWindow (display, juce_messageWindowHandle);
juce_messageWindowHandle = 0;
X11Symbols::getInstance()->xSync (display, True);
LinuxEventLoop::unregisterFdCallback (X11Symbols::getInstance()->xConnectionNumber (display));
}
}
JUCE_IMPLEMENT_SINGLETON (XWindowSystem)
//==============================================================================
ScopedXDisplay::ScopedXDisplay()
: display (XWindowSystem::getInstance()->displayRef())
{
}
ScopedXDisplay::~ScopedXDisplay()
{
XWindowSystem::getInstance()->displayUnref();
}
//==============================================================================
ScopedXLock::ScopedXLock (::Display* d)
: display (d)
{
if (display != nullptr)
X11Symbols::getInstance()->xLockDisplay (display);
}
ScopedXLock::~ScopedXLock()
{
if (display != nullptr)
X11Symbols::getInstance()->xUnlockDisplay (display);
}
//==============================================================================
Atoms::Atoms (::Display* display)
{
protocols = getIfExists (display, "WM_PROTOCOLS");
protocolList [TAKE_FOCUS] = getIfExists (display, "WM_TAKE_FOCUS");
protocolList [DELETE_WINDOW] = getIfExists (display, "WM_DELETE_WINDOW");
protocolList [PING] = getIfExists (display, "_NET_WM_PING");
changeState = getIfExists (display, "WM_CHANGE_STATE");
state = getIfExists (display, "WM_STATE");
userTime = getCreating (display, "_NET_WM_USER_TIME");
activeWin = getCreating (display, "_NET_ACTIVE_WINDOW");
pid = getCreating (display, "_NET_WM_PID");
windowType = getIfExists (display, "_NET_WM_WINDOW_TYPE");
windowState = getIfExists (display, "_NET_WM_STATE");
XdndAware = getCreating (display, "XdndAware");
XdndEnter = getCreating (display, "XdndEnter");
XdndLeave = getCreating (display, "XdndLeave");
XdndPosition = getCreating (display, "XdndPosition");
XdndStatus = getCreating (display, "XdndStatus");
XdndDrop = getCreating (display, "XdndDrop");
XdndFinished = getCreating (display, "XdndFinished");
XdndSelection = getCreating (display, "XdndSelection");
XdndTypeList = getCreating (display, "XdndTypeList");
XdndActionList = getCreating (display, "XdndActionList");
XdndActionCopy = getCreating (display, "XdndActionCopy");
XdndActionPrivate = getCreating (display, "XdndActionPrivate");
XdndActionDescription = getCreating (display, "XdndActionDescription");
XembedMsgType = getCreating (display, "_XEMBED");
XembedInfo = getCreating (display, "_XEMBED_INFO");
allowedMimeTypes[0] = getCreating (display, "UTF8_STRING");
allowedMimeTypes[1] = getCreating (display, "text/plain;charset=utf-8");
allowedMimeTypes[2] = getCreating (display, "text/plain");
allowedMimeTypes[3] = getCreating (display, "text/uri-list");
allowedActions[0] = getCreating (display, "XdndActionMove");
allowedActions[1] = XdndActionCopy;
allowedActions[2] = getCreating (display, "XdndActionLink");
allowedActions[3] = getCreating (display, "XdndActionAsk");
allowedActions[4] = XdndActionPrivate;
}
Atom Atoms::getIfExists (::Display* display, const char* name) { return X11Symbols::getInstance()->xInternAtom (display, name, True); }
Atom Atoms::getCreating (::Display* display, const char* name) { return X11Symbols::getInstance()->xInternAtom (display, name, False); }
String Atoms::getName (::Display* display, const Atom atom)
{
if (atom == None)
return "None";
return X11Symbols::getInstance()->xGetAtomName (display, atom);
}
bool Atoms::isMimeTypeFile (::Display* display, const Atom atom)
{
return getName (display, atom).equalsIgnoreCase ("text/uri-list");
}
const unsigned long Atoms::DndVersion = 3;
//==============================================================================
GetXProperty::GetXProperty (::Display* display, Window window, Atom atom,
long offset, long length, bool shouldDelete,
Atom requestedType)
{
success = (X11Symbols::getInstance()->xGetWindowProperty (display, window, atom, offset, length,
(Bool) shouldDelete, requestedType, &actualType,
&actualFormat, &numItems, &bytesLeft, &data) == Success)
&& data != nullptr;
}
GetXProperty::~GetXProperty()
{
if (data != nullptr)
X11Symbols::getInstance()->xFree (data);
}
} // namespace juce

View file

@ -1,135 +0,0 @@
/*
==============================================================================
This file is part of the JUCE 6 technical preview.
Copyright (c) 2017 - ROLI Ltd.
You may use this code under the terms of the GPL v3
(see www.gnu.org/licenses).
For this technical preview, this file is not subject to commercial licensing.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
struct _XDisplay;
namespace juce
{
typedef ::_XDisplay* XDisplay;
typedef unsigned long AtomType;
typedef unsigned long WindowType;
//==============================================================================
class XWindowSystem : public DeletedAtShutdown
{
public:
XDisplay displayRef() noexcept;
XDisplay displayUnref() noexcept;
JUCE_DECLARE_SINGLETON (XWindowSystem, false)
private:
bool xIsAvailable = false;
XDisplay display = {};
Atomic<int> displayCount;
XWindowSystem() noexcept;
~XWindowSystem() noexcept;
void initialiseXDisplay() noexcept;
void destroyXDisplay() noexcept;
};
//==============================================================================
/** Creates and holds a reference to the X display.
@tags{GUI}
*/
struct ScopedXDisplay
{
ScopedXDisplay();
~ScopedXDisplay();
const XDisplay display;
};
//==============================================================================
/** A handy class that uses XLockDisplay and XUnlockDisplay to lock the X server
using RAII (Only available in Linux!).
@tags{GUI}
*/
class ScopedXLock
{
public:
/** Creating a ScopedXLock object locks the X display.
This uses XLockDisplay() to grab the display that JUCE is using.
*/
ScopedXLock (XDisplay);
/** Deleting a ScopedXLock object unlocks the X display.
This calls XUnlockDisplay() to release the lock.
*/
~ScopedXLock();
private:
XDisplay display;
};
//==============================================================================
struct Atoms
{
Atoms (XDisplay);
enum ProtocolItems
{
TAKE_FOCUS = 0,
DELETE_WINDOW = 1,
PING = 2
};
AtomType protocols, protocolList[3], changeState, state, userTime,
activeWin, pid, windowType, windowState,
XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus,
XdndDrop, XdndFinished, XdndSelection, XdndTypeList, XdndActionList,
XdndActionDescription, XdndActionCopy, XdndActionPrivate,
XembedMsgType, XembedInfo,
allowedActions[5],
allowedMimeTypes[4];
static const unsigned long DndVersion;
static AtomType getIfExists (XDisplay, const char* name);
static AtomType getCreating (XDisplay, const char* name);
static String getName (XDisplay, AtomType);
static bool isMimeTypeFile (XDisplay, AtomType);
};
//==============================================================================
struct GetXProperty
{
GetXProperty (XDisplay, WindowType, AtomType,
long offset, long length, bool shouldDelete,
AtomType requestedType);
~GetXProperty();
bool success;
unsigned char* data = nullptr;
unsigned long numItems, bytesLeft;
AtomType actualType;
int actualFormat;
};
} // namespace juce

View file

@ -1,272 +0,0 @@
/*
==============================================================================
This file is part of the JUCE 6 technical preview.
Copyright (c) 2017 - ROLI Ltd.
You may use this code under the terms of the GPL v3
(see www.gnu.org/licenses).
For this technical preview, this file is not subject to commercial licensing.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
extern ::Window juce_messageWindowHandle;
namespace ClipboardHelpers
{
static String localClipboardContent;
static Atom atom_UTF8_STRING;
static Atom atom_CLIPBOARD;
static Atom atom_TARGETS;
//==============================================================================
static void initSelectionAtoms (::Display* display)
{
static bool isInitialised = false;
if (! isInitialised)
{
isInitialised = true;
atom_UTF8_STRING = Atoms::getCreating (display, "UTF8_STRING");
atom_CLIPBOARD = Atoms::getCreating (display, "CLIPBOARD");
atom_TARGETS = Atoms::getCreating (display, "TARGETS");
}
}
//==============================================================================
// Read the content of a window property as either a locale-dependent string or an utf8 string
// works only for strings shorter than 1000000 bytes
static String readWindowProperty (::Display* display, Window window, Atom prop)
{
String returnData;
if (display != nullptr)
{
char* clipData;
Atom actualType;
int actualFormat;
unsigned long numItems, bytesLeft;
if (X11Symbols::getInstance()->xGetWindowProperty (display, window, prop,
0L /* offset */, 1000000 /* length (max) */, False,
AnyPropertyType /* format */,
&actualType, &actualFormat, &numItems, &bytesLeft,
(unsigned char**) &clipData) == Success)
{
if (actualType == atom_UTF8_STRING && actualFormat == 8)
returnData = String::fromUTF8 (clipData, (int) numItems);
else if (actualType == XA_STRING && actualFormat == 8)
returnData = String (clipData, numItems);
if (clipData != nullptr)
X11Symbols::getInstance()->xFree (clipData);
jassert (bytesLeft == 0 || numItems == 1000000);
}
X11Symbols::getInstance()->xDeleteProperty (display, window, prop);
}
return returnData;
}
//==============================================================================
// Send a SelectionRequest to the window owning the selection and waits for its answer (with a timeout) */
static bool requestSelectionContent (::Display* display, String& selectionContent,
Atom selection, Atom requestedFormat)
{
auto property_name = X11Symbols::getInstance()->xInternAtom (display, "JUCE_SEL", false);
// The selection owner will be asked to set the JUCE_SEL property on the
// juce_messageWindowHandle with the selection content
X11Symbols::getInstance()->xConvertSelection (display, selection, requestedFormat, property_name,
juce_messageWindowHandle, CurrentTime);
int count = 50; // will wait at most for 200 ms
while (--count >= 0)
{
XEvent event;
if (X11Symbols::getInstance()->xCheckTypedWindowEvent (display, juce_messageWindowHandle, SelectionNotify, &event))
{
if (event.xselection.property == property_name)
{
jassert (event.xselection.requestor == juce_messageWindowHandle);
selectionContent = readWindowProperty (display, event.xselection.requestor,
event.xselection.property);
return true;
}
return false; // the format we asked for was denied.. (event.xselection.property == None)
}
// not very elegant.. we could do a select() or something like that...
// however clipboard content requesting is inherently slow on x11, it
// often takes 50ms or more so...
Thread::sleep (4);
}
return false;
}
//==============================================================================
// Called from the event loop in juce_linux_Messaging in response to SelectionRequest events
static void handleSelection (XSelectionRequestEvent& evt)
{
ClipboardHelpers::initSelectionAtoms (evt.display);
// the selection content is sent to the target window as a window property
XSelectionEvent reply;
reply.type = SelectionNotify;
reply.display = evt.display;
reply.requestor = evt.requestor;
reply.selection = evt.selection;
reply.target = evt.target;
reply.property = None; // == "fail"
reply.time = evt.time;
HeapBlock<char> data;
int propertyFormat = 0;
size_t numDataItems = 0;
if (evt.selection == XA_PRIMARY || evt.selection == ClipboardHelpers::atom_CLIPBOARD)
{
if (evt.target == XA_STRING || evt.target == ClipboardHelpers::atom_UTF8_STRING)
{
// translate to utf8
numDataItems = ClipboardHelpers::localClipboardContent.getNumBytesAsUTF8() + 1;
data.calloc (numDataItems + 1);
ClipboardHelpers::localClipboardContent.copyToUTF8 (data, numDataItems);
propertyFormat = 8; // bits/item
}
else if (evt.target == ClipboardHelpers::atom_TARGETS)
{
// another application wants to know what we are able to send
numDataItems = 2;
propertyFormat = 32; // atoms are 32-bit
data.calloc (numDataItems * 4);
Atom* atoms = reinterpret_cast<Atom*> (data.getData());
atoms[0] = ClipboardHelpers::atom_UTF8_STRING;
atoms[1] = XA_STRING;
evt.target = XA_ATOM;
}
}
else
{
DBG ("requested unsupported clipboard");
}
if (data != nullptr)
{
const size_t maxReasonableSelectionSize = 1000000;
// for very big chunks of data, we should use the "INCR" protocol , which is a pain in the *ss
if (evt.property != None && numDataItems < maxReasonableSelectionSize)
{
X11Symbols::getInstance()->xChangeProperty (evt.display, evt.requestor,
evt.property, evt.target,
propertyFormat /* 8 or 32 */, PropModeReplace,
reinterpret_cast<const unsigned char*> (data.getData()), (int) numDataItems);
reply.property = evt.property; // " == success"
}
}
X11Symbols::getInstance()->xSendEvent (evt.display, evt.requestor, 0, NoEventMask, (XEvent*) &reply);
}
}
//==============================================================================
typedef void (*SelectionRequestCallback) (XSelectionRequestEvent&);
extern SelectionRequestCallback handleSelectionRequest;
struct ClipboardCallbackInitialiser
{
ClipboardCallbackInitialiser()
{
handleSelectionRequest = ClipboardHelpers::handleSelection;
}
};
static ClipboardCallbackInitialiser clipboardInitialiser;
//==============================================================================
void SystemClipboard::copyTextToClipboard (const String& clipText)
{
ScopedXDisplay xDisplay;
if (auto display = xDisplay.display)
{
ClipboardHelpers::initSelectionAtoms (display);
ClipboardHelpers::localClipboardContent = clipText;
X11Symbols::getInstance()->xSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (display, ClipboardHelpers::atom_CLIPBOARD, juce_messageWindowHandle, CurrentTime);
}
}
String SystemClipboard::getTextFromClipboard()
{
String content;
ScopedXDisplay xDisplay;
if (auto display = xDisplay.display)
{
ClipboardHelpers::initSelectionAtoms (display);
/* 1) try to read from the "CLIPBOARD" selection first (the "high
level" clipboard that is supposed to be filled by ctrl-C
etc). When a clipboard manager is running, the content of this
selection is preserved even when the original selection owner
exits.
2) and then try to read from "PRIMARY" selection (the "legacy" selection
filled by good old x11 apps such as xterm)
*/
Atom selection = XA_PRIMARY;
Window selectionOwner = None;
if ((selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selection)) == None)
{
selection = ClipboardHelpers::atom_CLIPBOARD;
selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selection);
}
if (selectionOwner != None)
{
if (selectionOwner == juce_messageWindowHandle)
{
content = ClipboardHelpers::localClipboardContent;
}
else
{
// first try: we want an utf8 string
bool ok = ClipboardHelpers::requestSelectionContent (display, content,
selection, ClipboardHelpers::atom_UTF8_STRING);
if (! ok)
{
// second chance, ask for a good old locale-dependent string ..
ok = ClipboardHelpers::requestSelectionContent (display, content,
selection, XA_STRING);
}
}
}
}
return content;
}
} // namespace juce

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,551 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
extern void* createDraggingHandCursor();
extern ComponentPeer* getPeerFor (::Window);
//==============================================================================
class X11DragState
{
public:
X11DragState() = default;
//==============================================================================
bool isDragging() const noexcept
{
return dragging;
}
//==============================================================================
void handleExternalSelectionClear()
{
if (dragging)
externalResetDragAndDrop();
}
void handleExternalSelectionRequest (const XEvent& evt)
{
auto targetType = evt.xselectionrequest.target;
XEvent s;
s.xselection.type = SelectionNotify;
s.xselection.requestor = evt.xselectionrequest.requestor;
s.xselection.selection = evt.xselectionrequest.selection;
s.xselection.target = targetType;
s.xselection.property = None;
s.xselection.time = evt.xselectionrequest.time;
if (allowedTypes.contains (targetType))
{
s.xselection.property = evt.xselectionrequest.property;
X11Symbols::getInstance()->xChangeProperty (getDisplay(), evt.xselectionrequest.requestor, evt.xselectionrequest.property,
targetType, 8, PropModeReplace,
reinterpret_cast<const unsigned char*> (textOrFiles.toRawUTF8()),
(int) textOrFiles.getNumBytesAsUTF8());
}
X11Symbols::getInstance()->xSendEvent (getDisplay(), evt.xselectionrequest.requestor, True, 0, &s);
}
void handleExternalDragAndDropStatus (const XClientMessageEvent& clientMsg)
{
if (expectingStatus)
{
expectingStatus = false;
canDrop = false;
silentRect = {};
if ((clientMsg.data.l[1] & 1) != 0
&& ((Atom) clientMsg.data.l[4] == getAtoms().XdndActionCopy
|| (Atom) clientMsg.data.l[4] == getAtoms().XdndActionPrivate))
{
if ((clientMsg.data.l[1] & 2) == 0) // target requests silent rectangle
silentRect.setBounds ((int) clientMsg.data.l[2] >> 16, (int) clientMsg.data.l[2] & 0xffff,
(int) clientMsg.data.l[3] >> 16, (int) clientMsg.data.l[3] & 0xffff);
canDrop = true;
}
}
}
void handleExternalDragButtonReleaseEvent()
{
if (dragging)
X11Symbols::getInstance()->xUngrabPointer (getDisplay(), CurrentTime);
if (canDrop)
{
sendExternalDragAndDropDrop();
}
else
{
sendExternalDragAndDropLeave();
externalResetDragAndDrop();
}
}
void handleExternalDragMotionNotify()
{
auto newTargetWindow = externalFindDragTargetWindow (X11Symbols::getInstance()->xRootWindow (getDisplay(),
X11Symbols::getInstance()->xDefaultScreen (getDisplay())));
if (targetWindow != newTargetWindow)
{
if (targetWindow != None)
sendExternalDragAndDropLeave();
canDrop = false;
silentRect = {};
if (newTargetWindow == None)
return;
xdndVersion = getDnDVersionForWindow (newTargetWindow);
if (xdndVersion == -1)
return;
targetWindow = newTargetWindow;
sendExternalDragAndDropEnter();
}
if (! expectingStatus)
sendExternalDragAndDropPosition();
}
void handleDragAndDropPosition (const XClientMessageEvent& clientMsg, ComponentPeer* peer)
{
if (dragAndDropSourceWindow == 0)
return;
dragAndDropSourceWindow = (::Window) clientMsg.data.l[0];
if (windowH == 0)
windowH = (::Window) peer->getNativeHandle();
auto dropPos = Desktop::getInstance().getDisplays().physicalToLogical (Point<int> ((int) clientMsg.data.l[2] >> 16,
(int) clientMsg.data.l[2] & 0xffff));
dropPos -= peer->getBounds().getPosition();
auto targetAction = getAtoms().XdndActionCopy;
for (int i = numElementsInArray (getAtoms().allowedActions); --i >= 0;)
{
if ((Atom) clientMsg.data.l[4] == getAtoms().allowedActions[i])
{
targetAction = getAtoms().allowedActions[i];
break;
}
}
sendDragAndDropStatus (true, targetAction);
if (dragInfo.position != dropPos)
{
dragInfo.position = dropPos;
if (dragInfo.isEmpty())
updateDraggedFileList (clientMsg, (::Window) peer->getNativeHandle());
if (! dragInfo.isEmpty())
peer->handleDragMove (dragInfo);
}
}
void handleDragAndDropDrop (const XClientMessageEvent& clientMsg, ComponentPeer* peer)
{
if (dragInfo.isEmpty())
{
// no data, transaction finished in handleDragAndDropSelection()
finishAfterDropDataReceived = true;
updateDraggedFileList (clientMsg, (::Window) peer->getNativeHandle());
}
else
{
handleDragAndDropDataReceived(); // data was already received
}
}
void handleDragAndDropEnter (const XClientMessageEvent& clientMsg, ComponentPeer* peer)
{
dragInfo.clear();
srcMimeTypeAtomList.clear();
dragAndDropCurrentMimeType = 0;
auto dndCurrentVersion = static_cast<unsigned long> (clientMsg.data.l[1] & 0xff000000) >> 24;
if (dndCurrentVersion < 3 || dndCurrentVersion > XWindowSystemUtilities::Atoms::DndVersion)
{
dragAndDropSourceWindow = 0;
return;
}
dragAndDropSourceWindow = (::Window) clientMsg.data.l[0];
if ((clientMsg.data.l[1] & 1) != 0)
{
XWindowSystemUtilities::ScopedXLock xLock;
XWindowSystemUtilities::GetXProperty prop (dragAndDropSourceWindow, getAtoms().XdndTypeList, 0, 0x8000000L, false, XA_ATOM);
if (prop.success && prop.actualType == XA_ATOM && prop.actualFormat == 32 && prop.numItems != 0)
{
auto* types = prop.data;
for (unsigned long i = 0; i < prop.numItems; ++i)
{
unsigned long type;
memcpy (&type, types, sizeof (unsigned long));
if (type != None)
srcMimeTypeAtomList.add (type);
types += sizeof (unsigned long);
}
}
}
if (srcMimeTypeAtomList.isEmpty())
{
for (int i = 2; i < 5; ++i)
if (clientMsg.data.l[i] != None)
srcMimeTypeAtomList.add ((unsigned long) clientMsg.data.l[i]);
if (srcMimeTypeAtomList.isEmpty())
{
dragAndDropSourceWindow = 0;
return;
}
}
for (int i = 0; i < srcMimeTypeAtomList.size() && dragAndDropCurrentMimeType == 0; ++i)
for (int j = 0; j < numElementsInArray (getAtoms().allowedMimeTypes); ++j)
if (srcMimeTypeAtomList[i] == getAtoms().allowedMimeTypes[j])
dragAndDropCurrentMimeType = getAtoms().allowedMimeTypes[j];
handleDragAndDropPosition (clientMsg, peer);
}
void handleDragAndDropExit()
{
if (auto* peer = getPeerFor (windowH))
peer->handleDragExit (dragInfo);
}
void handleDragAndDropSelection (const XEvent& evt)
{
dragInfo.clear();
if (evt.xselection.property != None)
{
StringArray lines;
{
MemoryBlock dropData;
for (;;)
{
XWindowSystemUtilities::GetXProperty prop (evt.xany.window, evt.xselection.property,
(long) (dropData.getSize() / 4), 65536, false, AnyPropertyType);
if (! prop.success)
break;
dropData.append (prop.data, (size_t) (prop.actualFormat / 8) * prop.numItems);
if (prop.bytesLeft <= 0)
break;
}
lines.addLines (dropData.toString());
}
if (XWindowSystemUtilities::Atoms::isMimeTypeFile (getDisplay(), dragAndDropCurrentMimeType))
{
for (int i = 0; i < lines.size(); ++i)
dragInfo.files.add (URL::removeEscapeChars (lines[i].replace ("file://", String(), true)));
dragInfo.files.trim();
dragInfo.files.removeEmptyStrings();
}
else
{
dragInfo.text = lines.joinIntoString ("\n");
}
if (finishAfterDropDataReceived)
handleDragAndDropDataReceived();
}
}
void externalResetDragAndDrop()
{
if (dragging)
{
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xUngrabPointer (getDisplay(), CurrentTime);
}
if (completionCallback != nullptr)
completionCallback();
}
bool externalDragInit (::Window window, bool text, const String& str, std::function<void()>&& cb)
{
windowH = window;
isText = text;
textOrFiles = str;
targetWindow = windowH;
completionCallback = std::move (cb);
allowedTypes.add (XWindowSystemUtilities::Atoms::getCreating (getDisplay(), isText ? "text/plain" : "text/uri-list"));
auto pointerGrabMask = (unsigned int) (Button1MotionMask | ButtonReleaseMask);
XWindowSystemUtilities::ScopedXLock xLock;
if (X11Symbols::getInstance()->xGrabPointer (getDisplay(), windowH, True, pointerGrabMask,
GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == GrabSuccess)
{
// No other method of changing the pointer seems to work, this call is needed from this very context
X11Symbols::getInstance()->xChangeActivePointerGrab (getDisplay(), pointerGrabMask, (Cursor) createDraggingHandCursor(), CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (getDisplay(), getAtoms().XdndSelection, windowH, CurrentTime);
// save the available types to XdndTypeList
X11Symbols::getInstance()->xChangeProperty (getDisplay(), windowH, getAtoms().XdndTypeList, XA_ATOM, 32, PropModeReplace,
reinterpret_cast<const unsigned char*> (allowedTypes.getRawDataPointer()), allowedTypes.size());
dragging = true;
xdndVersion = getDnDVersionForWindow (targetWindow);
sendExternalDragAndDropEnter();
handleExternalDragMotionNotify();
return true;
}
return false;
}
private:
//==============================================================================
XWindowSystemUtilities::Atoms& getAtoms() const { return XWindowSystem::getInstance()->getAtoms(); }
::Display* getDisplay() const { return XWindowSystem::getInstance()->getDisplay(); }
//==============================================================================
void sendDragAndDropMessage (XClientMessageEvent& msg)
{
msg.type = ClientMessage;
msg.display = getDisplay();
msg.window = dragAndDropSourceWindow;
msg.format = 32;
msg.data.l[0] = (long) windowH;
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xSendEvent (getDisplay(), dragAndDropSourceWindow, False, 0, (XEvent*) &msg);
}
bool sendExternalDragAndDropMessage (XClientMessageEvent& msg)
{
msg.type = ClientMessage;
msg.display = getDisplay();
msg.window = targetWindow;
msg.format = 32;
msg.data.l[0] = (long) windowH;
XWindowSystemUtilities::ScopedXLock xLock;
return X11Symbols::getInstance()->xSendEvent (getDisplay(), targetWindow, False, 0, (XEvent*) &msg) != 0;
}
void sendExternalDragAndDropDrop()
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndDrop;
msg.data.l[2] = CurrentTime;
sendExternalDragAndDropMessage (msg);
}
void sendExternalDragAndDropEnter()
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndEnter;
msg.data.l[1] = (xdndVersion << 24);
for (int i = 0; i < 3; ++i)
msg.data.l[i + 2] = (long) allowedTypes[i];
sendExternalDragAndDropMessage (msg);
}
void sendExternalDragAndDropPosition()
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndPosition;
auto mousePos = Desktop::getInstance().getMousePosition();
if (silentRect.contains (mousePos)) // we've been asked to keep silent
return;
mousePos = Desktop::getInstance().getDisplays().logicalToPhysical (mousePos);
msg.data.l[1] = 0;
msg.data.l[2] = (mousePos.x << 16) | mousePos.y;
msg.data.l[3] = CurrentTime;
msg.data.l[4] = (long) getAtoms().XdndActionCopy; // this is all JUCE currently supports
expectingStatus = sendExternalDragAndDropMessage (msg);
}
void sendDragAndDropStatus (bool acceptDrop, Atom dropAction)
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndStatus;
msg.data.l[1] = (acceptDrop ? 1 : 0) | 2; // 2 indicates that we want to receive position messages
msg.data.l[4] = (long) dropAction;
sendDragAndDropMessage (msg);
}
void sendExternalDragAndDropLeave()
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndLeave;
sendExternalDragAndDropMessage (msg);
}
void sendDragAndDropFinish()
{
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndFinished;
sendDragAndDropMessage (msg);
}
void updateDraggedFileList (const XClientMessageEvent& clientMsg, ::Window requestor)
{
jassert (dragInfo.isEmpty());
if (dragAndDropSourceWindow != None && dragAndDropCurrentMimeType != None)
{
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xConvertSelection (getDisplay(), getAtoms().XdndSelection, dragAndDropCurrentMimeType,
XWindowSystemUtilities::Atoms::getCreating (getDisplay(), "JXSelectionWindowProperty"),
requestor, (::Time) clientMsg.data.l[2]);
}
}
bool isWindowDnDAware (::Window w) const
{
int numProperties = 0;
auto* properties = X11Symbols::getInstance()->xListProperties (getDisplay(), w, &numProperties);
bool dndAwarePropFound = false;
for (int i = 0; i < numProperties; ++i)
if (properties[i] == getAtoms().XdndAware)
dndAwarePropFound = true;
if (properties != nullptr)
X11Symbols::getInstance()->xFree (properties);
return dndAwarePropFound;
}
int getDnDVersionForWindow (::Window target)
{
XWindowSystemUtilities::GetXProperty prop (target, getAtoms().XdndAware, 0, 2, false, AnyPropertyType);
if (prop.success && prop.data != None && prop.actualFormat == 32 && prop.numItems == 1)
return jmin ((int) prop.data[0], (int) XWindowSystemUtilities::Atoms::DndVersion);
return -1;
}
::Window externalFindDragTargetWindow (::Window target)
{
if (target == None)
return None;
if (isWindowDnDAware (target))
return target;
::Window child, phonyWin;
int phony;
unsigned int uphony;
X11Symbols::getInstance()->xQueryPointer (getDisplay(), target, &phonyWin, &child, &phony, &phony, &phony, &phony, &uphony);
return externalFindDragTargetWindow (child);
}
void handleDragAndDropDataReceived()
{
ComponentPeer::DragInfo dragInfoCopy (dragInfo);
sendDragAndDropFinish();
if (! dragInfoCopy.isEmpty())
if (auto* peer = getPeerFor (windowH))
peer->handleDragDrop (dragInfoCopy);
}
//==============================================================================
::Window windowH = 0, targetWindow = 0, dragAndDropSourceWindow = 0;
int xdndVersion = -1;
bool isText = false, dragging = false, expectingStatus = false, canDrop = false, finishAfterDropDataReceived = false;
Atom dragAndDropCurrentMimeType;
Array<Atom> allowedTypes, srcMimeTypeAtomList;
ComponentPeer::DragInfo dragInfo;
Rectangle<int> silentRect;
String textOrFiles;
std::function<void()> completionCallback = nullptr;
//==============================================================================
JUCE_LEAK_DETECTOR (X11DragState)
};
} // namespace juce

View file

@ -43,7 +43,7 @@ namespace ReturnHelpers
//==============================================================================
class JUCE_API X11Symbols : public DeletedAtShutdown
class JUCE_API X11Symbols
{
public:
//==============================================================================
@ -223,7 +223,7 @@ public:
char*)
JUCE_GENERATE_FUNCTION_WITH_DEFAULT (XGetErrorDatabaseText, xGetErrorDatabaseText,
(::Display*, char*, const char*, const char*, int),
(::Display*, const char*, const char*, const char*, const char*, int),
void)
JUCE_GENERATE_FUNCTION_WITH_DEFAULT (XGetErrorText, xGetErrorText,

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,233 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
namespace XWindowSystemUtilities
{
//==============================================================================
/** A handy struct that uses XLockDisplay and XUnlockDisplay to lock the X server
using RAII.
@tags{GUI}
*/
struct ScopedXLock
{
ScopedXLock();
~ScopedXLock();
};
//==============================================================================
/** Gets a specified window property and stores its associated data, freeing it
on deletion.
@tags{GUI}
*/
struct GetXProperty
{
GetXProperty (::Window windowH, Atom property, long offset,
long length, bool shouldDelete, Atom requestedType);
~GetXProperty();
bool success = false;
unsigned char* data = nullptr;
unsigned long numItems = 0, bytesLeft = 0;
Atom actualType;
int actualFormat = -1;
};
//==============================================================================
/** Initialises and stores some atoms for the display.
@tags{GUI}
*/
struct Atoms
{
enum ProtocolItems
{
TAKE_FOCUS = 0,
DELETE_WINDOW = 1,
PING = 2
};
Atoms (::Display*);
static Atom getIfExists (::Display*, const char* name);
static Atom getCreating (::Display*, const char* name);
static String getName (::Display*, Atom);
static bool isMimeTypeFile (::Display*, Atom);
static constexpr unsigned long DndVersion = 3;
Atom protocols, protocolList[3], changeState, state, userTime, activeWin, pid, windowType, windowState,
XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus, XdndDrop, XdndFinished, XdndSelection,
XdndTypeList, XdndActionList, XdndActionDescription, XdndActionCopy, XdndActionPrivate,
XembedMsgType, XembedInfo, allowedActions[5], allowedMimeTypes[4], utf8String, clipboard, targets;
};
}
//==============================================================================
template<typename WindowHandle>
class LinuxComponentPeer;
class XWindowSystem : public DeletedAtShutdown
{
public:
//==============================================================================
::Window createWindow (::Window parentWindow, LinuxComponentPeer<::Window>* peer) const;
void destroyWindow (::Window windowH);
void setTitle (::Window windowH, const String& title) const;
void setIcon (::Window windowH, const Image& newIcon) const;
void setVisible (::Window windowH, bool shouldBeVisible) const;
void setBounds (::Window windowH, Rectangle<int> newBounds, bool fullScreen) const;
BorderSize<int> getBorderSize (::Window windowH) const;
Rectangle<int> getWindowBounds (::Window windowH, ::Window parentWindow);
Point<int> getParentScreenPosition() const;
bool contains (::Window windowH, Point<int> localPos) const;
void setMinimised (::Window windowH, bool shouldBeMinimised) const;
bool isMinimised (::Window windowH) const;
void toFront (::Window windowH, bool makeActive) const;
void toBehind (::Window windowH, ::Window otherWindow) const;
bool isFocused (::Window windowH) const;
bool grabFocus (::Window windowH) const;
bool canUseSemiTransparentWindows() const;
bool canUseARGBImages() const;
int getNumPaintsPending (::Window windowH) const;
Image createImage (int width, int height, bool argb) const;
void blitToWindow (::Window windowH, Image image, Rectangle<int> destinationRect, Rectangle<int> totalRect) const;
void setScreenSaverEnabled (bool enabled) const;
Point<float> getCurrentMousePosition() const;
void setMousePosition (Point<float> pos) const;
void* createCustomMouseCursorInfo (const Image& image, Point<int> hotspot) const;
void deleteMouseCursor (void* cursorHandle) const;
void* createStandardMouseCursor (MouseCursor::StandardCursorType type) const;
void showCursor (::Window windowH, void* cursorHandle) const;
bool isKeyCurrentlyDown (int keyCode) const;
ModifierKeys getNativeRealtimeModifiers() const;
Array<Displays::Display> findDisplays (float masterScale) const;
::Window createKeyProxy (::Window windowH) const;
void deleteKeyProxy (::Window keyProxy) const;
bool externalDragFileInit (LinuxComponentPeer<::Window>* peer, const StringArray& files, bool canMove, std::function<void()>&& callback) const;
bool externalDragTextInit (LinuxComponentPeer<::Window>* peer, const String& text, std::function<void()>&& callback) const;
void copyTextToClipboard (const String& clipText);
String getTextFromClipboard() const;
String getLocalClipboardContent() const { return localClipboardContent; }
::Display* getDisplay() { return display; }
XWindowSystemUtilities::Atoms& getAtoms() { jassert (atoms.get() != nullptr); return *atoms; }
//==============================================================================
void handleWindowMessage (LinuxComponentPeer<::Window>* peer, XEvent& event) const;
//==============================================================================
JUCE_DECLARE_SINGLETON (XWindowSystem, false)
private:
XWindowSystem();
~XWindowSystem();
//==============================================================================
void initialiseXDisplay();
void destroyXDisplay();
//==============================================================================
::Window getFocusWindow (::Window windowH) const;
bool isParentWindowOf (::Window windowH, ::Window possibleChild) const;
bool isFrontWindow (::Window windowH) const;
//==============================================================================
void xchangeProperty (::Window windowH, Atom property, Atom type, int format, const void* data, int numElements) const;
void removeWindowDecorations (::Window windowH) const;
void addWindowButtons (::Window windowH, int styleFlags) const;
void setWindowType (::Window windowH, int styleFlags) const;
void initialisePointerMap();
void deleteIconPixmaps (::Window windowH) const;
void updateModifierMappings() const;
long getUserTime (::Window windowH) const;
//==============================================================================
void handleKeyPressEvent (LinuxComponentPeer<::Window>*, XKeyEvent&) const;
void handleKeyReleaseEvent (LinuxComponentPeer<::Window>*, const XKeyEvent&) const;
void handleWheelEvent (LinuxComponentPeer<::Window>*, const XButtonPressedEvent&, float) const;
void handleButtonPressEvent (LinuxComponentPeer<::Window>*, const XButtonPressedEvent&, int) const;
void handleButtonPressEvent (LinuxComponentPeer<::Window>*, const XButtonPressedEvent&) const;
void handleButtonReleaseEvent (LinuxComponentPeer<::Window>*, const XButtonReleasedEvent&) const;
void handleMotionNotifyEvent (LinuxComponentPeer<::Window>*, const XPointerMovedEvent&) const;
void handleEnterNotifyEvent (LinuxComponentPeer<::Window>*, const XEnterWindowEvent&) const;
void handleLeaveNotifyEvent (LinuxComponentPeer<::Window>*, const XLeaveWindowEvent&) const;
void handleFocusInEvent (LinuxComponentPeer<::Window>*) const;
void handleFocusOutEvent (LinuxComponentPeer<::Window>*) const;
void handleExposeEvent (LinuxComponentPeer<::Window>*, XExposeEvent&) const;
void handleConfigureNotifyEvent (LinuxComponentPeer<::Window>*, XConfigureEvent&) const;
void handleGravityNotify (LinuxComponentPeer<::Window>*) const;
void handleMappingNotify (XMappingEvent&) const;
void handleClientMessageEvent (LinuxComponentPeer<::Window>*, XClientMessageEvent&, XEvent&) const;
void handleXEmbedMessage (LinuxComponentPeer<::Window>*, XClientMessageEvent&) const;
//==============================================================================
bool xIsAvailable = false;
std::unique_ptr<XWindowSystemUtilities::Atoms> atoms;
::Display* display = nullptr;
Colormap colormap = {};
Visual* visual = nullptr;
int depth = 0, shmCompletionEvent = 0;
int pointerMap[5] = {};
String localClipboardContent;
Point<int> parentScreenPosition;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XWindowSystem)
};
} // namespace juce

View file

@ -24,17 +24,16 @@ class SystemTrayIconComponent::Pimpl
public:
Pimpl (const Image& im, Window windowH) : image (im)
{
ScopedXDisplay xDisplay;
auto display = xDisplay.display;
XWindowSystemUtilities::ScopedXLock xLock;
ScopedXLock xlock (display);
auto* display = XWindowSystem::getInstance()->getDisplay();
auto* screen = X11Symbols::getInstance()->xDefaultScreenOfDisplay (display);
auto screenNumber = X11Symbols::getInstance()->xScreenNumberOfScreen (screen);
String screenAtom ("_NET_SYSTEM_TRAY_S");
screenAtom << screenNumber;
Atom selectionAtom = Atoms::getCreating (display, screenAtom.toUTF8());
Atom selectionAtom = XWindowSystemUtilities::Atoms::getCreating (display, screenAtom.toUTF8());
X11Symbols::getInstance()->xGrabServer (display);
auto managerWin = X11Symbols::getInstance()->xGetSelectionOwner (display, selectionAtom);
@ -50,7 +49,7 @@ public:
XEvent ev = { 0 };
ev.xclient.type = ClientMessage;
ev.xclient.window = managerWin;
ev.xclient.message_type = Atoms::getCreating (display, "_NET_SYSTEM_TRAY_OPCODE");
ev.xclient.message_type = XWindowSystemUtilities::Atoms::getCreating (display, "_NET_SYSTEM_TRAY_OPCODE");
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/;
@ -64,12 +63,12 @@ public:
// For older KDE's ...
long atomData = 1;
Atom trayAtom = Atoms::getCreating (display, "KWM_DOCKWINDOW");
Atom trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "KWM_DOCKWINDOW");
X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, trayAtom,
32, PropModeReplace, (unsigned char*) &atomData, 1);
// For more recent KDE's...
trayAtom = Atoms::getCreating (display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, XA_WINDOW,
32, PropModeReplace, (unsigned char*) &windowH, 1);

View file

@ -23,8 +23,8 @@ bool juce_handleXEmbedEvent (ComponentPeer*, void*);
Window juce_getCurrentFocusWindow (ComponentPeer*);
//==============================================================================
unsigned long juce_createKeyProxyWindow (ComponentPeer*);
void juce_deleteKeyProxyWindow (ComponentPeer*);
::Window juce_createKeyProxyWindow (ComponentPeer*);
void juce_deleteKeyProxyWindow (::Window);
//==============================================================================
enum
@ -75,7 +75,7 @@ public:
~SharedKeyWindow()
{
juce_deleteKeyProxyWindow (keyPeer);
juce_deleteKeyProxyWindow (keyProxy);
auto& keyWindows = getKeyWindows();
keyWindows.remove (keyPeer);
@ -130,8 +130,12 @@ public:
//==============================================================================
Pimpl (XEmbedComponent& parent, Window x11Window,
bool wantsKeyboardFocus, bool isClientInitiated, bool shouldAllowResize)
: owner (parent), atoms (x11display.display), clientInitiated (isClientInitiated),
wantsFocus (wantsKeyboardFocus), allowResize (shouldAllowResize)
: owner (parent),
infoAtom (XWindowSystem::getInstance()->getAtoms().XembedInfo),
messageTypeAtom (XWindowSystem::getInstance()->getAtoms().XembedMsgType),
clientInitiated (isClientInitiated),
wantsFocus (wantsKeyboardFocus),
allowResize (shouldAllowResize)
{
getWidgets().add (this);
@ -254,9 +258,7 @@ private:
//==============================================================================
XEmbedComponent& owner;
Window client = 0, host = 0;
ScopedXDisplay x11display;
Atoms atoms;
Atom infoAtom, messageTypeAtom;
bool clientInitiated;
bool wantsFocus = false;
@ -372,12 +374,12 @@ private:
return {};
}
Display* getDisplay() { return reinterpret_cast<Display*> (x11display.display); }
Display* getDisplay() { return XWindowSystem::getInstance()->getDisplay(); }
//==============================================================================
bool getXEmbedMappedFlag()
{
GetXProperty embedInfo (x11display.display, client, atoms.XembedInfo, 0, 2, false, atoms.XembedInfo);
XWindowSystemUtilities::GetXProperty embedInfo (client, infoAtom, 0, 2, false, infoAtom);
if (embedInfo.success && embedInfo.actualFormat == 32
&& embedInfo.numItems >= 2 && embedInfo.data != nullptr)
@ -405,7 +407,7 @@ private:
//==============================================================================
void propertyChanged (const Atom& a)
{
if (a == atoms.XembedInfo)
if (a == infoAtom)
updateMapping();
}
@ -561,7 +563,7 @@ private:
return true;
case ClientMessage:
if (e.xclient.message_type == atoms.XembedMsgType && e.xclient.format == 32)
if (e.xclient.message_type == messageTypeAtom && e.xclient.format == 32)
{
handleXembedCmd ((::Time) e.xclient.data.l[0], e.xclient.data.l[1],
e.xclient.data.l[2], e.xclient.data.l[3],
@ -588,7 +590,7 @@ private:
::memset (&msg, 0, sizeof (XClientMessageEvent));
msg.window = client;
msg.type = ClientMessage;
msg.message_type = atoms.XembedMsgType;
msg.message_type = messageTypeAtom;
msg.format = 32;
msg.data.l[0] = (long) xTime;
msg.data.l[1] = opcode;

View file

@ -23,7 +23,6 @@ extern XContext windowHandleXContext;
//==============================================================================
// Defined juce_linux_Windowing.cpp
Rectangle<int> juce_LinuxScaledToPhysicalBounds (ComponentPeer*, Rectangle<int>);
void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
void juce_LinuxRemoveRepaintListener (ComponentPeer*, Component* dummy);
@ -55,9 +54,10 @@ public:
OpenGLVersion)
: component (comp), contextToShareWith (shareContext), dummy (*this)
{
display = XWindowSystem::getInstance()->displayRef();
display = XWindowSystem::getInstance()->getDisplay();
XWindowSystemUtilities::ScopedXLock xLock;
ScopedXLock xlock (display);
X11Symbols::getInstance()->xSync (display, False);
GLint attribs[] =
@ -95,7 +95,7 @@ public:
auto glBounds = component.getTopLevelComponent()
->getLocalArea (&component, component.getLocalBounds());
glBounds = juce_LinuxScaledToPhysicalBounds (peer, glBounds);
glBounds = Desktop::getInstance().getDisplays().logicalToPhysical (glBounds);
embeddedWindow = X11Symbols::getInstance()->xCreateWindow (display, windowH,
glBounds.getX(), glBounds.getY(),
@ -123,20 +123,18 @@ public:
if (embeddedWindow != 0)
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xUnmapWindow (display, embeddedWindow);
X11Symbols::getInstance()->xDestroyWindow (display, embeddedWindow);
}
if (bestVisual != nullptr)
X11Symbols::getInstance()->xFree (bestVisual);
XWindowSystem::getInstance()->displayUnref();
}
bool initialiseOnRenderThread (OpenGLContext& c)
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
c.makeActive();
context = &c;
@ -146,7 +144,7 @@ public:
void shutdownOnRenderThread()
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
context = nullptr;
deactivateCurrentContext();
glXDestroyContext (display, renderContext);
@ -155,36 +153,38 @@ public:
bool makeActive() const noexcept
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
return renderContext != nullptr
&& glXMakeCurrent (display, embeddedWindow, renderContext);
}
bool isActive() const noexcept
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
return glXGetCurrentContext() == renderContext && renderContext != nullptr;
}
static void deactivateCurrentContext()
{
ScopedXDisplay xDisplay;
ScopedXLock xlock (xDisplay.display);
glXMakeCurrent (xDisplay.display, None, nullptr);
if (auto* display = XWindowSystem::getInstance()->getDisplay())
{
XWindowSystemUtilities::ScopedXLock xLock;
glXMakeCurrent (display, None, nullptr);
}
}
void swapBuffers()
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
glXSwapBuffers (display, embeddedWindow);
}
void updateWindowPosition (Rectangle<int> newBounds)
{
bounds = newBounds;
auto physicalBounds = juce_LinuxScaledToPhysicalBounds (component.getPeer(), bounds);
auto physicalBounds = Desktop::getInstance().getDisplays().logicalToPhysical (bounds);
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xMoveResizeWindow (display, embeddedWindow,
physicalBounds.getX(), physicalBounds.getY(),
(unsigned int) jmax (1, physicalBounds.getWidth()),
@ -199,7 +199,7 @@ public:
if (auto GLXSwapIntervalSGI
= (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI"))
{
ScopedXLock xlock (display);
XWindowSystemUtilities::ScopedXLock xLock;
swapFrames = numFramesPerSwap;
GLXSwapIntervalSGI (numFramesPerSwap);
return true;
@ -228,13 +228,13 @@ private:
int swapFrames = 0;
Rectangle<int> bounds;
XVisualInfo* bestVisual = {};
XVisualInfo* bestVisual = nullptr;
void* contextToShareWith;
OpenGLContext* context = {};
OpenGLContext* context = nullptr;
DummyComponent dummy;
::Display* display = {};
::Display* display = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};
@ -242,15 +242,8 @@ private:
//==============================================================================
bool OpenGLHelpers::isContextActive()
{
ScopedXDisplay xDisplay;
if (xDisplay.display)
{
ScopedXLock xlock (xDisplay.display);
return glXGetCurrentContext() != nullptr;
}
return false;
XWindowSystemUtilities::ScopedXLock xLock;
return glXGetCurrentContext() != nullptr;
}
} // namespace juce