]> git.saurik.com Git - apple/cf.git/blob - RunLoop.subproj/CFWindowsMessageQueue.c
CF-299.tar.gz
[apple/cf.git] / RunLoop.subproj / CFWindowsMessageQueue.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFWindowsMessageQueue.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
28 */
29
30 #if defined(__WIN32__)
31
32 #include "CFWindowsMessageQueue.h"
33 #include "CFInternal.h"
34
35 extern unsigned long __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode);
36 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, unsigned long mask, CFStringRef mode);
37
38 struct __CFWindowsMessageQueue {
39 CFRuntimeBase _base;
40 CFAllocatorRef _allocator;
41 CFSpinLock_t _lock;
42 DWORD _mask;
43 CFRunLoopSourceRef _source;
44 CFMutableArrayRef _runLoops;
45 };
46
47 /* Bit 3 in the base reserved bits is used for invalid state */
48
49 CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
50 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_info, 3, 3);
51 }
52
53 CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) {
54 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 1);
55 }
56
57 CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) {
58 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 0);
59 }
60
61 CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) {
62 __CFSpinLock(&(wmq->_lock));
63 }
64
65 CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) {
66 __CFSpinUnlock(&(wmq->_lock));
67 }
68
69 CFTypeID CFWindowsMessageQueueGetTypeID(void) {
70 return __kCFWindowsMessageQueueTypeID;
71 }
72
73 Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) {
74 CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1;
75 CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2;
76 return (wmq1 == wmq2);
77 }
78
79 CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) {
80 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
81 return (CFHashCode)wmq;
82 }
83
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);
98 return result;
99 }
100
101 CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) {
102 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
103 return wmq->_allocator;
104 }
105
106 void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) {
107 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
108 CFAllocatorRef allocator = CFGetAllocator(wmq);
109 CFAllocatorDeallocate(allocator, wmq);
110 CFRelease(allocator);
111 }
112
113 CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, DWORD mask) {
114 CFWindowsMessageQueueRef memory;
115 UInt32 size;
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);
121 return NULL;
122 }
123 __CFGenericInitBase(memory, NULL, __kCFWindowsMessageQueueTypeID);
124 memory->_allocator = allocator;
125 __CFWindowsMessageQueueSetValid(memory);
126 memory->_lock = 0;
127 memory->_mask = mask;
128 memory->_source = NULL;
129 memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL);
130 return memory;
131 }
132
133 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) {
134 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
135 CFRetain(wmq);
136 __CFWindowsMessageQueueLock(wmq);
137 if (__CFWindowsMessageQueueIsValid(wmq)) {
138 SInt32 idx;
139 __CFWindowsMessageQueueUnsetValid(wmq);
140 for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) {
141 CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx));
142 }
143 CFRelease(wmq->_runLoops);
144 wmq->_runLoops = NULL;
145 if (NULL != wmq->_source) {
146 CFRunLoopSourceInvalidate(wmq->_source);
147 CFRelease(wmq->_source);
148 wmq->_source = NULL;
149 }
150 }
151 __CFWindowsMessageQueueUnlock(wmq);
152 CFRelease(wmq);
153 }
154
155 Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
156 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
157 return __CFWindowsMessageQueueIsValid(wmq);
158 }
159
160 DWORD CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) {
161 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
162 return wmq->_mask;
163 }
164
165 static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
166 CFWindowsMessageQueueRef wmq = info;
167 __CFWindowsMessageQueueLock(wmq);
168 if (__CFWindowsMessageQueueIsValid(wmq)) {
169 unsigned long mask;
170 CFArrayAppendValue(wmq->_runLoops, rl);
171 mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode);
172 mask |= wmq->_mask;
173 __CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode);
174 }
175 __CFWindowsMessageQueueUnlock(wmq);
176 }
177
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
183 #warning CF: be done
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);
187 }
188 __CFWindowsMessageQueueUnlock(wmq);
189 }
190
191 static void __CFWindowsMessageQueuePerform(void *info) {
192 CFWindowsMessageQueueRef wmq = info;
193 MSG msg;
194 __CFWindowsMessageQueueLock(wmq);
195 if (!__CFWindowsMessageQueueIsValid(wmq)) {
196 __CFWindowsMessageQueueUnlock(wmq);
197 return;
198 }
199 __CFWindowsMessageQueueUnlock(wmq);
200 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
201 TranslateMessage(&msg);
202 DispatchMessage(&msg);
203 }
204 }
205
206 CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
207 CFRunLoopSourceRef result = NULL;
208 __CFWindowsMessageQueueLock(wmq);
209 if (NULL == wmq->_source) {
210 CFRunLoopSourceContext context;
211 context.version = 0;
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);
222 }
223 CFRetain(wmq->_source); /* This retain is for the receiver */
224 result = wmq->_source;
225 __CFWindowsMessageQueueUnlock(wmq);
226 return result;
227 }
228
229 #endif
230