The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
25KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. //==============================================================================
  20. bool juce_handleXEmbedEvent (ComponentPeer*, void*);
  21. Window juce_getCurrentFocusWindow (ComponentPeer*);
  22. //==============================================================================
  23. unsigned long juce_createKeyProxyWindow (ComponentPeer*);
  24. void juce_deleteKeyProxyWindow (ComponentPeer*);
  25. //==============================================================================
  26. class XEmbedComponent::Pimpl : private ComponentListener
  27. {
  28. public:
  29. enum
  30. {
  31. maxXEmbedVersionToSupport = 0
  32. };
  33. enum Flags
  34. {
  35. XEMBED_MAPPED = (1<<0)
  36. };
  37. enum
  38. {
  39. XEMBED_EMBEDDED_NOTIFY = 0,
  40. XEMBED_WINDOW_ACTIVATE = 1,
  41. XEMBED_WINDOW_DEACTIVATE = 2,
  42. XEMBED_REQUEST_FOCUS = 3,
  43. XEMBED_FOCUS_IN = 4,
  44. XEMBED_FOCUS_OUT = 5,
  45. XEMBED_FOCUS_NEXT = 6,
  46. XEMBED_FOCUS_PREV = 7,
  47. XEMBED_MODALITY_ON = 10,
  48. XEMBED_MODALITY_OFF = 11,
  49. XEMBED_REGISTER_ACCELERATOR = 12,
  50. XEMBED_UNREGISTER_ACCELERATOR = 13,
  51. XEMBED_ACTIVATE_ACCELERATOR = 14
  52. };
  53. enum
  54. {
  55. XEMBED_FOCUS_CURRENT = 0,
  56. XEMBED_FOCUS_FIRST = 1,
  57. XEMBED_FOCUS_LAST = 2
  58. };
  59. //==============================================================================
  60. class SharedKeyWindow
  61. {
  62. public:
  63. //==============================================================================
  64. struct Ref
  65. {
  66. Ref() {}
  67. Ref (Pimpl& p) { keyWindow = getKeyWindowForPeer (p.owner.getPeer()); }
  68. ~Ref() { free(); }
  69. //==============================================================================
  70. Ref (const Ref& o) : keyWindow (o.keyWindow) { if (keyWindow != nullptr) keyWindow->numRefs++; }
  71. Ref (Ref&& o) : keyWindow (o.keyWindow) { o.keyWindow = nullptr; }
  72. Ref (std::nullptr_t) {}
  73. //==============================================================================
  74. Ref& operator= (std::nullptr_t) { free(); return *this; }
  75. Ref& operator= (const Ref& o)
  76. {
  77. free();
  78. keyWindow = o.keyWindow;
  79. if (keyWindow != nullptr)
  80. keyWindow->numRefs++;
  81. return *this;
  82. }
  83. Ref& operator= (Ref && o)
  84. {
  85. if (keyWindow != o.keyWindow)
  86. {
  87. free();
  88. keyWindow = o.keyWindow;
  89. }
  90. o.keyWindow = nullptr;
  91. return *this;
  92. }
  93. //==============================================================================
  94. SharedKeyWindow& operator*() noexcept { return *keyWindow; }
  95. SharedKeyWindow* operator->() noexcept { return keyWindow; }
  96. //==============================================================================
  97. bool operator== (std::nullptr_t) const noexcept { return (keyWindow == nullptr); }
  98. bool operator!= (std::nullptr_t) const noexcept { return (keyWindow != nullptr); }
  99. private:
  100. //==============================================================================
  101. void free()
  102. {
  103. if (keyWindow != nullptr)
  104. {
  105. if (--keyWindow->numRefs == 0)
  106. delete keyWindow;
  107. keyWindow = nullptr;
  108. }
  109. }
  110. SharedKeyWindow* keyWindow = nullptr;
  111. };
  112. public:
  113. //==============================================================================
  114. Window getHandle() { return keyProxy; }
  115. static Window getCurrentFocusWindow (ComponentPeer* peerToLookFor)
  116. {
  117. if (keyWindows != nullptr && peerToLookFor != nullptr)
  118. if (auto* foundKeyWindow = (*keyWindows)[peerToLookFor])
  119. return foundKeyWindow->keyProxy;
  120. return {};
  121. }
  122. private:
  123. //==============================================================================
  124. SharedKeyWindow (ComponentPeer* peerToUse)
  125. : keyPeer (peerToUse),
  126. keyProxy (juce_createKeyProxyWindow (keyPeer))
  127. {}
  128. ~SharedKeyWindow()
  129. {
  130. juce_deleteKeyProxyWindow (keyPeer);
  131. if (keyWindows != nullptr)
  132. {
  133. keyWindows->remove (keyPeer);
  134. if (keyWindows->size() == 0)
  135. {
  136. delete keyWindows;
  137. keyWindows = nullptr;
  138. }
  139. }
  140. }
  141. ComponentPeer* keyPeer;
  142. Window keyProxy;
  143. int numRefs = 1;
  144. static SharedKeyWindow* getKeyWindowForPeer (ComponentPeer* peerToLookFor)
  145. {
  146. jassert (peerToLookFor != nullptr);
  147. if (keyWindows == nullptr)
  148. keyWindows = new HashMap<ComponentPeer*,SharedKeyWindow*>;
  149. auto foundKeyWindow = (*keyWindows)[peerToLookFor];
  150. if (foundKeyWindow == nullptr)
  151. {
  152. foundKeyWindow = new SharedKeyWindow (peerToLookFor);
  153. keyWindows->set (peerToLookFor, foundKeyWindow);
  154. }
  155. return foundKeyWindow;
  156. }
  157. //==============================================================================
  158. friend struct Ref;
  159. static HashMap<ComponentPeer*, SharedKeyWindow*>* keyWindows;
  160. };
  161. public:
  162. //==============================================================================
  163. Pimpl (XEmbedComponent& parent, Window x11Window,
  164. bool wantsKeyboardFocus, bool isClientInitiated, bool shouldAllowResize)
  165. : owner (parent), atoms (x11display.display), clientInitiated (isClientInitiated),
  166. wantsFocus (wantsKeyboardFocus), allowResize (shouldAllowResize)
  167. {
  168. getWidgets().add (this);
  169. createHostWindow();
  170. if (clientInitiated)
  171. setClient (x11Window, true);
  172. owner.setWantsKeyboardFocus (wantsFocus);
  173. owner.addComponentListener (this);
  174. }
  175. ~Pimpl()
  176. {
  177. owner.removeComponentListener (this);
  178. setClient (0, true);
  179. if (host != 0)
  180. {
  181. auto dpy = getDisplay();
  182. XDestroyWindow (dpy, host);
  183. XSync (dpy, false);
  184. const long mask = NoEventMask | KeyPressMask | KeyReleaseMask
  185. | EnterWindowMask | LeaveWindowMask | PointerMotionMask
  186. | KeymapStateMask | ExposureMask | StructureNotifyMask
  187. | FocusChangeMask;
  188. XEvent event;
  189. while (XCheckWindowEvent (dpy, host, mask, &event) == True)
  190. {}
  191. host = 0;
  192. }
  193. getWidgets().removeAllInstancesOf (this);
  194. }
  195. //==============================================================================
  196. void setClient (Window xembedClient, bool shouldReparent)
  197. {
  198. removeClient();
  199. if (xembedClient != 0)
  200. {
  201. auto dpy = getDisplay();
  202. client = xembedClient;
  203. // if the client has initiated the component then keep the clients size
  204. // otherwise the client should use the host's window' size
  205. if (clientInitiated)
  206. {
  207. configureNotify();
  208. }
  209. else
  210. {
  211. auto newBounds = getX11BoundsFromJuce();
  212. XResizeWindow (dpy, client, static_cast<unsigned int> (newBounds.getWidth()),
  213. static_cast<unsigned int> (newBounds.getHeight()));
  214. }
  215. XSelectInput (dpy, client, StructureNotifyMask | PropertyChangeMask | FocusChangeMask);
  216. getXEmbedMappedFlag();
  217. if (shouldReparent)
  218. XReparentWindow (dpy, client, host, 0, 0);
  219. if (supportsXembed)
  220. sendXEmbedEvent (CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, (long) host, xembedVersion);
  221. updateMapping();
  222. }
  223. }
  224. void focusGained (FocusChangeType changeType)
  225. {
  226. if (client != 0 && supportsXembed && wantsFocus)
  227. {
  228. updateKeyFocus();
  229. sendXEmbedEvent (CurrentTime, XEMBED_FOCUS_IN,
  230. (changeType == focusChangedByTabKey ? XEMBED_FOCUS_FIRST : XEMBED_FOCUS_CURRENT));
  231. }
  232. }
  233. void focusLost (FocusChangeType)
  234. {
  235. if (client != 0 && supportsXembed && wantsFocus)
  236. {
  237. sendXEmbedEvent (CurrentTime, XEMBED_FOCUS_OUT);
  238. updateKeyFocus();
  239. }
  240. }
  241. void broughtToFront()
  242. {
  243. if (client != 0 && supportsXembed)
  244. sendXEmbedEvent (CurrentTime, XEMBED_WINDOW_ACTIVATE);
  245. }
  246. unsigned long getHostWindowID()
  247. {
  248. // You are using the client initiated version of the protocol. You cannot
  249. // retrieve the window id of the host. Please read the documentation for
  250. // the XEmebedComponent class.
  251. jassert (! clientInitiated);
  252. return host;
  253. }
  254. private:
  255. //==============================================================================
  256. XEmbedComponent& owner;
  257. Window client = 0, host = 0;
  258. ScopedXDisplay x11display;
  259. Atoms atoms;
  260. bool clientInitiated;
  261. bool wantsFocus = false;
  262. bool allowResize = false;
  263. bool supportsXembed = false;
  264. bool hasBeenMapped = false;
  265. int xembedVersion = maxXEmbedVersionToSupport;
  266. ComponentPeer* lastPeer = nullptr;
  267. SharedKeyWindow::Ref keyWindow;
  268. //==============================================================================
  269. void componentParentHierarchyChanged (Component&) override { peerChanged (owner.getPeer()); }
  270. void componentMovedOrResized (Component&, bool, bool) override
  271. {
  272. if (host != 0 && lastPeer != nullptr)
  273. {
  274. auto dpy = getDisplay();
  275. auto newBounds = getX11BoundsFromJuce();
  276. XWindowAttributes attr;
  277. if (XGetWindowAttributes (dpy, host, &attr))
  278. {
  279. Rectangle<int> currentBounds (attr.x, attr.y, attr.width, attr.height);
  280. if (currentBounds != newBounds)
  281. {
  282. XMoveResizeWindow (dpy, host, newBounds.getX(), newBounds.getY(),
  283. static_cast<unsigned int> (newBounds.getWidth()),
  284. static_cast<unsigned int> (newBounds.getHeight()));
  285. }
  286. }
  287. if (client != 0 && XGetWindowAttributes (dpy, client, &attr))
  288. {
  289. Rectangle<int> currentBounds (attr.x, attr.y, attr.width, attr.height);
  290. if ((currentBounds.getWidth() != newBounds.getWidth()
  291. || currentBounds.getHeight() != newBounds.getHeight()))
  292. {
  293. XMoveResizeWindow (dpy, client, 0, 0,
  294. static_cast<unsigned int> (newBounds.getWidth()),
  295. static_cast<unsigned int> (newBounds.getHeight()));
  296. }
  297. }
  298. }
  299. }
  300. //==============================================================================
  301. void createHostWindow()
  302. {
  303. auto dpy = getDisplay();
  304. int defaultScreen = XDefaultScreen (dpy);
  305. Window root = RootWindow (dpy, defaultScreen);
  306. XSetWindowAttributes swa;
  307. swa.border_pixel = 0;
  308. swa.background_pixmap = None;
  309. swa.override_redirect = True;
  310. swa.event_mask = SubstructureNotifyMask | StructureNotifyMask | FocusChangeMask;
  311. host = XCreateWindow (dpy, root, 0, 0, 1, 1, 0, CopyFromParent,
  312. InputOutput, CopyFromParent,
  313. CWEventMask | CWBorderPixel | CWBackPixmap | CWOverrideRedirect,
  314. &swa);
  315. }
  316. void removeClient()
  317. {
  318. if (client != 0)
  319. {
  320. auto dpy = getDisplay();
  321. XSelectInput (dpy, client, 0);
  322. keyWindow = nullptr;
  323. int defaultScreen = XDefaultScreen (dpy);
  324. Window root = RootWindow (dpy, defaultScreen);
  325. if (hasBeenMapped)
  326. {
  327. XUnmapWindow (dpy, client);
  328. hasBeenMapped = false;
  329. }
  330. XReparentWindow (dpy, client, root, 0, 0);
  331. client = 0;
  332. }
  333. }
  334. void updateMapping()
  335. {
  336. if (client != 0)
  337. {
  338. const bool shouldBeMapped = getXEmbedMappedFlag();
  339. if (shouldBeMapped != hasBeenMapped)
  340. {
  341. hasBeenMapped = shouldBeMapped;
  342. if (shouldBeMapped)
  343. XMapWindow (getDisplay(), client);
  344. else
  345. XUnmapWindow (getDisplay(), client);
  346. }
  347. }
  348. }
  349. Window getParentX11Window()
  350. {
  351. if (auto peer = owner.getPeer())
  352. return reinterpret_cast<Window> (peer->getNativeHandle());
  353. return {};
  354. }
  355. Display* getDisplay() { return reinterpret_cast<Display*> (x11display.display); }
  356. //==============================================================================
  357. bool getXEmbedMappedFlag()
  358. {
  359. GetXProperty embedInfo (x11display.display, client, atoms.XembedInfo, 0, 2, false, atoms.XembedInfo);
  360. if (embedInfo.success && embedInfo.actualFormat == 32
  361. && embedInfo.numItems >= 2 && embedInfo.data != nullptr)
  362. {
  363. auto* buffer = (long*) embedInfo.data;
  364. supportsXembed = true;
  365. xembedVersion = jmin ((int) maxXEmbedVersionToSupport, (int) buffer[0]);
  366. return ((buffer[1] & XEMBED_MAPPED) != 0);
  367. }
  368. else
  369. {
  370. supportsXembed = false;
  371. xembedVersion = maxXEmbedVersionToSupport;
  372. }
  373. return true;
  374. }
  375. //==============================================================================
  376. void propertyChanged (const Atom& a)
  377. {
  378. if (a == atoms.XembedInfo)
  379. updateMapping();
  380. }
  381. void configureNotify()
  382. {
  383. XWindowAttributes attr;
  384. auto dpy = getDisplay();
  385. if (XGetWindowAttributes (dpy, client, &attr))
  386. {
  387. XWindowAttributes hostAttr;
  388. if (XGetWindowAttributes (dpy, host, &hostAttr))
  389. if (attr.width != hostAttr.width || attr.height != hostAttr.height)
  390. XResizeWindow (dpy, host, (unsigned int) attr.width, (unsigned int) attr.height);
  391. // as the client window is not on any screen yet, we need to guess
  392. // on which screen it might appear to get a scaling factor :-(
  393. auto& displays = Desktop::getInstance().getDisplays();
  394. auto* peer = owner.getPeer();
  395. const double scale = (peer != nullptr ? displays.getDisplayContaining (peer->getBounds().getCentre())
  396. : displays.getMainDisplay()).scale;
  397. Point<int> topLeftInPeer
  398. = (peer != nullptr ? peer->getComponent().getLocalPoint (&owner, Point<int> (0, 0))
  399. : owner.getBounds().getTopLeft());
  400. Rectangle<int> newBounds (topLeftInPeer.getX(), topLeftInPeer.getY(),
  401. static_cast<int> (static_cast<double> (attr.width) / scale),
  402. static_cast<int> (static_cast<double> (attr.height) / scale));
  403. if (peer != nullptr)
  404. newBounds = owner.getLocalArea (&peer->getComponent(), newBounds);
  405. jassert (newBounds.getX() == 0 && newBounds.getY() == 0);
  406. if (newBounds != owner.getLocalBounds())
  407. owner.setSize (newBounds.getWidth(), newBounds.getHeight());
  408. }
  409. }
  410. void peerChanged (ComponentPeer* newPeer)
  411. {
  412. if (newPeer != lastPeer)
  413. {
  414. if (lastPeer != nullptr)
  415. keyWindow = nullptr;
  416. auto dpy = getDisplay();
  417. Window rootWindow = RootWindow (dpy, DefaultScreen (dpy));
  418. Rectangle<int> newBounds = getX11BoundsFromJuce();
  419. if (newPeer == nullptr)
  420. XUnmapWindow (dpy, host);
  421. Window newParent = (newPeer != nullptr ? getParentX11Window() : rootWindow);
  422. XReparentWindow (dpy, host, newParent, newBounds.getX(), newBounds.getY());
  423. lastPeer = newPeer;
  424. if (newPeer != nullptr)
  425. {
  426. if (wantsFocus)
  427. {
  428. keyWindow = SharedKeyWindow::Ref (*this);
  429. updateKeyFocus();
  430. }
  431. componentMovedOrResized (owner, true, true);
  432. XMapWindow (dpy, host);
  433. broughtToFront();
  434. }
  435. }
  436. }
  437. void updateKeyFocus()
  438. {
  439. if (lastPeer != nullptr && lastPeer->isFocused())
  440. XSetInputFocus (getDisplay(), getCurrentFocusWindow (lastPeer), RevertToParent, CurrentTime);
  441. }
  442. //==============================================================================
  443. void handleXembedCmd (const ::Time& /*xTime*/, long opcode, long /*detail*/, long /*data1*/, long /*data2*/)
  444. {
  445. switch (opcode)
  446. {
  447. case XEMBED_REQUEST_FOCUS:
  448. if (wantsFocus)
  449. owner.grabKeyboardFocus();
  450. break;
  451. case XEMBED_FOCUS_NEXT:
  452. if (wantsFocus)
  453. owner.moveKeyboardFocusToSibling (true);
  454. break;
  455. case XEMBED_FOCUS_PREV:
  456. if (wantsFocus)
  457. owner.moveKeyboardFocusToSibling (false);
  458. break;
  459. }
  460. }
  461. bool handleX11Event (const XEvent& e)
  462. {
  463. if (e.xany.window == client && client != 0)
  464. {
  465. switch (e.type)
  466. {
  467. case PropertyNotify:
  468. propertyChanged (e.xproperty.atom);
  469. return true;
  470. case ConfigureNotify:
  471. if (allowResize)
  472. configureNotify();
  473. else
  474. MessageManager::callAsync([this] () {componentMovedOrResized (owner, true, true);});
  475. return true;
  476. }
  477. }
  478. else if (e.xany.window == host && host != 0)
  479. {
  480. switch (e.type)
  481. {
  482. case ReparentNotify:
  483. if (e.xreparent.parent == host && e.xreparent.window != client)
  484. {
  485. setClient (e.xreparent.window, false);
  486. return true;
  487. }
  488. break;
  489. case CreateNotify:
  490. if (e.xcreatewindow.parent != e.xcreatewindow.window && e.xcreatewindow.parent == host && e.xcreatewindow.window != client)
  491. {
  492. setClient (e.xcreatewindow.window, false);
  493. return true;
  494. }
  495. break;
  496. case GravityNotify:
  497. componentMovedOrResized (owner, true, true);
  498. return true;
  499. case ClientMessage:
  500. if (e.xclient.message_type == atoms.XembedMsgType && e.xclient.format == 32)
  501. {
  502. handleXembedCmd ((::Time) e.xclient.data.l[0], e.xclient.data.l[1],
  503. e.xclient.data.l[2], e.xclient.data.l[3],
  504. e.xclient.data.l[4]);
  505. return true;
  506. }
  507. break;
  508. }
  509. }
  510. return false;
  511. }
  512. void sendXEmbedEvent (const ::Time& xTime, long opcode,
  513. long opcodeMinor = 0, long data1 = 0, long data2 = 0)
  514. {
  515. XClientMessageEvent msg;
  516. auto dpy = getDisplay();
  517. ::memset (&msg, 0, sizeof (XClientMessageEvent));
  518. msg.window = client;
  519. msg.type = ClientMessage;
  520. msg.message_type = atoms.XembedMsgType;
  521. msg.format = 32;
  522. msg.data.l[0] = (long) xTime;
  523. msg.data.l[1] = opcode;
  524. msg.data.l[2] = opcodeMinor;
  525. msg.data.l[3] = data1;
  526. msg.data.l[4] = data2;
  527. XSendEvent (dpy, client, False, NoEventMask, (XEvent*) &msg);
  528. XSync (dpy, False);
  529. }
  530. Rectangle<int> getX11BoundsFromJuce()
  531. {
  532. if (auto* peer = owner.getPeer())
  533. {
  534. auto r = peer->getComponent().getLocalArea (&owner, owner.getLocalBounds());
  535. auto scale = Desktop::getInstance().getDisplays().getDisplayContaining (peer->localToGlobal (r.getCentre())).scale;
  536. return r * scale;
  537. }
  538. return owner.getLocalBounds();
  539. }
  540. //==============================================================================
  541. friend bool juce::juce_handleXEmbedEvent (ComponentPeer*, void*);
  542. friend unsigned long juce::juce_getCurrentFocusWindow (ComponentPeer*);
  543. static Array<Pimpl*>& getWidgets()
  544. {
  545. static Array<Pimpl*> i;
  546. return i;
  547. }
  548. static bool dispatchX11Event (ComponentPeer* p, const XEvent* eventArg)
  549. {
  550. if (eventArg != nullptr)
  551. {
  552. auto& e = *eventArg;
  553. if (auto w = e.xany.window)
  554. for (auto* widget : getWidgets())
  555. if (w == widget->host || w == widget->client)
  556. return widget->handleX11Event (e);
  557. }
  558. else
  559. {
  560. for (auto* widget : getWidgets())
  561. if (widget->owner.getPeer() == p)
  562. widget->peerChanged (nullptr);
  563. }
  564. return false;
  565. }
  566. static Window getCurrentFocusWindow (ComponentPeer* p)
  567. {
  568. if (p != nullptr)
  569. {
  570. for (auto* widget : getWidgets())
  571. if (widget->owner.getPeer() == p && widget->owner.hasKeyboardFocus (false))
  572. return widget->client;
  573. }
  574. return SharedKeyWindow::getCurrentFocusWindow (p);
  575. }
  576. };
  577. //==============================================================================
  578. HashMap<ComponentPeer*,XEmbedComponent::Pimpl::SharedKeyWindow*>* XEmbedComponent::Pimpl::SharedKeyWindow::keyWindows = nullptr;
  579. //==============================================================================
  580. XEmbedComponent::XEmbedComponent (bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent)
  581. : pimpl (new Pimpl (*this, 0, wantsKeyboardFocus, false, allowForeignWidgetToResizeComponent))
  582. {
  583. setOpaque (true);
  584. }
  585. XEmbedComponent::XEmbedComponent (unsigned long wID, bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent)
  586. : pimpl (new Pimpl (*this, wID, wantsKeyboardFocus, true, allowForeignWidgetToResizeComponent))
  587. {
  588. setOpaque (true);
  589. }
  590. XEmbedComponent::~XEmbedComponent() {}
  591. void XEmbedComponent::paint (Graphics& g)
  592. {
  593. g.fillAll (Colours::lightgrey);
  594. }
  595. void XEmbedComponent::focusGained (FocusChangeType changeType) { pimpl->focusGained (changeType); }
  596. void XEmbedComponent::focusLost (FocusChangeType changeType) { pimpl->focusLost (changeType); }
  597. void XEmbedComponent::broughtToFront() { pimpl->broughtToFront(); }
  598. unsigned long XEmbedComponent::getHostWindowID() { return pimpl->getHostWindowID(); }
  599. //==============================================================================
  600. bool juce_handleXEmbedEvent (ComponentPeer* p, void* e)
  601. {
  602. return ::XEmbedComponent::Pimpl::dispatchX11Event (p, reinterpret_cast<const XEvent*> (e));
  603. }
  604. unsigned long juce_getCurrentFocusWindow (ComponentPeer* peer)
  605. {
  606. return (unsigned long) ::XEmbedComponent::Pimpl::getCurrentFocusWindow (peer);
  607. }