/* * Copyright (c) 2005 Apple Computer, 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 uint32_t __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode); extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t 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)->_info, 3, 3); } CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) { __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 1); } CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) { __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 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("{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); __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); } 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); memory->_lock = 0; 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 = 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 = info; __CFWindowsMessageQueueLock(wmq); #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 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 = 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