diff --git a/AXApplication.h b/AXApplication.h index 2d286ea..83dfb0a 100644 --- a/AXApplication.h +++ b/AXApplication.h @@ -10,7 +10,7 @@ #import #import "FMNWindowGroup.h" -@interface AXApplication : NSObject { +@interface AXApplication : NSObject { @protected AXUIElementRef appElement; @protected ProcessSerialNumber psn; @protected pid_t pid; diff --git a/AXApplication.m b/AXApplication.m index d1080a6..ee4d7c6 100644 --- a/AXApplication.m +++ b/AXApplication.m @@ -126,4 +126,30 @@ - (void) dealloc [super dealloc]; } +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:appName forKey:@"AXAappName"]; + [encoder encodeBytes:(const uint8_t*)&appElement + length:sizeof(AXUIElementRef) + forKey:@"AXAappElement"]; + [encoder encodeInt64:(int64_t)pid forKey:@"AXApid"]; + [encoder encodeBytes:(const uint8_t*)&psn + length:sizeof(ProcessSerialNumber) + forKey:@"AXApsn"]; + +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + unsigned dummy; + self = [super init]; + appName = [[decoder decodeObjectForKey:@"AXAappName"] retain]; + appElement = *(AXUIElementRef *)[decoder decodeBytesForKey:@"AXAappElement" + returnedLength:&dummy]; + pid = (pid_t)[decoder decodeInt64ForKey:@"AXApid"]; + psn = *(ProcessSerialNumber *)[decoder decodeBytesForKey:@"AXApsn" + returnedLength:&dummy]; + return self; +} + @end diff --git a/AXWindow.h b/AXWindow.h index 5477887..c73c973 100644 --- a/AXWindow.h +++ b/AXWindow.h @@ -10,7 +10,7 @@ #import "FMNWindow.h" #import "AXApplication.h" -@interface AXWindow : NSObject { +@interface AXWindow : NSObject { AXUIElementRef windowElement; AXApplication *windowApp; } diff --git a/AXWindow.m b/AXWindow.m index f18724d..b7bb3e8 100644 --- a/AXWindow.m +++ b/AXWindow.m @@ -124,6 +124,12 @@ - (void) setWindowPosition : (NSPoint) pos Context : (NSDictionary*) context userInfo : nil ]; } + NSPoint afterPos = [self getWindowPosition]; + if (afterPos.x != pos.x || afterPos.y != pos.y) + { + NSLog(@"Failed to set position of %@ ((%f, %f) != (%f, %f)), and Accessibility API lied.", + self, pos.x, pos.y, afterPos.x, afterPos.y); + } CFRelease(value); } @@ -145,6 +151,12 @@ - (void) setWindowSize : (NSSize) size Context : (NSDictionary*) context userInfo : nil ]; } + NSSize afterSize = [self getWindowSize]; + if (afterSize.width != size.width || afterSize.height != size.height) + { + NSLog(@"Failed to set size of %@ ((%f, %f) != (%f, %f)), and Accessibility API lied.", + self, size.width, size.height, afterSize.width, afterSize.height); + } CFRelease(value); } @@ -168,4 +180,22 @@ - (void) dealloc [super dealloc]; } +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:windowApp forKey:@"AXWwindowApp"]; + [encoder encodeBytes:(const uint8_t*)&windowElement + length:sizeof(AXUIElementRef) + forKey:@"AXWwindowElement"]; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + unsigned dummy; + self = [super init]; + windowApp = [[decoder decodeObjectForKey:@"AXWwindowApp"] retain]; + windowElement = *(AXUIElementRef *)[decoder decodeBytesForKey:@"AXWwindowElement" + returnedLength:&dummy]; + return self; +} + @end diff --git a/CGDisplay.h b/CGDisplay.h index 94d56e0..4536e98 100644 --- a/CGDisplay.h +++ b/CGDisplay.h @@ -9,7 +9,7 @@ #import #import "FMNDisplay.h" -@interface CGDisplay : NSObject { +@interface CGDisplay : NSObject { @protected CGDirectDisplayID displayID; @protected NSRect orientation; } diff --git a/CGDisplay.m b/CGDisplay.m index f4d3a28..0995457 100644 --- a/CGDisplay.m +++ b/CGDisplay.m @@ -100,4 +100,31 @@ - (void) dealloc [super dealloc]; } +- (NSString*) description +{ + NSRect r = [self getDisplayOrientation]; + + return [NSString stringWithFormat: + @"CGDisplay 0x%x: %fx%f at (%f, %f)", + (int)displayID, r.size.width, r.size.height, r.origin.x, r.origin.y]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeBytes:(const uint8_t *)&displayID + length:sizeof(CGDirectDisplayID) + forKey:@"CGDdisplayID"]; + [encoder encodeRect:orientation forKey:@"CGDorientation"]; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + unsigned dummy; + self = [super init]; + displayID = *(CGDirectDisplayID *)[decoder decodeBytesForKey:@"CGDisplayID" + returnedLength:&dummy]; + orientation = [decoder decodeRectForKey:@"CGDorientation"]; + return self; +} + @end diff --git a/CGDisplayConfiguration.h b/CGDisplayConfiguration.h index 2639363..6576904 100644 --- a/CGDisplayConfiguration.h +++ b/CGDisplayConfiguration.h @@ -11,7 +11,7 @@ #define CG_MAX_DISPLAYS 128 -@interface CGDisplayConfiguration : NSObject { +@interface CGDisplayConfiguration : NSObject { @protected NSMutableArray* displays; @protected FMNDisplayRef mainDisplay; } diff --git a/CGDisplayConfiguration.m b/CGDisplayConfiguration.m index d89bc07..8f73163 100644 --- a/CGDisplayConfiguration.m +++ b/CGDisplayConfiguration.m @@ -142,4 +142,16 @@ - (void) dealloc [super dealloc]; } +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:displays forKey:@"CGDCdisplays"]; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + self = [super init]; + displays = [[decoder decodeObjectForKey:@"CGDCdisplays"] retain]; + return self; +} + @end diff --git a/DevelNotes.txt b/DevelNotes.txt index d66004b..5cae4b0 100644 --- a/DevelNotes.txt +++ b/DevelNotes.txt @@ -35,6 +35,9 @@ leak. Things that still bug n8: +* Need to track which disp is main -- coordinate system origin is at top-left of + of main display. + * The "launch at login" preference doesn't require FMN to be running, so we shouldn't disable it when FMN isn't running. diff --git a/FMN.m b/FMN.m index 040b4df..51a933c 100644 --- a/FMN.m +++ b/FMN.m @@ -37,9 +37,16 @@ - (void) unregisterScreenChangeNotificationHandler FMN_CGDisplayReconfigurationCallback,self); } +NSString* describeCurrentConfiguration() { + CGDisplayConfiguration *dc = [CGDisplayConfiguration configWithCurrent]; + NSString *s = [dc description]; + return s; +} + - (void) handlePreDisplayConfigurationChange { NSLog(@"******** Screen configuration about to be changed! ********"); + NSLog(@"Current configuration: %@", describeCurrentConfiguration()); NSDate *startDate = [NSDate date]; // Save the current restorables @@ -105,6 +112,7 @@ - (NSDictionary*) getRestorationContext : (FMNDisplayConfigurationRef) previousD - (void) handlePostDisplayConfigurationChange { NSLog(@"======== Screen configuration changed! ========"); + NSLog(@"New configuration: %@", describeCurrentConfiguration()); NSDate *startDate = [NSDate date]; FMNDisplayConfigurationRef previousDisplayConfiguration = currentDisplayConfiguration; @@ -196,9 +204,6 @@ - (id) init { return nil; } - - // Initialize dictionary of screen configurations - screenConfigurations = [[NSMutableDictionary alloc] init]; // Initialize the current display configuration currentDisplayConfiguration = @@ -210,6 +215,11 @@ - (id) init [[FMNModuleLoader allPluginsOfBundle:mainBundle withProtocol:@protocol(FMNModule)] retain]; + // XXX: Deserialize? + + // Initialize dictionary of screen configurations + screenConfigurations = [[NSMutableDictionary alloc] init]; + [self activateFMN]; return self; @@ -253,6 +263,18 @@ - (void) dealloc [super dealloc]; } +/* Archive the stored configurations */ +- (BOOL) archiveDisplayConfigurationsToFile:(NSString *)path +{ + return [NSKeyedArchiver archiveRootObject:screenConfigurations toFile:path]; +} + +/* Load stored configs from a file */ +- (void) loadDisplayConfigurationsFromFile:(NSString *)path +{ + screenConfigurations = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; +} + @end static void FMN_CGDisplayReconfigurationCallback ( @@ -262,11 +284,20 @@ static void FMN_CGDisplayReconfigurationCallback ( ) { FMN* fmn = (FMN*) userInfo; + static int state = 0; + + NSLog(@"Got %@display change notification on 0x%x, is %@main", + (flags & kCGDisplayBeginConfigurationFlag) ? @"pre-" : @"post-", + display, CGDisplayIsMain(display)? @"":@"not "); // Only want to react once, not once per screen - if (!CGDisplayIsMain(display)) + //if (!CGDisplayIsMain(display)) + if (state == 1 || state == 2){ + state++; return; - + } + state = (state + 1) % 4; + if(flags == kCGDisplayBeginConfigurationFlag) { [fmn handlePreDisplayConfigurationChange]; diff --git a/FMN.xcodeproj/project.pbxproj b/FMN.xcodeproj/project.pbxproj index 2cd80ec..f0817a2 100644 --- a/FMN.xcodeproj/project.pbxproj +++ b/FMN.xcodeproj/project.pbxproj @@ -49,7 +49,6 @@ 0E57434B0AA4C2B400A42972 /* Flower.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0E5743490AA4C2B400A42972 /* Flower.icns */; }; 660640E70ABD233800D7D5D7 /* FMNDockModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 660640E60ABD233800D7D5D7 /* FMNDockModule.m */; }; 660640ED0ABD23A800D7D5D7 /* DockModule.plugin in Copy Files into Forget-Me-Not.app */ = {isa = PBXBuildFile; fileRef = 660640D90ABD227D00D7D5D7 /* DockModule.plugin */; }; - 660641140ABD273600D7D5D7 /* DockRestorable.h in Copy Files into Forget-Me-Not.app */ = {isa = PBXBuildFile; fileRef = 660641120ABD273600D7D5D7 /* DockRestorable.h */; }; 660641150ABD273600D7D5D7 /* DockRestorable.m in Sources */ = {isa = PBXBuildFile; fileRef = 660641130ABD273600D7D5D7 /* DockRestorable.m */; }; 6613E2B80A676588003DA5B2 /* FMN.m in Sources */ = {isa = PBXBuildFile; fileRef = 6613E2B70A676588003DA5B2 /* FMN.m */; }; 6629992F0A6E0386005757CB /* CGDisplay.m in Sources */ = {isa = PBXBuildFile; fileRef = 6629992E0A6E0386005757CB /* CGDisplay.m */; }; @@ -197,7 +196,6 @@ dstSubfolderSpec = 16; files = ( 660640ED0ABD23A800D7D5D7 /* DockModule.plugin in Copy Files into Forget-Me-Not.app */, - 660641140ABD273600D7D5D7 /* DockRestorable.h in Copy Files into Forget-Me-Not.app */, ); name = "Copy Files into Forget-Me-Not.app"; runOnlyForDeploymentPostprocessing = 0; @@ -287,7 +285,7 @@ 66D404820ABCE52B0014F0F4 /* AutolaunchPrefpaneModule-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "AutolaunchPrefpaneModule-Info.plist"; sourceTree = ""; }; 66D405010ABCEE2D0014F0F4 /* AutolaunchPrefpaneModule.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = AutolaunchPrefpaneModule.nib; path = PreferencePane/AutolaunchPrefpaneModule.nib; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 8D1107320486CEB800E47090 /* Forget-Me-Not.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "Forget-Me-Not.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D1107320486CEB800E47090 /* Forget-Me-Not.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Forget-Me-Not.app"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -663,9 +661,11 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "FMN" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 29B97314FDCFA39411CA2CEA /* FMN */; projectDirPath = ""; + projectRoot = ""; targets = ( 8D1107260486CEB800E47090 /* Forget-Me-Not App */, 0E4DE4A40A9BCADA001C9EEF /* AXModule */, @@ -1276,7 +1276,9 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_OTHER_PREPROCESSOR_FLAGS = "-C"; INFOPLIST_PREFIX_HEADER = version.h; @@ -1284,7 +1286,6 @@ INFOPLIST_PREPROCESSOR_DEFINITIONS = ""; MACOSX_DEPLOYMENT_TARGET_i386 = 10.4; MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; - OTHER_LDFLAGS = "-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"; PREBINDING = NO; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; @@ -1297,7 +1298,9 @@ ppc, i386, ); + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_OTHER_PREPROCESSOR_FLAGS = "-C"; INFOPLIST_PREFIX_HEADER = version.h; diff --git a/FMNAXModule.m b/FMNAXModule.m index b39973b..dd53574 100644 --- a/FMNAXModule.m +++ b/FMNAXModule.m @@ -9,6 +9,8 @@ #import "FMNAXModule.h" #import "AXApplication.h" +#define MAX_WORKSPACE 16 + @implementation FMNAXModule - (void) setExclusions:(NSArray *)ex @@ -63,7 +65,7 @@ - (NSArray *) getRestorables NSDate *ws_startDate = [NSDate date]; int i; - for(i=0; i<20; ++i) + for(i=0; i) configWithCurrent; ++ (id) configWithCurrent; - (unsigned) getDisplayCount; - (FMNDisplayRef) getMainDisplay; @@ -21,5 +21,5 @@ @end -typedef id +typedef id FMNDisplayConfigurationRef; diff --git a/FMNWindowOrientation.h b/FMNWindowOrientation.h index fa0293e..360a5c5 100644 --- a/FMNWindowOrientation.h +++ b/FMNWindowOrientation.h @@ -10,7 +10,7 @@ #import "FMNWindow.h" #import "FMNRestorable.h" -@interface FMNWindowOrientation : NSObject { +@interface FMNWindowOrientation : NSObject { @protected NSPoint position; @protected NSSize size; @protected FMNWindowRef window; diff --git a/FMNWindowOrientation.m b/FMNWindowOrientation.m index 63f081f..840ae93 100644 --- a/FMNWindowOrientation.m +++ b/FMNWindowOrientation.m @@ -53,4 +53,20 @@ - (void) dealloc [super dealloc]; } +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodePoint:position forKey:@"FMNWOposition"]; + [encoder encodeSize:size forKey:@"FMNWOsize"]; + [encoder encodeObject:window forKey:@"FMNWOwindow"]; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + self = [super init]; + position = [decoder decodePointForKey:@"FMNWOposition"]; + size = [decoder decodeSizeForKey:@"FMNWOsize"]; + window = [[decoder decodeObjectForKey:@"FMNWOwindow"] retain]; + return self; +} + @end diff --git a/PreferencePane/FMNPrefPane.m b/PreferencePane/FMNPrefPane.m index 2b38917..da6b7c8 100644 --- a/PreferencePane/FMNPrefPane.m +++ b/PreferencePane/FMNPrefPane.m @@ -12,6 +12,8 @@ #import "FMNPrefpaneModule.h" #import "version.h" +#include // For sleep + @implementation FMNPrefPane + (void) growViewFrame: (NSView*) view down: (int) height diff --git a/X11Bridge.h b/X11Bridge.h index a177cf4..b1e1c50 100644 --- a/X11Bridge.h +++ b/X11Bridge.h @@ -18,11 +18,14 @@ #import "FMNModule.h" -@interface X11Bridge : NSObject { +@interface X11Bridge : NSObject { NSString *mDisplayName; Display *mDisplay; } +/* Designated initializer */ +- (id) initWithDisplayName:(NSString *)dispName; + - (NSMutableArray *) getRestorables; - (void) setDisplayName:(NSString *)name; diff --git a/X11Bridge.m b/X11Bridge.m index 3a18d06..08dea07 100644 --- a/X11Bridge.m +++ b/X11Bridge.m @@ -41,21 +41,28 @@ - (void) dealloc - (id) init { char *dispName; - self = [super init]; - if (!self) - return self; /* XXX: We should make this a preferences item */ if (!(dispName = getenv("DISPLAY"))) dispName = ":0"; - - mDisplayName = [[NSString stringWithCString:dispName] retain]; + return [self initWithDisplayName:[NSString stringWithCString:dispName]]; +} + +/* Designated initializer */ +- (id) initWithDisplayName:(NSString *)dispName +{ + self = [super init]; + if (!self) + return self; + + mDisplayName = [[NSString stringWithString:dispName] retain]; // I believe this only needs to be done once, even if we connect to // different servers in our lifetime. XSetErrorHandler(xErrHandler); XSetIOErrorHandler(ioErrHandler); return self; + } - (void) setDisplayName:(NSString *)name @@ -89,4 +96,15 @@ - (int) closeDisplay { return i; } +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:mDisplayName forKey:@"X11BdisplayName"]; +} + +- (id)initWithCoder:(NSCoder *)coder +{ + NSString *dname = [[coder decodeObjectForKey:@"X11BdisplayName"] retain]; + return [self initWithDisplayName:dname]; +} + @end diff --git a/X11Restorable.h b/X11Restorable.h index b5f85b0..f5fa94e 100644 --- a/X11Restorable.h +++ b/X11Restorable.h @@ -12,7 +12,7 @@ /* This class wraps all X11 windows in a single restorable so that the display can be opened and closed properly */ -@interface X11Restorable : NSObject { +@interface X11Restorable : NSObject { NSMutableArray *mWindows; X11Bridge *mX11Bridge; } diff --git a/X11Restorable.m b/X11Restorable.m index 4b8fd3a..69f3789 100644 --- a/X11Restorable.m +++ b/X11Restorable.m @@ -98,4 +98,18 @@ - (int) priority return kRestorableDefaultPriority; } +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:mX11Bridge forKey:@"X11Bridge"]; + [encoder encodeObject:mWindows forKey:@"X11Windows"]; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + self = [super init]; + mX11Bridge = [[decoder decodeObjectForKey:@"X11Bridge"] retain]; + mWindows = [[decoder decodeObjectForKey:@"X11Windows"] retain]; + return self; +} + @end diff --git a/X11WindowOrientation.h b/X11WindowOrientation.h index 5d7a5d7..7abea7c 100644 --- a/X11WindowOrientation.h +++ b/X11WindowOrientation.h @@ -10,7 +10,7 @@ /* For the X11 types */ #import "X11Bridge.h" -@interface X11WindowOrientation : NSObject { +@interface X11WindowOrientation : NSObject { Window mWindow; int mX, mY, mWidth, mHeight; } diff --git a/X11WindowOrientation.m b/X11WindowOrientation.m index 03c5eb4..cb07a00 100644 --- a/X11WindowOrientation.m +++ b/X11WindowOrientation.m @@ -58,4 +58,23 @@ - (void) restoreOnDisplay:(Display *)disp // mWindow, mX, mY, mWidth, mHeight); } +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeInt64:mWindow forKey:@"X11WOwindow"]; + [coder encodeInt:mX forKey:@"X11WOx"]; + [coder encodeInt:mY forKey:@"X11WOy"]; + [coder encodeInt:mWidth forKey:@"X11WOwidth"]; + [coder encodeInt:mHeight forKey:@"X11WOheight"]; +} + +- (id)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + mWindow = [coder decodeInt64ForKey:@"X11WOwindow"]; + mX = [coder decodeIntForKey:@"X11WOx"]; + mY = [coder decodeIntForKey:@"X11WOy"]; + mWidth = [coder decodeIntForKey:@"X11WOwidth"]; + mHeight = [coder decodeIntForKey:@"X11WOheight"]; + return self; +} @end