From eda6452792ea372d3a6ef6e876845c55f41fbd93 Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Wed, 13 May 2009 01:11:00 -0400 Subject: [PATCH] First Revision (from Archive) --- .gitignore | 3 + CGSInternal/CGSAccessibility.h | 48 ++++ CGSInternal/CGSCIFilter.h | 49 ++++ CGSInternal/CGSConnection.h | 88 +++++++ CGSInternal/CGSCursor.h | 77 ++++++ CGSInternal/CGSDebug.h | 114 +++++++++ CGSInternal/CGSDisplays.h | 66 ++++++ CGSInternal/CGSHotKeys.h | 120 ++++++++++ CGSInternal/CGSInternal.h | 49 ++++ CGSInternal/CGSMisc.h | 72 ++++++ CGSInternal/CGSNotifications.h | 97 ++++++++ CGSInternal/CGSRegion.h | 110 +++++++++ CGSInternal/CGSSession.h | 54 +++++ CGSInternal/CGSTransitions.h | 76 ++++++ CGSInternal/CGSWindow.h | 196 +++++++++++++++ CGSInternal/CGSWorkspace.h | 54 +++++ CGSInternal/CarbonHelpers.h | 40 ++++ English.lproj/InfoPlist.strings | Bin 0 -> 92 bytes Info.plist | 37 +++ WindowBlur.xcodeproj/TemplateIcon.icns | Bin 0 -> 52318 bytes WindowBlur.xcodeproj/project.pbxproj | 314 +++++++++++++++++++++++++ WindowBlurSIMBL.h | 17 ++ WindowBlurSIMBL.m | 43 ++++ WindowBlurWindowHack.h | 14 ++ WindowBlurWindowHack.m | 84 +++++++ WindowBlur_Prefix.pch | 7 + 26 files changed, 1829 insertions(+) create mode 100644 .gitignore create mode 100644 CGSInternal/CGSAccessibility.h create mode 100644 CGSInternal/CGSCIFilter.h create mode 100644 CGSInternal/CGSConnection.h create mode 100644 CGSInternal/CGSCursor.h create mode 100644 CGSInternal/CGSDebug.h create mode 100644 CGSInternal/CGSDisplays.h create mode 100644 CGSInternal/CGSHotKeys.h create mode 100644 CGSInternal/CGSInternal.h create mode 100644 CGSInternal/CGSMisc.h create mode 100644 CGSInternal/CGSNotifications.h create mode 100644 CGSInternal/CGSRegion.h create mode 100644 CGSInternal/CGSSession.h create mode 100644 CGSInternal/CGSTransitions.h create mode 100644 CGSInternal/CGSWindow.h create mode 100644 CGSInternal/CGSWorkspace.h create mode 100644 CGSInternal/CarbonHelpers.h create mode 100644 English.lproj/InfoPlist.strings create mode 100644 Info.plist create mode 100644 WindowBlur.xcodeproj/TemplateIcon.icns create mode 100644 WindowBlur.xcodeproj/project.pbxproj create mode 100644 WindowBlurSIMBL.h create mode 100644 WindowBlurSIMBL.m create mode 100644 WindowBlurWindowHack.h create mode 100644 WindowBlurWindowHack.m create mode 100644 WindowBlur_Prefix.pch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab810ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pbxuser +*.mode1v3 +.DS_Store diff --git a/CGSInternal/CGSAccessibility.h b/CGSInternal/CGSAccessibility.h new file mode 100644 index 0000000..cd3dde4 --- /dev/null +++ b/CGSInternal/CGSAccessibility.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" + +CG_EXTERN_C_BEGIN + +/*! Gets whether the display is zoomed. I'm not sure why there's two calls that appear to do the same thing - I think CGSIsZoomed calls through to CGSDisplayIsZoomed. */ +CG_EXTERN bool CGSDisplayIsZoomed(void); +CG_EXTERN CGError CGSIsZoomed(CGSConnectionID cid, bool *outIsZoomed); + +/*! Gets and sets the cursor scale. The largest the Universal Access prefpane allows you to go is 4.0. */ +CG_EXTERN CGError CGSGetCursorScale(CGSConnectionID cid, float *outScale); +CG_EXTERN CGError CGSSetCursorScale(CGSConnectionID cid, float scale); + +/*! Gets and sets the state of screen inversion. */ +CG_EXTERN bool CGDisplayUsesInvertedPolarity(void); +CG_EXTERN void CGDisplaySetInvertedPolarity(bool invertedPolarity); + +/*! Gets and sets whether the screen is grayscale. */ +CG_EXTERN bool CGDisplayUsesForceToGray(void); +CG_EXTERN void CGDisplayForceToGray(bool forceToGray); + +/*! Sets the display's contrast. There doesn't seem to be a get version of this function. */ +CG_EXTERN CGError CGSSetDisplayContrast(float contrast); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSCIFilter.h b/CGSInternal/CGSCIFilter.h new file mode 100644 index 0000000..7a646a0 --- /dev/null +++ b/CGSInternal/CGSCIFilter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" +#include "CGSWindow.h" + +typedef int CGSCIFilterID; + +/*! Creates a new CGSCIFilter from a filter name. These names are the same as you'd usually use for CIFilters. */ +CG_EXTERN CGError CGSNewCIFilterByName(CGSConnectionID cid, CFStringRef filterName, CGSCIFilterID *outFilter); + +/*! Adds or removes a CIFilter to a window. Flags are currently unknown (the Dock uses 0x3001). + Note: This stuff is VERY crashy under 10.4.10 - make sure to remove the filter before minimizing the window or closing it. */ +CG_EXTERN CGError CGSAddWindowFilter(CGSConnectionID cid, CGSWindowID wid, CGSCIFilterID filter, int flags); +CG_EXTERN CGError CGSRemoveWindowFilter(CGSConnectionID cid, CGSWindowID wid, CGSCIFilterID filter); + +enum { + kCGWindowFilterUnderlay = 1, + kCGWindowFilterDock = 0x3001, +}; + +/*! Loads a set of values into the CIFilter. */ +CG_EXTERN CGError CGSSetCIFilterValuesFromDictionary(CGSConnectionID cid, CGSCIFilterID filter, CFDictionaryRef filterValues); + +/*! Releases a CIFilter. */ +CG_EXTERN CGError CGSReleaseCIFilter(CGSConnectionID cid, CGSCIFilterID filter); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSConnection.h b/CGSInternal/CGSConnection.h new file mode 100644 index 0000000..6cd7812 --- /dev/null +++ b/CGSInternal/CGSConnection.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once + +typedef int CGSConnectionID; +static const CGSConnectionID kCGSNullConnectionID = 0; + + +CG_EXTERN_C_BEGIN + +/*! DOCUMENTATION PENDING - verify this is Leopard only! */ +CG_EXTERN CGError CGSSetLoginwindowConnection(CGSConnectionID cid) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CG_EXTERN CGError CGSSetLoginwindowConnectionWithOptions(CGSConnectionID cid, CFDictionaryRef options) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +/*! Enables or disables updates on a connection. The WindowServer will forcibly reenable updates after 1 second. */ +CG_EXTERN CGError CGSDisableUpdate(CGSConnectionID cid); +CG_EXTERN CGError CGSReenableUpdate(CGSConnectionID cid); + +/*! Is there a menubar associated with this connection? */ +CG_EXTERN bool CGSMenuBarExists(CGSConnectionID cid); + + + +#pragma mark notifications +/*! Registers or removes a function to get notified when a connection is created. Only gets notified for connections created in the current application. */ +typedef void (*CGSNewConnectionNotificationProc)(CGSConnectionID cid); +CG_EXTERN CGError CGSRegisterForNewConnectionNotification(CGSNewConnectionNotificationProc proc); +CG_EXTERN CGError CGSRemoveNewConnectionNotification(CGSNewConnectionNotificationProc proc); + +/*! Registers or removes a function to get notified when a connection is released. Only gets notified for connections created in the current application. */ +typedef void (*CGSConnectionDeathNotificationProc)(CGSConnectionID cid); +CG_EXTERN CGError CGSRegisterForConnectionDeathNotification(CGSConnectionDeathNotificationProc proc); +CG_EXTERN CGError CGSRemoveConnectionDeathNotification(CGSConnectionDeathNotificationProc proc); + +/*! Creates a new connection to the window server. */ +CG_EXTERN CGError CGSNewConnection(int unused, CGSConnectionID *outConnection); + +/*! Releases a CGSConnection and all CGSWindows owned by it. */ +CG_EXTERN CGError CGSReleaseConnection(CGSConnectionID cid); + +/*! Gets the default connection for this process. `CGSMainConnectionID` is just a more modern name. */ +CG_EXTERN CGSConnectionID _CGSDefaultConnection(void); +CG_EXTERN CGSConnectionID CGSMainConnectionID(void); + +/*! Gets the default connection for the current thread. */ +CG_EXTERN CGSConnectionID CGSDefaultConnectionForThread(void); + +/* Gets the `pid` that owns this CGSConnection. */ +CG_EXTERN CGError CGSConnectionGetPID(CGSConnectionID cid, pid_t *outPID); + +/*! Gets the CGSConnection for the PSN. */ +CG_EXTERN CGError CGSGetConnectionIDForPSN(CGSConnectionID cid, const ProcessSerialNumber *psn, CGSConnectionID *outOwnerCID); + +/*! Gets and sets a connection's property. */ +CG_EXTERN CGError CGSGetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef *outValue); +CG_EXTERN CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value); + +/*! Closes ALL connections used by the current application. Essentially, it turns it into a console application. */ +CG_EXTERN CGError CGSShutdownServerConnections(void); + +/*! Only the owner of a window can manipulate it. So, Apple has the concept of a universal owner that owns all windows and can manipulate them all. There can only be one universal owner at a time (the Dock). */ +CG_EXTERN CGError CGSSetUniversalOwner(CGSConnectionID cid); + +/*! Sets a connection to be a universal owner. This call requires `cid` be a universal connection. */ +CG_EXTERN CGError CGSSetOtherUniversalConnection(CGSConnectionID cid, CGSConnectionID otherConnection); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSCursor.h b/CGSInternal/CGSCursor.h new file mode 100644 index 0000000..c28b937 --- /dev/null +++ b/CGSInternal/CGSCursor.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" + +typedef int CGSCursorID; + + +CG_EXTERN_C_BEGIN + +/*! Does the system support hardware cursors? */ +CG_EXTERN CGError CGSSystemSupportsHardwareCursor(CGSConnectionID cid, bool *outSupportsHardwareCursor); + +/*! Does the system support hardware color cursors? */ +CG_EXTERN CGError CGSSystemSupportsColorHardwareCursor(CGSConnectionID cid, bool *outSupportsHardwareCursor); + +/*! Shows the cursor. */ +CG_EXTERN CGError CGSShowCursor(CGSConnectionID cid); + +/*! Hides the cursor. */ +CG_EXTERN CGError CGSHideCursor(CGSConnectionID cid); + +/*! Hides the cursor until the mouse is moved. */ +CG_EXTERN CGError CGSObscureCursor(CGSConnectionID cid); + +/*! Gets the cursor location. */ +CG_EXTERN CGError CGSGetCurrentCursorLocation(CGSConnectionID cid, CGPoint *outPos); + +/*! Gets the name (in reverse DNS form) of a system cursor. */ +CG_EXTERN char *CGSCursorNameForSystemCursor(CGSCursorID cursor); + +/*! Gets the size of the data for the connection's cursor. */ +CG_EXTERN CGError CGSGetCursorDataSize(CGSConnectionID cid, int *outDataSize); + +/*! Gets the data for the connection's cursor. */ +CG_EXTERN CGError CGSGetCursorData(CGSConnectionID cid, void *outData); + +/*! Gets the size of the data for the current cursor. */ +CG_EXTERN CGError CGSGetGlobalCursorDataSize(CGSConnectionID cid, int *outDataSize); + +/*! Gets the data for the current cursor. */ +CG_EXTERN CGError CGSGetGlobalCursorData(CGSConnectionID cid, void *outData, int *outRowBytes, CGRect *outRect, CGRect *outHotSpot, int *outDepth, int *outComponents, int *outBitsPerComponent); + +/*! Gets the size of data for a system-defined cursor. */ +CG_EXTERN CGError CGSGetSystemDefinedCursorDataSize(CGSConnectionID cid, CGSCursorID cursor, int *outDataSize); + +/*! Gets the data for a system-defined cursor. */ +CG_EXTERN CGError CGSGetSystemDefinedCursorData(CGSConnectionID cid, CGSCursorID cursor, void *outData, int *outRowBytes, CGRect *outRect, CGRect *outHotSpot, int *outDepth, int *outComponents, int *outBitsPerComponent); + +/*! Gets the cursor 'seed'. Every time the cursor is updated, the seed changes. */ +CG_EXTERN int CGSCurrentCursorSeed(void); + +/*! Shows or hides the spinning beachball of death. */ +CG_EXTERN CGError CGSForceWaitCursorActive(CGSConnectionID cid, bool showWaitCursor); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSDebug.h b/CGSInternal/CGSDebug.h new file mode 100644 index 0000000..a26f136 --- /dev/null +++ b/CGSInternal/CGSDebug.h @@ -0,0 +1,114 @@ +/* + * Routines for debugging the window server and application drawing. + * + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" + +typedef enum { + /*! Clears all flags. */ + kCGSDebugOptionNone = 0, + + /*! All screen updates are flashed in yellow. Regions under a DisableUpdate are flashed in orange. Regions that are hardware accellerated are painted green. */ + kCGSDebugOptionFlashScreenUpdates = 0x4, + + /*! Colors windows green if they are accellerated, otherwise red. Doesn't cause things to refresh properly - leaves excess rects cluttering the screen. */ + kCGSDebugOptionColorByAccelleration = 0x20, + + /*! Disables shadows on all windows. */ + kCGSDebugOptionNoShadows = 0x4000, + + /*! Setting this disables the pause after a flash when using FlashScreenUpdates or FlashIdenticalUpdates. */ + kCGSDebugOptionNoDelayAfterFlash = 0x20000, + + /*! Flushes the contents to the screen after every drawing operation. */ + kCGSDebugOptionAutoflushDrawing = 0x40000, + + /*! Highlights mouse tracking areas. Doesn't cause things to refresh correctly - leaves excess rectangles cluttering the screen. */ + kCGSDebugOptionShowMouseTrackingAreas = 0x100000, + + /*! Flashes identical updates in red. */ + kCGSDebugOptionFlashIdenticalUpdates = 0x4000000, + + /*! Dumps a list of windows to /tmp/WindowServer.winfo.out. This is what Quartz Debug uses to get the window list. */ + kCGSDebugOptionDumpWindowListToFile = 0x80000001, + + /*! Dumps a list of connections to /tmp/WindowServer.cinfo.out. */ + kCGSDebugOptionDumpConnectionListToFile = 0x80000002, + + /*! Dumps a very verbose debug log of the WindowServer to /tmp/CGLog_WinServer_. */ + kCGSDebugOptionVerboseLogging = 0x80000006, + + /*! Dumps a very verbose debug log of all processes to /tmp/CGLog__. */ + kCGSDebugOptionVerboseLoggingAllApps = 0x80000007, + + /*! Dumps a list of hotkeys to /tmp/WindowServer.keyinfo.out. */ + kCGSDebugOptionDumpHotKeyListToFile = 0x8000000E, + + /*! Dumps information about OpenGL extensions, etc to /tmp/WindowServer.glinfo.out. */ + kCGSDebugOptionDumpOpenGLInfoToFile = 0x80000013, + + /*! Dumps a list of shadows to /tmp/WindowServer.shinfo.out. */ + kCGSDebugOptionDumpShadowListToFile = 0x80000014, + + /*! Leopard: Dumps information about caches to `/tmp/WindowServer.scinfo.out`. */ + kCGSDebugOptionDumpCacheInformationToFile = 0x80000015, + + /*! Leopard: Purges some sort of cache - most likely the same caches dummped with `kCGSDebugOptionDumpCacheInformationToFile`. */ + kCGSDebugOptionPurgeCaches = 0x80000016, + + /*! Leopard: Dumps a list of windows to `/tmp/WindowServer.winfo.plist`. This is what Quartz Debug on 10.5 uses to get the window list. */ + kCGSDebugOptionDumpWindowListToPlist = 0x80000017, + + /*! Leopard: DOCUMENTATION PENDING */ + kCGSDebugOptionEnableSurfacePurging = 0x8000001B, + + // Leopard: 0x8000001C - invalid + + /*! Leopard: DOCUMENTATION PENDING */ + kCGSDebugOptionDisableSurfacePurging = 0x8000001D, + + /*! Leopard: Dumps information about an application's resource usage to `/tmp/CGResources__`. */ + kCGSDebugOptionDumpResourceUsageToFiles = 0x80000020, + + // Leopard: 0x80000022 - something about QuartzGL? + + // Leopard: Returns the magic mirror to its normal mode. The magic mirror is what the Dock uses to draw the screen reflection. For more information, see `CGSSetMagicMirror`. */ + kCGSDebugOptionSetMagicMirrorModeNormal = 0x80000023, + + /*! Leopard: Disables the magic mirror. It still appears but draws black instead of a reflection. */ + kCGSDebugOptionSetMagicMirrorModeDisabled = 0x80000024, +} CGSDebugOption; + + +CG_EXTERN_C_BEGIN + +/*! Gets and sets the debug options. These options are global and are not reset when your application dies! */ +CG_EXTERN CGError CGSGetDebugOptions(int *outCurrentOptions); +CG_EXTERN CGError CGSSetDebugOptions(int options); + +/*! Queries the server about its performance. This is how Quartz Debug gets the FPS meter, but not the CPU meter (for that it uses host_processor_info). Quartz Debug subtracts 25 so that it is at zero with the minimum FPS. */ +CG_EXTERN CGError CGSGetPerformanceData(CGSConnectionID cid, float *outFPS, float *unk, float *unk2, float *unk3); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSDisplays.h b/CGSInternal/CGSDisplays.h new file mode 100644 index 0000000..3876425 --- /dev/null +++ b/CGSInternal/CGSDisplays.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * Ryan Govostes ryan@alacatia.com + * + */ + +#pragma once + +CG_EXTERN_C_BEGIN + +/*! Begins a new display configuration transacation. */ +CG_EXTERN CGDisplayErr CGSBeginDisplayConfiguration(CGDisplayConfigRef *config); + +/*! Sets the origin of a display relative to the main display. The main display is at (0, 0) and contains the menubar. */ +CG_EXTERN CGDisplayErr CGSConfigureDisplayOrigin(CGDisplayConfigRef config, CGDirectDisplayID display, CGDisplayCoord x, CGDisplayCoord y); + +/*! Applies the configuration changes made in this transaction. */ +CG_EXTERN CGDisplayErr CGSCompleteDisplayConfiguration(CGDisplayConfigRef config); + +/*! Gets the main display. */ +CG_EXTERN CGDirectDisplayID CGSMainDisplayID(void); + +/*! Drops the configuration changes made in this transaction. */ +CG_EXTERN CGDisplayErr CGSCancelDisplayConfiguration(CGDisplayConfigRef config); + +/*! Gets a list of on line displays */ +CG_EXTERN CGDisplayErr CGSGetOnlineDisplayList(CGDisplayCount maxDisplays, CGDirectDisplayID *displays, CGDisplayCount *outDisplayCount); + +/*! Gets a list of active displays */ +CG_EXTERN CGDisplayErr CGSGetActiveDisplayList(CGDisplayCount maxDisplays, CGDirectDisplayID *displays, CGDisplayCount *outDisplayCount); + +/*! Gets the depth of a display. */ +CG_EXTERN CGError CGSGetDisplayDepth(CGDirectDisplayID display, int *outDepth); + +/*! Gets the displays at a point. Note that multiple displays can have the same point - think mirroring. */ +CG_EXTERN CGError CGSGetDisplaysWithPoint(const CGPoint *point, int maxDisplayCount, CGDirectDisplayID *outDisplays, int *outDisplayCount); + +/*! Gets the displays which contain a rect. Note that multiple displays can have the same bounds - think mirroring. */ +CG_EXTERN CGError CGSGetDisplaysWithRect(const CGRect *point, int maxDisplayCount, CGDirectDisplayID *outDisplays, int *outDisplayCount); + +/*! Gets the bounds for the display. Note that multiple displays can have the same bounds - think mirroring. */ +CG_EXTERN CGError CGSGetDisplayRegion(CGDirectDisplayID display, CGSRegionObj *outRegion); +CG_EXTERN CGError CGSGetDisplayBounds(CGDirectDisplayID display, CGRect *outRect); + +/*! Gets the number of bytes per row. */ +CG_EXTERN CGError CGSGetDisplayRowBytes(CGDirectDisplayID display, int *outRowBytes); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSHotKeys.h b/CGSInternal/CGSHotKeys.h new file mode 100644 index 0000000..eb54301 --- /dev/null +++ b/CGSInternal/CGSHotKeys.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" + +// A symbolic hotkey is basically a named hotkey which is remembered between application launches. +typedef enum { + // full keyboard access hotkeys + kCGSHotKeyToggleFullKeyboardAccess = 12, + kCGSHotKeyFocusMenubar = 7, + kCGSHotKeyFocusDock = 8, + kCGSHotKeyFocusNextGlobalWindow = 9, + kCGSHotKeyFocusToolbar = 10, + kCGSHotKeyFocusFloatingWindow = 11, + kCGSHotKeyFocusApplicationWindow = 27, + kCGSHotKeyFocusNextControl = 13, + kCGSHotKeyFocusDrawer = 51, + kCGSHotKeyFocusStatusItems = 57, + + // screenshot hotkeys + kCGSHotKeyScreenshot = 28, + kCGSHotKeyScreenshotToClipboard = 29, + kCGSHotKeyScreenshotRegion = 30, + kCGSHotKeyScreenshotRegionToClipboard = 31, + + // universal access + kCGSHotKeyToggleZoom = 15, + kCGSHotKeyZoomOut = 19, + kCGSHotKeyZoomIn = 17, + kCGSHotKeyZoomToggleSmoothing = 23, + kCGSHotKeyIncreaseContrast = 25, + kCGSHotKeyDecreaseContrast = 26, + kCGSHotKeyInvertScreen = 21, + kCGSHotKeyToggleVoiceOver = 59, + + // Dock + kCGSHotKeyToggleDockAutohide = 52, + kCGSHotKeyExposeAllWindows = 32, + kCGSHotKeyExposeAllWindowsSlow = 34, + kCGSHotKeyExposeApplicationWindows = 33, + kCGSHotKeyExposeApplicationWindowsSlow = 35, + kCGSHotKeyExposeDesktop = 36, + kCGSHotKeyExposeDesktopsSlow = 37, + kCGSHotKeyDashboard = 62, + kCGSHotKeyDashboardSlow = 63, + + // spaces (Leopard and later) + kCGSHotKeySpaces = 75, + kCGSHotKeySpacesSlow = 76, + // 77 - fn F7 (disabled) + // 78 - ⇧fn F7 (disabled) + kCGSHotKeySpaceLeft = 79, + kCGSHotKeySpaceLeftSlow = 80, + kCGSHotKeySpaceRight = 81, + kCGSHotKeySpaceRightSlow = 82, + kCGSHotKeySpaceDown = 83, + kCGSHotKeySpaceDownSlow = 84, + kCGSHotKeySpaceUp = 85, + kCGSHotKeySpaceUpSlow = 86, + + // input + kCGSHotKeyToggleCharacterPallette = 50, + kCGSHotKeySelectPreviousInputSource = 60, + kCGSHotKeySelectNextInputSource = 61, + + // Spotlight + kCGSHotKeySpotlightSearchField = 64, + kCGSHotKeySpotlightWindow = 65, + + kCGSHotKeyToggleFrontRow = 73, + kCGSHotKeyLookUpWordInDictionary = 70, + kCGSHotKeyHelp = 98, //AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER + + // displays - not verified + kCGSHotKeyDecreaseDisplayBrightness = 53, + kCGSHotKeyIncreaseDisplayBrightness = 54, +} CGSSymbolicHotKey; + +typedef enum { + kCGSGlobalHotKeyEnable, + kCGSGlobalHotKeyDisable, + kCGSGlobalHotKeyDisableAllButUniversalAccess +} CGSGlobalHotKeyOperatingMode; + + +CG_EXTERN_C_BEGIN + +/*! DOCUMENTATION PENDING */ +CG_EXTERN CGError CGSGetSymbolicHotKeyValue(CGSSymbolicHotKey hotKey, int *unknown, int *outVirtualKeyCode, int *outModifiers); + +/*! Gets and sets whether a symbolic hot key is enabled. */ +CG_EXTERN bool CGSIsSymbolicHotKeyEnabled(CGSSymbolicHotKey hotKey); +CG_EXTERN CGError CGSSetSymbolicHotKeyEnabled(CGSSymbolicHotKey hotKey, bool isEnabled); + +/*! Gets and sets the global hotkey operating mode. This can be used to disable all hotkeys. */ +CG_EXTERN CGError CGSGetGlobalHotKeyOperatingMode(CGSConnectionID cid, CGSGlobalHotKeyOperatingMode *outMode); +CG_EXTERN CGError CGSSetGlobalHotKeyOperatingMode(CGSConnectionID cid, CGSGlobalHotKeyOperatingMode mode); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSInternal.h b/CGSInternal/CGSInternal.h new file mode 100644 index 0000000..dea6cc0 --- /dev/null +++ b/CGSInternal/CGSInternal.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include +#include + +#warning CGSInternal contains PRIVATE FUNCTIONS and should NOT BE USED in shipping applications! + +#ifndef MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER UNAVAILABLE_ATTRIBUTE + #define DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER +#endif + +#include "CarbonHelpers.h" +#include "CGSAccessibility.h" +#include "CGSCIFilter.h" +#include "CGSConnection.h" +#include "CGSCursor.h" +#include "CGSDebug.h" +#include "CGSDisplays.h" +#include "CGSHotKeys.h" +#include "CGSNotifications.h" +#include "CGSMisc.h" +#include "CGSRegion.h" +#include "CGSSession.h" +#include "CGSTransitions.h" +#include "CGSWindow.h" +#include "CGSWorkspace.h" diff --git a/CGSInternal/CGSMisc.h b/CGSInternal/CGSMisc.h new file mode 100644 index 0000000..049669a --- /dev/null +++ b/CGSInternal/CGSMisc.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSInternal.h" + +CG_EXTERN_C_BEGIN + +/*! DOCUMENTATION PENDING */ +CG_EXTERN CGError CGSFetchDirtyScreenRegion(CGSConnectionID cid, CGSRegionObj *outDirtyRegion); + +/*! Is someone watching this screen? Applies to Apple's remote desktop only? */ +CG_EXTERN bool CGSIsScreenWatcherPresent(void); + +/*! Returns `True` if the application has been deemed unresponsive for a certain amount of time. */ +CG_EXTERN bool CGSEventIsAppUnresponsive(CGSConnectionID cid, const ProcessSerialNumber *psn); + +/*! Sets the amount of time it takes for an application to be considered unresponsive. */ +CG_EXTERN CGError CGSEventSetAppIsUnresponsiveNotificationTimeout(CGSConnectionID cid, double time); + +/*! Sets the cursor position. */ +CG_EXTERN CGError CGSWarpCursorPosition(CGSConnectionID cid, float x, float y); + +/*! DOCUMENTATION PENDING */ +CG_EXTERN CGError CGSHideBackstopMenuBar(CGSConnectionID cid); +CG_EXTERN CGError CGSShowBackstopMenuBar(CGSConnectionID cid); + +/*! Determines if this computer is portable. Internally this just checks to see if it has a battery. */ +CG_EXTERN bool CGSIsPortableMachine(void); + +/*! Sets the area taken up by the dock. Requires the caller to be a universal owner. */ +CG_EXTERN CGError CGSSetDockRect(CGSConnectionID cid, float x, float y, float width, float height); + +/*! DOCUMENTATION PENDING - returns false. Perhaps related to the CGSTBE_QDACCEL env variable. */ +CG_EXTERN bool CGSIsClassicBuffered(void); + +#pragma mark errors +/* Logs an error and returns `err`. */ +CG_EXTERN CGError CGSGlobalError(CGError err, const char *msg); + +/* Logs an error and returns `err`. */ +CG_EXTERN CGError CGSGlobalErrorv(CGError err, const char *msg, ...); + +/*! Gets the error message for an error code. */ +CG_EXTERN char *CGSErrorString(CGError error); + +#pragma mark input +/*! Gets and sets the status of secure input. When secure input is enabled, keyloggers, etc are harder to do. */ +CG_EXTERN bool CGSIsSecureEventInputSet(void); +CG_EXTERN CGError CGSSetSecureEventInput(CGSConnectionID cid, bool useSecureInput); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSNotifications.h b/CGSInternal/CGSNotifications.h new file mode 100644 index 0000000..178e77f --- /dev/null +++ b/CGSInternal/CGSNotifications.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSInternal.h" +#include "CGSTransitions.h" + +typedef enum { + kCGSNotificationDebugOptionsChanged = 200, + + kCGSNotificationMouseMoved = 715, + + kCGSNotificationTrackingRegionEntered = 718, + kCGSNotificationTrackingRegionExited = 719, + + // 724 - keyboard preferences changed + + // 729, 730 seem to be process deactivated / activated - but only for this process + // 731 seems to be this process hidden or shown + + kCGSNotificationAppUnresponsive = 750, + kCGSNotificationAppResponsive = 751, + + // 761 - hotkey disabled + // 762 - hotkey enabled (do these two fire twice?) + + // 763 - hotkey begins editing + // 764 - hotkey ends editing + + // 765, 766 seem to be about the hotkey state (all disabled, etc) + + kCGSNotificationWorkspaceChanged = 1401, + + kCGSNotificationTransitionEnded = 1700, +} CGSNotificationType; + +//! The data sent with kCGSNotificationAppUnresponsive and kCGSNotificationAppResponsive. +typedef struct { +#if __BIG_ENDIAN__ + uint16_t majorVersion; + uint16_t minorVersion; +#else + uint16_t minorVersion; + uint16_t majorVersion; +#endif + + //! The length of the entire notification. + uint32_t length; + + CGSConnectionID cid; + pid_t pid; + ProcessSerialNumber psn; +} CGSProcessNotificationData; + +//! The data sent with kCGSNotificationDebugOptionsChanged. +typedef struct { + int newOptions; + int unknown[2]; // these two seem to be zero +} CGSDebugNotificationData; + +//! The data sent with kCGSNotificationTransitionEnded +typedef struct { + CGSTransitionID transition; +} CGSTransitionNotificationData; + + +typedef void (*CGSNotifyProcPtr)(CGSNotificationType type, void *data, unsigned int dataLength, void *userData); + +CG_EXTERN_C_BEGIN + +//! Registers a function to receive notifications. +CG_EXTERN CGError CGSRegisterNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType type, void *userData); + +//! Unregisters a function that was registered to receive notifications. +CG_EXTERN CGError CGSRemoveNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType type, void *userData); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSRegion.h b/CGSInternal/CGSRegion.h new file mode 100644 index 0000000..b275c4d --- /dev/null +++ b/CGSInternal/CGSRegion.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once + +#pragma mark types +#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED + // on Leopard and up these are CFTypes + typedef CFTypeRef CGSRegionObj; + typedef CFTypeRef CGSRegionEnumeratorObj; +#else + // but opaque types under 10.4 + typedef int CGSRegionObj; + typedef int CGSRegionEnumeratorObj; +#endif + +CG_EXTERN_C_BEGIN + +/*! Creates a region from a `CGRect`. */ +CG_EXTERN CGError CGSNewRegionWithRect(const CGRect *rect, CGSRegionObj *outRegion); + +/*! Creates a region from a list of `CGRect`s. */ +CG_EXTERN CGError CGSNewRegionWithRectList(const CGRect *rects, int rectCount, CGSRegionObj *outRegion); + +/*! Creates a new region from a QuickDraw region. */ +CG_EXTERN CGError CGSNewRegionWithQDRgn(RgnHandle region, CGSRegionObj *outRegion); + +/*! Creates an empty region. */ +CG_EXTERN CGError CGSNewEmptyRegion(CGSRegionObj *outRegion); + +/*! Releases a region. */ +CG_EXTERN CGError CGSReleaseRegion(CGSRegionObj region); + +/*! Creates a `CGRect` from a region. */ +CG_EXTERN CGError CGSGetRegionBounds(CGSRegionObj region, CGRect *outRect); + +/*! Determines if two regions are equal. */ +CG_EXTERN bool CGSRegionsEqual(CGSRegionObj region1, CGSRegionObj region2); + +/* Created a new region by changing the origin an existing one. */ +CG_EXTERN CGError CGSOffsetRegion(CGSRegionObj region, float offsetLeft, float offsetTop, CGSRegionObj *outRegion); + +/*! Creates a new region by copying an existing one. */ +CG_EXTERN CGError CGSCopyRegion(CGSRegionObj region, CGSRegionObj *outRegion); + +/*! Creates a new region by combining two regions together. */ +CG_EXTERN CGError CGSUnionRegion(CGSRegionObj region1, CGSRegionObj region2, CGSRegionObj *outRegion); + +/*! Creates a new region by combining a region and a rect. */ +CG_EXTERN CGError CGSUnionRegionWithRect(CGSRegionObj region, CGRect *rect, CGSRegionObj *outRegion); + +/*! Creates a region by XORing two regions together. */ +CG_EXTERN CGError CGSXorRegion(CGSRegionObj region1, CGSRegionObj region2, CGSRegionObj *outRegion); + +/*! Determines if the region is empty. */ +CG_EXTERN bool CGSRegionIsEmpty(CGSRegionObj region); + +/*! Determines if the region is rectangular. */ +CG_EXTERN bool CGSRegionIsRectangular(CGSRegionObj region); + +/*! Determines if a point in a region. */ +CG_EXTERN bool CGSPointInRegion(CGSRegionObj region, const CGPoint *point); + +/*! Determines if a rect is in a region. */ +CG_EXTERN bool CGSRectInRegion(CGSRegionObj region, const CGRect *rect); + +/*! Determines if a region is inside of a region. */ +CG_EXTERN bool CGSRegionInRegion(CGSRegionObj region1, CGSRegionObj region2); + +/*! Determines if a rect intersects a region. */ +CG_EXTERN bool CGSRegionIntersectsRect(CGSRegionObj obj, const CGRect *rect); + +/*! Determines if a region intersects a region. */ +CG_EXTERN bool CGSRegionIntersectsRegion(CGSRegionObj region1, CGSRegionObj region2); + +/*! Creates a rect from the difference of two regions. */ +CG_EXTERN CGError CGSDiffRegion(CGSRegionObj region1, CGSRegionObj region2, CGSRegionObj *outRegion); + + +#pragma mark region enumerators +/*! Gets the enumerator for a region. */ +CG_EXTERN CGSRegionEnumeratorObj CGSRegionEnumerator(CGSRegionObj region); + +/*! Releases a region enumerator. */ +CG_EXTERN void CGSReleaseRegionEnumerator(CGSRegionEnumeratorObj enumerator); + +/*! Gets the next rect of a region. */ +CG_EXTERN CGRect* CGSNextRect(CGSRegionEnumeratorObj enumerator); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSSession.h b/CGSInternal/CGSSession.h new file mode 100644 index 0000000..75607c7 --- /dev/null +++ b/CGSInternal/CGSSession.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSInternal.h" + +typedef int CGSSessionID; + +CG_EXTERN_C_BEGIN + +/*! Gets information about the current login session. Keys as of 10.4: + kCGSSessionGroupIDKey + kCGSSessionOnConsoleKey + kCGSSessionIDKey + kCGSSessionUserNameKey + kCGSessionLoginDoneKey + kCGSessionLongUserNameKey + kCGSSessionSystemSafeBoot + kCGSSessionLoginwindowSafeLogin + kCGSSessionConsoleSetKey + kCGSSessionUserIDKey + */ +CG_EXTERN CFDictionaryRef CGSCopyCurrentSessionDictionary(void); + +/*! Creates a new "blank" login session. Switches to the LoginWindow. This does NOT check to see if fast user switching is enabled! */ +CG_EXTERN CGError CGSCreateLoginSession(CGSSessionID *outSession); + +/*! Releases a session. */ +CG_EXTERN CGError CGSReleaseSession(CGSSessionID session); + +/*! Gets a list of sessions. Each session dictionary is in the format returned by `CGSCopyCurrentSessionDictionary`. */ +CG_EXTERN CFArrayRef CGSCopySessionList(void); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSTransitions.h b/CGSInternal/CGSTransitions.h new file mode 100644 index 0000000..40f902b --- /dev/null +++ b/CGSInternal/CGSTransitions.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" + +typedef int CGSTransitionID; + +typedef enum { + kCGSTransitionNone, + kCGSTransitionFade, + kCGSTransitionZoom, + kCGSTransitionReveal, + kCGSTransitionSlide, + kCGSTransitionWarpFade, + kCGSTransitionSwap, + kCGSTransitionCube, + kCGSTransitionWarpSwitch, + kCGSTransitionFlip +} CGSTransitionType; + +typedef enum { + /*! Directions for the transition. Some directions don't apply to some transitions. */ + kCGSTransitionDirectionLeft = 1 << 0, + kCGSTransitionDirectionRight = 1 << 1, + kCGSTransitionDirectionDown = 1 << 2, + kCGSTransitionDirectionUp = 1 << 3, + kCGSTransitionDirectionCenter = 1 << 4, + + /*! Reverses a transition. Doesn't apply for all transitions. */ + kCGSTransitionFlagReversed = 1 << 5, + + /*! Ignore the background color and only transition the window. */ + kCGSTransitionFlagTransparent = 1 << 7, +} CGSTransitionFlags; + +typedef struct { + int unknown; // always set to zero + CGSTransitionType type; + CGSTransitionFlags options; + CGSWindowID wid; /* 0 means a full screen transition. */ + float *backColor; /* NULL means black. */ +} CGSTransitionSpec; + +CG_EXTERN_C_BEGIN + +/*! Creates a new transition from a `CGSTransitionSpec`. */ +CG_EXTERN CGError CGSNewTransition(CGSConnectionID cid, const CGSTransitionSpec *spec, CGSTransitionID *outTransition); + +/*! Invokes a transition asynchronously. Note that `duration` is in seconds. */ +CG_EXTERN CGError CGSInvokeTransition(CGSConnectionID cid, CGSTransitionID transition, float duration); + +/*! Releases a transition. */ +CG_EXTERN CGError CGSReleaseTransition(CGSConnectionID cid, CGSTransitionID transition); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSWindow.h b/CGSInternal/CGSWindow.h new file mode 100644 index 0000000..cc72e0b --- /dev/null +++ b/CGSInternal/CGSWindow.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" +#include "CGSRegion.h" + +typedef int CGSWindowID; +typedef int CGSAnimationObj; +typedef struct { CGPoint localPoint; CGPoint globalPoint; } CGSWarpPoint; + +typedef enum { + kCGSSharingNone, + kCGSSharingReadOnly, + kCGSSharingReadWrite +} CGSSharingState; + +typedef enum { + kCGSOrderBelow = -1, + kCGSOrderOut, /* hides the window */ + kCGSOrderAbove, + kCGSOrderIn /* shows the window */ +} CGSWindowOrderingMode; + +typedef enum { + kCGSBackingNonRetianed, + kCGSBackingRetained, + kCGSBackingBuffered, +} CGSBackingType; + + +CG_EXTERN_C_BEGIN + +/*! Switches to the next (or previous) window in the global list. */ +CG_EXTERN CGError CGSCycleWindows(CGSConnectionID cid, CGSWindowOrderingMode order); + +/*! Gets and sets the desktop window. Not sure what happens if more than one process sets the desktop window. */ +CG_EXTERN CGError CGSDesktopWindow(CGSConnectionID cid, CGSWindowID *outWID); +CG_EXTERN CGError CGSSetDesktopWindow(CGSConnectionID cid, CGSWindowID wid); + +/*! Sets the window's title. Internally this simply calls `CGSSetWindowProperty(cid, wid, kCGSWindowTitle, title)`. */ +CG_EXTERN CGError CGSSetWindowTitle(CGSConnectionID cid, CGSWindowID wid, CFStringRef title); + +/*! Gets and sets a property for a window. */ +CG_EXTERN CGError CGSGetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef *outValue); +CG_EXTERN CGError CGSSetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef value); + +/*! Gets and sets the window's transparency. */ +CG_EXTERN CGError CGSGetWindowAlpha(CGSConnectionID cid, CGSWindowID wid, float *outAlpha); +CG_EXTERN CGError CGSSetWindowAlpha(CGSConnectionID cid, CGSWindowID wid, float alpha); + +/*! Sets the alpha of a group of windows over a period of time. Note that `duration` is in seconds. */ +CG_EXTERN CGError CGSSetWindowListAlpha(CGSConnectionID cid, const CGSWindowID *widList, int widCount, float alpha, float duration); + +/*! Gets and sets the `CGConnectionID` that owns this window. Only the owner can change most properties of the window. */ +CG_EXTERN CGError CGSGetWindowOwner(CGSConnectionID cid, CGSWindowID wid, CGSConnectionID *outOwner); +CG_EXTERN CGError CGSSetWindowOwner(CGSConnectionID cid, CGSWindowID wid, CGSConnectionID owner); + +/*! Sets the background color of the window. */ +CG_EXTERN CGError CGSSetWindowAutofillColor(CGSConnectionID cid, CGSWindowID wid, float red, float green, float blue); + +/*! Locks a window to the cursor, so that whenever the cursor moves, the window moves with it. There doesn't seem to be a way to unlock the window from the cursor. */ +CG_EXTERN CGError CGSLockWindowToCursor(CGSConnectionID cid, CGSWindowID wid, float offsetLeft, float offsetTop); + +/*! Sets the warp for the window. The mesh maps a local (window) point to a point on screen. */ +CG_EXTERN CGError CGSSetWindowWarp(CGSConnectionID cid, CGSWindowID wid, int warpWidth, int warpHeight, const CGSWarpPoint *warp); + +/*! Gets or sets whether the window server should auto-fill the window's background. */ +CG_EXTERN CGError CGSGetWindowAutofill(CGSConnectionID cid, CGSWindowID wid, bool *outShouldAutoFill); +CG_EXTERN CGError CGSSetWindowAutofill(CGSConnectionID cid, CGSWindowID wid, bool shouldAutoFill); + +/*! Gets the screen rect for a window. */ +CG_EXTERN CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *outRect); + +/*! Gets and sets the window level for a window. */ +CG_EXTERN CGError CGSGetWindowLevel(CGSConnectionID cid, CGSWindowID wid, CGWindowLevel *outLevel); +CG_EXTERN CGError CGSSetWindowLevel(CGSConnectionID cid, CGSWindowID wid, CGWindowLevel level); + +/*! Gets and sets the sharing state. This determines the level of access other applications have over this window. */ +CG_EXTERN CGError CGSGetWindowSharingState(CGSConnectionID cid, CGSWindowID wid, CGSSharingState *outState); +CG_EXTERN CGError CGSSetWindowSharingState(CGSConnectionID cid, CGSWindowID wid, CGSSharingState state); + +/*! Sets whether this window is ignored in the global window cycle (Control-F4 by default). There is no Get version? */ +CG_EXTERN CGError CGSSetIgnoresCycle(CGSConnectionID cid, CGSWindowID wid, bool ignoresCycle); + +/*! Creates a graphics context for the window. */ +CG_EXTERN CGContextRef CGWindowContextCreate(CGSConnectionID cid, CGSWindowID wid, int unknown); + +/*! Sets the order of a window */ +CG_EXTERN CGError CGSOrderWindow(CGSConnectionID cid, CGSWindowID wid, CGSWindowOrderingMode mode, CGSWindowID relativeToWID); + +/*! Sets the origin (top-left) of a window */ +CG_EXTERN CGError CGSMoveWindow(CGSConnectionID cid, CGSWindowID wid, const CGPoint *origin); + +/*! Sets the origin (top-left) of a window relative to another window's origin. */ +CG_EXTERN CGError CGSSetWindowOriginRelativeToWindow(CGSConnectionID cid, CGSWindowID wid, CGSWindowID relativeToWID, float offsetX, float offsetY); + +/* Flushes a window's buffer to the screen. */ +CG_EXTERN CGError CGSFlushWindow(CGSConnectionID cid, CGSWindowID wid, CGSRegionObj flushRegion); + + +#pragma mark shadows +/*! Gets and sets the shadow information for a window. Values for `flags` are unknown. */ +CG_EXTERN CGError CGSSetWindowShadowAndRimParameters(CGSConnectionID cid, CGSWindowID wid, float standardDeviation, float density, int offsetX, int offsetY, int flags); +CG_EXTERN CGError CGSGetWindowShadowAndRimParameters(CGSConnectionID cid, CGSWindowID wid, float *outStandardDeviation, float *outDensity, int *outOffsetX, int *outOffsetY, int *outFlags); + +/*! Sets the shadow information for a window. Simply calls through to `CGSSetWindowShadowAndRimParameters` passing 1 for `flags`. */ +CG_EXTERN CGError CGSSetWindowShadowParameters(CGSConnectionID cid, CGSWindowID wid, float standardDeviation, float density, int offsetX, int offsetY); + +/*! Invalidates a window's shadow. */ +CG_EXTERN CGError CGSInvalidateWindowShadow(CGSConnectionID cid, CGSWindowID wid); + + +#pragma mark window lists +/*! Gets the number of windows the `targetCID` owns. */ +CG_EXTERN CGError CGSGetWindowCount(CGSConnectionID cid, CGSConnectionID targetCID, int *outCount); + +/*! Gets a list of windows owned by `targetCID`. */ +CG_EXTERN CGError CGSGetWindowList(CGSConnectionID cid, CGSConnectionID targetCID, int count, CGSWindowID *list, int *outCount); + +/*! Gets the number of windows owned by `targetCID` that are on screen. */ +CG_EXTERN CGError CGSGetOnScreenWindowCount(CGSConnectionID cid, CGSConnectionID targetCID, int *outCount); + +/*! Gets a list of windows oned by `targetCID` that are on screen. */ +CG_EXTERN CGError CGSGetOnScreenWindowList(CGSConnectionID cid, CGSConnectionID targetCID, int count, CGSWindowID *list, int *outCount); + + +#pragma mark window management +/*! Creates a new CGSWindow. The real window top/left is the sum of the region's top/left and the top/left parameters. */ +CG_EXTERN CGError CGSNewWindow(CGSConnectionID cid, CGSBackingType backingType, float left, float top, CGSRegionObj region, CGSWindowID *outWID); + +/*! Creates a new CGSWindow. The real window top/left is the sum of the region's top/left and the top/left parameters. */ +CG_EXTERN CGError CGSNewWindowWithOpaqueShape(CGSConnectionID cid, CGSBackingType backingType, float left, float top, CGSRegionObj region, CGSRegionObj opaqueShape, int unknown, const int *tags, int tagSize, CGSWindowID *outWID); + +/*! Releases a CGSWindow. */ +CG_EXTERN CGError CGSReleaseWindow(CGSConnectionID cid, CGSWindowID wid); + + +#pragma mark animations +/*! Creates a Dock-style genie animation that goes from `wid` to `destinationWID`. */ +CG_EXTERN CGError CGSCreateGenieWindowAnimation(CGSConnectionID cid, CGSWindowID wid, CGSWindowID destinationWID, CGSAnimationObj *outAnimation); + +/*! Creates a sheet animation that's used when the parent window is brushed metal. Oddly enough, seems to be the only one used, even if the parent window isn't metal. */ +CG_EXTERN CGError CGSCreateMetalSheetWindowAnimationWithParent(CGSConnectionID cid, CGSWindowID wid, CGSWindowID parentWID, CGSAnimationObj *outAnimation); + +/*! Sets the progress of an animation. */ +CG_EXTERN CGError CGSSetWindowAnimationProgress(CGSAnimationObj animation, float progress); + +/*! DOCUMENTATION PENDING */ +CG_EXTERN CGError CGSWindowAnimationChangeLevel(CGSAnimationObj animation, CGWindowLevel level); + +/*! DOCUMENTATION PENDING */ +CG_EXTERN CGError CGSWindowAnimationSetParent(CGSAnimationObj animation, CGSWindowID parent) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +/*! Releases a window animation. */ +CG_EXTERN CGError CGSReleaseWindowAnimation(CGSAnimationObj animation); + + +#pragma mark window accelleration +/*! Gets the state of accelleration for the window. */ +CG_EXTERN CGError CGSWindowIsAccelerated(CGSConnectionID cid, CGSWindowID wid, bool *outIsAccelerated); + +/*! Gets and sets if this window can be accellerated. I don't know if playing with this is safe. */ +CG_EXTERN CGError CGSWindowCanAccelerate(CGSConnectionID cid, CGSWindowID wid, bool *outCanAccelerate); +CG_EXTERN CGError CGSWindowSetCanAccelerate(CGSConnectionID cid, CGSWindowID wid, bool canAccelerate); + + +#pragma mark system status items +/*! Registers or unregisters a window as a global status item (see `NSStatusItem`, `NSMenuExtra`). Once a window is registered, the window server takes care of placing it in the apropriate location. */ +CG_EXTERN CGError CGSRegisterWindowWithSystemStatusBar(CGSConnectionID cid, CGSWindowID wid, int priority); +CG_EXTERN CGError CGSUnregisterWindowWithSystemStatusBar(CGSConnectionID cid, CGSWindowID wid); + +/*! Rearranges items in the system status bar. You should call this after registering or unregistering a status item or changing the window's width. */ +CG_EXTERN CGError CGSAdjustSystemStatusBarWindows(CGSConnectionID cid); + +CG_EXTERN_C_END diff --git a/CGSInternal/CGSWorkspace.h b/CGSInternal/CGSWorkspace.h new file mode 100644 index 0000000..5872cb4 --- /dev/null +++ b/CGSInternal/CGSWorkspace.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSConnection.h" +#include "CGSWindow.h" +#include "CGSTransitions.h" + +typedef unsigned int CGSWorkspaceID; + +/*! The space id given when we're switching spaces. */ +static const CGSWorkspaceID kCGSTransitioningWorkspaceID = 65538; + + + +CG_EXTERN_C_BEGIN + +/*! Gets and sets the current workspace. */ +CG_EXTERN CGError CGSGetWorkspace(CGSConnectionID cid, CGSWorkspaceID *outWorkspace); +CG_EXTERN CGError CGSSetWorkspace(CGSConnectionID cid, CGSWorkspaceID workspace); + +/*! Transitions to a workspace asynchronously. Note that `duration` is in seconds. */ +CG_EXTERN CGError CGSSetWorkspaceWithTransition(CGSConnectionID cid, CGSWorkspaceID workspace, CGSTransitionType transition, CGSTransitionFlags options, float duration); + +/*! Gets and sets the workspace for a window. */ +CG_EXTERN CGError CGSGetWindowWorkspace(CGSConnectionID cid, CGSWindowID wid, CGSWorkspaceID *outWorkspace); +CG_EXTERN CGError CGSSetWindowWorkspace(CGSConnectionID cid, CGSWindowID wid, CGSWorkspaceID workspace); + +/*! Gets the number of windows in the workspace. */ +CG_EXTERN CGError CGSGetWorkspaceWindowCount(CGSConnectionID cid, int workspaceNumber, int *outCount); +CG_EXTERN CGError CGSGetWorkspaceWindowList(CGSConnectionID cid, int workspaceNumber, int count, CGSWindowID *list, int *outCount); + + +CG_EXTERN_C_END diff --git a/CGSInternal/CarbonHelpers.h b/CGSInternal/CarbonHelpers.h new file mode 100644 index 0000000..a7c796d --- /dev/null +++ b/CGSInternal/CarbonHelpers.h @@ -0,0 +1,40 @@ +/* + * Contains utilities for using Carbon with CGS routines. + * + * Copyright (C) 2007-2008 Alacatia Labs + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * Joe Ranieri joe@alacatia.com + * + */ + +#pragma once +#include "CGSWindow.h" + + +CG_EXTERN_C_BEGIN + +/* Gets a CGSWindowID for a WindowRef. Implemented in Carbon.framework. + This call is deprecated in 10.5. Please use the public alternative, `HIWindowGetCGWindowID`. */ +CG_EXTERN CGSWindowID GetNativeWindowFromWindowRef(WindowRef ref) DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER; + +/* Gets a WindowRef (in the current process) from a CGSWindowID. Implemented in Carbon.framework. + This call is deprecated in 10.5. Please use the public alternative, `HIWindowFromCGWindowID`. */ +CG_EXTERN WindowRef GetWindowRefFromNativeWindow(CGSWindowID wid) DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER; + +CG_EXTERN_C_END diff --git a/English.lproj/InfoPlist.strings b/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..5e45963c382ba690b781b953a00585212b898ac5 GIT binary patch literal 92 zcmW-XQ3`+{5C!MkQ~2$No+IcIkqMDxWCV8j>LCj|yTg2Mz+o9F%uHlf9u}h9EuK`F a!Y*1dX%G66ZqL#C$|bw0ZoP5@jOGW1ArT7z literal 0 HcmV?d00001 diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..b153b46 --- /dev/null +++ b/Info.plist @@ -0,0 +1,37 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + WindowBlurSIMBL + SIMBLTargetApplications + + + BundleIdentifier + com.apple.Terminal + MaxBundleVersion + 240 + MinBundleVersion + 240 + + + + diff --git a/WindowBlur.xcodeproj/TemplateIcon.icns b/WindowBlur.xcodeproj/TemplateIcon.icns new file mode 100644 index 0000000000000000000000000000000000000000..62cb7015e09d6ea3e65d7f7949c4c07f9246a908 GIT binary patch literal 52318 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 WhsmLR^b3` + +void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel); + +@interface WindowBlurSIMBL : NSObject { + +} + +@end \ No newline at end of file diff --git a/WindowBlurSIMBL.m b/WindowBlurSIMBL.m new file mode 100644 index 0000000..49b8bdc --- /dev/null +++ b/WindowBlurSIMBL.m @@ -0,0 +1,43 @@ +// +// WindowBlurSIMBL.m +// WindowBlur +// +// Created by Joseph Spiros on 5/12/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "WindowBlurSIMBL.h" +#import "WindowBlurWindowHack.h" +#import + +void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel) +{ + Method orig_method = nil, alt_method = nil; + + // First, look for the methods + orig_method = class_getInstanceMethod(aClass, orig_sel); + alt_method = class_getInstanceMethod(aClass, alt_sel); + + // If both are found, swizzle them + if ((orig_method != nil) && (alt_method != nil)) + { + char *temp1; + IMP temp2; + + temp1 = orig_method->method_types; + orig_method->method_types = alt_method->method_types; + alt_method->method_types = temp1; + + temp2 = orig_method->method_imp; + orig_method->method_imp = alt_method->method_imp; + alt_method->method_imp = temp2; + } +} + +@implementation WindowBlurSIMBL + ++ (void)load { + [WindowBlurWindowHack poseAsClass:[NSWindow class]]; +} + +@end diff --git a/WindowBlurWindowHack.h b/WindowBlurWindowHack.h new file mode 100644 index 0000000..a811b44 --- /dev/null +++ b/WindowBlurWindowHack.h @@ -0,0 +1,14 @@ +// +// WindowBlurWindowHack.h +// WindowBlur +// +// Created by Joseph Spiros on 5/12/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import + +@interface WindowBlurWindowHack : NSWindow + + +@end diff --git a/WindowBlurWindowHack.m b/WindowBlurWindowHack.m new file mode 100644 index 0000000..16696a1 --- /dev/null +++ b/WindowBlurWindowHack.m @@ -0,0 +1,84 @@ +// +// WindowBlurWindowHack.m +// WindowBlur +// +// Created by Joseph Spiros on 5/12/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "WindowBlurSIMBL.h" +#import "WindowBlurWindowHack.h" +#import "CGSInternal.h" + +static NSMutableDictionary *instanceIDToIvars = nil; +static BOOL needToSwizzleDealloc = YES; + +@implementation WindowBlurWindowHack + +- (id)PRE__instanceID +{ + return [NSValue valueWithPointer:self]; +} + +- (NSMutableDictionary *)PRE__ivars +{ + NSMutableDictionary *ivars; + + if (needToSwizzleDealloc) + { + MethodSwizzle([NSWindow class], + @selector(dealloc), + @selector(PRE__deallocSwizzler)); + needToSwizzleDealloc = NO; + } + + if (instanceIDToIvars == nil) + { + instanceIDToIvars = [[NSMutableDictionary alloc] init]; + } + + ivars = [instanceIDToIvars objectForKey:[self PRE__instanceID]]; + if (ivars == nil) + { + ivars = [NSMutableDictionary dictionary]; + [instanceIDToIvars setObject:ivars forKey:[self PRE__instanceID]]; + } + + return ivars; +} + +- (void)PRE__deallocSwizzler +{ + [instanceIDToIvars removeObjectForKey:[self PRE__instanceID]]; + if ([instanceIDToIvars count] == 0) + { + [instanceIDToIvars release]; + instanceIDToIvars = nil; + } + + [self PRE__deallocSwizzler]; +} + +- (void)update { + if ([[[self PRE__ivars] objectForKey:@"blurred"] boolValue] != YES) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + if (floor(NSAppKitVersionNumber) > 824) { + NSLog(@"AppKit Check Confirmed"); + CGSConnectionID con = CGSMainConnectionID(); + if (con) { + NSLog(@"CGSConnection Confirmed"); + int blurFilter; + if (noErr == CGSNewCIFilterByName(con, (CFStringRef)@"CIGaussianBlur", &blurFilter)) { + NSLog(@"Should work!"); + NSDictionary *optionsDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:2.0] forKey:@"inputRadius"]; + CGSSetCIFilterValuesFromDictionary(con, blurFilter, (CFDictionaryRef)optionsDict); + CGSAddWindowFilter(con, [self windowNumber], blurFilter, kCGWindowFilterUnderlay); + [[self PRE__ivars] setObject:[NSNumber numberWithBool:YES] forKey:@"blurred"]; + } + } + } +#endif + } +} + +@end diff --git a/WindowBlur_Prefix.pch b/WindowBlur_Prefix.pch new file mode 100644 index 0000000..c4bc93d --- /dev/null +++ b/WindowBlur_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'WindowBlur' target in the 'WindowBlur' project. +// + +#ifdef __OBJC__ + #import +#endif -- 2.20.1