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.

548 lines
18KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. class JuceIStorage : public IStorage
  23. {
  24. int refCount;
  25. public:
  26. JuceIStorage() : refCount (1) {}
  27. virtual ~JuceIStorage()
  28. {
  29. jassert (refCount == 0);
  30. }
  31. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  32. {
  33. if (id == IID_IUnknown || id == IID_IStorage)
  34. {
  35. AddRef();
  36. *result = this;
  37. return S_OK;
  38. }
  39. *result = 0;
  40. return E_NOINTERFACE;
  41. }
  42. ULONG __stdcall AddRef() { return ++refCount; }
  43. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  44. HRESULT __stdcall CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
  45. HRESULT __stdcall OpenStream (const WCHAR*, void*, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
  46. HRESULT __stdcall CreateStorage (const WCHAR*, DWORD, DWORD, DWORD, IStorage**) { return E_NOTIMPL; }
  47. HRESULT __stdcall OpenStorage (const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage**) { return E_NOTIMPL; }
  48. HRESULT __stdcall CopyTo (DWORD, IID const*, SNB, IStorage*) { return E_NOTIMPL; }
  49. HRESULT __stdcall MoveElementTo (const OLECHAR*,IStorage*, const OLECHAR*, DWORD) { return E_NOTIMPL; }
  50. HRESULT __stdcall Commit (DWORD) { return E_NOTIMPL; }
  51. HRESULT __stdcall Revert() { return E_NOTIMPL; }
  52. HRESULT __stdcall EnumElements (DWORD, void*, DWORD, IEnumSTATSTG**) { return E_NOTIMPL; }
  53. HRESULT __stdcall DestroyElement (const OLECHAR*) { return E_NOTIMPL; }
  54. HRESULT __stdcall RenameElement (const WCHAR*, const WCHAR*) { return E_NOTIMPL; }
  55. HRESULT __stdcall SetElementTimes (const WCHAR*, FILETIME const*, FILETIME const*, FILETIME const*) { return E_NOTIMPL; }
  56. HRESULT __stdcall SetClass (REFCLSID) { return S_OK; }
  57. HRESULT __stdcall SetStateBits (DWORD, DWORD) { return E_NOTIMPL; }
  58. HRESULT __stdcall Stat (STATSTG*, DWORD) { return E_NOTIMPL; }
  59. juce_UseDebuggingNewOperator
  60. };
  61. class JuceOleInPlaceFrame : public IOleInPlaceFrame
  62. {
  63. int refCount;
  64. HWND window;
  65. public:
  66. JuceOleInPlaceFrame (HWND window_)
  67. : refCount (1),
  68. window (window_)
  69. {
  70. }
  71. virtual ~JuceOleInPlaceFrame()
  72. {
  73. jassert (refCount == 0);
  74. }
  75. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  76. {
  77. if (id == IID_IUnknown || id == IID_IOleInPlaceFrame)
  78. {
  79. AddRef();
  80. *result = this;
  81. return S_OK;
  82. }
  83. *result = 0;
  84. return E_NOINTERFACE;
  85. }
  86. ULONG __stdcall AddRef() { return ++refCount; }
  87. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  88. HRESULT __stdcall GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
  89. HRESULT __stdcall ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
  90. HRESULT __stdcall GetBorder (LPRECT) { return E_NOTIMPL; }
  91. HRESULT __stdcall RequestBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
  92. HRESULT __stdcall SetBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
  93. HRESULT __stdcall SetActiveObject (IOleInPlaceActiveObject*, LPCOLESTR) { return S_OK; }
  94. HRESULT __stdcall InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) { return E_NOTIMPL; }
  95. HRESULT __stdcall SetMenu (HMENU, HOLEMENU, HWND) { return S_OK; }
  96. HRESULT __stdcall RemoveMenus (HMENU) { return E_NOTIMPL; }
  97. HRESULT __stdcall SetStatusText (LPCOLESTR) { return S_OK; }
  98. HRESULT __stdcall EnableModeless (BOOL) { return S_OK; }
  99. HRESULT __stdcall TranslateAccelerator(LPMSG, WORD) { return E_NOTIMPL; }
  100. juce_UseDebuggingNewOperator
  101. };
  102. class JuceIOleInPlaceSite : public IOleInPlaceSite
  103. {
  104. int refCount;
  105. HWND window;
  106. JuceOleInPlaceFrame* frame;
  107. public:
  108. JuceIOleInPlaceSite (HWND window_)
  109. : refCount (1),
  110. window (window_)
  111. {
  112. frame = new JuceOleInPlaceFrame (window);
  113. }
  114. virtual ~JuceIOleInPlaceSite()
  115. {
  116. jassert (refCount == 0);
  117. frame->Release();
  118. }
  119. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  120. {
  121. if (id == IID_IUnknown || id == IID_IOleInPlaceSite)
  122. {
  123. AddRef();
  124. *result = this;
  125. return S_OK;
  126. }
  127. *result = 0;
  128. return E_NOINTERFACE;
  129. }
  130. ULONG __stdcall AddRef() { return ++refCount; }
  131. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  132. HRESULT __stdcall GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
  133. HRESULT __stdcall ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
  134. HRESULT __stdcall CanInPlaceActivate() { return S_OK; }
  135. HRESULT __stdcall OnInPlaceActivate() { return S_OK; }
  136. HRESULT __stdcall OnUIActivate() { return S_OK; }
  137. HRESULT __stdcall GetWindowContext (LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO lpFrameInfo)
  138. {
  139. frame->AddRef();
  140. *lplpFrame = frame;
  141. *lplpDoc = 0;
  142. lpFrameInfo->fMDIApp = FALSE;
  143. lpFrameInfo->hwndFrame = window;
  144. lpFrameInfo->haccel = 0;
  145. lpFrameInfo->cAccelEntries = 0;
  146. return S_OK;
  147. }
  148. HRESULT __stdcall Scroll (SIZE) { return E_NOTIMPL; }
  149. HRESULT __stdcall OnUIDeactivate (BOOL) { return S_OK; }
  150. HRESULT __stdcall OnInPlaceDeactivate() { return S_OK; }
  151. HRESULT __stdcall DiscardUndoState() { return E_NOTIMPL; }
  152. HRESULT __stdcall DeactivateAndUndo() { return E_NOTIMPL; }
  153. HRESULT __stdcall OnPosRectChange (LPCRECT) { return S_OK; }
  154. juce_UseDebuggingNewOperator
  155. };
  156. class JuceIOleClientSite : public IOleClientSite
  157. {
  158. int refCount;
  159. JuceIOleInPlaceSite* inplaceSite;
  160. public:
  161. JuceIOleClientSite (HWND window)
  162. : refCount (1)
  163. {
  164. inplaceSite = new JuceIOleInPlaceSite (window);
  165. }
  166. virtual ~JuceIOleClientSite()
  167. {
  168. jassert (refCount == 0);
  169. inplaceSite->Release();
  170. }
  171. HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result)
  172. {
  173. if (id == IID_IUnknown || id == IID_IOleClientSite)
  174. {
  175. AddRef();
  176. *result = this;
  177. return S_OK;
  178. }
  179. else if (id == IID_IOleInPlaceSite)
  180. {
  181. inplaceSite->AddRef();
  182. *result = inplaceSite;
  183. return S_OK;
  184. }
  185. *result = 0;
  186. return E_NOINTERFACE;
  187. }
  188. ULONG __stdcall AddRef() { return ++refCount; }
  189. ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; }
  190. HRESULT __stdcall SaveObject() { return E_NOTIMPL; }
  191. HRESULT __stdcall GetMoniker (DWORD, DWORD, IMoniker**) { return E_NOTIMPL; }
  192. HRESULT __stdcall GetContainer (LPOLECONTAINER* ppContainer) { *ppContainer = 0; return E_NOINTERFACE; }
  193. HRESULT __stdcall ShowObject() { return S_OK; }
  194. HRESULT __stdcall OnShowWindow (BOOL) { return E_NOTIMPL; }
  195. HRESULT __stdcall RequestNewObjectLayout() { return E_NOTIMPL; }
  196. juce_UseDebuggingNewOperator
  197. };
  198. //==============================================================================
  199. class ActiveXControlData : public ComponentMovementWatcher
  200. {
  201. ActiveXControlComponent* const owner;
  202. bool wasShowing;
  203. public:
  204. HWND controlHWND;
  205. IStorage* storage;
  206. IOleClientSite* clientSite;
  207. IOleObject* control;
  208. //==============================================================================
  209. ActiveXControlData (HWND hwnd,
  210. ActiveXControlComponent* const owner_)
  211. : ComponentMovementWatcher (owner_),
  212. owner (owner_),
  213. wasShowing (owner_ != 0 && owner_->isShowing()),
  214. controlHWND (0),
  215. storage (new JuceIStorage()),
  216. clientSite (new JuceIOleClientSite (hwnd)),
  217. control (0)
  218. {
  219. }
  220. ~ActiveXControlData()
  221. {
  222. if (control != 0)
  223. {
  224. control->Close (OLECLOSE_NOSAVE);
  225. control->Release();
  226. }
  227. clientSite->Release();
  228. storage->Release();
  229. }
  230. //==============================================================================
  231. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  232. {
  233. Component* const topComp = owner->getTopLevelComponent();
  234. if (topComp->getPeer() != 0)
  235. {
  236. int x = 0, y = 0;
  237. owner->relativePositionToOtherComponent (topComp, x, y);
  238. owner->setControlBounds (Rectangle (x, y, owner->getWidth(), owner->getHeight()));
  239. }
  240. }
  241. void componentPeerChanged()
  242. {
  243. const bool isShowingNow = owner->isShowing();
  244. if (wasShowing != isShowingNow)
  245. {
  246. wasShowing = isShowingNow;
  247. owner->setControlVisible (isShowingNow);
  248. }
  249. componentMovedOrResized (true, true);
  250. }
  251. void componentVisibilityChanged (Component&)
  252. {
  253. componentPeerChanged();
  254. }
  255. static bool doesWindowMatch (const ActiveXControlComponent* const ax, HWND hwnd)
  256. {
  257. return ((ActiveXControlData*) ax->control) != 0
  258. && ((ActiveXControlData*) ax->control)->controlHWND == hwnd;
  259. }
  260. };
  261. //==============================================================================
  262. static VoidArray activeXComps;
  263. static HWND getHWND (const ActiveXControlComponent* const component)
  264. {
  265. HWND hwnd = 0;
  266. const IID iid = IID_IOleWindow;
  267. IOleWindow* const window = (IOleWindow*) component->queryInterface (&iid);
  268. if (window != 0)
  269. {
  270. window->GetWindow (&hwnd);
  271. window->Release();
  272. }
  273. return hwnd;
  274. }
  275. static void offerActiveXMouseEventToPeer (ComponentPeer* const peer, HWND hwnd, UINT message, LPARAM lParam)
  276. {
  277. RECT activeXRect, peerRect;
  278. GetWindowRect (hwnd, &activeXRect);
  279. GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
  280. const int mx = GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left;
  281. const int my = GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top;
  282. const int64 mouseEventTime = getMouseEventTime();
  283. const int oldModifiers = currentModifiers;
  284. ModifierKeys::getCurrentModifiersRealtime(); // to update the mouse button flags
  285. switch (message)
  286. {
  287. case WM_MOUSEMOVE:
  288. if (ModifierKeys (currentModifiers).isAnyMouseButtonDown())
  289. peer->handleMouseDrag (mx, my, mouseEventTime);
  290. else
  291. peer->handleMouseMove (mx, my, mouseEventTime);
  292. break;
  293. case WM_LBUTTONDOWN:
  294. case WM_MBUTTONDOWN:
  295. case WM_RBUTTONDOWN:
  296. peer->handleMouseDown (mx, my, mouseEventTime);
  297. break;
  298. case WM_LBUTTONUP:
  299. case WM_MBUTTONUP:
  300. case WM_RBUTTONUP:
  301. peer->handleMouseUp (oldModifiers, mx, my, mouseEventTime);
  302. break;
  303. default:
  304. break;
  305. }
  306. }
  307. // intercepts events going to an activeX control, so we can sneakily use the mouse events
  308. static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  309. {
  310. for (int i = activeXComps.size(); --i >= 0;)
  311. {
  312. const ActiveXControlComponent* const ax = (const ActiveXControlComponent*) activeXComps.getUnchecked(i);
  313. if (ActiveXControlData::doesWindowMatch (ax, hwnd))
  314. {
  315. switch (message)
  316. {
  317. case WM_MOUSEMOVE:
  318. case WM_LBUTTONDOWN:
  319. case WM_MBUTTONDOWN:
  320. case WM_RBUTTONDOWN:
  321. case WM_LBUTTONUP:
  322. case WM_MBUTTONUP:
  323. case WM_RBUTTONUP:
  324. case WM_LBUTTONDBLCLK:
  325. case WM_MBUTTONDBLCLK:
  326. case WM_RBUTTONDBLCLK:
  327. if (ax->isShowing())
  328. {
  329. ComponentPeer* const peer = ax->getPeer();
  330. if (peer != 0)
  331. {
  332. offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
  333. if (! ax->areMouseEventsAllowed())
  334. return 0;
  335. }
  336. }
  337. break;
  338. default:
  339. break;
  340. }
  341. return CallWindowProc ((WNDPROC) (ax->originalWndProc), hwnd, message, wParam, lParam);
  342. }
  343. }
  344. return DefWindowProc (hwnd, message, wParam, lParam);
  345. }
  346. ActiveXControlComponent::ActiveXControlComponent()
  347. : originalWndProc (0),
  348. control (0),
  349. mouseEventsAllowed (true)
  350. {
  351. activeXComps.add (this);
  352. }
  353. ActiveXControlComponent::~ActiveXControlComponent()
  354. {
  355. deleteControl();
  356. activeXComps.removeValue (this);
  357. }
  358. void ActiveXControlComponent::paint (Graphics& g)
  359. {
  360. if (control == 0)
  361. g.fillAll (Colours::lightgrey);
  362. }
  363. bool ActiveXControlComponent::createControl (const void* controlIID)
  364. {
  365. deleteControl();
  366. ComponentPeer* const peer = getPeer();
  367. // the component must have already been added to a real window when you call this!
  368. jassert (dynamic_cast <Win32ComponentPeer*> (peer) != 0);
  369. if (dynamic_cast <Win32ComponentPeer*> (peer) != 0)
  370. {
  371. int x = 0, y = 0;
  372. relativePositionToOtherComponent (getTopLevelComponent(), x, y);
  373. HWND hwnd = (HWND) peer->getNativeHandle();
  374. ActiveXControlData* const info = new ActiveXControlData (hwnd, this);
  375. HRESULT hr;
  376. if ((hr = OleCreate (*(const IID*) controlIID, IID_IOleObject, 1 /*OLERENDER_DRAW*/, 0,
  377. info->clientSite, info->storage,
  378. (void**) &(info->control))) == S_OK)
  379. {
  380. info->control->SetHostNames (L"Juce", 0);
  381. if (OleSetContainedObject (info->control, TRUE) == S_OK)
  382. {
  383. RECT rect;
  384. rect.left = x;
  385. rect.top = y;
  386. rect.right = x + getWidth();
  387. rect.bottom = y + getHeight();
  388. if (info->control->DoVerb (OLEIVERB_SHOW, 0, info->clientSite, 0, hwnd, &rect) == S_OK)
  389. {
  390. control = info;
  391. setControlBounds (Rectangle (x, y, getWidth(), getHeight()));
  392. info->controlHWND = getHWND (this);
  393. if (info->controlHWND != 0)
  394. {
  395. originalWndProc = (void*) (pointer_sized_int) GetWindowLongPtr ((HWND) info->controlHWND, GWLP_WNDPROC);
  396. SetWindowLongPtr ((HWND) info->controlHWND, GWLP_WNDPROC, (LONG_PTR) activeXHookWndProc);
  397. }
  398. return true;
  399. }
  400. }
  401. }
  402. delete info;
  403. }
  404. return false;
  405. }
  406. void ActiveXControlComponent::deleteControl()
  407. {
  408. ActiveXControlData* const info = (ActiveXControlData*) control;
  409. if (info != 0)
  410. {
  411. delete info;
  412. control = 0;
  413. originalWndProc = 0;
  414. }
  415. }
  416. void* ActiveXControlComponent::queryInterface (const void* iid) const
  417. {
  418. ActiveXControlData* const info = (ActiveXControlData*) control;
  419. void* result = 0;
  420. if (info != 0 && info->control != 0
  421. && info->control->QueryInterface (*(const IID*) iid, &result) == S_OK)
  422. return result;
  423. return 0;
  424. }
  425. void ActiveXControlComponent::setControlBounds (const Rectangle& newBounds) const
  426. {
  427. HWND hwnd = ((ActiveXControlData*) control)->controlHWND;
  428. if (hwnd != 0)
  429. MoveWindow (hwnd, newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight(), TRUE);
  430. }
  431. void ActiveXControlComponent::setControlVisible (const bool shouldBeVisible) const
  432. {
  433. HWND hwnd = ((ActiveXControlData*) control)->controlHWND;
  434. if (hwnd != 0)
  435. ShowWindow (hwnd, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
  436. }
  437. void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachControl)
  438. {
  439. mouseEventsAllowed = eventsCanReachControl;
  440. }
  441. #endif