2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* CFWindowsMessageQueue.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #if defined(__WIN32__)
30 #include "CFWindowsMessageQueue.h"
31 #include "CFInternal.h"
33 extern DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef mode
);
34 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef mode
);
36 struct __CFWindowsMessageQueue
{
38 CFAllocatorRef _allocator
;
41 CFRunLoopSourceRef _source
;
42 CFMutableArrayRef _runLoops
;
45 /* Bit 3 in the base reserved bits is used for invalid state */
47 CF_INLINE Boolean
__CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
48 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
51 CF_INLINE
void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq
) {
52 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
55 CF_INLINE
void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq
) {
56 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
59 CF_INLINE
void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq
) {
60 __CFSpinLock(&(wmq
->_lock
));
63 CF_INLINE
void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq
) {
64 __CFSpinUnlock(&(wmq
->_lock
));
67 static Boolean
__CFWindowsMessageQueueEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
68 CFWindowsMessageQueueRef wmq1
= (CFWindowsMessageQueueRef
)cf1
;
69 CFWindowsMessageQueueRef wmq2
= (CFWindowsMessageQueueRef
)cf2
;
70 return (wmq1
== wmq2
);
73 static CFHashCode
__CFWindowsMessageQueueHash(CFTypeRef cf
) {
74 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
75 return (CFHashCode
)wmq
;
78 static CFStringRef
__CFWindowsMessageQueueCopyDescription(CFTypeRef cf
) {
79 /* Some commentary, possibly as out of date as much of the rest of the file was
80 #warning CF: this and many other CopyDescription functions are probably
81 #warning CF: broken, in that some of these fields being printed out can
82 #warning CF: be NULL, when the object is in the invalid state
84 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
85 CFMutableStringRef result
;
86 result
= CFStringCreateMutable(CFGetAllocator(wmq
), 0);
87 __CFWindowsMessageQueueLock(wmq
);
88 /* More commentary, which we don't really need to see with every build
89 #warning CF: here, and probably everywhere with a per-instance lock,
90 #warning CF: the locked state will always be true because we lock,
91 #warning CF: and you cannot call description if the object is locked;
92 #warning CF: probably should not lock description, and call it unsafe
94 CFStringAppendFormat(result
, NULL
, CFSTR("<CFWindowsMessageQueue %p [%p]>{locked = %s, valid = %s, mask = 0x%x,\n run loops = %@}"), cf
, CFGetAllocator(wmq
), (wmq
->_lock
.LockCount
? "Yes" : "No"), (__CFWindowsMessageQueueIsValid(wmq
) ? "Yes" : "No"), (UInt32
)wmq
->_mask
, wmq
->_runLoops
);
95 __CFWindowsMessageQueueUnlock(wmq
);
99 CFAllocatorRef
__CFWindowsMessageQueueGetAllocator(CFTypeRef cf
) {
100 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
101 return wmq
->_allocator
;
104 static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf
) {
105 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
106 CFAllocatorRef allocator
= CFGetAllocator(wmq
);
107 CFAllocatorDeallocate(allocator
, wmq
);
108 CFRelease(allocator
);
109 DeleteCriticalSection(&(wmq
->_lock
));
112 static CFTypeID __kCFWindowsMessageQueueTypeID
= _kCFRuntimeNotATypeID
;
114 static const CFRuntimeClass __CFWindowsMessageQueueClass
= {
116 "CFWindowsMessageQueue",
119 __CFWindowsMessageQueueDeallocate
,
120 __CFWindowsMessageQueueEqual
,
121 __CFWindowsMessageQueueHash
,
123 __CFWindowsMessageQueueCopyDescription
126 __private_extern__
void __CFWindowsMessageQueueInitialize(void) {
127 __kCFWindowsMessageQueueTypeID
= _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass
);
130 CFTypeID
CFWindowsMessageQueueGetTypeID(void) {
131 return __kCFWindowsMessageQueueTypeID
;
134 CFWindowsMessageQueueRef
CFWindowsMessageQueueCreate(CFAllocatorRef allocator
, DWORD mask
) {
135 CFWindowsMessageQueueRef memory
;
136 UInt32 size
= sizeof(struct __CFWindowsMessageQueue
) - sizeof(CFRuntimeBase
);
137 memory
= (CFWindowsMessageQueueRef
)_CFRuntimeCreateInstance(allocator
, __kCFWindowsMessageQueueTypeID
, size
, NULL
);
138 if (NULL
== memory
) {
141 __CFWindowsMessageQueueSetValid(memory
);
143 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
144 memory
->_mask
= mask
;
145 memory
->_source
= NULL
;
146 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
150 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq
) {
151 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
153 __CFWindowsMessageQueueLock(wmq
);
154 if (__CFWindowsMessageQueueIsValid(wmq
)) {
156 __CFWindowsMessageQueueUnsetValid(wmq
);
157 for (idx
= CFArrayGetCount(wmq
->_runLoops
); idx
--;) {
158 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(wmq
->_runLoops
, idx
));
160 CFRelease(wmq
->_runLoops
);
161 wmq
->_runLoops
= NULL
;
162 if (NULL
!= wmq
->_source
) {
163 CFRunLoopSourceInvalidate(wmq
->_source
);
164 CFRelease(wmq
->_source
);
168 __CFWindowsMessageQueueUnlock(wmq
);
172 Boolean
CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
173 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
174 return __CFWindowsMessageQueueIsValid(wmq
);
177 DWORD
CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq
) {
178 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
182 static void __CFWindowsMessageQueueSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
183 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
184 __CFWindowsMessageQueueLock(wmq
);
185 if (__CFWindowsMessageQueueIsValid(wmq
)) {
187 CFArrayAppendValue(wmq
->_runLoops
, rl
);
188 mask
= __CFRunLoopGetWindowsMessageQueueMask(rl
, mode
);
190 __CFRunLoopSetWindowsMessageQueueMask(rl
, mask
, mode
);
192 __CFWindowsMessageQueueUnlock(wmq
);
195 static void __CFWindowsMessageQueueCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
196 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
197 __CFWindowsMessageQueueLock(wmq
);
198 #if defined (__WIN32__)
199 //#warning CF: should fix up run loop modes mask here, if not done
200 //#warning CF: previously by the invalidation, where it should also
201 //#warning CF: be done
203 #warning CF: should fix up run loop modes mask here, if not done
204 #warning CF: previously by the invalidation, where it should also
207 if (NULL
!= wmq
->_runLoops
) {
208 SInt32 idx
= CFArrayGetFirstIndexOfValue(wmq
->_runLoops
, CFRangeMake(0, CFArrayGetCount(wmq
->_runLoops
)), rl
);
209 if (0 <= idx
) CFArrayRemoveValueAtIndex(wmq
->_runLoops
, idx
);
211 __CFWindowsMessageQueueUnlock(wmq
);
214 static void __CFWindowsMessageQueuePerform(void *info
) {
215 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
217 __CFWindowsMessageQueueLock(wmq
);
218 if (!__CFWindowsMessageQueueIsValid(wmq
)) {
219 __CFWindowsMessageQueueUnlock(wmq
);
222 __CFWindowsMessageQueueUnlock(wmq
);
223 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
224 TranslateMessage(&msg
);
225 DispatchMessage(&msg
);
229 CFRunLoopSourceRef
CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator
, CFWindowsMessageQueueRef wmq
, CFIndex order
) {
230 CFRunLoopSourceRef result
= NULL
;
231 __CFWindowsMessageQueueLock(wmq
);
232 if (NULL
== wmq
->_source
) {
233 CFRunLoopSourceContext context
;
235 context
.info
= (void *)wmq
;
236 context
.retain
= CFRetain
;
237 context
.release
= CFRelease
;
238 context
.copyDescription
= __CFWindowsMessageQueueCopyDescription
;
239 context
.equal
= __CFWindowsMessageQueueEqual
;
240 context
.hash
= __CFWindowsMessageQueueHash
;
241 context
.schedule
= __CFWindowsMessageQueueSchedule
;
242 context
.cancel
= __CFWindowsMessageQueueCancel
;
243 context
.perform
= __CFWindowsMessageQueuePerform
;
244 wmq
->_source
= CFRunLoopSourceCreate(allocator
, order
, &context
);
246 CFRetain(wmq
->_source
); /* This retain is for the receiver */
247 result
= wmq
->_source
;
248 __CFWindowsMessageQueueUnlock(wmq
);