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.

553 lines
18KB

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