]> git.saurik.com Git - apple/cf.git/blobdiff - CFWindowsMessageQueue.c
CF-476.10.tar.gz
[apple/cf.git] / CFWindowsMessageQueue.c
diff --git a/CFWindowsMessageQueue.c b/CFWindowsMessageQueue.c
new file mode 100644 (file)
index 0000000..77eece0
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*     CFWindowsMessageQueue.c
+       Copyright 1999-2002, Apple, Inc. All rights reserved.
+       Responsibility: Christopher Kane
+*/
+
+#if defined(__WIN32__)
+
+#include "CFWindowsMessageQueue.h"
+#include "CFInternal.h"
+
+extern DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode);
+extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef mode);
+
+struct __CFWindowsMessageQueue {
+    CFRuntimeBase _base;
+    CFAllocatorRef _allocator;
+    CFSpinLock_t _lock;
+    DWORD _mask;
+    CFRunLoopSourceRef _source;
+    CFMutableArrayRef _runLoops;
+};
+
+/* Bit 3 in the base reserved bits is used for invalid state */
+
+CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
+    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3);
+}
+
+CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) {
+    __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
+}
+
+CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) {
+    __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
+}
+
+CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) {
+    __CFSpinLock(&(wmq->_lock));
+}
+
+CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) {
+    __CFSpinUnlock(&(wmq->_lock));
+}
+
+static Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) {
+    CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1;
+    CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2;
+    return (wmq1 == wmq2);
+}
+
+static CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
+    return (CFHashCode)wmq;
+}
+
+static CFStringRef __CFWindowsMessageQueueCopyDescription(CFTypeRef cf) {
+/* Some commentary, possibly as out of date as much of the rest of the file was
+#warning CF: this and many other CopyDescription functions are probably
+#warning CF: broken, in that some of these fields being printed out can
+#warning CF: be NULL, when the object is in the invalid state
+*/
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
+    CFMutableStringRef result;
+    result = CFStringCreateMutable(CFGetAllocator(wmq), 0);
+    __CFWindowsMessageQueueLock(wmq);
+/* More commentary, which we don't really need to see with every build
+#warning CF: here, and probably everywhere with a per-instance lock,
+#warning CF: the locked state will always be true because we lock,
+#warning CF: and you cannot call description if the object is locked;
+#warning CF: probably should not lock description, and call it unsafe
+*/
+    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);
+    __CFWindowsMessageQueueUnlock(wmq);
+    return result;
+}
+
+CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
+    return wmq->_allocator;
+}
+
+static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
+    CFAllocatorRef allocator = CFGetAllocator(wmq);
+    CFAllocatorDeallocate(allocator, wmq);
+    CFRelease(allocator);
+    DeleteCriticalSection(&(wmq->_lock));
+}
+
+static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID;
+
+static const CFRuntimeClass __CFWindowsMessageQueueClass = {
+    0,
+    "CFWindowsMessageQueue",
+    NULL,      // init
+    NULL,      // copy
+    __CFWindowsMessageQueueDeallocate,
+    __CFWindowsMessageQueueEqual,
+    __CFWindowsMessageQueueHash,
+    NULL,      //
+    __CFWindowsMessageQueueCopyDescription
+};
+
+__private_extern__ void __CFWindowsMessageQueueInitialize(void) {
+    __kCFWindowsMessageQueueTypeID = _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass);
+}
+
+CFTypeID CFWindowsMessageQueueGetTypeID(void) {
+    return __kCFWindowsMessageQueueTypeID;
+}
+
+CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, DWORD mask) {
+    CFWindowsMessageQueueRef memory;
+    UInt32 size = sizeof(struct __CFWindowsMessageQueue) - sizeof(CFRuntimeBase);
+    memory = (CFWindowsMessageQueueRef)_CFRuntimeCreateInstance(allocator, __kCFWindowsMessageQueueTypeID, size, NULL);
+    if (NULL == memory) {
+        return NULL;
+    }
+    __CFWindowsMessageQueueSetValid(memory);
+
+    CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
+    memory->_mask = mask;   
+    memory->_source = NULL;
+    memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL);
+    return memory;
+}
+
+void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) {
+    __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
+    CFRetain(wmq);
+    __CFWindowsMessageQueueLock(wmq);
+    if (__CFWindowsMessageQueueIsValid(wmq)) {
+       SInt32 idx;
+       __CFWindowsMessageQueueUnsetValid(wmq);
+       for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) {
+           CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx));
+       }
+       CFRelease(wmq->_runLoops);
+       wmq->_runLoops = NULL;
+       if (NULL != wmq->_source) {
+           CFRunLoopSourceInvalidate(wmq->_source);
+           CFRelease(wmq->_source);
+           wmq->_source = NULL;
+       }
+    }
+    __CFWindowsMessageQueueUnlock(wmq);
+    CFRelease(wmq);
+}
+
+Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
+    __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
+    return __CFWindowsMessageQueueIsValid(wmq);
+}
+
+DWORD CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) {
+    __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
+    return wmq->_mask;
+}
+
+static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
+    __CFWindowsMessageQueueLock(wmq);
+    if (__CFWindowsMessageQueueIsValid(wmq)) {
+       uint32_t mask;
+       CFArrayAppendValue(wmq->_runLoops, rl);
+       mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode);
+       mask |= wmq->_mask;
+       __CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode);
+    }
+    __CFWindowsMessageQueueUnlock(wmq);
+}
+
+static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
+    __CFWindowsMessageQueueLock(wmq);
+#if defined (__WIN32__)
+//#warning CF: should fix up run loop modes mask here, if not done
+//#warning CF: previously by the invalidation, where it should also
+//#warning CF: be done
+#else
+#warning CF: should fix up run loop modes mask here, if not done
+#warning CF: previously by the invalidation, where it should also
+#warning CF: be done
+#endif //__WIN32__
+    if (NULL != wmq->_runLoops) {
+       SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl);
+       if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx);
+    }
+    __CFWindowsMessageQueueUnlock(wmq);
+}
+
+static void __CFWindowsMessageQueuePerform(void *info) {
+    CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
+    MSG msg;
+    __CFWindowsMessageQueueLock(wmq);
+    if (!__CFWindowsMessageQueueIsValid(wmq)) {
+       __CFWindowsMessageQueueUnlock(wmq);
+       return;
+    }
+    __CFWindowsMessageQueueUnlock(wmq);
+    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
+       TranslateMessage(&msg);
+       DispatchMessage(&msg);
+    }
+}
+
+CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
+    CFRunLoopSourceRef result = NULL;
+    __CFWindowsMessageQueueLock(wmq);
+    if (NULL == wmq->_source) {
+       CFRunLoopSourceContext context;
+       context.version = 0;
+       context.info = (void *)wmq;
+       context.retain = CFRetain;
+       context.release = CFRelease;
+       context.copyDescription = __CFWindowsMessageQueueCopyDescription;
+       context.equal = __CFWindowsMessageQueueEqual;
+       context.hash = __CFWindowsMessageQueueHash;
+       context.schedule = __CFWindowsMessageQueueSchedule;
+       context.cancel = __CFWindowsMessageQueueCancel;
+       context.perform = __CFWindowsMessageQueuePerform;
+       wmq->_source = CFRunLoopSourceCreate(allocator, order, &context);
+    }
+    CFRetain(wmq->_source);    /* This retain is for the receiver */
+    result = wmq->_source;
+    __CFWindowsMessageQueueUnlock(wmq);
+    return result;
+}
+
+#endif
+