Audio plugin host https://kx.studio/carla
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.

juce_linux_XEmbedComponent.cpp 24KB

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