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.

412 lines
16KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. extern int64 getMouseEventTime();
  19. namespace ActiveXHelpers
  20. {
  21. //==============================================================================
  22. class JuceIStorage : public ComBaseClassHelper <IStorage>
  23. {
  24. public:
  25. JuceIStorage() {}
  26. JUCE_COMRESULT CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
  27. JUCE_COMRESULT OpenStream (const WCHAR*, void*, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
  28. JUCE_COMRESULT CreateStorage (const WCHAR*, DWORD, DWORD, DWORD, IStorage**) { return E_NOTIMPL; }
  29. JUCE_COMRESULT OpenStorage (const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage**) { return E_NOTIMPL; }
  30. JUCE_COMRESULT CopyTo (DWORD, IID const*, SNB, IStorage*) { return E_NOTIMPL; }
  31. JUCE_COMRESULT MoveElementTo (const OLECHAR*,IStorage*, const OLECHAR*, DWORD) { return E_NOTIMPL; }
  32. JUCE_COMRESULT Commit (DWORD) { return E_NOTIMPL; }
  33. JUCE_COMRESULT Revert() { return E_NOTIMPL; }
  34. JUCE_COMRESULT EnumElements (DWORD, void*, DWORD, IEnumSTATSTG**) { return E_NOTIMPL; }
  35. JUCE_COMRESULT DestroyElement (const OLECHAR*) { return E_NOTIMPL; }
  36. JUCE_COMRESULT RenameElement (const WCHAR*, const WCHAR*) { return E_NOTIMPL; }
  37. JUCE_COMRESULT SetElementTimes (const WCHAR*, FILETIME const*, FILETIME const*, FILETIME const*) { return E_NOTIMPL; }
  38. JUCE_COMRESULT SetClass (REFCLSID) { return S_OK; }
  39. JUCE_COMRESULT SetStateBits (DWORD, DWORD) { return E_NOTIMPL; }
  40. JUCE_COMRESULT Stat (STATSTG*, DWORD) { return E_NOTIMPL; }
  41. };
  42. //==============================================================================
  43. class JuceOleInPlaceFrame : public ComBaseClassHelper <IOleInPlaceFrame>
  44. {
  45. public:
  46. JuceOleInPlaceFrame (HWND window_) : window (window_) {}
  47. JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
  48. JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
  49. JUCE_COMRESULT GetBorder (LPRECT) { return E_NOTIMPL; }
  50. JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
  51. JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
  52. JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject*, LPCOLESTR) { return S_OK; }
  53. JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) { return E_NOTIMPL; }
  54. JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND) { return S_OK; }
  55. JUCE_COMRESULT RemoveMenus (HMENU) { return E_NOTIMPL; }
  56. JUCE_COMRESULT SetStatusText (LPCOLESTR) { return S_OK; }
  57. JUCE_COMRESULT EnableModeless (BOOL) { return S_OK; }
  58. JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD) { return E_NOTIMPL; }
  59. private:
  60. HWND window;
  61. };
  62. //==============================================================================
  63. class JuceIOleInPlaceSite : public ComBaseClassHelper <IOleInPlaceSite>
  64. {
  65. public:
  66. JuceIOleInPlaceSite (HWND window_)
  67. : window (window_),
  68. frame (new JuceOleInPlaceFrame (window))
  69. {}
  70. ~JuceIOleInPlaceSite()
  71. {
  72. frame->Release();
  73. }
  74. JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
  75. JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
  76. JUCE_COMRESULT CanInPlaceActivate() { return S_OK; }
  77. JUCE_COMRESULT OnInPlaceActivate() { return S_OK; }
  78. JUCE_COMRESULT OnUIActivate() { return S_OK; }
  79. JUCE_COMRESULT GetWindowContext (LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO lpFrameInfo)
  80. {
  81. /* Note: if you call AddRef on the frame here, then some types of object (e.g. web browser control) cause leaks..
  82. If you don't call AddRef then others crash (e.g. QuickTime).. Bit of a catch-22, so letting it leak is probably preferable.
  83. */
  84. if (lplpFrame != nullptr) { frame->AddRef(); *lplpFrame = frame; }
  85. if (lplpDoc != nullptr) *lplpDoc = 0;
  86. lpFrameInfo->fMDIApp = FALSE;
  87. lpFrameInfo->hwndFrame = window;
  88. lpFrameInfo->haccel = 0;
  89. lpFrameInfo->cAccelEntries = 0;
  90. return S_OK;
  91. }
  92. JUCE_COMRESULT Scroll (SIZE) { return E_NOTIMPL; }
  93. JUCE_COMRESULT OnUIDeactivate (BOOL) { return S_OK; }
  94. JUCE_COMRESULT OnInPlaceDeactivate() { return S_OK; }
  95. JUCE_COMRESULT DiscardUndoState() { return E_NOTIMPL; }
  96. JUCE_COMRESULT DeactivateAndUndo() { return E_NOTIMPL; }
  97. JUCE_COMRESULT OnPosRectChange (LPCRECT) { return S_OK; }
  98. private:
  99. HWND window;
  100. JuceOleInPlaceFrame* frame;
  101. };
  102. //==============================================================================
  103. class JuceIOleClientSite : public ComBaseClassHelper <IOleClientSite>
  104. {
  105. public:
  106. JuceIOleClientSite (HWND window)
  107. : inplaceSite (new JuceIOleInPlaceSite (window))
  108. {}
  109. ~JuceIOleClientSite()
  110. {
  111. inplaceSite->Release();
  112. }
  113. JUCE_COMRESULT QueryInterface (REFIID type, void** result)
  114. {
  115. if (type == IID_IOleInPlaceSite)
  116. {
  117. inplaceSite->AddRef();
  118. *result = static_cast <IOleInPlaceSite*> (inplaceSite);
  119. return S_OK;
  120. }
  121. return ComBaseClassHelper <IOleClientSite>::QueryInterface (type, result);
  122. }
  123. JUCE_COMRESULT SaveObject() { return E_NOTIMPL; }
  124. JUCE_COMRESULT GetMoniker (DWORD, DWORD, IMoniker**) { return E_NOTIMPL; }
  125. JUCE_COMRESULT GetContainer (LPOLECONTAINER* ppContainer) { *ppContainer = 0; return E_NOINTERFACE; }
  126. JUCE_COMRESULT ShowObject() { return S_OK; }
  127. JUCE_COMRESULT OnShowWindow (BOOL) { return E_NOTIMPL; }
  128. JUCE_COMRESULT RequestNewObjectLayout() { return E_NOTIMPL; }
  129. private:
  130. JuceIOleInPlaceSite* inplaceSite;
  131. };
  132. //==============================================================================
  133. static Array<ActiveXControlComponent*> activeXComps;
  134. HWND getHWND (const ActiveXControlComponent* const component)
  135. {
  136. HWND hwnd = 0;
  137. const IID iid = IID_IOleWindow;
  138. IOleWindow* const window = (IOleWindow*) component->queryInterface (&iid);
  139. if (window != nullptr)
  140. {
  141. window->GetWindow (&hwnd);
  142. window->Release();
  143. }
  144. return hwnd;
  145. }
  146. void offerActiveXMouseEventToPeer (ComponentPeer* const peer, HWND hwnd, UINT message, LPARAM lParam)
  147. {
  148. RECT activeXRect, peerRect;
  149. GetWindowRect (hwnd, &activeXRect);
  150. GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
  151. switch (message)
  152. {
  153. case WM_MOUSEMOVE:
  154. case WM_LBUTTONDOWN:
  155. case WM_MBUTTONDOWN:
  156. case WM_RBUTTONDOWN:
  157. case WM_LBUTTONUP:
  158. case WM_MBUTTONUP:
  159. case WM_RBUTTONUP:
  160. peer->handleMouseEvent (0, Point<int> (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left,
  161. GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top),
  162. ModifierKeys::getCurrentModifiersRealtime(),
  163. getMouseEventTime());
  164. break;
  165. default:
  166. break;
  167. }
  168. }
  169. }
  170. //==============================================================================
  171. class ActiveXControlComponent::Pimpl : public ComponentMovementWatcher
  172. {
  173. public:
  174. Pimpl (HWND hwnd, ActiveXControlComponent& owner_)
  175. : ComponentMovementWatcher (&owner_),
  176. owner (owner_),
  177. controlHWND (0),
  178. storage (new ActiveXHelpers::JuceIStorage()),
  179. clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd)),
  180. control (nullptr),
  181. originalWndProc (0)
  182. {
  183. }
  184. ~Pimpl()
  185. {
  186. if (control != nullptr)
  187. {
  188. control->Close (OLECLOSE_NOSAVE);
  189. control->Release();
  190. }
  191. clientSite->Release();
  192. storage->Release();
  193. }
  194. void setControlBounds (const Rectangle<int>& bounds) const
  195. {
  196. if (controlHWND != 0)
  197. MoveWindow (controlHWND, bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), TRUE);
  198. }
  199. void setControlVisible (bool shouldBeVisible) const
  200. {
  201. if (controlHWND != 0)
  202. ShowWindow (controlHWND, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
  203. }
  204. //==============================================================================
  205. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  206. {
  207. Component* const topComp = owner.getTopLevelComponent();
  208. if (topComp->getPeer() != nullptr)
  209. setControlBounds (topComp->getLocalArea (&owner, owner.getLocalBounds()));
  210. }
  211. void componentPeerChanged()
  212. {
  213. componentMovedOrResized (true, true);
  214. }
  215. void componentVisibilityChanged()
  216. {
  217. setControlVisible (owner.isShowing());
  218. componentPeerChanged();
  219. }
  220. // intercepts events going to an activeX control, so we can sneakily use the mouse events
  221. static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  222. {
  223. for (int i = ActiveXHelpers::activeXComps.size(); --i >= 0;)
  224. {
  225. const ActiveXControlComponent* const ax = ActiveXHelpers::activeXComps.getUnchecked(i);
  226. if (ax->control != nullptr && ax->control->controlHWND == hwnd)
  227. {
  228. switch (message)
  229. {
  230. case WM_MOUSEMOVE:
  231. case WM_LBUTTONDOWN:
  232. case WM_MBUTTONDOWN:
  233. case WM_RBUTTONDOWN:
  234. case WM_LBUTTONUP:
  235. case WM_MBUTTONUP:
  236. case WM_RBUTTONUP:
  237. case WM_LBUTTONDBLCLK:
  238. case WM_MBUTTONDBLCLK:
  239. case WM_RBUTTONDBLCLK:
  240. if (ax->isShowing())
  241. {
  242. ComponentPeer* const peer = ax->getPeer();
  243. if (peer != nullptr)
  244. {
  245. ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
  246. if (! ax->areMouseEventsAllowed())
  247. return 0;
  248. }
  249. }
  250. break;
  251. default:
  252. break;
  253. }
  254. return CallWindowProc (ax->control->originalWndProc, hwnd, message, wParam, lParam);
  255. }
  256. }
  257. return DefWindowProc (hwnd, message, wParam, lParam);
  258. }
  259. private:
  260. ActiveXControlComponent& owner;
  261. public:
  262. HWND controlHWND;
  263. IStorage* storage;
  264. IOleClientSite* clientSite;
  265. IOleObject* control;
  266. WNDPROC originalWndProc;
  267. };
  268. //==============================================================================
  269. ActiveXControlComponent::ActiveXControlComponent()
  270. : mouseEventsAllowed (true)
  271. {
  272. ActiveXHelpers::activeXComps.add (this);
  273. }
  274. ActiveXControlComponent::~ActiveXControlComponent()
  275. {
  276. deleteControl();
  277. ActiveXHelpers::activeXComps.removeValue (this);
  278. }
  279. void ActiveXControlComponent::paint (Graphics& g)
  280. {
  281. if (control == nullptr)
  282. g.fillAll (Colours::lightgrey);
  283. }
  284. bool ActiveXControlComponent::createControl (const void* controlIID)
  285. {
  286. deleteControl();
  287. ComponentPeer* const peer = getPeer();
  288. // the component must have already been added to a real window when you call this!
  289. jassert (peer != nullptr);
  290. if (peer != nullptr)
  291. {
  292. const Rectangle<int> bounds (getTopLevelComponent()->getLocalArea (this, getLocalBounds()));
  293. HWND hwnd = (HWND) peer->getNativeHandle();
  294. ScopedPointer<Pimpl> newControl (new Pimpl (hwnd, *this));
  295. HRESULT hr;
  296. if ((hr = OleCreate (*(const IID*) controlIID, IID_IOleObject, 1 /*OLERENDER_DRAW*/, 0,
  297. newControl->clientSite, newControl->storage,
  298. (void**) &(newControl->control))) == S_OK)
  299. {
  300. newControl->control->SetHostNames (L"Juce", 0);
  301. if (OleSetContainedObject (newControl->control, TRUE) == S_OK)
  302. {
  303. RECT rect;
  304. rect.left = bounds.getX();
  305. rect.top = bounds.getY();
  306. rect.right = bounds.getRight();
  307. rect.bottom = bounds.getBottom();
  308. if (newControl->control->DoVerb (OLEIVERB_SHOW, 0, newControl->clientSite, 0, hwnd, &rect) == S_OK)
  309. {
  310. control = newControl;
  311. control->controlHWND = ActiveXHelpers::getHWND (this);
  312. if (control->controlHWND != 0)
  313. {
  314. control->setControlBounds (bounds);
  315. control->originalWndProc = (void*) (pointer_sized_int) GetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC);
  316. SetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC, (LONG_PTR) Pimpl::activeXHookWndProc);
  317. }
  318. return true;
  319. }
  320. }
  321. }
  322. }
  323. return false;
  324. }
  325. void ActiveXControlComponent::deleteControl()
  326. {
  327. control = nullptr;
  328. }
  329. void* ActiveXControlComponent::queryInterface (const void* iid) const
  330. {
  331. void* result = nullptr;
  332. if (control != nullptr && control->control != nullptr
  333. && SUCCEEDED (control->control->QueryInterface (*(const IID*) iid, &result)))
  334. return result;
  335. return nullptr;
  336. }
  337. void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachControl)
  338. {
  339. mouseEventsAllowed = eventsCanReachControl;
  340. }