75 : keyPeer (peerToUse),
76 keyProxy (juce_createKeyProxyWindow (keyPeer)),
77 association (peerToUse, keyProxy)
83 juce_deleteKeyProxyWindow (keyProxy);
85 auto& keyWindows = getKeyWindows();
86 keyWindows.remove (keyPeer);
92 Window getHandle() {
return keyProxy; }
94 static Window getCurrentFocusWindow (
ComponentPeer* peerToLookFor)
96 auto& keyWindows = getKeyWindows();
98 if (peerToLookFor !=
nullptr)
99 if (
auto* foundKeyWindow = keyWindows[peerToLookFor])
100 return foundKeyWindow->keyProxy;
107 jassert (peerToLookFor !=
nullptr);
109 auto& keyWindows = getKeyWindows();
110 auto foundKeyWindow = keyWindows[peerToLookFor];
112 if (foundKeyWindow ==
nullptr)
115 keyWindows.set (peerToLookFor, foundKeyWindow);
118 return foundKeyWindow;
138 bool wantsKeyboardFocus,
bool isClientInitiated,
bool shouldAllowResize)
140 infoAtom (
XWindowSystem::getInstance()->getAtoms().XembedInfo),
141 messageTypeAtom (
XWindowSystem::getInstance()->getAtoms().XembedMsgType),
142 clientInitiated (isClientInitiated),
143 wantsFocus (wantsKeyboardFocus),
144 allowResize (shouldAllowResize)
146 getWidgets().add (
this);
151 setClient (x11Window,
true);
164 auto dpy = getDisplay();
166 X11Symbols::getInstance()->xDestroyWindow (dpy, host);
167 X11Symbols::getInstance()->xSync (dpy,
false);
169 auto mask = NoEventMask | KeyPressMask | KeyReleaseMask
170 | EnterWindowMask | LeaveWindowMask | PointerMotionMask
171 | KeymapStateMask | ExposureMask | StructureNotifyMask
175 while (X11Symbols::getInstance()->xCheckWindowEvent (dpy, host, mask, &event) == True)
181 getWidgets().removeAllInstancesOf (
this);
185 void setClient (Window xembedClient,
bool shouldReparent)
189 if (xembedClient != 0)
191 auto dpy = getDisplay();
193 client = xembedClient;
203 auto newBounds = getX11BoundsFromJuce();
204 X11Symbols::getInstance()->xResizeWindow (dpy, client,
static_cast<unsigned int> (newBounds.getWidth()),
205 static_cast<unsigned int> (newBounds.getHeight()));
208 auto eventMask = StructureNotifyMask | PropertyChangeMask | FocusChangeMask;
210 XWindowAttributes clientAttr;
211 X11Symbols::getInstance()->xGetWindowAttributes (dpy, client, &clientAttr);
213 if ((eventMask & clientAttr.your_event_mask) != eventMask)
214 X11Symbols::getInstance()->xSelectInput (dpy, client, clientAttr.your_event_mask | eventMask);
216 getXEmbedMappedFlag();
219 X11Symbols::getInstance()->xReparentWindow (dpy, client, host, 0, 0);
222 sendXEmbedEvent (CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, (
long) host, xembedVersion);
230 if (client != 0 && supportsXembed && wantsFocus)
233 sendXEmbedEvent (CurrentTime, XEMBED_FOCUS_IN,
240 if (client != 0 && supportsXembed && wantsFocus)
242 sendXEmbedEvent (CurrentTime, XEMBED_FOCUS_OUT);
247 void broughtToFront()
249 if (client != 0 && supportsXembed)
250 sendXEmbedEvent (CurrentTime, XEMBED_WINDOW_ACTIVATE);
253 unsigned long getHostWindowID()
263 void updateEmbeddedBounds()
265 componentMovedOrResized (owner,
true,
true);
270 XEmbedComponent& owner;
271 Window client = 0, host = 0;
272 Atom infoAtom, messageTypeAtom;
274 bool clientInitiated;
275 bool wantsFocus =
false;
276 bool allowResize =
false;
277 bool supportsXembed =
false;
278 bool hasBeenMapped =
false;
279 int xembedVersion = maxXEmbedVersionToSupport;
281 ComponentPeer* lastPeer =
nullptr;
282 SharedKeyWindow::Ptr keyWindow;
285 void componentParentHierarchyChanged (
Component&)
override { peerChanged (owner.getPeer()); }
286 void componentMovedOrResized (
Component&,
bool,
bool)
override
288 if (host != 0 && lastPeer !=
nullptr)
290 auto dpy = getDisplay();
291 auto newBounds = getX11BoundsFromJuce();
292 XWindowAttributes attr;
294 if (X11Symbols::getInstance()->xGetWindowAttributes (dpy, host, &attr))
296 Rectangle<int> currentBounds (attr.x, attr.y, attr.width, attr.height);
297 if (currentBounds != newBounds)
299 X11Symbols::getInstance()->xMoveResizeWindow (dpy, host, newBounds.getX(), newBounds.getY(),
300 static_cast<unsigned int> (newBounds.getWidth()),
301 static_cast<unsigned int> (newBounds.getHeight()));
305 if (client != 0 && X11Symbols::getInstance()->xGetWindowAttributes (dpy, client, &attr))
307 Rectangle<int> currentBounds (attr.x, attr.y, attr.width, attr.height);
309 if ((currentBounds.getWidth() != newBounds.getWidth()
310 || currentBounds.getHeight() != newBounds.getHeight()))
312 X11Symbols::getInstance()->xMoveResizeWindow (dpy, client, 0, 0,
313 static_cast<unsigned int> (newBounds.getWidth()),
314 static_cast<unsigned int> (newBounds.getHeight()));
321 void createHostWindow()
323 auto dpy = getDisplay();
324 int defaultScreen = X11Symbols::getInstance()->xDefaultScreen (dpy);
325 Window root = X11Symbols::getInstance()->xRootWindow (dpy, defaultScreen);
327 XSetWindowAttributes swa;
328 swa.border_pixel = 0;
329 swa.background_pixmap = None;
330 swa.override_redirect = True;
331 swa.event_mask = SubstructureNotifyMask | StructureNotifyMask | FocusChangeMask;
333 host = X11Symbols::getInstance()->xCreateWindow (dpy, root, 0, 0, 1, 1, 0, CopyFromParent,
334 InputOutput, CopyFromParent,
335 CWEventMask | CWBorderPixel | CWBackPixmap | CWOverrideRedirect,
343 auto dpy = getDisplay();
344 X11Symbols::getInstance()->xSelectInput (dpy, client, 0);
348 int defaultScreen = X11Symbols::getInstance()->xDefaultScreen (dpy);
349 Window root = X11Symbols::getInstance()->xRootWindow (dpy, defaultScreen);
353 X11Symbols::getInstance()->xUnmapWindow (dpy, client);
354 hasBeenMapped =
false;
357 X11Symbols::getInstance()->xReparentWindow (dpy, client, root, 0, 0);
360 X11Symbols::getInstance()->xSync (dpy, False);
368 const bool shouldBeMapped = getXEmbedMappedFlag();
370 if (shouldBeMapped != hasBeenMapped)
372 hasBeenMapped = shouldBeMapped;
375 X11Symbols::getInstance()->xMapWindow (getDisplay(), client);
377 X11Symbols::getInstance()->xUnmapWindow (getDisplay(), client);
382 Window getParentX11Window()
384 if (
auto* peer = owner.getPeer())
385 return reinterpret_cast<Window
> (peer->getNativeHandle());
390 Display* getDisplay() {
return XWindowSystem::getInstance()->getDisplay(); }
393 bool getXEmbedMappedFlag()
395 XWindowSystemUtilities::GetXProperty embedInfo (getDisplay(), client, infoAtom, 0, 2,
false, infoAtom);
397 if (embedInfo.success && embedInfo.actualFormat == 32
398 && embedInfo.numItems >= 2 && embedInfo.data !=
nullptr)
401 memcpy (&version, embedInfo.data, sizeof (
long));
403 supportsXembed =
true;
404 xembedVersion =
jmin ((
int) maxXEmbedVersionToSupport, (
int) version);
407 memcpy (&flags, embedInfo.data + sizeof (
long),
sizeof (
long));
409 return ((flags & XEMBED_MAPPED) != 0);
413 supportsXembed =
false;
414 xembedVersion = maxXEmbedVersionToSupport;
421 void propertyChanged (
const Atom& a)
427 void configureNotify()
429 XWindowAttributes attr;
430 auto dpy = getDisplay();
432 if (X11Symbols::getInstance()->xGetWindowAttributes (dpy, client, &attr))
434 XWindowAttributes hostAttr;
436 if (X11Symbols::getInstance()->xGetWindowAttributes (dpy, host, &hostAttr))
437 if (attr.width != hostAttr.width || attr.height != hostAttr.height)
438 X11Symbols::getInstance()->xResizeWindow (dpy, host, (
unsigned int) attr.width, (
unsigned int) attr.height);
443 auto* peer = owner.getPeer();
444 const double scale = (peer !=
nullptr ? peer->getPlatformScaleFactor()
445 : displays.getPrimaryDisplay()->scale);
447 Point<int> topLeftInPeer
448 = (peer !=
nullptr ? peer->getComponent().getLocalPoint (&owner, Point<int> (0, 0))
451 Rectangle<int> newBounds (topLeftInPeer.getX(), topLeftInPeer.getY(),
452 static_cast<int> (
static_cast<double> (attr.width) / scale),
453 static_cast<int> (
static_cast<double> (attr.height) / scale));
457 newBounds = owner.getLocalArea (&peer->getComponent(), newBounds);
459 jassert (newBounds.getX() == 0 && newBounds.getY() == 0);
461 if (newBounds != owner.getLocalBounds())
462 owner.setSize (newBounds.getWidth(), newBounds.getHeight());
466 void peerChanged (ComponentPeer* newPeer)
468 if (newPeer != lastPeer)
470 if (lastPeer !=
nullptr)
473 auto dpy = getDisplay();
474 Window rootWindow = X11Symbols::getInstance()->xRootWindow (dpy, DefaultScreen (dpy));
475 Rectangle<int> newBounds = getX11BoundsFromJuce();
477 if (newPeer ==
nullptr)
478 X11Symbols::getInstance()->xUnmapWindow (dpy, host);
480 Window newParent = (newPeer !=
nullptr ? getParentX11Window() : rootWindow);
481 X11Symbols::getInstance()->xReparentWindow (dpy, host, newParent, newBounds.getX(), newBounds.getY());
485 if (newPeer !=
nullptr)
489 keyWindow = SharedKeyWindow::getKeyWindowForPeer (newPeer);
493 componentMovedOrResized (owner,
true,
true);
494 X11Symbols::getInstance()->xMapWindow (dpy, host);
501 void updateKeyFocus()
503 if (lastPeer !=
nullptr && lastPeer->isFocused())
504 X11Symbols::getInstance()->xSetInputFocus (getDisplay(), getCurrentFocusWindow (lastPeer), RevertToParent, CurrentTime);
508 void handleXembedCmd (const ::Time& ,
long opcode,
long ,
long ,
long )
512 case XEMBED_REQUEST_FOCUS:
514 owner.grabKeyboardFocus();
517 case XEMBED_FOCUS_NEXT:
519 owner.moveKeyboardFocusToSibling (
true);
522 case XEMBED_FOCUS_PREV:
524 owner.moveKeyboardFocusToSibling (
false);
532 bool handleX11Event (
const XEvent& e)
534 if (e.xany.window == client && client != 0)
539 propertyChanged (e.xproperty.atom);
542 case ConfigureNotify:
554 else if (e.xany.window == host && host != 0)
559 if (e.xreparent.parent == host && e.xreparent.window != client)
561 setClient (e.xreparent.window,
false);
567 if (e.xcreatewindow.parent != e.xcreatewindow.window && e.xcreatewindow.parent == host && e.xcreatewindow.window != client)
569 setClient (e.xcreatewindow.window,
false);
575 componentMovedOrResized (owner,
true,
true);
579 if (e.xclient.message_type == messageTypeAtom && e.xclient.format == 32)
581 handleXembedCmd ((::Time) e.xclient.data.l[0], e.xclient.data.l[1],
582 e.xclient.data.l[2], e.xclient.data.l[3],
583 e.xclient.data.l[4]);
597 void sendXEmbedEvent (const ::Time& xTime,
long opcode,
598 long opcodeMinor = 0,
long data1 = 0,
long data2 = 0)
600 XClientMessageEvent msg;
601 auto dpy = getDisplay();
603 ::memset (&msg, 0,
sizeof (XClientMessageEvent));
605 msg.type = ClientMessage;
606 msg.message_type = messageTypeAtom;
608 msg.data.l[0] = (
long) xTime;
609 msg.data.l[1] = opcode;
610 msg.data.l[2] = opcodeMinor;
611 msg.data.l[3] = data1;
612 msg.data.l[4] = data2;
614 X11Symbols::getInstance()->xSendEvent (dpy, client, False, NoEventMask, (XEvent*) &msg);
615 X11Symbols::getInstance()->xSync (dpy, False);
618 Rectangle<int> getX11BoundsFromJuce()
620 if (
auto* peer = owner.getPeer())
622 auto r = peer->getComponent().getLocalArea (&owner, owner.getLocalBounds());
623 return r * peer->getPlatformScaleFactor() * peer->getComponent().getDesktopScaleFactor();
626 return owner.getLocalBounds();
630 friend bool juce::juce_handleXEmbedEvent (ComponentPeer*,
void*);
631 friend unsigned long juce::juce_getCurrentFocusWindow (ComponentPeer*);
633 static Array<Pimpl*>& getWidgets()
635 static Array<Pimpl*> i;
639 static bool dispatchX11Event (ComponentPeer* p,
const XEvent* eventArg)
641 if (eventArg !=
nullptr)
645 if (
auto w = e.xany.window)
646 for (
auto* widget : getWidgets())
647 if (w == widget->host || w == widget->client)
648 return widget->handleX11Event (e);
652 for (
auto* widget : getWidgets())
653 if (widget->owner.
getPeer() == p)
654 widget->peerChanged (nullptr);
660 static Window getCurrentFocusWindow (ComponentPeer* p)
664 for (
auto* widget : getWidgets())
666 return widget->client;
669 return SharedKeyWindow::getCurrentFocusWindow (p);