]> git.saurik.com Git - apple/cf.git/blob - RunLoop.subproj/CFWindowsMessageQueue.c
CF-368.1.tar.gz
[apple/cf.git] / RunLoop.subproj / CFWindowsMessageQueue.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFWindowsMessageQueue.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #if defined(__WIN32__)
29
30 #include "CFWindowsMessageQueue.h"
31 #include "CFInternal.h"
32
33 extern uint32_t __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode);
34 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t mask, CFStringRef mode);
35
36 struct __CFWindowsMessageQueue {
37 CFRuntimeBase _base;
38 CFAllocatorRef _allocator;
39 CFSpinLock_t _lock;
40 DWORD _mask;
41 CFRunLoopSourceRef _source;
42 CFMutableArrayRef _runLoops;
43 };
44
45 /* Bit 3 in the base reserved bits is used for invalid state */
46
47 CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
48 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_info, 3, 3);
49 }
50
51 CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) {
52 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 1);
53 }
54
55 CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) {
56 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 0);
57 }
58
59 CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) {
60 __CFSpinLock(&(wmq->_lock));
61 }
62
63 CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) {
64 __CFSpinUnlock(&(wmq->_lock));
65 }
66
67 static Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) {
68 CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1;
69 CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2;
70 return (wmq1 == wmq2);
71 }
72
73 static CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) {
74 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
75 return (CFHashCode)wmq;
76 }
77
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
83 */
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
93 */
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);
96 return result;
97 }
98
99 CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) {
100 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
101 return wmq->_allocator;
102 }
103
104 static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) {
105 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
106 CFAllocatorRef allocator = CFGetAllocator(wmq);
107 CFAllocatorDeallocate(allocator, wmq);
108 CFRelease(allocator);
109 }
110
111 static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID;
112
113 static const CFRuntimeClass __CFWindowsMessageQueueClass = {
114 0,
115 "CFWindowsMessageQueue",
116 NULL, // init
117 NULL, // copy
118 __CFWindowsMessageQueueDeallocate,
119 __CFWindowsMessageQueueEqual,
120 __CFWindowsMessageQueueHash,
121 NULL, //
122 __CFWindowsMessageQueueCopyDescription
123 };
124
125 __private_extern__ void __CFWindowsMessageQueueInitialize(void) {
126 __kCFWindowsMessageQueueTypeID = _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass);
127 }
128
129 CFTypeID CFWindowsMessageQueueGetTypeID(void) {
130 return __kCFWindowsMessageQueueTypeID;
131 }
132
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) {
138 return NULL;
139 }
140 __CFWindowsMessageQueueSetValid(memory);
141 memory->_lock = 0;
142 memory->_mask = mask;
143 memory->_source = NULL;
144 memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL);
145 return memory;
146 }
147
148 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) {
149 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
150 CFRetain(wmq);
151 __CFWindowsMessageQueueLock(wmq);
152 if (__CFWindowsMessageQueueIsValid(wmq)) {
153 SInt32 idx;
154 __CFWindowsMessageQueueUnsetValid(wmq);
155 for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) {
156 CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx));
157 }
158 CFRelease(wmq->_runLoops);
159 wmq->_runLoops = NULL;
160 if (NULL != wmq->_source) {
161 CFRunLoopSourceInvalidate(wmq->_source);
162 CFRelease(wmq->_source);
163 wmq->_source = NULL;
164 }
165 }
166 __CFWindowsMessageQueueUnlock(wmq);
167 CFRelease(wmq);
168 }
169
170 Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
171 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
172 return __CFWindowsMessageQueueIsValid(wmq);
173 }
174
175 DWORD CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) {
176 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
177 return wmq->_mask;
178 }
179
180 static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
181 CFWindowsMessageQueueRef wmq = info;
182 __CFWindowsMessageQueueLock(wmq);
183 if (__CFWindowsMessageQueueIsValid(wmq)) {
184 uint32_t mask;
185 CFArrayAppendValue(wmq->_runLoops, rl);
186 mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode);
187 mask |= wmq->_mask;
188 __CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode);
189 }
190 __CFWindowsMessageQueueUnlock(wmq);
191 }
192
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
198 #warning CF: be done
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);
202 }
203 __CFWindowsMessageQueueUnlock(wmq);
204 }
205
206 static void __CFWindowsMessageQueuePerform(void *info) {
207 CFWindowsMessageQueueRef wmq = info;
208 MSG msg;
209 __CFWindowsMessageQueueLock(wmq);
210 if (!__CFWindowsMessageQueueIsValid(wmq)) {
211 __CFWindowsMessageQueueUnlock(wmq);
212 return;
213 }
214 __CFWindowsMessageQueueUnlock(wmq);
215 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
216 TranslateMessage(&msg);
217 DispatchMessage(&msg);
218 }
219 }
220
221 CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
222 CFRunLoopSourceRef result = NULL;
223 __CFWindowsMessageQueueLock(wmq);
224 if (NULL == wmq->_source) {
225 CFRunLoopSourceContext context;
226 context.version = 0;
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);
237 }
238 CFRetain(wmq->_source); /* This retain is for the receiver */
239 result = wmq->_source;
240 __CFWindowsMessageQueueUnlock(wmq);
241 return result;
242 }
243
244 #endif
245