2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* CFWindowsMessageQueue.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #if defined(__WIN32__)
32 #include "CFWindowsMessageQueue.h"
33 #include "CFInternal.h"
35 extern unsigned long __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef mode
);
36 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, unsigned long mask
, CFStringRef mode
);
38 struct __CFWindowsMessageQueue
{
40 CFAllocatorRef _allocator
;
43 CFRunLoopSourceRef _source
;
44 CFMutableArrayRef _runLoops
;
47 /* Bit 3 in the base reserved bits is used for invalid state */
49 CF_INLINE Boolean
__CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
50 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)wmq
)->_info
, 3, 3);
53 CF_INLINE
void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq
) {
54 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_info
, 3, 3, 1);
57 CF_INLINE
void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq
) {
58 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_info
, 3, 3, 0);
61 CF_INLINE
void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq
) {
62 __CFSpinLock(&(wmq
->_lock
));
65 CF_INLINE
void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq
) {
66 __CFSpinUnlock(&(wmq
->_lock
));
69 CFTypeID
CFWindowsMessageQueueGetTypeID(void) {
70 return __kCFWindowsMessageQueueTypeID
;
73 Boolean
__CFWindowsMessageQueueEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
74 CFWindowsMessageQueueRef wmq1
= (CFWindowsMessageQueueRef
)cf1
;
75 CFWindowsMessageQueueRef wmq2
= (CFWindowsMessageQueueRef
)cf2
;
76 return (wmq1
== wmq2
);
79 CFHashCode
__CFWindowsMessageQueueHash(CFTypeRef cf
) {
80 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
81 return (CFHashCode
)wmq
;
84 CFStringRef
__CFWindowsMessageQueueCopyDescription(CFTypeRef cf
) {
85 #warning CF: this and many other CopyDescription functions are probably
86 #warning CF: broken, in that some of these fields being printed out can
87 #warning CF: be NULL, when the object is in the invalid state
88 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
89 CFMutableStringRef result
;
90 result
= CFStringCreateMutable(CFGetAllocator(wmq
), 0);
91 __CFWindowsMessageQueueLock(wmq
);
92 #warning CF: here, and probably everywhere with a per-instance lock,
93 #warning CF: the locked state will always be true because we lock,
94 #warning CF: and you cannot call description if the object is locked;
95 #warning CF: probably should not lock description, and call it unsafe
96 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
);
97 __CFWindowsMessageQueueUnlock(wmq
);
101 CFAllocatorRef
__CFWindowsMessageQueueGetAllocator(CFTypeRef cf
) {
102 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
103 return wmq
->_allocator
;
106 void __CFWindowsMessageQueueDeallocate(CFTypeRef cf
) {
107 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
108 CFAllocatorRef allocator
= CFGetAllocator(wmq
);
109 CFAllocatorDeallocate(allocator
, wmq
);
110 CFRelease(allocator
);
113 CFWindowsMessageQueueRef
CFWindowsMessageQueueCreate(CFAllocatorRef allocator
, DWORD mask
) {
114 CFWindowsMessageQueueRef memory
;
116 size
= sizeof(struct __CFWindowsMessageQueue
);
117 allocator
= (NULL
== allocator
) ? CFRetain(__CFGetDefaultAllocator()) : CFRetain(allocator
);
118 memory
= CFAllocatorAllocate(allocator
, size
, 0);
119 if (NULL
== memory
) {
120 CFRelease(allocator
);
123 __CFGenericInitBase(memory
, NULL
, __kCFWindowsMessageQueueTypeID
);
124 memory
->_allocator
= allocator
;
125 __CFWindowsMessageQueueSetValid(memory
);
127 memory
->_mask
= mask
;
128 memory
->_source
= NULL
;
129 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
133 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq
) {
134 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
136 __CFWindowsMessageQueueLock(wmq
);
137 if (__CFWindowsMessageQueueIsValid(wmq
)) {
139 __CFWindowsMessageQueueUnsetValid(wmq
);
140 for (idx
= CFArrayGetCount(wmq
->_runLoops
); idx
--;) {
141 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(wmq
->_runLoops
, idx
));
143 CFRelease(wmq
->_runLoops
);
144 wmq
->_runLoops
= NULL
;
145 if (NULL
!= wmq
->_source
) {
146 CFRunLoopSourceInvalidate(wmq
->_source
);
147 CFRelease(wmq
->_source
);
151 __CFWindowsMessageQueueUnlock(wmq
);
155 Boolean
CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
156 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
157 return __CFWindowsMessageQueueIsValid(wmq
);
160 DWORD
CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq
) {
161 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
165 static void __CFWindowsMessageQueueSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
166 CFWindowsMessageQueueRef wmq
= info
;
167 __CFWindowsMessageQueueLock(wmq
);
168 if (__CFWindowsMessageQueueIsValid(wmq
)) {
170 CFArrayAppendValue(wmq
->_runLoops
, rl
);
171 mask
= __CFRunLoopGetWindowsMessageQueueMask(rl
, mode
);
173 __CFRunLoopSetWindowsMessageQueueMask(rl
, mask
, mode
);
175 __CFWindowsMessageQueueUnlock(wmq
);
178 static void __CFWindowsMessageQueueCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
179 CFWindowsMessageQueueRef wmq
= info
;
180 __CFWindowsMessageQueueLock(wmq
);
181 #warning CF: should fix up run loop modes mask here, if not done
182 #warning CF: previously by the invalidation, where it should also
184 if (NULL
!= wmq
->_runLoops
) {
185 SInt32 idx
= CFArrayGetFirstIndexOfValue(wmq
->_runLoops
, CFRangeMake(0, CFArrayGetCount(wmq
->_runLoops
)), rl
);
186 if (0 <= idx
) CFArrayRemoveValueAtIndex(wmq
->_runLoops
, idx
);
188 __CFWindowsMessageQueueUnlock(wmq
);
191 static void __CFWindowsMessageQueuePerform(void *info
) {
192 CFWindowsMessageQueueRef wmq
= info
;
194 __CFWindowsMessageQueueLock(wmq
);
195 if (!__CFWindowsMessageQueueIsValid(wmq
)) {
196 __CFWindowsMessageQueueUnlock(wmq
);
199 __CFWindowsMessageQueueUnlock(wmq
);
200 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
201 TranslateMessage(&msg
);
202 DispatchMessage(&msg
);
206 CFRunLoopSourceRef
CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator
, CFWindowsMessageQueueRef wmq
, CFIndex order
) {
207 CFRunLoopSourceRef result
= NULL
;
208 __CFWindowsMessageQueueLock(wmq
);
209 if (NULL
== wmq
->_source
) {
210 CFRunLoopSourceContext context
;
212 context
.info
= (void *)wmq
;
213 context
.retain
= (const void *(*)(const void *))CFRetain
;
214 context
.release
= (void (*)(const void *))CFRelease
;
215 context
.copyDescription
= (CFStringRef (*)(const void *))__CFWindowsMessageQueueCopyDescription
;
216 context
.equal
= (Boolean (*)(const void *, const void *))__CFWindowsMessageQueueEqual
;
217 context
.hash
= (CFHashCode (*)(const void *))__CFWindowsMessageQueueHash
;
218 context
.schedule
= __CFWindowsMessageQueueSchedule
;
219 context
.cancel
= __CFWindowsMessageQueueCancel
;
220 context
.perform
= __CFWindowsMessageQueuePerform
;
221 wmq
->_source
= CFRunLoopSourceCreate(allocator
, order
, &context
);
223 CFRetain(wmq
->_source
); /* This retain is for the receiver */
224 result
= wmq
->_source
;
225 __CFWindowsMessageQueueUnlock(wmq
);