2 * Copyright (c) 2005 Apple Computer, 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 uint32_t __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef mode
);
34 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, uint32_t 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
)->_info
, 3, 3);
51 CF_INLINE
void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq
) {
52 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_info
, 3, 3, 1);
55 CF_INLINE
void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq
) {
56 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_info
, 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 0x%x [0x%x]>{locked = %s, valid = %s, mask = 0x%x,\n run loops = %@}"), (UInt32
)cf
, (UInt32
)CFGetAllocator(wmq
), (wmq
->_lock
? "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
);
111 static CFTypeID __kCFWindowsMessageQueueTypeID
= _kCFRuntimeNotATypeID
;
113 static const CFRuntimeClass __CFWindowsMessageQueueClass
= {
115 "CFWindowsMessageQueue",
118 __CFWindowsMessageQueueDeallocate
,
119 __CFWindowsMessageQueueEqual
,
120 __CFWindowsMessageQueueHash
,
122 __CFWindowsMessageQueueCopyDescription
125 __private_extern__
void __CFWindowsMessageQueueInitialize(void) {
126 __kCFWindowsMessageQueueTypeID
= _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass
);
129 CFTypeID
CFWindowsMessageQueueGetTypeID(void) {
130 return __kCFWindowsMessageQueueTypeID
;
133 CFWindowsMessageQueueRef
CFWindowsMessageQueueCreate(CFAllocatorRef allocator
, DWORD mask
) {
134 CFWindowsMessageQueueRef memory
;
135 UInt32 size
= sizeof(struct __CFWindowsMessageQueue
) - sizeof(CFRuntimeBase
);
136 memory
= (CFWindowsMessageQueueRef
)_CFRuntimeCreateInstance(allocator
, __kCFWindowsMessageQueueTypeID
, size
, NULL
);
137 if (NULL
== memory
) {
140 __CFWindowsMessageQueueSetValid(memory
);
142 memory
->_mask
= mask
;
143 memory
->_source
= NULL
;
144 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
148 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq
) {
149 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
151 __CFWindowsMessageQueueLock(wmq
);
152 if (__CFWindowsMessageQueueIsValid(wmq
)) {
154 __CFWindowsMessageQueueUnsetValid(wmq
);
155 for (idx
= CFArrayGetCount(wmq
->_runLoops
); idx
--;) {
156 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(wmq
->_runLoops
, idx
));
158 CFRelease(wmq
->_runLoops
);
159 wmq
->_runLoops
= NULL
;
160 if (NULL
!= wmq
->_source
) {
161 CFRunLoopSourceInvalidate(wmq
->_source
);
162 CFRelease(wmq
->_source
);
166 __CFWindowsMessageQueueUnlock(wmq
);
170 Boolean
CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
171 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
172 return __CFWindowsMessageQueueIsValid(wmq
);
175 DWORD
CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq
) {
176 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
180 static void __CFWindowsMessageQueueSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
181 CFWindowsMessageQueueRef wmq
= info
;
182 __CFWindowsMessageQueueLock(wmq
);
183 if (__CFWindowsMessageQueueIsValid(wmq
)) {
185 CFArrayAppendValue(wmq
->_runLoops
, rl
);
186 mask
= __CFRunLoopGetWindowsMessageQueueMask(rl
, mode
);
188 __CFRunLoopSetWindowsMessageQueueMask(rl
, mask
, mode
);
190 __CFWindowsMessageQueueUnlock(wmq
);
193 static void __CFWindowsMessageQueueCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
194 CFWindowsMessageQueueRef wmq
= info
;
195 __CFWindowsMessageQueueLock(wmq
);
196 #warning CF: should fix up run loop modes mask here, if not done
197 #warning CF: previously by the invalidation, where it should also
199 if (NULL
!= wmq
->_runLoops
) {
200 SInt32 idx
= CFArrayGetFirstIndexOfValue(wmq
->_runLoops
, CFRangeMake(0, CFArrayGetCount(wmq
->_runLoops
)), rl
);
201 if (0 <= idx
) CFArrayRemoveValueAtIndex(wmq
->_runLoops
, idx
);
203 __CFWindowsMessageQueueUnlock(wmq
);
206 static void __CFWindowsMessageQueuePerform(void *info
) {
207 CFWindowsMessageQueueRef wmq
= info
;
209 __CFWindowsMessageQueueLock(wmq
);
210 if (!__CFWindowsMessageQueueIsValid(wmq
)) {
211 __CFWindowsMessageQueueUnlock(wmq
);
214 __CFWindowsMessageQueueUnlock(wmq
);
215 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
216 TranslateMessage(&msg
);
217 DispatchMessage(&msg
);
221 CFRunLoopSourceRef
CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator
, CFWindowsMessageQueueRef wmq
, CFIndex order
) {
222 CFRunLoopSourceRef result
= NULL
;
223 __CFWindowsMessageQueueLock(wmq
);
224 if (NULL
== wmq
->_source
) {
225 CFRunLoopSourceContext context
;
227 context
.info
= (void *)wmq
;
228 context
.retain
= CFRetain
;
229 context
.release
= CFRelease
;
230 context
.copyDescription
= __CFWindowsMessageQueueCopyDescription
;
231 context
.equal
= __CFWindowsMessageQueueEqual
;
232 context
.hash
= __CFWindowsMessageQueueHash
;
233 context
.schedule
= __CFWindowsMessageQueueSchedule
;
234 context
.cancel
= __CFWindowsMessageQueueCancel
;
235 context
.perform
= __CFWindowsMessageQueuePerform
;
236 wmq
->_source
= CFRunLoopSourceCreate(allocator
, order
, &context
);
238 CFRetain(wmq
->_source
); /* This retain is for the receiver */
239 result
= wmq
->_source
;
240 __CFWindowsMessageQueueUnlock(wmq
);