1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-29 02:40:05 +00:00

Linux: Improved XEmbed support

This commit makes some minor improvements to the XEmbedComponent class and adds support for embedding JUCE windows in other hosts using the XEmbed protocol. It also includes some minor fixes for X11 peers when they have a parent window.
This commit is contained in:
ed 2019-06-27 14:21:44 +01:00
parent fd76cbc70d
commit f9dad9d608
3 changed files with 103 additions and 82 deletions

View file

@ -139,4 +139,39 @@ struct GetXProperty
int actualFormat;
};
//==============================================================================
enum
{
maxXEmbedVersionToSupport = 0
};
enum
{
XEMBED_MAPPED = (1<<0)
};
enum
{
XEMBED_EMBEDDED_NOTIFY = 0,
XEMBED_WINDOW_ACTIVATE = 1,
XEMBED_WINDOW_DEACTIVATE = 2,
XEMBED_REQUEST_FOCUS = 3,
XEMBED_FOCUS_IN = 4,
XEMBED_FOCUS_OUT = 5,
XEMBED_FOCUS_NEXT = 6,
XEMBED_FOCUS_PREV = 7,
XEMBED_MODALITY_ON = 10,
XEMBED_MODALITY_OFF = 11,
XEMBED_REGISTER_ACCELERATOR = 12,
XEMBED_UNREGISTER_ACCELERATOR = 13,
XEMBED_ACTIVATE_ACCELERATOR = 14
};
enum
{
XEMBED_FOCUS_CURRENT = 0,
XEMBED_FOCUS_FIRST = 1,
XEMBED_FOCUS_LAST = 2
};
} // namespace juce

View file

@ -1163,6 +1163,20 @@ public:
}
}
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); });
}
}
void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override
{
if (fullScreen && ! isNowFullScreen)
@ -1200,16 +1214,10 @@ public:
bounds = newBounds.withSize (jmax (1, newBounds.getWidth()),
jmax (1, newBounds.getHeight()));
auto& displays = Desktop::getInstance().getDisplays();
updateScaleFactorFromNewBounds (bounds, false);
auto newScaleFactor = displays.findDisplayForRect (bounds, true).scale / Desktop::getInstance().getGlobalScaleFactor();
if (! approximatelyEqual (newScaleFactor, currentScaleFactor))
{
currentScaleFactor = newScaleFactor;
scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (currentScaleFactor); });
}
auto physicalBounds = displays.logicalToPhysical (bounds);
auto physicalBounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
: bounds * currentScaleFactor);
WeakReference<Component> deletionChecker (&component);
ScopedXLock xlock (display);
@ -1245,21 +1253,21 @@ public:
}
}
Rectangle<int> getBounds() const override { return bounds; }
Point<float> localToGlobal (Point<float> relativePosition) override
Point<int> getScreenPosition (bool physical) const
{
return relativePosition + bounds.getPosition().toFloat();
if (physical)
return Desktop::getInstance().getDisplays().logicalToPhysical (bounds.getTopLeft());
return bounds.getTopLeft();
}
Rectangle<int> getBounds() const override { return bounds; }
using ComponentPeer::localToGlobal;
Point<float> globalToLocal (Point<float> screenPosition) override
{
return screenPosition - bounds.getPosition().toFloat();
}
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(); }
void setAlpha (float /* newAlpha */) override
{
@ -1624,7 +1632,7 @@ public:
case ClientMessage: handleClientMessageEvent (event.xclient, event); break;
case SelectionNotify: handleDragAndDropSelection (event); break;
case ConfigureNotify: handleConfigureNotifyEvent (event.xconfigure); break;
case ReparentNotify: handleReparentNotifyEvent(); break;
case ReparentNotify:
case GravityNotify: handleGravityNotify(); break;
case SelectionClear: handleExternalSelectionClear(); break;
case SelectionRequest: handleExternalSelectionRequest (event); break;
@ -2012,24 +2020,6 @@ public:
handleBroughtToFront();
}
void handleReparentNotifyEvent()
{
parentWindow = 0;
Window wRoot = 0;
Window* wChild = nullptr;
unsigned int numChildren;
{
ScopedXLock xlock (display);
XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren);
}
if (parentWindow == windowH || parentWindow == wRoot)
parentWindow = 0;
handleGravityNotify();
}
void handleGravityNotify()
{
updateWindowBounds();
@ -2112,6 +2102,10 @@ public:
{
externalResetDragAndDrop();
}
else if (clientMsg.message_type == atoms->XembedMsgType && clientMsg.format == 32)
{
handleXEmbedMessage (clientMsg);
}
}
bool externalDragTextInit (const String& text, std::function<void()> cb)
@ -2140,6 +2134,27 @@ public:
return externalDragInit (false, uriList.joinIntoString ("\r\n"), cb);
}
void handleXEmbedMessage (XClientMessageEvent& clientMsg)
{
switch (clientMsg.data.l[1])
{
case XEMBED_EMBEDDED_NOTIFY:
parentWindow = (::Window) clientMsg.data.l[3];
updateWindowBounds();
component.setBounds (bounds);
break;
case XEMBED_FOCUS_IN:
handleFocusInEvent();
break;
case XEMBED_FOCUS_OUT:
handleFocusOutEvent();
break;
default:
break;
}
}
//==============================================================================
void showMouseCursor (Cursor cursor) noexcept
{
@ -2714,6 +2729,9 @@ private:
xchangeProperty (windowH, atoms->XdndActionDescription, XA_STRING, 8, "", 0);
xchangeProperty (windowH, atoms->XdndAware, XA_ATOM, 32, &atoms->DndVersion, 1);
unsigned long info[2] = { 0, 1 };
xchangeProperty (windowH, atoms->XembedInfo, atoms->XembedInfo, 32, (unsigned char*) info, 2);
initialisePointerMap();
updateModifierMappings();
}
@ -2823,21 +2841,16 @@ private:
ScopedXLock xlock (display);
if (XGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth))
if (XGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth) && parentWindow == 0)
if (! XTranslateCoordinates (display, windowH, root, 0, 0, &wx, &wy, &child))
wx = wy = 0;
Rectangle<int> physicalBounds (wx, wy, (int) ww, (int) wh);
auto& displays = Desktop::getInstance().getDisplays();
auto newScaleFactor = displays.findDisplayForRect (physicalBounds, true).scale / Desktop::getInstance().getGlobalScaleFactor();
if (! approximatelyEqual (newScaleFactor, currentScaleFactor))
{
currentScaleFactor = newScaleFactor;
scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (currentScaleFactor); });
}
updateScaleFactorFromNewBounds (physicalBounds, true);
bounds = displays.physicalToLogical (physicalBounds);
bounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
: physicalBounds / currentScaleFactor);
}
}

View file

@ -38,40 +38,6 @@ void juce_deleteKeyProxyWindow (ComponentPeer*);
class XEmbedComponent::Pimpl : private ComponentListener
{
public:
enum
{
maxXEmbedVersionToSupport = 0
};
enum Flags
{
XEMBED_MAPPED = (1<<0)
};
enum
{
XEMBED_EMBEDDED_NOTIFY = 0,
XEMBED_WINDOW_ACTIVATE = 1,
XEMBED_WINDOW_DEACTIVATE = 2,
XEMBED_REQUEST_FOCUS = 3,
XEMBED_FOCUS_IN = 4,
XEMBED_FOCUS_OUT = 5,
XEMBED_FOCUS_NEXT = 6,
XEMBED_FOCUS_PREV = 7,
XEMBED_MODALITY_ON = 10,
XEMBED_MODALITY_OFF = 11,
XEMBED_REGISTER_ACCELERATOR = 12,
XEMBED_UNREGISTER_ACCELERATOR = 13,
XEMBED_ACTIVATE_ACCELERATOR = 14
};
enum
{
XEMBED_FOCUS_CURRENT = 0,
XEMBED_FOCUS_FIRST = 1,
XEMBED_FOCUS_LAST = 2
};
//==============================================================================
struct SharedKeyWindow : public ReferenceCountedObject
{
@ -201,7 +167,14 @@ public:
static_cast<unsigned int> (newBounds.getHeight()));
}
XSelectInput (dpy, client, StructureNotifyMask | PropertyChangeMask | FocusChangeMask);
auto eventMask = StructureNotifyMask | PropertyChangeMask | FocusChangeMask;
XWindowAttributes clientAttr;
XGetWindowAttributes (dpy, client, &clientAttr);
if ((eventMask & clientAttr.your_event_mask) != eventMask)
XSelectInput (dpy, client, clientAttr.your_event_mask | eventMask);
getXEmbedMappedFlag();
if (shouldReparent)
@ -365,7 +338,7 @@ private:
Window getParentX11Window()
{
if (auto peer = owner.getPeer())
if (auto* peer = owner.getPeer())
return reinterpret_cast<Window> (peer->getNativeHandle());
return {};