2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_win32_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
31 //==============================================================================
32 class HiddenMessageWindow
35 HiddenMessageWindow (const TCHAR
* const messageWindowName
, WNDPROC wndProc
)
37 String
className ("JUCE_");
38 className
<< String::toHexString (Time::getHighResolutionTicks());
40 HMODULE moduleHandle
= (HMODULE
) PlatformUtilities::getCurrentModuleInstanceHandle();
42 WNDCLASSEX wc
= { 0 };
43 wc
.cbSize
= sizeof (wc
);
44 wc
.lpfnWndProc
= wndProc
;
46 wc
.hInstance
= moduleHandle
;
47 wc
.lpszClassName
= className
.toWideCharPointer();
49 atom
= RegisterClassEx (&wc
);
52 hwnd
= CreateWindow (getClassNameFromAtom(), messageWindowName
,
53 0, 0, 0, 0, 0, 0, 0, moduleHandle
, 0);
57 ~HiddenMessageWindow()
60 UnregisterClass (getClassNameFromAtom(), 0);
63 inline HWND
getHWND() const noexcept
{ return hwnd
; }
69 LPCTSTR
getClassNameFromAtom() noexcept
{ return (LPCTSTR
) MAKELONG (atom
, 0); }
73 //==============================================================================
74 HWND juce_messageWindowHandle
= 0; // (this is referred to by other parts of the codebase)
76 //==============================================================================
77 class JuceWindowIdentifier
80 static bool isJUCEWindow (HWND hwnd
) noexcept
82 return GetWindowLong (hwnd
, GWLP_USERDATA
) == improbableWindowNumber
;
85 static void setAsJUCEWindow (HWND hwnd
, bool isJuceWindow
) noexcept
87 SetWindowLongPtr (hwnd
, GWLP_USERDATA
, isJuceWindow
? improbableWindowNumber
: 0);
91 enum { improbableWindowNumber
= 0xf965aa01 };
95 //==============================================================================
96 namespace WindowsMessageHelpers
98 const unsigned int specialId
= WM_APP
+ 0x4400;
99 const unsigned int broadcastId
= WM_APP
+ 0x4403;
100 const unsigned int specialCallbackId
= WM_APP
+ 0x4402;
102 const TCHAR messageWindowName
[] = _T("JUCEWindow");
103 ScopedPointer
<HiddenMessageWindow
> messageWindow
;
105 //==============================================================================
106 LRESULT CALLBACK
messageWndProc (HWND h
, const UINT message
, const WPARAM wParam
, const LPARAM lParam
) noexcept
110 if (h
== juce_messageWindowHandle
)
112 if (message
== specialCallbackId
)
114 MessageCallbackFunction
* const func
= (MessageCallbackFunction
*) wParam
;
115 return (LRESULT
) (*func
) ((void*) lParam
);
117 else if (message
== specialId
)
119 // these are trapped early in the dispatch call, but must also be checked
120 // here in case there are windows modal dialog boxes doing their own
121 // dispatch loop and not calling our version
123 Message
* const message
= reinterpret_cast <Message
*> (lParam
);
124 MessageManager::getInstance()->deliverMessage (message
);
125 message
->decReferenceCount();
128 else if (message
== broadcastId
)
130 const ScopedPointer
<String
> messageString ((String
*) lParam
);
131 MessageManager::getInstance()->deliverBroadcastMessage (*messageString
);
134 else if (message
== WM_COPYDATA
&& ((const COPYDATASTRUCT
*) lParam
)->dwData
== broadcastId
)
136 const COPYDATASTRUCT
* data
= (COPYDATASTRUCT
*) lParam
;
138 const String
messageString (CharPointer_UTF32 ((const CharPointer_UTF32::CharType
*) data
->lpData
),
139 data
->cbData
/ sizeof (CharPointer_UTF32::CharType
));
141 PostMessage (juce_messageWindowHandle
, broadcastId
, 0, (LPARAM
) new String (messageString
));
148 return DefWindowProc (h
, message
, wParam
, lParam
);
151 bool isHWNDBlockedByModalComponents (HWND h
) noexcept
153 for (int i
= Desktop::getInstance().getNumComponents(); --i
>= 0;)
155 Component
* const c
= Desktop::getInstance().getComponent (i
);
158 && (! c
->isCurrentlyBlockedByAnotherModalComponent())
159 && IsChild ((HWND
) c
->getWindowHandle(), h
))
166 bool isEventBlockedByModalComps (MSG
& m
)
168 if (Component::getNumCurrentlyModalComponents() == 0 || JuceWindowIdentifier::isJUCEWindow (m
.hwnd
))
175 case 0x020A: /* WM_MOUSEWHEEL */
176 case 0x020E: /* WM_MOUSEHWHEEL */
184 case WM_MOUSEACTIVATE
:
185 case WM_NCMOUSEHOVER
:
187 return isHWNDBlockedByModalComponents (m
.hwnd
);
189 case WM_NCLBUTTONDOWN
:
190 case WM_NCLBUTTONDBLCLK
:
191 case WM_NCRBUTTONDOWN
:
192 case WM_NCRBUTTONDBLCLK
:
193 case WM_NCMBUTTONDOWN
:
194 case WM_NCMBUTTONDBLCLK
:
196 case WM_LBUTTONDBLCLK
:
198 case WM_MBUTTONDBLCLK
:
200 case WM_RBUTTONDBLCLK
:
203 if (isHWNDBlockedByModalComponents (m
.hwnd
))
205 Component
* const modal
= Component::getCurrentlyModalComponent (0);
206 if (modal
!= nullptr)
207 modal
->inputAttemptWhenModal();
220 BOOL CALLBACK
broadcastEnumWindowProc (HWND hwnd
, LPARAM lParam
)
222 if (hwnd
!= juce_messageWindowHandle
)
223 reinterpret_cast <Array
<HWND
>*> (lParam
)->add (hwnd
);
229 //==============================================================================
230 bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
)
232 using namespace WindowsMessageHelpers
;
235 if (returnIfNoPendingMessages
&& ! PeekMessage (&m
, (HWND
) 0, 0, 0, 0))
238 if (GetMessage (&m
, (HWND
) 0, 0, 0) >= 0)
240 if (m
.message
== specialId
&& m
.hwnd
== juce_messageWindowHandle
)
242 Message
* const message
= reinterpret_cast <Message
*> (m
.lParam
);
243 MessageManager::getInstance()->deliverMessage (message
);
244 message
->decReferenceCount();
246 else if (m
.message
== WM_QUIT
)
248 if (JUCEApplication::getInstance() != nullptr)
249 JUCEApplication::getInstance()->systemRequestedQuit();
251 else if (! WindowsMessageHelpers::isEventBlockedByModalComps (m
))
253 if ((m
.message
== WM_LBUTTONDOWN
|| m
.message
== WM_RBUTTONDOWN
)
254 && ! JuceWindowIdentifier::isJUCEWindow (m
.hwnd
))
256 // if it's someone else's window being clicked on, and the focus is
257 // currently on a juce window, pass the kb focus over..
258 HWND currentFocus
= GetFocus();
260 if (currentFocus
== 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus
))
264 TranslateMessage (&m
);
265 DispatchMessage (&m
);
272 bool MessageManager::postMessageToSystemQueue (Message
* message
)
274 message
->incReferenceCount();
275 return PostMessage (juce_messageWindowHandle
, WindowsMessageHelpers::specialId
, 0, (LPARAM
) message
) != 0;
278 void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction
* callback
,
281 if (MessageManager::getInstance()->isThisTheMessageThread())
283 return (*callback
) (userData
);
287 // If a thread has a MessageManagerLock and then tries to call this method, it'll
288 // deadlock because the message manager is blocked from running, and can't
289 // call your function..
290 jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager());
292 return (void*) SendMessage (juce_messageWindowHandle
,
293 WindowsMessageHelpers::specialCallbackId
,
299 void MessageManager::broadcastMessage (const String
& value
)
302 EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc
, (LPARAM
) &windows
);
304 const String
localCopy (value
);
307 data
.dwData
= WindowsMessageHelpers::broadcastId
;
308 data
.cbData
= (localCopy
.length() + 1) * sizeof (CharPointer_UTF32::CharType
);
309 data
.lpData
= (void*) localCopy
.toUTF32().getAddress();
311 for (int i
= windows
.size(); --i
>= 0;)
313 HWND hwnd
= windows
.getUnchecked(i
);
315 TCHAR windowName
[64]; // no need to read longer strings than this
316 GetWindowText (hwnd
, windowName
, 64);
319 if (String (windowName
) == WindowsMessageHelpers::messageWindowName
)
322 SendMessageTimeout (hwnd
, WM_COPYDATA
,
323 (WPARAM
) juce_messageWindowHandle
,
325 SMTO_BLOCK
| SMTO_ABORTIFHUNG
, 8000, &result
);
330 //==============================================================================
331 void MessageManager::doPlatformSpecificInitialisation()
335 using namespace WindowsMessageHelpers
;
336 messageWindow
= new HiddenMessageWindow (messageWindowName
, (WNDPROC
) messageWndProc
);
337 juce_messageWindowHandle
= messageWindow
->getHWND();
340 void MessageManager::doPlatformSpecificShutdown()
342 WindowsMessageHelpers::messageWindow
= nullptr;
347 //==============================================================================
348 class DeviceChangeDetector
// (Used by various audio classes)
351 DeviceChangeDetector (const wchar_t* const name
)
352 : messageWindow (name
, (WNDPROC
) deviceChangeEventCallback
)
354 SetWindowLongPtr (messageWindow
.getHWND(), GWLP_USERDATA
, (LONG_PTR
) this);
357 virtual ~DeviceChangeDetector() {}
360 virtual void systemDeviceChanged() = 0;
363 HiddenMessageWindow messageWindow
;
365 static LRESULT CALLBACK
deviceChangeEventCallback (HWND h
, const UINT message
,
366 const WPARAM wParam
, const LPARAM lParam
)
368 if (message
== WM_DEVICECHANGE
369 && (wParam
== 0x8000 /*DBT_DEVICEARRIVAL*/
370 || wParam
== 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/
371 || wParam
== 0x0007 /*DBT_DEVNODES_CHANGED*/))
373 ((DeviceChangeDetector
*) GetWindowLongPtr (h
, GWLP_USERDATA
))->systemDeviceChanged();
376 return DefWindowProc (h
, message
, wParam
, lParam
);