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.

758 lines
26KB

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