diff --git a/.clang-format b/.clang-format index 4a284be50..a2bbc1626 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,8 @@ BasedOnStyle: Google AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false AlwaysBreakBeforeMultilineStrings: false BreakBeforeBraces: Custom BraceWrapping: @@ -22,3 +24,8 @@ AllowAllArgumentsOnNextLine: false PointerAlignment: Right ColumnLimit: 100 SortIncludes: Never +PointerAlignment: Right +AlignConsecutiveBitFields: AcrossEmptyLinesAndComments +AlignTrailingComments: true +AlignEscapedNewlines: Left +AlignOperands: Align diff --git a/Applications/Login/Controller.m b/Applications/Login/Controller.m index e0cd7a3ae..73419cc00 100644 --- a/Applications/Login/Controller.m +++ b/Applications/Login/Controller.m @@ -20,6 +20,7 @@ // #import "Controller.h" +#include "Foundation/NSObjCRuntime.h" #import "UserSession.h" #import @@ -31,6 +32,7 @@ #endif #import +#import #import #import @@ -169,9 +171,9 @@ - (void)setRootWindowBackground winattrs.cursor = XCreateFontCursor(xDisplay, XC_left_ptr); XChangeWindowAttributes(xDisplay, xRootWindow, CWCursor, &winattrs); - XSetWindowBackground(xDisplay, xRootWindow, 5460853L); - XClearWindow(xDisplay, xRootWindow); - XSync(xDisplay, false); + [[OSEScreen sharedScreen] setBackgroundColorRed:83.0 / 255.0 + green:83.0 / 255.0 + blue:116.0 / 255.0]; } - (void)setWindowVisible:(BOOL)flag diff --git a/Applications/Login/Login_main.m b/Applications/Login/Login_main.m index 19cede29b..6d9961c88 100644 --- a/Applications/Login/Login_main.m +++ b/Applications/Login/Login_main.m @@ -349,7 +349,7 @@ int main(int argc, const char **argv) // do window decorations ourselves [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"GSX11HandlesWindowDecorations"]; - setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); + // setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); // Start our application without appicon [LoginApplication sharedApplication]; NSApplicationMain(argc, argv); diff --git a/Applications/Login/UserSession.m b/Applications/Login/UserSession.m index 9f2fe535f..9dca643c0 100644 --- a/Applications/Login/UserSession.m +++ b/Applications/Login/UserSession.m @@ -117,7 +117,7 @@ - (BOOL)_setUserEnvironment setenv("GNUSTEP_PATHLIST", [[NSString stringWithFormat:@"%s:/:/usr/NextSpace:/Network", user->pw_dir] cString], 1); setenv("INFOPATH", [[NSString stringWithFormat:@"%s/Library/Documentation/info:/Library/Documentation/info:/usr/NextSpace/Documentation/info", user->pw_dir] cString], 1); - setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); + // setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 1); // For developers setenv("GNUSTEP_MAKEFILES", "/Developer/Makefiles", 1); diff --git a/Applications/Login/compile_flags.txt b/Applications/Login/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Login/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/OpenUp/compile_flags.txt b/Applications/OpenUp/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/OpenUp/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Preferences/AppController.m b/Applications/Preferences/AppController.m index f31f717b9..fd426bc75 100644 --- a/Applications/Preferences/AppController.m +++ b/Applications/Preferences/AppController.m @@ -94,6 +94,8 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotif if ([screen savedBackgroundColorRed:&red green:&green blue:&blue] == YES) { [screen setBackgroundColorRed:red green:green blue:blue]; } + } else { + [self showPreferencesWindow]; } } @@ -111,6 +113,7 @@ - (void)applicationWillTerminate:(NSNotification *)aNotif - (void)applicationDidBecomeActive:(NSNotification*)aNotification { + [self showPreferencesWindow]; } - (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName diff --git a/Applications/Preferences/Modules/Font/Font.h b/Applications/Preferences/Modules/Font/Font.h index 5afbce5f1..521025d45 100644 --- a/Applications/Preferences/Modules/Font/Font.h +++ b/Applications/Preferences/Modules/Font/Font.h @@ -46,8 +46,6 @@ NSImage *image; NSString *exampleString; - NSString *normalExampleString; - NSString *boldExampleString; } - (IBAction)fontCategoryChanged:(id)sender; diff --git a/Applications/Preferences/Modules/Font/Font.m b/Applications/Preferences/Modules/Font/Font.m index 675da8554..1ee37a05f 100644 --- a/Applications/Preferences/Modules/Font/Font.m +++ b/Applications/Preferences/Modules/Font/Font.m @@ -40,6 +40,8 @@ #import #import +#import + #import "Font.h" @interface Font (Private) @@ -50,24 +52,24 @@ - (void) updateUI; @implementation Font (Private) -static NSBundle *bundle = nil; -static NSUserDefaults *defaults = nil; +static NSBundle *bundle = nil; +static NSUserDefaults *defaults = nil; static NSMutableDictionary *domain = nil; -static NSPanel *fontPanel = nil; +static NSPanel *fontPanel = nil; -// + userFontOfSize: [Application Font] +// + userFontOfSize: [Application Font] // + userFixedPitchFontOfSize: [Fixed Pitch Font] -// + systemFontOfSize: [System Font] -// + boldSystemFontOfSize: [Bold System Font] +// + systemFontOfSize: [System Font] +// + boldSystemFontOfSize: [Bold System Font] // ========================== MACOSX, GS_API_LATEST =========================== -// + toolTipsFontOfSize: [System Font:11] -// + menuFontOfSize: [System Font] -// + messageFontOfSize: [System Font:14] -// + controlContentFontOfSize: [System Font] -// + labelFontOfSize: [System Font] -// + titleBarFontOfSize: [Bold System Font] -// + menuBarFontOfSize: [Bold System Font] -// + paletteFontOfSize: [Bold System Font] +// + toolTipsFontOfSize: [System Font:11] +// + menuFontOfSize: [System Font] +// + messageFontOfSize: [System Font:14] +// + controlContentFontOfSize: [System Font] +// + labelFontOfSize: [System Font] +// + titleBarFontOfSize: [Bold System Font] +// + menuBarFontOfSize: [Bold System Font] +// + paletteFontOfSize: [Bold System Font] // ========================== MACOSX, GS_API_LATEST =========================== static NSMutableDictionary *defaultValues(void) @@ -186,45 +188,46 @@ static void setIntDefault(int anInt, NSString *name) userDefPath = [NSString stringWithFormat:@"%@/.NextSpace/WM.plist", GSDefaultsRootForUser(NSUserName())]; - if (![[NSFileManager defaultManager] fileExistsAtPath:userDefPath]) { - userDefPath = nil; - } + // if (![[NSFileManager defaultManager] fileExistsAtPath:userDefPath]) { + // userDefPath = nil; + // } return userDefPath; } -- (void)setWMFont:(NSFont *)font key:(NSString *)key +- (void)setWMPreference:(NSString *)value forKey:(NSString *)key { - NSString *wmDefaultsPath = WWMDefaultsPath(); + NSString *wmDefaultsPath = WWMDefaultsPath(); NSMutableDictionary *wmDefaults; - NSMutableString *value; if (![[NSFileManager defaultManager] fileExistsAtPath:wmDefaultsPath]) { - /* TODO: WM doesn't track WM.plist changes if it doesn't exist. - We need to send WMDidChangeWindowAppearanceSettings to the distributed - notification center (WM should handle this notification and reread file). */ NSLog(@"[Font] can't find existing WM defaults database! Creating new..."); wmDefaults = [NSMutableDictionary new]; - } - else { + } else { wmDefaults = [[NSMutableDictionary alloc] initWithContentsOfFile:wmDefaultsPath]; } - - // Convert font name into the FontConfig format. - value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=false", - [font familyName], [font fontName], [font pointSize]]; - NSLog(@"[Font] set WM font %@ = `%@`", key, value); [wmDefaults setObject:value forKey:key]; [wmDefaults writeToFile:wmDefaultsPath atomically:YES]; [wmDefaults release]; } +- (void)setWMFont:(NSFont *)font forKey:(NSString *)key +{ + NSMutableString *value; + + // Convert font name into the FontConfig format. + value = [NSMutableString stringWithFormat:@"%@:postscriptname=%@:pixelsize=%.0f:antialias=%@", + [font familyName], [font fontName], [font pointSize], + [enableAntiAliasingButton state] ? @"true" : @"false"]; + [self setWMPreference:value forKey:key]; +} + - (void)updateUI { NSString *fontKey; NSString *fontSizeKey; - NSFont *font, *boldFont; + NSFont *font; fontKey = [fontCategories objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; @@ -238,21 +241,13 @@ - (void)updateUI fontSizeKey = [NSString stringWithFormat:@"%@Size", fontKey]; font = [NSFont fontWithName:getStringDefault(domain, fontKey) size:getFloatDefault(domain, fontSizeKey)]; - boldFont = [[NSFontManager sharedFontManager] convertFont:font - toHaveTrait:NSBoldFontMask]; - // [fontNameTextField setFont:font]; [fontNameTextField setStringValue:[NSString stringWithFormat: @"%@ %g point", [font displayName], [font pointSize]]]; - // [fontExampleTextView setFont:font]; - [fontExampleTextView setFont:boldFont - range:NSMakeRange([normalExampleString length], - [boldExampleString length]+1)]; - // [enableAntiAliasingButton setIntValue:getBoolDefault(domain, @"GSFontAntiAlias")]; @@ -293,10 +288,10 @@ - (void)dealloc [image release]; [fontCategories dealloc]; - if (view) { - [normalExampleString release]; - [boldExampleString release]; - } + // if (view) { + // [normalExampleString release]; + // [boldExampleString release]; + // } [super dealloc]; } @@ -336,16 +331,7 @@ - (void)awakeFromNib exampleString = NSLocalizedStringFromTableInBundle(@"Example Text", @"Localizable", bundle, @""); - normalExampleString = [[NSString alloc] initWithFormat:@"Normal:\n%@", - exampleString]; - boldExampleString = [[NSString alloc] initWithFormat:@"Bold:\n%@", - exampleString]; - - [fontExampleTextView setText:[NSString stringWithFormat:@"%@\n%@", - normalExampleString, - boldExampleString]]; - // [fontExampleTextView - // readRTFDFromFile:[bundle pathForResource:@"ExampleText" ofType:@"rtf"]]; + [fontExampleTextView setText:exampleString]; [self updateUI]; } @@ -392,8 +378,12 @@ - (IBAction)setFont:(id)sender - (IBAction)enableAntiAliasingChanged:(id)sender { + // GS setBoolDefault([sender intValue], @"GSFontAntiAlias"); setIntDefault(0, @"back-art-subpixel-text"); + + // WM + [self setWMPreference:([sender intValue] ? @"YES" : @"NO") forKey:@"UseAntialiasedText"]; [self updateUI]; } @@ -402,28 +392,25 @@ - (IBAction)enableAntiAliasingChanged:(id)sender - (void)changeFont:(id)sender { - NSString *fontName, *fontKey; - CGFloat fontSize; + NSString *fontName, *fontKey; + CGFloat fontSize; NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFont *font; + NSFont *font; font = [fontManager convertFont:[fontExampleTextView font]]; fontName = [font fontName]; fontSize = [font pointSize]; - fontKey = [fontCategories - objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; + fontKey = [fontCategories objectForKey:[fontCategoryPopUp titleOfSelectedItem]]; - if ([fontKey isEqualToString:@"NSUserFont"]) { // Application + if ([fontKey isEqualToString:@"NSUserFont"]) { // Application // NSUserFont, NSUserFontSize=12 setStringDefault(fontName, @"NSUserFont"); setFloatDefault(fontSize, @"NSUserFontSize"); - } - else if ([fontKey isEqualToString:@"NSUserFixedPitchFont"]) {// Fixed Pitch + } else if ([fontKey isEqualToString:@"NSUserFixedPitchFont"]) { // Fixed Pitch // NSUserFixedPitchFont, NSUserFixedPitchFontSize setStringDefault(fontName, @"NSUserFixedPitchFont"); setFloatDefault(fontSize, @"NSUserFixedPitchFontSize"); - } - else if ([fontKey isEqualToString:@"NSFont"]) { // System + } else if ([fontKey isEqualToString:@"NSFont"]) { // System // NSFont, NSFontSize=12 setStringDefault(fontName, @"NSFont"); setFloatDefault(fontSize, @"NSFontSize"); @@ -440,16 +427,16 @@ - (void)changeFont:(id)sender setStringDefault(fontName, @"NSLabelFont"); setFloatDefault(fontSize, @"NSLabelFontSize"); // NSMiniFontSize=9, NSSmallFontSize=11 - setFloatDefault(fontSize - 4.0, @"NSMiniFontSize"); + setFloatDefault(fontSize - 3.0, @"NSMiniFontSize"); setFloatDefault(fontSize - 2.0, @"NSSmallFontSize"); // WM - [self setWMFont:[NSFont fontWithName:[font familyName] size:fontSize - 4.0] - key:@"IconTitleFont"]; - [self setWMFont:font key:@"MenuTextFont"]; - [self setWMFont:[NSFont fontWithName:[font familyName] size:fontSize * 2.0] - key:@"LargeDisplayFont"]; - } - else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System + [self setWMFont:font forKey:@"MenuTextFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize - 3.0] forKey:@"IconTitleFont"]; + [self setWMFont:[NSFont fontWithName:fontName size:fontSize * 2.0] forKey:@"LargeDisplayFont"]; + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:WMDidChangeAppearanceSettingsNotification + object:@"GSWorkspaceNotification"]; + } else if ([fontKey isEqualToString:@"NSBoldFont"]) { // Bold System // NSBoldFont, NSBoldFontSize=12 setStringDefault(fontName, @"NSBoldFont"); setFloatDefault(fontSize, @"NSBoldFontSize"); @@ -462,10 +449,12 @@ - (void)changeFont:(id)sender setStringDefault(fontName, @"NSPaletteFont"); setFloatDefault(fontSize, @"NSPaletteFontSize"); // WM - [self setWMFont:font key:@"MenuTitleFont"]; - [self setWMFont:font key:@"WindowTitleFont"]; - } - else if ([fontKey isEqualToString:@"NSToolTipsFont"]) { // Tool Tips + [self setWMFont:font forKey:@"MenuTitleFont"]; + [self setWMFont:font forKey:@"WindowTitleFont"]; + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:WMDidChangeAppearanceSettingsNotification + object:@"GSWorkspaceNotification"]; + } else if ([fontKey isEqualToString:@"NSToolTipsFont"]) { // Tool Tips // NSToolTipsFont, NSToolTipsFontSize=11 setStringDefault(fontName, @"NSToolTipsFont"); setFloatDefault(fontSize, @"NSToolTipsFontSize"); @@ -474,8 +463,8 @@ - (void)changeFont:(id)sender [defaults synchronize]; [self updateUI]; [[NSDistributedNotificationCenter defaultCenter] - postNotificationName:@"NXTSystemFontPreferencesDidChangeNotification" - object:@"Preferences"]; + postNotificationName:@"NXTSystemFontPreferencesDidChangeNotification" + object:@"Preferences"]; } @end // Font diff --git a/Applications/Preferences/compile_flags.txt b/Applications/Preferences/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Preferences/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Review/compile_flags.txt b/Applications/Review/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Review/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Terminal/compile_flags.txt b/Applications/Terminal/compile_flags.txt deleted file mode 100644 index 7642bb6e4..000000000 --- a/Applications/Terminal/compile_flags.txt +++ /dev/null @@ -1,27 +0,0 @@ --MMD --MP --DGNUSTEP --DGNUSTEP_BASE_LIBRARY=1 --DGNU_GUI_LIBRARY=1 --DGNUSTEP_RUNTIME=1 --D_NONFRAGILE_ABI=1 --DGNUSTEP_BASE_LIBRARY=1 --fno-strict-aliasing --fexceptions --fobjc-exceptions --D_NATIVE_OBJC_EXCEPTIONS --pthread --fPIC --DDEBUG --fno-omit-frame-pointer --Wno-import --g --fobjc-runtime=gnustep-2.0 --fblocks --fconstant-string-class=NSConstantString --I. --I.. --I../.. --I/Users/me/Library/Headers --I/Developer/Headers --I/usr/NextSpace/include diff --git a/Applications/Terminal/compile_flags.txt b/Applications/Terminal/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Terminal/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/TextEdit/compile_flags.txt b/Applications/TextEdit/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/TextEdit/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/TimeMon/compile_flags.txt b/Applications/TimeMon/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/TimeMon/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Weather/compile_flags.txt b/Applications/Weather/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Applications/Weather/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Applications/Workspace/Controller+NSWorkspace.h b/Applications/Workspace/Controller+NSWorkspace.h index 49c97c4e1..3b55e3bec 100644 --- a/Applications/Workspace/Controller+NSWorkspace.h +++ b/Applications/Workspace/Controller+NSWorkspace.h @@ -154,28 +154,18 @@ //--- Manipulating Files //----------------------------------------------------------------------------- -//--- Possible values for operation in performFileOperation:... -APPKIT_EXPORT NSString *NSWorkspaceMoveOperation; -APPKIT_EXPORT NSString *NSWorkspaceCopyOperation; -APPKIT_EXPORT NSString *NSWorkspaceLinkOperation; -APPKIT_EXPORT NSString *NSWorkspaceCompressOperation; -APPKIT_EXPORT NSString *NSWorkspaceDecompressOperation; -APPKIT_EXPORT NSString *NSWorkspaceEncryptOperation; -APPKIT_EXPORT NSString *NSWorkspaceDecryptOperation; -APPKIT_EXPORT NSString *NSWorkspaceDestroyOperation; -APPKIT_EXPORT NSString *NSWorkspaceRecycleOperation; -APPKIT_EXPORT NSString *NSWorkspaceDuplicateOperation; - /** Requests the Workspace Manager to perform a file operation on a set of files in the source directory specifying the destination directory if needed using tag as an identifier for asynchronous operations; returns YES - if operation succeeded and NO otherwise.*/ -// TODO: [NSWorkspace _workspaceApplication] -// - (BOOL)performFileOperation:(NSString*)operation -// source:(NSString*)source -// destination:(NSString*)destination -// files:(NSArray*)files -// tag:(int*)tag; + if operation succeeded and NO otherwise. + + Strings for operation types defined in AppKit/NSWorkspace.h*/ +// --- [NSWorkspace _workspaceApplication] +- (BOOL)performFileOperation:(NSString *)operation + source:(NSString *)source + destination:(NSString *)destination + files:(NSArray *)files + tag:(int *)tag; /** Instructs Workspace Manager to select the file specified by fullPath opening a new file viewer if a path is specified by rootFullpath; returns @@ -255,12 +245,10 @@ APPKIT_EXPORT NSString *NSShellCommandFileType; /** Returns whether a change to the file system has been registered with a noteFileSystemChanged message since the last fileSystemChanged message.*/ -// CHECK -// - (BOOL)fileSystemChanged; +- (BOOL)fileSystemChanged; /** Informs Workspace Manager that the file system has changed.*/ -// CHECK -// - (void)noteFileSystemChanged; +- (void)noteFileSystemChanged; //----------------------------------------------------------------------------- //--- Updating Registered Services and File Types @@ -339,9 +327,14 @@ APPKIT_EXPORT NSString *NSShellCommandFileType; @"NSApplicationProcessSerialNumberLow" - The low long of the process serial number (PSN), as an NSNumber object. */ -// TODO: [NSWorkspace _workspaceApplication] +// --- [NSWorkspace _workspaceApplication] - (NSDictionary *)activeApplication; +// Return not only GNUstep application but also registered X11 applications. +// Such application record has separate field @"IsXWindowApplication" set to @"YES". +// --- [NSWorkspace _workspaceApplication] +- (NSArray*) launchedApplications; + //----------------------------------------------------------------------------- //--- Unmounting a Device //----------------------------------------------------------------------------- diff --git a/Applications/Workspace/Controller+NSWorkspace.m b/Applications/Workspace/Controller+NSWorkspace.m index ea712f82d..189622f20 100644 --- a/Applications/Workspace/Controller+NSWorkspace.m +++ b/Applications/Workspace/Controller+NSWorkspace.m @@ -36,6 +36,10 @@ #include #import +#include "AppKit/NSWorkspace.h" +#include "Foundation/NSValue.h" +#include "Foundation/NSBundle.h" +#include "AppKit/NSImage.h" #import #import @@ -166,10 +170,6 @@ - (id)initNSWorkspace if (_applications == nil) { [self findApplications]; } - // [_workspaceCenter addObserver:self - // selector:@selector(_workspacePreferencesChanged:) - // name:GSWorkspacePreferencesChanged - // object:nil]; /* icon association and caching */ folderPathIconDict = [[NSMutableDictionary alloc] initWithCapacity:5]; @@ -322,7 +322,8 @@ - (BOOL)openFile:(NSString *)fullPath NSString *wmName; NSBundle *appBundle; NSDictionary *appInfo; - NSString *iconPath; + NSString *iconName = nil; + NSString *iconPath = nil; NSString *launchPath; // Don't launch ourself and Login panel @@ -356,7 +357,18 @@ - (BOOL)openFile:(NSString *)fullPath nil, nil, nil, appName, fullPath); return NO; } - iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; + + if ((iconName = appInfo[@"NSIcon"]) != nil) { + iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; + if (iconPath == nil) { + NSLog(@"No icon for application found in app bundle!"); + } + } else { + iconName = @"NXUnknownApplication"; + } + if (iconPath == nil) { + iconPath = [[NSBundle mainBundle] pathForImageResource:iconName]; + } [raceLock lock]; wLaunchingAppIconCreate([[wmName stringByDeletingPathExtension] cString], "GNUstep", @@ -380,35 +392,46 @@ - (BOOL)openFile:(NSString *)fullPath NSBundle *appBundle; NSDictionary *appInfo; NSString *wmName; + NSString *wmClass; NSString *iconPath; NSString *launchPath; + launchPath = [self _locateApplicationBinary:appName]; + if (launchPath == nil) { + return NO; + } + appBundle = [self _bundleForApp:appName]; if (appBundle) { appInfo = [appBundle infoDictionary]; iconPath = [appBundle pathForImageResource:[appInfo objectForKey:@"NSIcon"]]; wmName = [appInfo objectForKey:@"NSExecutable"]; - launchPath = [self _locateApplicationBinary:appName]; - if (launchPath == nil) { - return NO; + wmClass = [wmName pathExtension]; + + if ([wmClass isEqualToString:@""] == NO) { + wmName = [wmName stringByDeletingPathExtension]; + } else { + wmClass = @"GNUstep"; } + [raceLock lock]; - wLaunchingAppIconCreate([[wmName stringByDeletingPathExtension] cString], "GNUstep", - [launchPath cString], point.x, point.y, [iconPath cString]); + wLaunchingAppIconCreate([wmName cString], [wmClass cString], [launchPath cString], point.x, + point.y, [iconPath cString]); [raceLock unlock]; - } - if (![self openFile:fullPath withApplication:appName andDeactivate:YES]) { - NXTRunAlertPanel(_(@"Workspace"), _(@"Failed to start application \"%@\" for file \"%@\""), - nil, nil, nil, appName, [fullPath lastPathComponent]); - return NO; - } - // If multiple files are opened at once we need to wait for app to start. - // Otherwise two copies of one application become alive. - while ([self _connectApplication:appName] == nil) { - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; + if (![self openFile:fullPath withApplication:appName andDeactivate:YES]) { + NXTRunAlertPanel(_(@"Workspace"), _(@"Failed to start application \"%@\" for file \"%@\""), + nil, nil, nil, appName, [fullPath lastPathComponent]); + return NO; + } + // If multiple files are opened at once we need to wait for app to start. + // Otherwise two copies of one application become alive. + while (([wmClass isEqualToString:@"GNUstep"] != NO) && + ([self _connectApplication:appName] == nil)) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; + } + return YES; } - return YES; } return NO; @@ -417,17 +440,52 @@ - (BOOL)openFile:(NSString *)fullPath //------------------------------------------------------------------------------------------------- //--- Manipulating Files //------------------------------------------------------------------------------------------------- -// FIXME: TODO -// - (BOOL)performFileOperation:(NSString*)operation -// source:(NSString*)source -// destination:(NSString*)destination -// files:(NSArray*)files -// tag:(int*)tag -// { -// // FiXME - -// return NO; -// } +// Operation types supported by ProcessManager: Copy, Duplicate, Move, Link, Delete, Recycle +- (BOOL)performFileOperation:(NSString*)operation + source:(NSString*)source + destination:(NSString*)destination + files:(NSArray*)files + tag:(int*)tag +{ + OperationType opType = 0; + + if ([operation isEqualToString:NSWorkspaceCopyOperation]) { + opType = CopyOperation; + } else if ([operation isEqualToString:NSWorkspaceDuplicateOperation]) { + opType = DuplicateOperation; + } else if ([operation isEqualToString:NSWorkspaceMoveOperation]) { + opType = MoveOperation; + } else if ([operation isEqualToString:NSWorkspaceLinkOperation]) { + opType = LinkOperation; + } else if ([operation isEqualToString:NSWorkspaceDestroyOperation]) { + opType = DeleteOperation; + } else if ([operation isEqualToString:NSWorkspaceRecycleOperation]) { + opType = RecycleOperation; + } /*else if ([operation isEqualToString:NSWorkspaceCompressOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceDecompressOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceEncryptOperation]) { + opType = ; + } else if ([operation isEqualToString:NSWorkspaceDecryptOperation]) { + opType = ; + }*/ + + if (opType) { + id operation = [procManager startOperationWithType:opType + source:source + target:destination + files:files]; + if (operation) { + NSNumber *opHash = [NSNumber numberWithUnsignedInteger:[operation hash]]; + *tag = [opHash intValue]; + return YES; + } else { + return NO; + } + } + return NO; +} // From OpenUp: // [[NSWorkspace sharedWorkspace] selectFile:archivePath @@ -734,18 +792,18 @@ - (NSImage *)iconForOpenedDirectory:(NSString *)fullPath //------------------------------------------------------------------------------------------------- //--- Tracking Changes to the File System //------------------------------------------------------------------------------------------------- -// - (BOOL)fileSystemChanged -// { -// BOOL flag = _fileSystemChanged; +- (BOOL)fileSystemChanged +{ + BOOL flag = _fileSystemChanged; -// _fileSystemChanged = NO; -// return flag; -// } + _fileSystemChanged = NO; + return flag; +} -// - (void)noteFileSystemChanged -// { -// _fileSystemChanged = YES; -// } +- (void)noteFileSystemChanged +{ + _fileSystemChanged = YES; +} //------------------------------------------------------------------------------------------------- //--- Updating Registered Services and File Types @@ -802,6 +860,11 @@ - (NSDictionary *)activeApplication return [[ProcessManager shared] activeApplication]; } +- (NSArray *)launchedApplications +{ + return [[ProcessManager shared] applications]; +} + //------------------------------------------------------------------------------------------------- //--- Unmounting a Device //------------------------------------------------------------------------------------------------- @@ -837,7 +900,7 @@ - (NSArray *)mountedRemovableMedia - (NSNotificationCenter *)notificationCenter { - return _workspaceCenter; + return _windowManagerCenter; } //------------------------------------------------------------------------------------------------- @@ -1200,31 +1263,25 @@ - (BOOL)_extension:(NSString *)ext role:(NSString *)role app:(NSString **)app // * TODO add a user info to aNotification, which includes a bitmask // * denoting the updated preference files. // */ -// NSFileManager *mgr = [NSFileManager defaultManager]; -// NSData *data; -// NSDictionary *dict; - -// if ([mgr isReadableFileAtPath: extPrefPath] == YES) -// { -// data = [NSData dataWithContentsOfFile: extPrefPath]; -// if (data) -// { -// dict = [NSDeserializer deserializePropertyListFromData: data -// mutableContainers: NO]; -// ASSIGN(extPreferences, dict); -// } +// NSFileManager *mgr = [NSFileManager defaultManager]; +// NSData *data; +// NSDictionary *dict; + +// if ([mgr isReadableFileAtPath:extPrefPath] == YES) { +// data = [NSData dataWithContentsOfFile:extPrefPath]; +// if (data) { +// dict = [NSDeserializer deserializePropertyListFromData:data mutableContainers:NO]; +// ASSIGN(extPreferences, dict); // } +// } -// if ([mgr isReadableFileAtPath: appListPath] == YES) -// { -// data = [NSData dataWithContentsOfFile: appListPath]; -// if (data) -// { -// dict = [NSDeserializer deserializePropertyListFromData: data -// mutableContainers: NO]; -// ASSIGN(applications, dict); -// } +// if ([mgr isReadableFileAtPath:appListPath] == YES) { +// data = [NSData dataWithContentsOfFile:appListPath]; +// if (data) { +// dict = [NSDeserializer deserializePropertyListFromData:data mutableContainers:NO]; +// ASSIGN(applications, dict); // } +// } // /* // * Invalidate the cache of icons for file extensions. // */ @@ -1287,7 +1344,7 @@ - (BOOL)_launchApplication:(NSString *)appName arguments:(NSArray *)args @"NSApplicationPath" : appName }; NSLog(@"Application UserInfo: %@", userinfo); - [_workspaceCenter postNotificationName:NSWorkspaceWillLaunchApplicationNotification + [_windowManagerCenter postNotificationName:NSWorkspaceWillLaunchApplicationNotification object:self userInfo:userinfo]; task = [NSTask launchedTaskWithLaunchPath:path arguments:args]; @@ -1323,7 +1380,7 @@ - (void)_launchedApplicationDidTerminate:(NSNotification *)aNotif if (appicon) { wLaunchingAppIconDestroy(wDefaultScreen(), appicon); } - [_workspaceCenter + [_windowManagerCenter postNotificationName:NSWorkspaceDidTerminateApplicationNotification object:self userInfo:@{@"NSApplicationName" : [[task launchPath] lastPathComponent]}]; @@ -1349,9 +1406,7 @@ - (id)_connectApplication:(NSString *)appName if (host == nil) { host = @""; } else { - NSHost *h; - - h = [NSHost hostWithName:host]; + NSHost *h = [NSHost hostWithName:host]; if ([h isEqual:[NSHost currentHost]] == YES) { host = @""; } @@ -1653,10 +1708,10 @@ - (void)_setBestApp:(NSString *)appName inRole:(NSString *)role forExtension:(NS _extPreferences = map; data = [NSSerializer serializePropertyList:_extPreferences]; if ([data writeToFile:_extPrefPath atomically:YES]) { - // [_workspaceCenter postNotificationName:GSWorkspacePreferencesChanged + // [NSNotificationCenter defaultCenter] postNotificationName:GSWorkspacePreferencesChanged // object:self]; } else { - NSLog(@"Update %@ of failed", _extPrefPath); + NSDebugLLog(@"Workspace", @"Update %@ of failed", _extPrefPath); } } @@ -1692,10 +1747,10 @@ - (void)_setBestIcon:(NSString *)iconPath forExtension:(NSString *)ext _extPreferences = map; data = [NSSerializer serializePropertyList:_extPreferences]; if ([data writeToFile:_extPrefPath atomically:YES]) { - // [_workspaceCenter postNotificationName:GSWorkspacePreferencesChanged + // [NSNotificationCenter defaultCenter] postNotificationName:GSWorkspacePreferencesChanged // object:self]; } else { - NSLog(@"Update %@ of failed", _extPrefPath); + NSDebugLLog(@"Workspace", @"Update %@ of failed", _extPrefPath); } } diff --git a/Applications/Workspace/Controller.h b/Applications/Workspace/Controller.h index abedf7ab8..fe845d408 100644 --- a/Applications/Workspace/Controller.h +++ b/Applications/Workspace/Controller.h @@ -83,7 +83,7 @@ NSMutableDictionary *_iconMap; NSMutableDictionary *_launched; NSArray *_wrappers; - NSNotificationCenter *_workspaceCenter; + NSNotificationCenter *_windowManagerCenter; BOOL _fileSystemChanged; BOOL _userDefaultsChanged; // ~/Library/Services/.GNUstepAppList diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index b56c60293..d8314106f 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -21,7 +21,6 @@ #import #import #import -#include "Foundation/NSNotification.h" #import #import @@ -30,7 +29,8 @@ #include #import -#import +#import + #import #import #import @@ -60,9 +60,6 @@ #import #import -#import -#import - static NSString *WorkspaceVersion = @"0.8"; //============================================================================ @@ -390,7 +387,7 @@ - (void)_finishTerminateProcess // We don't need to handle events on quit. [[NSNotificationCenter defaultCenter] removeObserver:self]; // Not need to remove observers explicitely for NSWorkspaceCenter. - [_workspaceCenter release]; + [_windowManagerCenter release]; // Close and save file viewers, close panels. [self _saveWindowsStateAndClose]; @@ -626,14 +623,14 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notif [self updateKeyboardBadge:nil]; // Workspace Notification Central - _workspaceCenter = [WMNotificationCenter defaultCenter]; + _windowManagerCenter = [WMNotificationCenter defaultCenter]; // Window Manager events - [_workspaceCenter addObserver:self + [_windowManagerCenter addObserver:self selector:@selector(updateWorkspaceBadge:) name:CF_NOTIFICATION(WMDidChangeDesktopNotification) object:nil]; - [_workspaceCenter addObserver:self + [_windowManagerCenter addObserver:self selector:@selector(updateKeyboardBadge:) name:CF_NOTIFICATION(WMDidChangeKeyboardLayoutNotification) object:nil]; @@ -750,6 +747,8 @@ - (void)activateApplication:(NSNotification *)aNotification // Workspace quit. // Log Out and Power Off terminate quitting when some application won't stop, // some removable media won't unmount/eject (optional: think). +#define LogOut NSAlertDefaultReturn +#define PowerOff NSAlertAlternateReturn - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { NSApplicationTerminateReply terminateReply; @@ -758,59 +757,49 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende switch (NXTRunAlertPanel(_(@"Log Out"), _(@"Do you really want to log out?"), _(@"Log out"), _(@"Power off"), _(@"Cancel"))) { - case NSAlertDefaultReturn: // Log Out + case LogOut: { [[NSApp mainMenu] close]; - _isQuitting = YES; - if ([procManager terminateAllBGOperations] == NO) { - _isQuitting = NO; - terminateReply = NSTerminateCancel; - } + _isQuitting = [procManager terminateAllBGOperations]; if (_isQuitting != NO) { // Save running applications [self _saveRunningApplications]; - - if ([procManager terminateAllApps] == NO) { - NXTRunAlertPanel(_(@"Log Out"), _(@"Some application terminate power off process."), - _(@"Dismiss"), nil, nil); - _isQuitting = NO; - terminateReply = NSTerminateCancel; + _isQuitting = [procManager terminateAllApps]; + if (_isQuitting == NO) { + NXTRunAlertPanel(_(@"Log Out"), _(@"'%@' application request to cancel Log Out."), _(@"Dismiss"), nil, nil, + [self activeApplication][@"NSApplicationName"]); } } - if (_isQuitting != NO) { + + if (_isQuitting == NO) { + terminateReply = NSTerminateCancel; + } else { // Close Workspace windows, hide Dock, quit WM [self _finishTerminateProcess]; terminateReply = NSTerminateNow; ws_quit_code = WSLogoutOnQuit; - } else { - [[NSApp mainMenu] display]; } } break; - case NSAlertAlternateReturn: // Power off + case PowerOff: { [[NSApp mainMenu] close]; - _isQuitting = YES; - if ([procManager terminateAllBGOperations] == NO) { - _isQuitting = NO; - terminateReply = NSTerminateCancel; - } + _isQuitting = [procManager terminateAllBGOperations]; if (_isQuitting != NO) { // Save running applications [self _saveRunningApplications]; - - if ([procManager terminateAllApps] == NO) { - NXTRunAlertPanel(_(@"Power Off"), _(@"Some application terminate power off process."), - _(@"Dismiss"), nil, nil); - _isQuitting = NO; - terminateReply = NSTerminateCancel; + _isQuitting = [procManager terminateAllApps]; + if (_isQuitting == NO) { + NXTRunAlertPanel(_(@"Power Off"), _(@"'%@' application request to cancel Power Off."), + _(@"Dismiss"), nil, nil, [self activeApplication][@"NSApplicationName"]); } } - if (_isQuitting != NO) { + if (_isQuitting == NO) { + terminateReply = NSTerminateCancel; + } else { [self _finishTerminateProcess]; terminateReply = NSTerminateNow; ws_quit_code = WSPowerOffOnQuit; - } else { - [[NSApp mainMenu] display]; + } } break; default: @@ -819,6 +808,16 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende break; } + if (_isQuitting == NO) { + [[NSApp mainMenu] display]; + // FIXME: restore Workspace focus. It's not correct from user POV - managed application + // may want to have focus to review unsaved data. For now it's better not to have two app + // menus visible with focus mess. Currently WM info about focused window differs from + // GNUstep app. + [[NSApp mainWindow] makeKeyAndOrderFront:self]; + NSDebugLLog(@"Workspace", @"Active application: %@", [self activeApplication][@"NSApplicationName"]); + } + wDefaultScreen()->flags.ignore_focus_events = 0; return terminateReply; @@ -1040,8 +1039,20 @@ - (void)updateKeyboardBadge:(NSNotification *)aNotification // Application menu //============================================================================ +- (void)hideOtherApplications:(id)sender +{ + Window xWindow = (Window)[GSCurrentServer() windowDevice:[[NSApp keyWindow] windowNumber]]; + NSDictionary *info = + @{@"WindowID" : [NSNumber numberWithUnsignedLong:xWindow], @"ApplicationName" : @"Workspace"}; + + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:CF_NOTIFICATION(WMShouldHideOthersNotification) + object:@"GSWorkspaceNotification" + userInfo:info]; +} + // Info -- (void)showInfoPanel:sender +- (void)showInfoPanel:(id)sender { if (infoPanel == nil) { [NSBundle loadNibNamed:@"InfoPanel" owner:self]; @@ -1052,7 +1063,7 @@ - (void)showInfoPanel:sender [infoPanel makeKeyAndOrderFront:nil]; } -- (void)showLegalPanel:sender +- (void)showLegalPanel:(id)sender { if (legalPanel == nil) { NSScrollView *sv; @@ -1071,7 +1082,7 @@ - (void)showLegalPanel:sender } // TODO -- (void)saveLegalToFile:sender +- (void)saveLegalToFile:(id)sender { NSSavePanel *sp = [NXTSavePanel savePanel]; @@ -1147,7 +1158,7 @@ - (void)updateViewers:(id)sender } // Tools -> Inspector -- (void)showAttributesInspector:sender +- (void)showAttributesInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1155,7 +1166,7 @@ - (void)showAttributesInspector:sender [inspector showAttributesInspector:self]; } -- (void)showContentsInspector:sender +- (void)showContentsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1163,7 +1174,7 @@ - (void)showContentsInspector:sender [inspector showContentsInspector:self]; } -- (void)showToolsInspector:sender +- (void)showToolsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1171,7 +1182,7 @@ - (void)showToolsInspector:sender [inspector showToolsInspector:self]; } -- (void)showPermissionsInspector:sender +- (void)showPermissionsInspector:(id)sender { if (!inspector) { [self _loadInpectors]; @@ -1210,7 +1221,7 @@ - (void)showConsole:(id)sender [console activate]; } -- (void)showLauncher:sender +- (void)showLauncher:(id)sender { if (launcher == nil) { launcher = [[Launcher alloc] init]; diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes index 2f128f15c..18cef8c95 100644 --- a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes +++ b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.classes @@ -24,7 +24,8 @@ "setDockCollapse:", "setIconYardVisibility:", "showHelpPanel:", - "hide:" + "hide:", + "hideOtherApplications:" ); Outlets = ( deviceManager, diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info index c2d6894a6..a97a2a906 100644 Binary files a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info and b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/data.info differ diff --git a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm index be27c85cd..263c8235f 100644 Binary files a/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm and b/Applications/Workspace/English.lproj/WorkspaceManager.gorm/objects.gorm differ diff --git a/Applications/Workspace/GNUmakefile.WM b/Applications/Workspace/GNUmakefile.WM index f54f9ee9c..c9dd3cb02 100644 --- a/Applications/Workspace/GNUmakefile.WM +++ b/Applications/Workspace/GNUmakefile.WM @@ -69,7 +69,8 @@ $(APP_NAME)_C_FILES += \ $(WM_DIR)/xrandr.c \ $(WM_DIR)/xutil.c \ $(WM_DIR)/xmodifier.c \ - $(WM_DIR)/xdnd.c + $(WM_DIR)/xdnd.c \ + $(WM_DIR)/wmcomposer.c ifeq ($(findstring freebsd, $(GNUSTEP_TARGET_OS)), freebsd) $(APP_NAME)_C_FILES += $(WM_DIR)/osdep_bsd.c diff --git a/Applications/Workspace/GNUmakefile.preamble b/Applications/Workspace/GNUmakefile.preamble index 2f7d3cfda..385e6bb9c 100644 --- a/Applications/Workspace/GNUmakefile.preamble +++ b/Applications/Workspace/GNUmakefile.preamble @@ -33,3 +33,4 @@ ADDITIONAL_CFLAGS += -DNDEBUG -D_XOPEN_SOURCE=600 -D_GNU_SOURCE ADDITIONAL_INCLUDE_DIRS += -I./$(WM_DIR) -I./$(WM_DIR)/core ADDITIONAL_INCLUDE_DIRS += `pkg-config --cflags fontconfig` ADDITIONAL_GUI_LIBS += -lfontconfig -lXft -lwraster -lXext -lXrandr -lXfixes -lXcursor +ADDITIONAL_GUI_LIBS += -lXrender -lXdamage -lXcomposite diff --git a/Applications/Workspace/Preferences/Dock/DockPrefs.m b/Applications/Workspace/Preferences/Dock/DockPrefs.m index 9d71b6621..c3f55c4bc 100644 --- a/Applications/Workspace/Preferences/Dock/DockPrefs.m +++ b/Applications/Workspace/Preferences/Dock/DockPrefs.m @@ -121,7 +121,7 @@ void WMSetDockAppImage(NSString *path, int position, BOOL save) CFMutableDictionaryRef winAttrs, appAttrs; CFStringRef appKey, iconFile; - winAttrs = w_global.domain.window_attr->dictionary; + winAttrs = w_global.domain.window_attrs->dictionary; appKey = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%s.%s"), btn->wm_instance, btn->wm_class); diff --git a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info index 744f736ac..a97a2a906 100644 Binary files a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info and b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/data.info differ diff --git a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm index a199711a0..5e5033f9b 100644 Binary files a/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm and b/Applications/Workspace/Processes/English.lproj/FileMoverUI.gorm/objects.gorm differ diff --git a/Applications/Workspace/Processes/ProcessManager.h b/Applications/Workspace/Processes/ProcessManager.h index b6094bee2..13e3723ab 100644 --- a/Applications/Workspace/Processes/ProcessManager.h +++ b/Applications/Workspace/Processes/ProcessManager.h @@ -66,7 +66,7 @@ extern NSString *WMOperationProcessingFileNotification; extern NSString *WMApplicationDidTerminateSubprocessNotification; typedef enum { - CopyOperation, + CopyOperation = 1, DuplicateOperation, MoveOperation, LinkOperation, diff --git a/Applications/Workspace/Processes/ProcessManager.m b/Applications/Workspace/Processes/ProcessManager.m index 0e66af168..a325cc11e 100644 --- a/Applications/Workspace/Processes/ProcessManager.m +++ b/Applications/Workspace/Processes/ProcessManager.m @@ -22,8 +22,9 @@ #include #include -#import #import + +#import #import #include "CoreFoundationBridge.h" @@ -249,7 +250,7 @@ - (void)applicationDidTerminate:(NSNotification *)notif - (void)applicationDidBecomeActive:(NSNotification *)notif { - WMLogWarning("ApplicationDidBecomeActive: %@", convertNStoCFDictionary([notif userInfo])); + // WMLogWarning("ApplicationDidBecomeActive: %@", convertNStoCFDictionary([notif userInfo])); _activeApplication = [[notif userInfo] copy]; } @@ -261,7 +262,7 @@ - (void)sendSignal:(int)signal toApplication:(NSDictionary *)appInfo for (NSNumber *pid in pidList) { // If PID is '-1' let window manager kill that app. if ([pid intValue] != -1) { - NSLog(@"Sending INT signal to %i", [pid intValue]); + NSDebugLLog(@"Workspace", @"Sending signal %i to %i", signal, [pid intValue]); kill([pid intValue], signal); } @@ -289,45 +290,27 @@ - (BOOL)_terminateApplication:(NSDictionary *)appInfo return YES; } - NSLog(@"Terminating - %@", _appName); + NSDebugLLog(@"Workspace", @"Terminating - %@", _appName); _app = [NSConnection rootProxyForConnectionWithRegisteredName:_appName host:@""]; if (_app == nil) { - NSLog(@"Connection to %@ failed. Removing from list of known applications", _appName); + NSDebugLLog(@"Workspace", @"Connection to %@ failed. Removing from list of known applications", _appName); [applications removeObject:appInfo]; return YES; } - // NSLog(@"_terminateApplication - performSelector:withObject:"); - // id terminateObj = [_app performSelector:@selector(applicationShouldTerminate:) - // withObject:NSApp]; - // NSApplicationTerminateReply shouldTerminate = NSTerminateNow; - // if ([_app respondsToSelector:@selector(applicationShouldTerminate:)]) { - // NSLog(@"_terminateApplication - applicationShouldTerminate:"); - // shouldTerminate = ([_app applicationShouldTerminate:NSApp] & 0xff); - // NSLog(@"_terminateApplication: %@ - %li", terminateObj ? [terminateObj className] : terminateObj, shouldTerminate); - // } - - // // NSApplicationTerminateReply shouldTerminate = ([_app applicationShouldTerminate:nil] & 0xff); - // if (shouldTerminate != NSTerminateNow) { - // NSLog(@"Application '%@' is not terminated!", _appName); - // return NO; - // } - - // NSLog(@"Application '%@' should terminate: %li", _appName, shouldTerminate); - // [[_app connectionForProxy] invalidate]; - // [self sendSignal:SIGINT toApplication:appInfo]; - - // libobjc2 prints out info to console all exception (even catched). - // I've switched to singal-based (above) to analyze and fix other cases with exceptions. @try { - [_app terminate:nil]; + [_app terminate:NSApp]; } @catch (NSException *e) { // application terminated -- remove app from launched apps list [applications removeObject:appInfo]; [[_app connectionForProxy] invalidate]; + // libobjc2 prints out info to console all exception (even catched). + NSDebugLLog(@"Workspace", @"Application %@ was terminated. Ignore ObjC runtime exception - it's catched.", _appName); return YES; } + [[_app connectionForProxy] invalidate]; + return NO; } @@ -362,10 +345,6 @@ - (BOOL)terminateAllApps break; } - // while ([applications count] > 1 && _workspaceQuitting != NO) { - // NSDebugLLog(@"Workspace", @"Waiting for applications to terminate..."); - // [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - // } NSDebugLLog(@"Workspace", @"Terminating of runnig apps completed!"); [_appsCopy release]; diff --git a/Applications/Workspace/Recycler.m b/Applications/Workspace/Recycler.m index a63d878ce..32ae48e20 100644 --- a/Applications/Workspace/Recycler.m +++ b/Applications/Workspace/Recycler.m @@ -218,6 +218,7 @@ - (id)initWithDock:(WDock *)dock } _appIcon = [[RecyclerIcon alloc] initWithWindowRef:&_dockIcon->icon->core->window recycler:self]; + [_appIcon setLevel:NSDockWindowLevel]; appIconView = [[RecyclerIconView alloc] initWithFrame:NSMakeRect(0, 0, 64, 64)]; [_appIcon setContentView:appIconView]; diff --git a/Applications/Workspace/WM/GNUstep.h b/Applications/Workspace/WM/GNUstep.h index ad5494010..c88897b3c 100644 --- a/Applications/Workspace/WM/GNUstep.h +++ b/Applications/Workspace/WM/GNUstep.h @@ -39,24 +39,24 @@ enum { #ifndef __Foundation_h_GNUSTEP_BASE_INCLUDE /* - * Window levels are taken from GNUstep (gui/AppKit/NSWindow.h) + * Window level names are taken from GNUstep (gui/AppKit/NSWindow.h) * Applications are actually permitted to use any value in the * range INT_MIN+1 to INT_MAX */ enum { - // // OPENSTEP // MacOS // GNUstep - NSDesktopWindowLevel = -1000, // ---- // 2 // -1000 - NSSunkenWindowLevel = -1, // ---- // ---- // ---- - NSNormalWindowLevel = 0, // 0 // 3 // 0 - NSFloatingWindowLevel = 3, // 3 // 4 // 2 - NSDockWindowLevel = 5, // 5 // 6 // 21 - NSSubmenuWindowLevel = 10, // 10 // 5 // 3 - NSTornOffMenuWindowLevel = 10, // ---- // 5 // 3 - NSMainMenuWindowLevel = 20, // 20 // 7 // 20 - NSStatusWindowLevel = 21, // ---- // 8 // 21 - NSModalPanelWindowLevel = 100, // ---- // 9 // 100 - NSPopUpMenuWindowLevel = 101, // ---- // 10 // 101 - NSScreenSaverWindowLevel = 1000 // ---- // 12 // 1000 + // NEXTSPACE // OPENSTEP // MacOS // GNUstep // EWMH + NSDesktopWindowLevel = -1000, // -------- // 2 // -1000 _NET_WM_WINDOW_TYPE_DESKTOP + NSSunkenWindowLevel = -1, // -------- // ----- // ------- ------- + NSNormalWindowLevel = 0, // 0 // 3 // 0 _NET_WM_WINDOW_TYPE_NORMAL + NSFloatingWindowLevel = 3, // 3 // 4 // 2 _NET_WM_WINDOW_TYPE_UTILITY + NSDockWindowLevel = 5, // 5 // 6 // 21 _NET_WM_WINDOW_TYPE_DOCK + NSSubmenuWindowLevel = 10, // 10 // 5 // 3 _NET_WM_WINDOW_TYPE_MENU + NSTornOffMenuWindowLevel = 10, // -------- // 5 // 3 _NET_WM_WINDOW_TYPE_MENU + NSMainMenuWindowLevel = 20, // 20 // 7 // 20 _NET_WM_WINDOW_TYPE_TOOLBAR + NSStatusWindowLevel = 21, // -------- // 8 // 21 _NET_WM_WINDOW_TYPE_DOCK + NSModalPanelWindowLevel = 100, // -------- // 9 // 100 _NET_WM_WINDOW_TYPE_NORMAL (!) + NSPopUpMenuWindowLevel = 101, // -------- // 10 // 101 _NET_WM_WINDOW_TYPE_TOOLTIP or _DIALOG + NSScreenSaverWindowLevel = 1000 // -------- // 12 // 1000 ------- }; /* typedef NSUInteger NSWindowStyleMask; */ enum { diff --git a/Applications/Workspace/WM/WM.h b/Applications/Workspace/WM/WM.h index 6bc0f39a0..bc9ccb266 100644 --- a/Applications/Workspace/WM/WM.h +++ b/Applications/Workspace/WM/WM.h @@ -241,8 +241,9 @@ extern struct wm_global_variables { /* Global Domains, for storing dictionaries */ struct { /* Note: you must #include if you want to use them */ - struct WDDomain *wm; - struct WDDomain *window_attr; + struct WDDomain *wm_state; + struct WDDomain *wm_preferences; + struct WDDomain *window_attrs; struct WDDomain *root_menu; } domain; @@ -377,7 +378,7 @@ extern CFStringRef WMDidCreateDesktopNotification; extern CFStringRef WMDidDestroyDesktopNotification; extern CFStringRef WMDidChangeDesktopNotification; extern CFStringRef WMDidChangeDesktopNameNotification; -/* Appearance */ +/* Appearance and settings - WM.plist */ extern CFStringRef WMDidChangeWindowAppearanceSettings; extern CFStringRef WMDidChangeIconAppearanceSettings; extern CFStringRef WMDidChangeIconTileSettings; @@ -386,18 +387,22 @@ extern CFStringRef WMDidChangeMenuTitleAppearanceSettings; /* Other */ // userInfo = { "XkbGroup" = CFNumber } extern CFStringRef WMDidChangeKeyboardLayoutNotification; -extern CFStringRef WMDidChangeDockContentNotification; /* Notifications to communicate with applications. Manadatory prefixes in notification names are: - WMShould for notification from application to perform some action - WMDid to notify application about action completion + Every WMDid should complement WMShould notification. - Every WMDid should complement WMDid notification. - - All notifications must contain in userInfo: + All WMShould* and WMDid* notifications must contain in userInfo: "WindowID" = CFNumber; - "ApplicationName" = CFString; */ + "ApplicationName" = CFString; + Objective C definitions located in DesktopKit/NXTWorkspace.[hm]. +*/ +// WM.plist +extern CFStringRef WMDidChangeAppearanceSettingsNotification; +// WMState.plist +extern CFStringRef WMDidChangeDockContentNotification; // Hide All extern CFStringRef WMShouldHideOthersNotification; extern CFStringRef WMDidHideOthersNotification; diff --git a/Applications/Workspace/WM/appicon.c b/Applications/Workspace/WM/appicon.c index c1396e5ec..8923dd3c8 100644 --- a/Applications/Workspace/WM/appicon.c +++ b/Applications/Workspace/WM/appicon.c @@ -955,7 +955,7 @@ Bool wHandleAppIconMove(WAppIcon *aicon, XEvent *event) static void wApplicationSaveIconPathFor(const char *iconPath, const char *wm_instance, const char *wm_class) { - CFMutableDictionaryRef dict = w_global.domain.window_attr->dictionary; + CFMutableDictionaryRef dict = w_global.domain.window_attrs->dictionary; CFMutableDictionaryRef adict = NULL; CFTypeRef val; CFStringRef key; @@ -994,7 +994,7 @@ static void wApplicationSaveIconPathFor(const char *iconPath, const char *wm_ins } if (val && !wPreferences.flags.noupdates) { - WMUserDefaultsWrite(w_global.domain.window_attr->dictionary, w_global.domain.window_attr->name); + WMUserDefaultsWrite(w_global.domain.window_attrs->dictionary, w_global.domain.window_attrs->name); } if (adict) { @@ -1171,8 +1171,8 @@ WAppIcon *wLaunchingAppIconCreate(const char *wm_instance, const char *wm_class, WAppIcon *app_icon = NULL; Window icon_window; - if (wm_instance == NULL || wm_class == NULL) { - // Can't create launching icon without application name + if (wm_instance == NULL || wm_class == NULL || image_path == NULL) { + // Can't create launching icon without application name and icon path return NULL; } diff --git a/Applications/Workspace/WM/application.c b/Applications/Workspace/WM/application.c index c5a31a330..31cfd144f 100644 --- a/Applications/Workspace/WM/application.c +++ b/Applications/Workspace/WM/application.c @@ -114,27 +114,66 @@ static void shadeObserver(CFNotificationCenterRef center, } } +static void hideObserver(CFNotificationCenterRef center, + void *wobserver, // wapp + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + WApplication *wapp = (WApplication *)wobserver; + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("NSApplicationName")); + + if (!appName || CFStringCompare(appName, wapp->appName, 0) != 0) { + // Unknown application or application is not observed object + // WMLogInfo("hideObserver: `%@` application is not observed object - %@.", + // appName, wapp->appName); + return; + } + + wapp->flags.hidden = 1; + WMLogInfo("hideObserver: %@ did HIDE.", wapp->appName); +} + +static void unhideObserver(CFNotificationCenterRef center, + void *wobserver, // wapp + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + WApplication *wapp = (WApplication *)wobserver; + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("NSApplicationName")); + + if (!appName || CFStringCompare(appName, wapp->appName, 0) != 0) { + // Unknown application or application is not observed object + // WMLogInfo("unhideObserver: `%@` application is not observed object - %@.", + // appName, wapp->appName); + return; + } + wapp->flags.hidden = 0; + WMLogInfo("unhideObserver: %@ did UNHIDE.", wapp->appName); +} + static void hideOthersObserver(CFNotificationCenterRef center, void *wobserver, // wapp CFNotificationName name, const void *object, // object - ignored CFDictionaryRef userInfo) { - CFNumberRef windowID = CFDictionaryGetValue(userInfo, CFSTR("WindowID")); - /* WApplication *observer_wapp = (WApplication *)wobserver; */ - /* WApplication *wapp; */ - Window window = 0; - WWindow *wwin; + CFStringRef appName = CFDictionaryGetValue(userInfo, CFSTR("ApplicationName")); + WApplication *wapp = (WApplication *)wobserver; - if (windowID) { - WMLogInfo("Will hide other applications for window %lu", window); - CFNumberGetValue(windowID, kCFNumberLongType, &window); - wwin = wWindowFor(window); - wApplicationHideOthers(wwin); - postWorkspaceNotification(wwin, WMDidHideOthersNotification); + if (wApplicationOf(wapp->main_window) == NULL) { + // WMLogCritical("You've forgot to remove CFNotificationObserver to WMShouldHideOthersNotification!!!"); + return; + } + + if (CFStringCompare(appName, wapp->appName, 0) == 0) { + wApplicationHideOthers(wapp->main_wwin); } } + + static WWindow *makeMainWindow(WScreen *scr, Window window) { WWindow *wwin; @@ -290,8 +329,6 @@ WApplication *wApplicationCreate(WWindow *wwin) wapp->appName = CFStringCreateWithCString(kCFAllocatorDefault, wwin->wm_class, kCFStringEncodingUTF8); } - /* wapp->app_name = wwin->flags.is_gnustep ? wstrdup(wwin->wm_instance) : wstrdup(wwin->wm_class); - */ wApplicationAddWindow(wapp, wwin); @@ -356,10 +393,16 @@ WApplication *wApplicationCreate(WWindow *wwin) CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideOthersObserver, WMShouldHideOthersNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(scr->notificationCenter, wapp, hideObserver, + CFSTR("NSApplicationDidHideNotification"), NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(scr->notificationCenter, wapp, unhideObserver, + CFSTR("NSApplicationDidUnhideNotification"), NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); // Notify Workspace's ProcessManager CFNotificationCenterPostNotification(scr->notificationCenter, - WMDidCreateApplicationNotification, wapp, NULL, TRUE); + WMDidCreateApplicationNotification, wapp, NULL, true); } return wapp; @@ -393,6 +436,10 @@ void wApplicationDestroy(WApplication *wapp) if (wapp->refcount > 0) return; + scr = wapp->main_wwin->screen; + + CFNotificationCenterRemoveEveryObserver(scr->notificationCenter, wapp); + CFArrayRemoveAllValues(wapp->windows); CFRelease(wapp->windows); /* WMLogError("wapp->windows retain count: %li", CFGetRetainCount(wapp->windows)); */ @@ -428,11 +475,11 @@ void wApplicationDestroy(WApplication *wapp) return; } - scr = wapp->main_wwin->screen; - // Notify Workspace's ProcessManager - CFNotificationCenterPostNotification(scr->notificationCenter, WMDidDestroyApplicationNotification, - wapp, NULL, TRUE); + if (!wapp->flags.is_gnustep) { + CFNotificationCenterPostNotification(scr->notificationCenter, + WMDidDestroyApplicationNotification, wapp, NULL, TRUE); + } if (wapp == scr->wapp_list) { if (wapp->next) @@ -479,22 +526,21 @@ void wApplicationActivate(WApplication *wapp) wApplicationMakeFirst(wapp); - if (wapp->flags.is_gnustep || wapp->app_menu->flags.mapped) { - return; - } - - if (wapp->menus_state && !wapp->app_menu->flags.restored) { - wApplicationMenuRestoreFromState(wapp->app_menu, wapp->menus_state); - wapp->app_menu->flags.restored = 1; - } else if (wapp->app_menu->flags.hidden) { - wApplicationMenuShow(wapp->app_menu); - } else { - wMenuMap(wapp->app_menu); - } + if (!wapp->flags.is_gnustep && !wapp->app_menu->flags.mapped) { + if (wapp->menus_state && !wapp->app_menu->flags.restored) { + wApplicationMenuRestoreFromState(wapp->app_menu, wapp->menus_state); + wapp->app_menu->flags.restored = 1; + } else if (wapp->app_menu->flags.hidden) { + wApplicationMenuShow(wapp->app_menu); + } else { + wMenuMap(wapp->app_menu); + } - if (!wapp->appState) { - wapp->appState = CFDictionaryCreateMutable( - kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!wapp->appState) { + wapp->appState = CFDictionaryCreateMutable( + kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + wapp->last_focused = scr->focused_window; } if (scr->notificationCenter) { @@ -558,7 +604,7 @@ static inline void flushExpose(void) XSync(dpy, 0); } -static void hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) +static void _hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) { if (wwin->flags.miniaturized) { if (wwin->icon) { @@ -595,9 +641,9 @@ static void hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin) void wApplicationHide(WApplication *wapp) { WScreen *scr; - WWindow *wlist; + WWindow *list_wwin; int hadfocus; - Bool is_workspace = False; + Bool wapp_is_workspace = False; if (!wapp) { WMLogWarning("trying to hide a non grouped window"); @@ -608,14 +654,25 @@ void wApplicationHide(WApplication *wapp) return; } + WMLogWarning("wApplicationHide(%@)", wapp->appName); + + if (wapp->flags.hidden) { + WMLogWarning("trying to hide already hidden application `%@`", wapp->appName); + return; + } + scr = wapp->main_wwin->screen; hadfocus = 0; - wlist = scr->focused_window; - if (!wlist) { + list_wwin = scr->focused_window; + if (!list_wwin) { + WMLogWarning("(wmApplicationHide) no focused window for app `%@`", wapp->appName); return; } - if (wlist->main_window == wapp->main_window) { - wapp->last_focused = wlist; + + wapp->flags.skip_next_animation = 1; + + if (list_wwin->main_window == wapp->main_window) { + wapp->last_focused = list_wwin; } else { wapp->last_focused = NULL; } @@ -623,40 +680,47 @@ void wApplicationHide(WApplication *wapp) /* Special treatment of Workspace: set focus to main menu prior to any window hiding to prevent searching for next focused window. Workspace's main menu will not be unmapped on hiding. */ - if (wapp->gsmenu_wwin && !strcmp(wapp->gsmenu_wwin->wm_instance, "Workspace")) { + if (wapp->flags.is_gnustep && !CFStringCompare(wapp->appName, CFSTR("Workspace"), 0)) { XSetInputFocus(dpy, wapp->gsmenu_wwin->client_win, RevertToParent, CurrentTime); - is_workspace = True; + wapp_is_workspace = True; } - while (wlist) { - if (wlist->main_window == wapp->main_window && - (is_workspace == False || wlist != wapp->gsmenu_wwin)) { - if (wlist->flags.focused) { + // Perform windows hiding + while (list_wwin) { + if (list_wwin->main_window == wapp->main_window) { + if (list_wwin->flags.focused) { hadfocus = 1; } - if (wapp->app_icon) { - hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, wlist); + if (wapp->app_icon && (wapp_is_workspace == False || list_wwin != wapp->gsmenu_wwin)) { + WMLogInfo("Hiding window %lu (%s) of %s", list_wwin->client_win, + (WINDOW_LEVEL(list_wwin) == NSMainMenuWindowLevel) ? "menu" : "window", + list_wwin->wm_instance); + _hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos, wapp->app_icon->y_pos, list_wwin); } } - wlist = wlist->prev; + list_wwin = list_wwin->prev; } + wapp->flags.hidden = 1; + wapp->flags.skip_next_animation = 0; - if (hadfocus && is_workspace == False) { - wlist = scr->focused_window; - while (wlist) { - if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden && - (wlist->flags.mapped || wlist->flags.shaded)) { + if (hadfocus && wapp_is_workspace == False) { + list_wwin = scr->focused_window; + // WMLogInfo("(wApplicationHide:) searching for window to focus... focused: %s", scr->focused_window->wm_instance); + while (list_wwin) { + if (!WFLAGP(list_wwin, no_focusable) && !list_wwin->flags.hidden && + (list_wwin->flags.mapped || list_wwin->flags.shaded)) { break; } - wlist = wlist->prev; + list_wwin = list_wwin->prev; + } + if (list_wwin) { + WMLogInfo("(wApplicationHide:) Setting focus to window: %s", list_wwin->wm_instance); + wSetFocusTo(scr, list_wwin); } - wSetFocusTo(scr, wlist); } - wapp->flags.hidden = 1; - if (wPreferences.auto_arrange_icons) { wArrangeIcons(scr, True); } @@ -667,41 +731,43 @@ void wApplicationHide(WApplication *wapp) #endif } -void wApplicationHideOthers(WWindow *awin) +void wApplicationHideOthers(WWindow *wwin) { - WWindow *wwin; + WWindow *list_wwin; + WApplication *list_wapp; WApplication *wapp; - WApplication *tapp; - if (!awin) + if (!wwin) { return; - wwin = awin->screen->focused_window; - wapp = wApplicationOf(wwin->main_window); - - while (wwin) { - tapp = wApplicationOf(wwin->main_window); - if (wwin != awin && tapp != wapp && wwin->frame->desktop == awin->screen->current_desktop && - !(wwin->flags.miniaturized || wwin->flags.hidden) && !wwin->flags.internal_window && - !WFLAGP(wwin, no_hide_others)) { - if (tapp != wapp && wwin->protocols.HIDE_APP) { - /* WMLogInfo("send WM_HIDE_APP protocol message to client."); */ - wClientSendProtocol(wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); - } else if (wwin->main_window == None || WFLAGP(wwin, no_appicon)) { - if (!WFLAGP(wwin, no_miniaturizable)) { - wwin->flags.skip_next_animation = 1; - wIconifyWindow(wwin); - } - } else if (wwin->main_window != None && awin->main_window != wwin->main_window) { - if (tapp) { - tapp->flags.skip_next_animation = 1; - wApplicationHide(tapp); - } else if (!WFLAGP(wwin, no_miniaturizable)) { - wwin->flags.skip_next_animation = 1; - wIconifyWindow(wwin); + } + list_wwin = wwin->screen->focused_window; + wapp = wApplicationOf(list_wwin->main_window); + + WMLogWarning("wApplicationHideOthers(%@)", wapp->appName); + + while (list_wwin) { + list_wapp = wApplicationOf(list_wwin->main_window); + if (list_wapp != wapp && list_wwin->frame->desktop == wwin->screen->current_desktop && + !(list_wwin->flags.miniaturized || list_wwin->flags.hidden) && + !list_wwin->flags.internal_window) { + if (list_wapp && list_wwin->main_window != None && + list_wwin->main_window != wwin->main_window) { + wApplicationHide(list_wapp); + if (list_wwin->protocols.HIDE_APP && CFStringCompare(list_wapp->appName, CFSTR("Workspace"), 0)) { + // Inform client about hiding. + // Normally WMFHideApplication comes from application (GNUstep) - it's a one call to + // wApplicationHide() through handleClientMessage() (event.c). + // In this case we hide app windows on previous line and send client message to draw + // hidden dot on appicon. This leads to second call to wApplicationHide(). + wClientSendProtocol(list_wwin, w_global.atom.gnustep.wm_hide_app, CurrentTime); } + } else if ((list_wwin->main_window == None || WFLAGP(list_wwin, no_appicon)) && + !WFLAGP(list_wwin, no_miniaturizable)) { + list_wwin->flags.skip_next_animation = 1; + wIconifyWindow(list_wwin); } } - wwin = wwin->prev; + list_wwin = list_wwin->prev; } } diff --git a/Applications/Workspace/WM/compile_flags.txt b/Applications/Workspace/WM/compile_flags.txt new file mode 100644 index 000000000..5f26959d0 --- /dev/null +++ b/Applications/Workspace/WM/compile_flags.txt @@ -0,0 +1,41 @@ +-xc +-MMD +-MP +-DGNUSTEP +-DGNUSTEP_BASE_LIBRARY=1 +-DGNU_GUI_LIBRARY=1 +-DGNUSTEP_RUNTIME=1 +-D_NONFRAGILE_ABI=1 +-DGNUSTEP_BASE_LIBRARY=1 +-fno-strict-aliasing +-fexceptions +-fobjc-exceptions +-D_NATIVE_OBJC_EXCEPTIONS +-DHAVE_CONFIG_H +-DWITH_GNUSTEP +-D_XOPEN_SOURCE=600 +-D_GNU_SOURCE +-pthread +-fPIC +-DDEBUG +-fno-omit-frame-pointer +-Wall +-Wno-import +-Wno-unused-variable +-Wno-typedef-redefinition +-g +-fobjc-runtime=gnustep-2.0 +-fblocks +-fconstant-string-class=NSConstantString +-I. +-I.. +-I/Users/me/Library/Headers +-I/Developer/Headers +-I/usr/NextSpace/include +-I/usr/include/freetype2 +-I/usr/include/libpng16 +-I/usr/include/harfbuzz +-I/usr/include/glib-2.0 +-I/usr/lib64/glib-2.0/include +-I/usr/include/sysprof-4 +-I/usr/include/libxml2 diff --git a/Applications/Workspace/WM/core/compile_flags.txt b/Applications/Workspace/WM/core/compile_flags.txt new file mode 120000 index 000000000..acd65fc91 --- /dev/null +++ b/Applications/Workspace/WM/core/compile_flags.txt @@ -0,0 +1 @@ +../compile_flags.txt \ No newline at end of file diff --git a/Applications/Workspace/WM/core/wfont.c b/Applications/Workspace/WM/core/wfont.c index bd2ca8e14..069a386a6 100644 --- a/Applications/Workspace/WM/core/wfont.c +++ b/Applications/Workspace/WM/core/wfont.c @@ -174,7 +174,6 @@ WMFont *WMCreateFont(WMScreen *scrPtr, const char *fontName) fname = wstrdup(fontName); } - /* if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) { */ if (!scrPtr->antialiasedText && !strstr(fname, ":antialias=")) { fname = wstrappend(fname, ":antialias=false"); } @@ -199,9 +198,7 @@ WMFont *WMCreateFont(WMScreen *scrPtr, const char *fontName) font->height = font->font->ascent + font->font->descent; font->y = font->font->ascent; - font->refCount = 1; - font->name = fname; #ifdef USE_PANGO diff --git a/Applications/Workspace/WM/core/wscreen.c b/Applications/Workspace/WM/core/wscreen.c index 061cdb4ec..5b07bb968 100644 --- a/Applications/Workspace/WM/core/wscreen.c +++ b/Applications/Workspace/WM/core/wscreen.c @@ -257,9 +257,7 @@ WMScreen *WMCreateScreenWithRContext(Display *display, int screen, RContext *con scrPtr->stipple = stipple; - /* scrPtr->antialiasedText = WINGsConfiguration.antialiasedText; */ - scrPtr->antialiasedText = False; /* TODO */ - WMLogWarning("[TODO] Antialised text is set to false. No option exists to configure it."); + scrPtr->antialiasedText = False; scrPtr->normalFont = WMSystemFontOfSize(scrPtr, 0); diff --git a/Applications/Workspace/WM/defaults.c b/Applications/Workspace/WM/defaults.c index 0b34fc2e1..0e669da1a 100644 --- a/Applications/Workspace/WM/defaults.c +++ b/Applications/Workspace/WM/defaults.c @@ -175,6 +175,8 @@ static WDECallbackUpdate setModifierKeyLabels; static WDECallbackConvert getCursor; static WDECallbackUpdate setCursor; +static WDECallbackUpdate setAntialiasedText; + /* * Tables to convert strings to enumeration values. * Values stored are char @@ -348,212 +350,323 @@ WDefaultEntry staticOptionList[] = { /* dynamic options */ WDefaultEntry optionList[] = { - {"IconPosition", "blh", seIconPositions, &wPreferences.icon_yard, getEnum, setIconPosition, NULL, NULL}, - {"IconificationStyle", "Zoom", seIconificationStyles, &wPreferences.iconification_style, getEnum, NULL, NULL, NULL}, - {"ImagePaths", DEF_IMAGE_PATHS, NULL, &wPreferences.image_paths, getPathList, NULL, NULL, NULL}, - {"ColormapMode", "Auto", seColormapModes, &wPreferences.colormap_mode, getEnum, NULL, NULL, NULL}, - {"AutoFocus", "YES", NULL, &wPreferences.auto_focus, getBool, NULL, NULL, NULL}, - {"RaiseDelay", "0", NULL, &wPreferences.raise_delay, getInt, NULL, NULL, NULL}, - {"CirculateRaise", "YES", NULL, &wPreferences.circ_raise, getBool, NULL, NULL, NULL}, - {"Superfluous", "NO", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, - {"StickyIcons", "YES", NULL, &wPreferences.sticky_icons, getBool, setStickyIcons, NULL, NULL}, - {"SaveSessionOnExit", "NO", NULL, &wPreferences.save_session_on_exit, getBool, NULL, NULL, NULL}, - {"ScrollableMenus", "YES", NULL, &wPreferences.scrollable_menus, getBool, NULL, NULL, NULL}, - {"MenuScrollSpeed", "medium", seSpeeds, &wPreferences.menu_scroll_speed, getEnum, NULL, NULL, NULL}, - {"IconSlideSpeed", "Slow", seSpeeds, &wPreferences.icon_slide_speed, getEnum, NULL, NULL, NULL}, - {"ClipAutoraiseDelay", "600", NULL, &wPreferences.clip_auto_raise_delay, getInt, NULL, NULL, NULL}, - {"ClipAutolowerDelay", "1000", NULL, &wPreferences.clip_auto_lower_delay, getInt, NULL, NULL, NULL}, - {"ClipAutoexpandDelay", "600", NULL, &wPreferences.clip_auto_expand_delay, getInt, NULL, NULL, NULL}, - {"ClipAutocollapseDelay", "1000", NULL, &wPreferences.clip_auto_collapse_delay, getInt, NULL, NULL, NULL}, - {"WrapAppiconsInDock", "NO", NULL, NULL, getBool, setWrapAppiconsInDock, NULL, NULL}, - {"AlignSubmenus", "YES", NULL, &wPreferences.align_menus, getBool, NULL, NULL, NULL}, - {"ViKeyMenus", "NO", NULL, &wPreferences.vi_key_menus, getBool, NULL, NULL, NULL}, - {"OpenTransientOnOwnerWorkspace", "YES", NULL, &wPreferences.open_transients_with_parent, getBool, NULL, NULL, NULL}, - {"WindowPlacement", "cascade", sePlacements, &wPreferences.window_placement, getEnum, NULL, NULL, NULL}, - {"IgnoreFocusClick", "NO", NULL, &wPreferences.ignore_focus_click, getBool, NULL, NULL, NULL}, - {"UseSaveUnders", "NO", NULL, &wPreferences.use_saveunders, getBool, NULL, NULL, NULL}, - {"OpaqueMove", "YES", NULL, &wPreferences.opaque_move, getBool, NULL, NULL, NULL}, - {"OpaqueResize", "NO", NULL, &wPreferences.opaque_resize, getBool, NULL, NULL, NULL}, - {"OpaqueMoveResizeKeyboard", "NO", NULL, &wPreferences.opaque_move_resize_keyboard, getBool, NULL, NULL, NULL}, - {"DisableAnimations", "NO", NULL, &wPreferences.no_animations, getBool, NULL, NULL, NULL}, - {"DontLinkWorkspaces", "NO", NULL, &wPreferences.no_autowrap, getBool, NULL, NULL, NULL}, - {"WindowSnapping", "NO", NULL, &wPreferences.window_snapping, getBool, NULL, NULL, NULL}, - {"SnapEdgeDetect", "1", NULL, &wPreferences.snap_edge_detect, getInt, NULL, NULL, NULL}, - {"SnapCornerDetect", "10", NULL, &wPreferences.snap_corner_detect, getInt, NULL, NULL, NULL}, - {"DragMaximizedWindow", "Move", seDragMaximizedWindow, &wPreferences.drag_maximized_window, getEnum, NULL, NULL, NULL}, - {"AutoArrangeIcons", "NO", NULL, &wPreferences.auto_arrange_icons, getBool, NULL, NULL, NULL}, - {"NoWindowOverDock", "YES", NULL, &wPreferences.no_window_over_dock, getBool, updateUsableArea, NULL, NULL}, - {"NoWindowOverIcons", "YES", NULL, &wPreferences.no_window_over_icons, getBool, updateUsableArea, NULL, NULL}, - {"WindowPlaceOrigin", "(100, 100)", NULL, &wPreferences.window_place_origin, getCoord, NULL, NULL, NULL}, - {"ResizeDisplay", "Titlebar", seGeomDisplays, &wPreferences.size_display, getEnum, NULL, NULL, NULL}, - {"MoveDisplay", "Titlebar", seGeomDisplays, &wPreferences.move_display, getEnum, NULL, NULL, NULL}, - {"DontConfirmKill", "NO", NULL, &wPreferences.dont_confirm_kill, getBool, NULL, NULL, NULL}, - {"WindowTitleBalloons", "NO", NULL, &wPreferences.window_balloon, getBool, NULL, NULL, NULL}, - {"MiniwindowTitleBalloons", "YES", NULL, &wPreferences.miniwin_title_balloon, getBool, NULL, NULL, NULL}, - {"MiniwindowPreviewBalloons", "NO", NULL, &wPreferences.miniwin_preview_balloon, getBool, NULL, NULL, NULL}, - {"AppIconBalloons", "NO", NULL, &wPreferences.appicon_balloon, getBool, NULL, NULL, NULL}, - {"HelpBalloons", "NO", NULL, &wPreferences.help_balloon, getBool, NULL, NULL, NULL}, - {"EdgeResistance", "30", NULL, &wPreferences.edge_resistance, getInt, NULL, NULL, NULL}, - {"ResizeIncrement", "0", NULL, &wPreferences.resize_increment, getInt, NULL, NULL, NULL}, - {"Attraction", "NO", NULL, &wPreferences.attract, getBool, NULL, NULL, NULL}, - {"DisableBlinking", "NO", NULL, &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, - {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, - {"StrictWindozeCycle", "YES", NULL, &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, - NULL}, - {"SwitchPanelOnlyOpen", "NO", NULL, &wPreferences.panel_only_open, getBool, NULL, NULL, NULL}, - {"MiniPreviewSize", "128", NULL, &wPreferences.minipreview_size, getInt, NULL, NULL, NULL}, - {"IgnoreGtkHints", "NO", NULL, &wPreferences.ignore_gtk_decoration_hints, getBool, NULL, NULL, - NULL}, - - /* --- Mouse options --- */ - - {"DoubleClickTime", "350", (void *)&wPreferences.dblclick_time, &wPreferences.dblclick_time, getInt, setDoubleClick, NULL, NULL}, - {"DisableWSMouseActions", "NO", NULL, &wPreferences.disable_root_mouse, getBool, NULL, NULL, NULL}, - {"MouseLeftButtonAction", "SelectWindows", seMouseButtonActions, &wPreferences.mouse_button1, getEnum, NULL, NULL, NULL}, - {"MouseMiddleButtonAction", "OpenWindowListMenu", seMouseButtonActions, &wPreferences.mouse_button2, getEnum, NULL, NULL, NULL}, - {"MouseRightButtonAction", "OpenApplicationsMenu", seMouseButtonActions, &wPreferences.mouse_button3, getEnum, NULL, NULL, NULL}, - {"MouseBackwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button8, getEnum, NULL, NULL, NULL}, - {"MouseForwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button9, getEnum, NULL, NULL, NULL}, - {"MouseWheelAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_scroll, getEnum, NULL, NULL, NULL}, - {"MouseWheelTiltAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_tilt, getEnum, NULL, NULL, NULL}, - - /* --- Workspaces --- */ - - {"AdvanceToNewWorkspace", "NO", NULL, &wPreferences.ws_advance, getBool, NULL, NULL, NULL}, - {"CycleWorkspaces", "NO", NULL, &wPreferences.ws_cycle, getBool, NULL, NULL, NULL}, - {"WorkspaceNameDisplayPosition", "center", seDisplayPositions, &wPreferences.workspace_name_display_position, getEnum, NULL, NULL, NULL}, - {"WorkspaceBorder", "AllDirections", seWorkspaceBorder, &wPreferences.workspace_border_position, getEnum, updateUsableArea, NULL, NULL}, - {"WorkspaceBorderSize", "0", NULL, &wPreferences.workspace_border_size, getInt, updateUsableArea, NULL, NULL}, - - /* --- Animations --- */ - - {"ShadeSpeed", "medium", seSpeeds, &wPreferences.shade_speed, getEnum, NULL, NULL, NULL}, - {"BounceAppIconsWhenUrgent", "YES", NULL, &wPreferences.bounce_appicons_when_urgent, getBool, NULL, NULL, NULL}, - {"RaiseAppIconsWhenBouncing", "NO", NULL, &wPreferences.raise_appicons_when_bouncing, getBool, NULL, NULL, NULL}, - {"DoNotMakeAppIconsBounce", "YES", NULL, &wPreferences.do_not_make_appicons_bounce, getBool, NULL, NULL, NULL}, - - /* --- Options need to get rid of or fix --- */ - - /* --- Style options --- */ - - {"MenuStyle", "normal", seMenuStyles, &wPreferences.menu_style, getEnum, setMenuStyle, NULL, NULL}, - {"WidgetColor", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setWidgetColor, NULL, NULL}, - {"IconBack", "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")", NULL, NULL, getTexture, setIconTile, NULL, NULL}, - {"MiniwindowBack", "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")", NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, /* NEXTSPACE */ - {"TitleJustify", "center", seJustifications, &wPreferences.title_justification, getEnum, setJustify, NULL, NULL}, - {"WindowTitleFont", DEF_TITLE_FONT, NULL, NULL, getFont, setWinTitleFont, NULL, NULL}, {"WindowTitleExtendSpace", DEF_WINDOW_TITLE_EXTEND_SPACE, NULL, &wPreferences.window_title_clearance, getInt, setClearance, NULL, NULL}, - {"WindowTitleMinHeight", "22", NULL, &wPreferences.window_title_min_height, getInt, setClearance, NULL, NULL}, - {"WindowTitleMaxHeight", "22", NULL, &wPreferences.window_title_max_height, getInt, setClearance, NULL, NULL}, - {"MenuTitleExtendSpace", DEF_MENU_TITLE_EXTEND_SPACE, NULL, &wPreferences.menu_title_clearance, getInt, setClearance, NULL, NULL}, - {"MenuTitleMinHeight", "22", NULL, &wPreferences.menu_title_min_height, getInt, setClearance, NULL, NULL}, - {"MenuTitleMaxHeight", "22", NULL, &wPreferences.menu_title_max_height, getInt, setClearance, NULL, NULL}, - {"MenuTextExtendSpace", DEF_MENU_TEXT_EXTEND_SPACE, NULL, &wPreferences.menu_text_clearance, getInt, setClearance, NULL, NULL}, - {"MenuTitleFont", DEF_MENU_TITLE_FONT, NULL, NULL, getFont, setMenuTitleFont, NULL, NULL}, - {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL, NULL, getFont, setMenuTextFont, NULL, NULL}, - {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL, NULL, getFont, setIconTitleFont, NULL, NULL}, - {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL, NULL, getFont, setClipTitleFont, NULL, NULL}, - {"ShowClipTitle", "YES", NULL, &wPreferences.show_clip_title, getBool, NULL, NULL, NULL}, - {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL, NULL, getFont, setLargeDisplayFont, NULL, NULL}, - {"HighlightColor", "white", NULL, NULL, getColor, setHightlight, NULL, NULL}, - {"HighlightTextColor", "black", NULL, NULL, getColor, setHightlightText, NULL, NULL}, - {"ClipTitleColor", "black", (void *)CLIP_NORMAL, NULL, getColor, setClipTitleColor, NULL, NULL}, - {"CClipTitleColor", "\"#454045\"", (void *)CLIP_COLLAPSED, NULL, getColor, setClipTitleColor, NULL, NULL}, - {"FTitleColor", "white", (void *)WS_FOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"PTitleColor", "white", (void *)WS_PFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"UTitleColor", "black", (void *)WS_UNFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, - {"FTitleBack", "(solid, black)", NULL, NULL, getTexture, setFTitleBack, NULL, NULL}, - {"PTitleBack", "(solid, \"#555555\")", NULL, NULL, getTexture, setPTitleBack, NULL, NULL}, - {"UTitleBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setUTitleBack, NULL, NULL}, - {"ResizebarBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setResizebarBack, NULL, NULL}, - {"MenuTitleColor", "white", NULL, NULL, getColor, setMenuTitleColor, NULL, NULL}, - {"MenuTextColor", "black", NULL, NULL, getColor, setMenuTextColor, NULL, NULL}, - {"MenuDisabledColor", "\"#555555\"", NULL, NULL, getColor, setMenuDisabledColor, NULL, NULL}, - {"MenuTitleBack", "(solid, black)", NULL, NULL, getTexture, setMenuTitleBack, NULL, NULL}, - {"MenuTextBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setMenuTextBack, NULL, NULL}, - {"IconTitleColor", "white", NULL, NULL, getColor, setIconTitleColor, NULL, NULL}, - {"IconTitleBack", "black", NULL, NULL, getColor, setIconTitleBack, NULL, NULL}, - {"SwitchPanelImages", "(swtile.png, swback.png, 30, 40)", &wPreferences, NULL, getPropList, setSwPOptions, NULL, NULL}, - {"ModifierKeyLabels", "(\"Shift+\", \"Control+\", \"Alt+\", \"Mod2+\", \"Mod3+\", \"Super+\", \"Mod5+\")", &wPreferences, NULL, getPropList, setModifierKeyLabels, NULL, NULL}, - {"FrameBorderWidth", "1", NULL, NULL, getInt, setFrameBorderWidth, NULL, NULL}, - {"FrameBorderColor", "black", NULL, NULL, getColor, setFrameBorderColor, NULL, NULL}, - {"FrameFocusedBorderColor", "black", NULL, NULL, getColor, setFrameFocusedBorderColor, NULL, NULL}, - {"FrameSelectedBorderColor", "white", NULL, NULL, getColor, setFrameSelectedBorderColor, NULL, NULL}, - {"WorkspaceMapBack", "(solid, black)", NULL, NULL, getTexture, setWorkspaceMapBackground, NULL, NULL}, - - /* --- Key bindings --- */ - - {"CommandModifierKey", "Alt", NULL, &wPreferences.cmd_modifier_mask, getModMask, NULL, NULL, NULL}, - {"AlternateModifierKey", "Super", NULL, &wPreferences.alt_modifier_mask, getAltModMask, NULL, NULL, NULL}, - /* Dock and Icon Yard */ - /* {"DockHideShowKey", "\"Alternate+D\"", (void *)WKBD_DOCKHIDESHOW, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"IconYardHideShowKey", "\"Alternate+Y\"", (void *)WKBD_YARDHIDESHOW, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Window Resizing */ - /* {"MaximusKey", "\"Super+KP_5\"", (void *)WKBD_MAXIMUS, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"ShadeKey", "\"Alternate+KP_Subtract\"", (void *)WKBD_SHADE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MaximizeKey", "\"Alternate+KP_Add\"", (void *)WKBD_MAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"VMaximizeKey", "\"Alternate+Up\"", (void *)WKBD_VMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HMaximizeKey", "\"Alternate+Right\"", (void *)WKBD_HMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LHMaximizeKey", "\"Alternate+KP_4\"", (void *)WKBD_LHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RHMaximizeKey", "\"Alternate+KP_6\"", (void *)WKBD_RHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"THMaximizeKey", "\"Alternate+KP_8\"", (void *)WKBD_THMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"BHMaximizeKey", "\"Alternate+KP_2\"", (void *)WKBD_BHMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LTCMaximizeKey", "\"Alternate+KP_7\"", (void *)WKBD_LTCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RTCMaximizeKey", "\"Alternate+KP_9\"", (void *)WKBD_RTCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LBCMaximizeKey", "\"Alternate+KP_1\"", (void *)WKBD_LBCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"RBCMaximizeKey", "\"Alternate+KP_3\"", (void *)WKBD_RBCMAXIMIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Window Ordering */ - /* {"CloseKey", "\"Command+w\"", (void *)WKBD_CLOSE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HideKey", "\"Command+h\"", (void *)WKBD_HIDE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"HideOthersKey", "\"Command+H\"", (void *)WKBD_HIDE_OTHERS, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MiniaturizeKey", "\"Command+m\"", (void *)WKBD_MINIATURIZE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"MinimizeAllKey", "\"Command+M\"", (void *)WKBD_MINIMIZEALL, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* Focus switch */ - /* {"RaiseKey", "\"Command+Up\"", (void *)WKBD_RAISE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - /* {"LowerKey", "\"Command+Down\"", (void *)WKBD_LOWER, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ - {"FocusNextKey", "\"Command+Tab\"", (void *)WKBD_FOCUSNEXT, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"FocusPrevKey", "\"Command+Shift+Tab\"", (void *)WKBD_FOCUSPREV, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"GroupNextKey", "\"Command+grave\"", (void *)WKBD_GROUPNEXT, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"GroupPrevKey", "\"Command+Shift+grave\"", (void *)WKBD_GROUPPREV, NULL, getKeybind, setKeyGrab, NULL, NULL}, - /* Workspaces */ - {"NextWorkspaceKey", "\"Control+Right\"", (void *)WKBD_NEXT_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"PrevWorkspaceKey", "\"Control+Left\"", (void *)WKBD_PREV_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"LastWorkspaceKey", "None", (void *)WKBD_LAST_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop1Key", "\"Control+1\"", (void *)WKBD_DESKTOP_1, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop2Key", "\"Control+2\"", (void *)WKBD_DESKTOP_2, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop3Key", "\"Control+3\"", (void *)WKBD_DESKTOP_3, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop4Key", "\"Control+4\"", (void *)WKBD_DESKTOP_4, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop5Key", "\"Control+5\"", (void *)WKBD_DESKTOP_5, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop6Key", "\"Control+6\"", (void *)WKBD_DESKTOP_6, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop7Key", "\"Control+7\"", (void *)WKBD_DESKTOP_7, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop8Key", "\"Control+8\"", (void *)WKBD_DESKTOP_8, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop9Key", "\"Control+9\"", (void *)WKBD_DESKTOP_9, NULL, getKeybind, setKeyGrab, NULL, NULL}, - {"Desktop10Key", "\"Control+0\"", (void *)WKBD_DESKTOP_10, NULL, getKeybind, setKeyGrab, NULL, NULL}, - - {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, NULL, getKeybind, setKeyGrab, NULL, NULL}, - - /* --- Mouse cursors --- */ - {"NormalCursor", "(builtin, left_ptr)", (void *)WCUR_ROOT, NULL, getCursor, setCursor, NULL, NULL}, - {"ArrowCursor", "(builtin, left_ptr)", (void *)WCUR_ARROW, NULL, getCursor, setCursor, NULL, NULL}, - {"ResizeCursor", "(builtin, sizing)", (void *)WCUR_RESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"WaitCursor", "(builtin, watch)", (void *)WCUR_WAIT, NULL, getCursor, setCursor, NULL, NULL}, - {"QuestionCursor", "(builtin, question_arrow)", (void *)WCUR_QUESTION, NULL, getCursor, setCursor, NULL, NULL}, - {"TextCursor", "(builtin, xterm)", (void *)WCUR_TEXT, NULL, getCursor, setCursor, NULL, NULL}, - {"SelectCursor", "(builtin, cross)", (void *)WCUR_SELECT, NULL, getCursor, setCursor, NULL, NULL}, - {"MoveCursor", "(library, move)", (void *)WCUR_MOVE, NULL, getCursor, setCursor, NULL, NULL}, - {"TopLeftResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_TOPLEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"TopRightResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_TOPRIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"BottomLeftResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_BOTTOMLEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"BottomRightResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_BOTTOMRIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"VerticalResizeCursor", "(library, wm_v_double_arrow)", (void *)WCUR_VERTICALRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"HorizontalResizeCursor", "(library, wm_h_double_arrow)", (void *)WCUR_HORIZONRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"UpResizeCursor", "(library, wm_up_arrow)", (void *)WCUR_UPRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"DownResizeCursor", "(library, wm_down_arrow)", (void *)WCUR_DOWNRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"LeftResizeCursor", "(library, wm_left_arrow)", (void *)WCUR_LEFTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"RightResizeCursor", "(library, wm_right_arrow)", (void *)WCUR_RIGHTRESIZE, NULL, getCursor, setCursor, NULL, NULL}, - {"DialogHistoryLines", "500", NULL, &wPreferences.history_lines, getInt, NULL, NULL, NULL}, - {"CycleActiveHeadOnly", "NO", NULL, &wPreferences.cycle_active_head_only, getBool, NULL, NULL, NULL}, - {"CycleIgnoreMinimized", "NO", NULL, &wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, NULL} -}; + {"IconPosition", "blh", seIconPositions, &wPreferences.icon_yard, getEnum, setIconPosition, + NULL, NULL}, + {"IconificationStyle", "Zoom", seIconificationStyles, &wPreferences.iconification_style, + getEnum, NULL, NULL, NULL}, + {"ImagePaths", DEF_IMAGE_PATHS, NULL, &wPreferences.image_paths, getPathList, NULL, NULL, NULL}, + {"ColormapMode", "Auto", seColormapModes, &wPreferences.colormap_mode, getEnum, NULL, NULL, + NULL}, + {"AutoFocus", "YES", NULL, &wPreferences.auto_focus, getBool, NULL, NULL, NULL}, + {"RaiseDelay", "0", NULL, &wPreferences.raise_delay, getInt, NULL, NULL, NULL}, + {"CirculateRaise", "YES", NULL, &wPreferences.circ_raise, getBool, NULL, NULL, NULL}, + {"Superfluous", "YES", NULL, &wPreferences.superfluous, getBool, NULL, NULL, NULL}, + {"StickyIcons", "YES", NULL, &wPreferences.sticky_icons, getBool, setStickyIcons, NULL, NULL}, + {"SaveSessionOnExit", "NO", NULL, &wPreferences.save_session_on_exit, getBool, NULL, NULL, + NULL}, + {"ScrollableMenus", "YES", NULL, &wPreferences.scrollable_menus, getBool, NULL, NULL, NULL}, + {"MenuScrollSpeed", "medium", seSpeeds, &wPreferences.menu_scroll_speed, getEnum, NULL, NULL, + NULL}, + {"IconSlideSpeed", "Slow", seSpeeds, &wPreferences.icon_slide_speed, getEnum, NULL, NULL, NULL}, + {"ClipAutoraiseDelay", "600", NULL, &wPreferences.clip_auto_raise_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutolowerDelay", "1000", NULL, &wPreferences.clip_auto_lower_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutoexpandDelay", "600", NULL, &wPreferences.clip_auto_expand_delay, getInt, NULL, NULL, + NULL}, + {"ClipAutocollapseDelay", "1000", NULL, &wPreferences.clip_auto_collapse_delay, getInt, NULL, + NULL, NULL}, + {"WrapAppiconsInDock", "NO", NULL, NULL, getBool, setWrapAppiconsInDock, NULL, NULL}, + {"AlignSubmenus", "YES", NULL, &wPreferences.align_menus, getBool, NULL, NULL, NULL}, + {"ViKeyMenus", "NO", NULL, &wPreferences.vi_key_menus, getBool, NULL, NULL, NULL}, + {"OpenTransientOnOwnerWorkspace", "YES", NULL, &wPreferences.open_transients_with_parent, + getBool, NULL, NULL, NULL}, + {"WindowPlacement", "cascade", sePlacements, &wPreferences.window_placement, getEnum, NULL, + NULL, NULL}, + {"IgnoreFocusClick", "NO", NULL, &wPreferences.ignore_focus_click, getBool, NULL, NULL, NULL}, + {"UseSaveUnders", "NO", NULL, &wPreferences.use_saveunders, getBool, NULL, NULL, NULL}, + {"OpaqueMove", "YES", NULL, &wPreferences.opaque_move, getBool, NULL, NULL, NULL}, + {"OpaqueResize", "NO", NULL, &wPreferences.opaque_resize, getBool, NULL, NULL, NULL}, + {"OpaqueMoveResizeKeyboard", "NO", NULL, &wPreferences.opaque_move_resize_keyboard, getBool, + NULL, NULL, NULL}, + {"DisableAnimations", "NO", NULL, &wPreferences.no_animations, getBool, NULL, NULL, NULL}, + {"DontLinkWorkspaces", "NO", NULL, &wPreferences.no_autowrap, getBool, NULL, NULL, NULL}, + {"WindowSnapping", "NO", NULL, &wPreferences.window_snapping, getBool, NULL, NULL, NULL}, + {"SnapEdgeDetect", "1", NULL, &wPreferences.snap_edge_detect, getInt, NULL, NULL, NULL}, + {"SnapCornerDetect", "10", NULL, &wPreferences.snap_corner_detect, getInt, NULL, NULL, NULL}, + {"DragMaximizedWindow", "Move", seDragMaximizedWindow, &wPreferences.drag_maximized_window, + getEnum, NULL, NULL, NULL}, + {"AutoArrangeIcons", "NO", NULL, &wPreferences.auto_arrange_icons, getBool, NULL, NULL, NULL}, + {"NoWindowOverDock", "YES", NULL, &wPreferences.no_window_over_dock, getBool, updateUsableArea, + NULL, NULL}, + {"NoWindowOverIcons", "YES", NULL, &wPreferences.no_window_over_icons, getBool, + updateUsableArea, NULL, NULL}, + {"WindowPlaceOrigin", "(100, 100)", NULL, &wPreferences.window_place_origin, getCoord, NULL, + NULL, NULL}, + {"ResizeDisplay", "Titlebar", seGeomDisplays, &wPreferences.size_display, getEnum, NULL, NULL, + NULL}, + {"MoveDisplay", "Titlebar", seGeomDisplays, &wPreferences.move_display, getEnum, NULL, NULL, + NULL}, + {"DontConfirmKill", "NO", NULL, &wPreferences.dont_confirm_kill, getBool, NULL, NULL, NULL}, + {"WindowTitleBalloons", "NO", NULL, &wPreferences.window_balloon, getBool, NULL, NULL, NULL}, + {"MiniwindowTitleBalloons", "YES", NULL, &wPreferences.miniwin_title_balloon, getBool, NULL, + NULL, NULL}, + {"MiniwindowPreviewBalloons", "NO", NULL, &wPreferences.miniwin_preview_balloon, getBool, NULL, + NULL, NULL}, + {"AppIconBalloons", "NO", NULL, &wPreferences.appicon_balloon, getBool, NULL, NULL, NULL}, + {"HelpBalloons", "NO", NULL, &wPreferences.help_balloon, getBool, NULL, NULL, NULL}, + {"EdgeResistance", "30", NULL, &wPreferences.edge_resistance, getInt, NULL, NULL, NULL}, + {"ResizeIncrement", "0", NULL, &wPreferences.resize_increment, getInt, NULL, NULL, NULL}, + {"Attraction", "NO", NULL, &wPreferences.attract, getBool, NULL, NULL, NULL}, + {"DisableBlinking", "NO", NULL, &wPreferences.dont_blink, getBool, NULL, NULL, NULL}, + {"SingleClickLaunch", "NO", NULL, &wPreferences.single_click, getBool, NULL, NULL, NULL}, + {"StrictWindozeCycle", "YES", NULL, &wPreferences.strict_windoze_cycle, getBool, NULL, NULL, + NULL}, + {"SwitchPanelOnlyOpen", "NO", NULL, &wPreferences.panel_only_open, getBool, NULL, NULL, NULL}, + {"MiniPreviewSize", "128", NULL, &wPreferences.minipreview_size, getInt, NULL, NULL, NULL}, + {"IgnoreGtkHints", "NO", NULL, &wPreferences.ignore_gtk_decoration_hints, getBool, NULL, NULL, + NULL}, + + /* --- Mouse options --- */ + + {"DoubleClickTime", "350", (void *)&wPreferences.dblclick_time, &wPreferences.dblclick_time, + getInt, setDoubleClick, NULL, NULL}, + {"DisableWSMouseActions", "NO", NULL, &wPreferences.disable_root_mouse, getBool, NULL, NULL, + NULL}, + {"MouseLeftButtonAction", "SelectWindows", seMouseButtonActions, &wPreferences.mouse_button1, + getEnum, NULL, NULL, NULL}, + {"MouseMiddleButtonAction", "OpenWindowListMenu", seMouseButtonActions, + &wPreferences.mouse_button2, getEnum, NULL, NULL, NULL}, + {"MouseRightButtonAction", "OpenApplicationsMenu", seMouseButtonActions, + &wPreferences.mouse_button3, getEnum, NULL, NULL, NULL}, + {"MouseBackwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button8, + getEnum, NULL, NULL, NULL}, + {"MouseForwardButtonAction", "None", seMouseButtonActions, &wPreferences.mouse_button9, getEnum, + NULL, NULL, NULL}, + {"MouseWheelAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_scroll, getEnum, + NULL, NULL, NULL}, + {"MouseWheelTiltAction", "None", seMouseWheelActions, &wPreferences.mouse_wheel_tilt, getEnum, + NULL, NULL, NULL}, + + /* --- Workspaces --- */ + + {"AdvanceToNewWorkspace", "NO", NULL, &wPreferences.ws_advance, getBool, NULL, NULL, NULL}, + {"CycleWorkspaces", "NO", NULL, &wPreferences.ws_cycle, getBool, NULL, NULL, NULL}, + {"WorkspaceNameDisplayPosition", "center", seDisplayPositions, + &wPreferences.workspace_name_display_position, getEnum, NULL, NULL, NULL}, + {"WorkspaceBorder", "AllDirections", seWorkspaceBorder, &wPreferences.workspace_border_position, + getEnum, updateUsableArea, NULL, NULL}, + {"WorkspaceBorderSize", "0", NULL, &wPreferences.workspace_border_size, getInt, + updateUsableArea, NULL, NULL}, + + /* --- Animations --- */ + + {"ShadeSpeed", "medium", seSpeeds, &wPreferences.shade_speed, getEnum, NULL, NULL, NULL}, + {"BounceAppIconsWhenUrgent", "YES", NULL, &wPreferences.bounce_appicons_when_urgent, getBool, + NULL, NULL, NULL}, + {"RaiseAppIconsWhenBouncing", "NO", NULL, &wPreferences.raise_appicons_when_bouncing, getBool, + NULL, NULL, NULL}, + {"DoNotMakeAppIconsBounce", "YES", NULL, &wPreferences.do_not_make_appicons_bounce, getBool, + NULL, NULL, NULL}, + + /* --- Options need to get rid of or fix --- */ + + /* --- Style options --- */ + + {"MenuStyle", "normal", seMenuStyles, &wPreferences.menu_style, getEnum, setMenuStyle, NULL, + NULL}, + {"WidgetColor", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setWidgetColor, NULL, NULL}, + {"IconBack", DEF_ICON_BACK, NULL, NULL, getTexture, setIconTile, NULL, NULL}, + /* NEXTSPACE */ + {"MiniwindowBack", DEF_MINIWINDOW_BACK, NULL, NULL, getTexture, setMiniwindowTile, NULL, NULL}, + {"TitleJustify", "center", seJustifications, &wPreferences.title_justification, getEnum, + setJustify, NULL, NULL}, + {"WindowTitleFont", DEF_TITLE_FONT, NULL, NULL, getFont, setWinTitleFont, NULL, NULL}, + {"WindowTitleExtendSpace", DEF_WINDOW_TITLE_EXTEND_SPACE, NULL, + &wPreferences.window_title_clearance, getInt, setClearance, NULL, NULL}, + {"WindowTitleMinHeight", "22", NULL, &wPreferences.window_title_min_height, getInt, + setClearance, NULL, NULL}, + {"WindowTitleMaxHeight", "22", NULL, &wPreferences.window_title_max_height, getInt, + setClearance, NULL, NULL}, + {"MenuTitleExtendSpace", DEF_MENU_TITLE_EXTEND_SPACE, NULL, &wPreferences.menu_title_clearance, + getInt, setClearance, NULL, NULL}, + {"MenuTitleMinHeight", "22", NULL, &wPreferences.menu_title_min_height, getInt, setClearance, + NULL, NULL}, + {"MenuTitleMaxHeight", "22", NULL, &wPreferences.menu_title_max_height, getInt, setClearance, + NULL, NULL}, + {"MenuTextExtendSpace", DEF_MENU_TEXT_EXTEND_SPACE, NULL, &wPreferences.menu_text_clearance, + getInt, setClearance, NULL, NULL}, + {"MenuTitleFont", DEF_MENU_TITLE_FONT, NULL, NULL, getFont, setMenuTitleFont, NULL, NULL}, + {"MenuTextFont", DEF_MENU_ENTRY_FONT, NULL, NULL, getFont, setMenuTextFont, NULL, NULL}, + {"IconTitleFont", DEF_ICON_TITLE_FONT, NULL, NULL, getFont, setIconTitleFont, NULL, NULL}, + {"ClipTitleFont", DEF_CLIP_TITLE_FONT, NULL, NULL, getFont, setClipTitleFont, NULL, NULL}, + {"UseAntialiasedText", "NO", NULL, NULL, getBool, setAntialiasedText, NULL, NULL}, + {"ShowClipTitle", "YES", NULL, &wPreferences.show_clip_title, getBool, NULL, NULL, NULL}, + {"LargeDisplayFont", DEF_WORKSPACE_NAME_FONT, NULL, NULL, getFont, setLargeDisplayFont, NULL, + NULL}, + {"HighlightColor", "white", NULL, NULL, getColor, setHightlight, NULL, NULL}, + {"HighlightTextColor", "black", NULL, NULL, getColor, setHightlightText, NULL, NULL}, + {"ClipTitleColor", "black", (void *)CLIP_NORMAL, NULL, getColor, setClipTitleColor, NULL, NULL}, + {"CClipTitleColor", "\"#454045\"", (void *)CLIP_COLLAPSED, NULL, getColor, setClipTitleColor, + NULL, NULL}, + {"FTitleColor", "white", (void *)WS_FOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"PTitleColor", "white", (void *)WS_PFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"UTitleColor", "black", (void *)WS_UNFOCUSED, NULL, getColor, setWTitleColor, NULL, NULL}, + {"FTitleBack", "(solid, black)", NULL, NULL, getTexture, setFTitleBack, NULL, NULL}, + {"PTitleBack", "(solid, \"#555555\")", NULL, NULL, getTexture, setPTitleBack, NULL, NULL}, + {"UTitleBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setUTitleBack, NULL, NULL}, + {"ResizebarBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setResizebarBack, NULL, NULL}, + {"MenuTitleColor", "white", NULL, NULL, getColor, setMenuTitleColor, NULL, NULL}, + {"MenuTextColor", "black", NULL, NULL, getColor, setMenuTextColor, NULL, NULL}, + {"MenuDisabledColor", "\"#555555\"", NULL, NULL, getColor, setMenuDisabledColor, NULL, NULL}, + {"MenuTitleBack", "(solid, black)", NULL, NULL, getTexture, setMenuTitleBack, NULL, NULL}, + {"MenuTextBack", "(solid, \"#aaaaaa\")", NULL, NULL, getTexture, setMenuTextBack, NULL, NULL}, + {"IconTitleColor", "white", NULL, NULL, getColor, setIconTitleColor, NULL, NULL}, + {"IconTitleBack", "black", NULL, NULL, getColor, setIconTitleBack, NULL, NULL}, + {"SwitchPanelImages", "(swtile.png, swback.png, 30, 40)", &wPreferences, NULL, getPropList, + setSwPOptions, NULL, NULL}, + {"ModifierKeyLabels", + "(\"Shift+\", \"Control+\", \"Alt+\", \"Mod2+\", \"Mod3+\", \"Super+\", \"Mod5+\")", + &wPreferences, NULL, getPropList, setModifierKeyLabels, NULL, NULL}, + {"FrameBorderWidth", "1", NULL, NULL, getInt, setFrameBorderWidth, NULL, NULL}, + {"FrameBorderColor", "black", NULL, NULL, getColor, setFrameBorderColor, NULL, NULL}, + {"FrameFocusedBorderColor", "black", NULL, NULL, getColor, setFrameFocusedBorderColor, NULL, + NULL}, + {"FrameSelectedBorderColor", "white", NULL, NULL, getColor, setFrameSelectedBorderColor, NULL, + NULL}, + {"WorkspaceMapBack", "(solid, black)", NULL, NULL, getTexture, setWorkspaceMapBackground, NULL, + NULL}, + + /* --- Key bindings --- */ + + {"CommandModifierKey", "Alt", NULL, &wPreferences.cmd_modifier_mask, getModMask, NULL, NULL, + NULL}, + {"AlternateModifierKey", "Super", NULL, &wPreferences.alt_modifier_mask, getAltModMask, NULL, + NULL, NULL}, + /* Dock and Icon Yard */ + /* {"DockHideShowKey", "\"Alternate+D\"", (void *)WKBD_DOCKHIDESHOW, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"IconYardHideShowKey", "\"Alternate+Y\"", (void *)WKBD_YARDHIDESHOW, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* Window Resizing */ + /* {"MaximusKey", "\"Super+KP_5\"", (void *)WKBD_MAXIMUS, NULL, getKeybind, setKeyGrab, NULL, + NULL}, */ + /* {"ShadeKey", "\"Alternate+KP_Subtract\"", (void *)WKBD_SHADE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MaximizeKey", "\"Alternate+KP_Add\"", (void *)WKBD_MAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"VMaximizeKey", "\"Alternate+Up\"", (void *)WKBD_VMAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"HMaximizeKey", "\"Alternate+Right\"", (void *)WKBD_HMAXIMIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"LHMaximizeKey", "\"Alternate+KP_4\"", (void *)WKBD_LHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RHMaximizeKey", "\"Alternate+KP_6\"", (void *)WKBD_RHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"THMaximizeKey", "\"Alternate+KP_8\"", (void *)WKBD_THMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"BHMaximizeKey", "\"Alternate+KP_2\"", (void *)WKBD_BHMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"LTCMaximizeKey", "\"Alternate+KP_7\"", (void *)WKBD_LTCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RTCMaximizeKey", "\"Alternate+KP_9\"", (void *)WKBD_RTCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"LBCMaximizeKey", "\"Alternate+KP_1\"", (void *)WKBD_LBCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* {"RBCMaximizeKey", "\"Alternate+KP_3\"", (void *)WKBD_RBCMAXIMIZE, NULL, getKeybind, + setKeyGrab, NULL, NULL}, */ + /* Window Ordering */ + /* {"CloseKey", "\"Command+w\"", (void *)WKBD_CLOSE, NULL, getKeybind, setKeyGrab, NULL, NULL}, + */ + /* {"HideKey", "\"Command+h\"", (void *)WKBD_HIDE, NULL, getKeybind, setKeyGrab, NULL, NULL}, */ + /* {"HideOthersKey", "\"Command+H\"", (void *)WKBD_HIDE_OTHERS, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MiniaturizeKey", "\"Command+m\"", (void *)WKBD_MINIATURIZE, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* {"MinimizeAllKey", "\"Command+M\"", (void *)WKBD_MINIMIZEALL, NULL, getKeybind, setKeyGrab, + NULL, NULL}, */ + /* Focus switch */ + /* {"RaiseKey", "\"Command+Up\"", (void *)WKBD_RAISE, NULL, getKeybind, setKeyGrab, NULL, NULL}, + */ + /* {"LowerKey", "\"Command+Down\"", (void *)WKBD_LOWER, NULL, getKeybind, setKeyGrab, NULL, + NULL}, */ + {"FocusNextKey", "\"Command+Tab\"", (void *)WKBD_FOCUSNEXT, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"FocusPrevKey", "\"Command+Shift+Tab\"", (void *)WKBD_FOCUSPREV, NULL, getKeybind, setKeyGrab, + NULL, NULL}, + {"GroupNextKey", "\"Command+grave\"", (void *)WKBD_GROUPNEXT, NULL, getKeybind, setKeyGrab, + NULL, NULL}, + {"GroupPrevKey", "\"Command+Shift+grave\"", (void *)WKBD_GROUPPREV, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + /* Workspaces */ + {"NextWorkspaceKey", "\"Control+Right\"", (void *)WKBD_NEXT_DESKTOP, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + {"PrevWorkspaceKey", "\"Control+Left\"", (void *)WKBD_PREV_DESKTOP, NULL, getKeybind, + setKeyGrab, NULL, NULL}, + {"LastWorkspaceKey", "None", (void *)WKBD_LAST_DESKTOP, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop1Key", "\"Control+1\"", (void *)WKBD_DESKTOP_1, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop2Key", "\"Control+2\"", (void *)WKBD_DESKTOP_2, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop3Key", "\"Control+3\"", (void *)WKBD_DESKTOP_3, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop4Key", "\"Control+4\"", (void *)WKBD_DESKTOP_4, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop5Key", "\"Control+5\"", (void *)WKBD_DESKTOP_5, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop6Key", "\"Control+6\"", (void *)WKBD_DESKTOP_6, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop7Key", "\"Control+7\"", (void *)WKBD_DESKTOP_7, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop8Key", "\"Control+8\"", (void *)WKBD_DESKTOP_8, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop9Key", "\"Control+9\"", (void *)WKBD_DESKTOP_9, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + {"Desktop10Key", "\"Control+0\"", (void *)WKBD_DESKTOP_10, NULL, getKeybind, setKeyGrab, NULL, + NULL}, + + {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, NULL, getKeybind, setKeyGrab, NULL, NULL}, + + /* --- Mouse cursors --- */ + {"NormalCursor", "(builtin, left_ptr)", (void *)WCUR_ROOT, NULL, getCursor, setCursor, NULL, + NULL}, + {"ArrowCursor", "(builtin, left_ptr)", (void *)WCUR_ARROW, NULL, getCursor, setCursor, NULL, + NULL}, + {"ResizeCursor", "(builtin, sizing)", (void *)WCUR_RESIZE, NULL, getCursor, setCursor, NULL, + NULL}, + {"WaitCursor", "(builtin, watch)", (void *)WCUR_WAIT, NULL, getCursor, setCursor, NULL, NULL}, + {"QuestionCursor", "(builtin, question_arrow)", (void *)WCUR_QUESTION, NULL, getCursor, + setCursor, NULL, NULL}, + {"TextCursor", "(builtin, xterm)", (void *)WCUR_TEXT, NULL, getCursor, setCursor, NULL, NULL}, + {"SelectCursor", "(builtin, cross)", (void *)WCUR_SELECT, NULL, getCursor, setCursor, NULL, + NULL}, + {"MoveCursor", "(library, move)", (void *)WCUR_MOVE, NULL, getCursor, setCursor, NULL, NULL}, + {"TopLeftResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_TOPLEFTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"TopRightResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_TOPRIGHTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"BottomLeftResizeCursor", "(library, fd_double_arrow)", (void *)WCUR_BOTTOMLEFTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"BottomRightResizeCursor", "(library, bd_double_arrow)", (void *)WCUR_BOTTOMRIGHTRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"VerticalResizeCursor", "(library, wm_v_double_arrow)", (void *)WCUR_VERTICALRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"HorizontalResizeCursor", "(library, wm_h_double_arrow)", (void *)WCUR_HORIZONRESIZE, NULL, + getCursor, setCursor, NULL, NULL}, + {"UpResizeCursor", "(library, wm_up_arrow)", (void *)WCUR_UPRESIZE, NULL, getCursor, setCursor, + NULL, NULL}, + {"DownResizeCursor", "(library, wm_down_arrow)", (void *)WCUR_DOWNRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"LeftResizeCursor", "(library, wm_left_arrow)", (void *)WCUR_LEFTRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"RightResizeCursor", "(library, wm_right_arrow)", (void *)WCUR_RIGHTRESIZE, NULL, getCursor, + setCursor, NULL, NULL}, + {"DialogHistoryLines", "500", NULL, &wPreferences.history_lines, getInt, NULL, NULL, NULL}, + {"CycleActiveHeadOnly", "NO", NULL, &wPreferences.cycle_active_head_only, getBool, NULL, NULL, + NULL}, + {"CycleIgnoreMinimized", "NO", NULL, &wPreferences.cycle_ignore_minimized, getBool, NULL, NULL, + NULL}}; /* set `plkey` and `plvalue` fields of entries in `optionList` and `staticOptionList` */ static void _initializeOptionLists(void) @@ -624,38 +737,41 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) } #ifdef HAVE_INOTIFY - wDefaultsShouldTrackChanges(domain, false); + if (domain->inotify_watch >= 0) { + wDefaultsShouldTrackChanges(domain, false); + } #endif + WMLogWarning("Updating domain %@...", domain->name); /* User dictionary */ dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, false); if (dict) { - if (CFGetTypeID(dict) != CFDictionaryGetTypeID()) { - CFRelease(dict); - dict = NULL; - WMLogError("Domain %@ of defaults database is corrupted!", domain->name); - } - else { - if ((scr = wDefaultScreen())) { - wDefaultsRead(scr, dict, shouldNotify); + if (CFGetTypeID(dict) == CFDictionaryGetTypeID()) { + if ((scr = wDefaultScreen()) && CFStringCompare(domain->name, CFSTR("WM"), 0) == 0) { + wDefaultsReadPreferences(scr, dict, shouldNotify); } if (domain->dictionary) { CFRelease(domain->dictionary); } - domain->dictionary = dict; + domain->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); + } else { + WMLogError("Domain %@ of defaults database is corrupted!", domain->name); } - } - else { + CFRelease(dict); + dict = NULL; + } else { WMLogError("Could not load domain %@. It is not dictionary!", domain->name); if (domain->dictionary) { WMLogError("Write from memory to path %@.", domain->path); WMUserDefaultsWrite(domain->dictionary, domain->name); } } - + domain->timestamp = WMUserDefaultsFileModificationTime(domain->name, 0); #ifdef HAVE_INOTIFY - wDefaultsShouldTrackChanges(domain, true); + if (domain->shouldTrackChanges) { + wDefaultsShouldTrackChanges(domain, true); + } #endif } @@ -663,11 +779,14 @@ static void _updateDomain(WDDomain *domain, Bool shouldNotify) static WDDomain *_domainForWatchDescriptor(int wd) { - if (wd == w_global.domain.wm->inotify_watch) { - return w_global.domain.wm; + if (wd == w_global.domain.wm_preferences->inotify_watch) { + return w_global.domain.wm_preferences; + } + if (wd == w_global.domain.wm_state->inotify_watch) { + return w_global.domain.wm_state; } - if (wd == w_global.domain.window_attr->inotify_watch) { - return w_global.domain.window_attr; + if (wd == w_global.domain.window_attrs->inotify_watch) { + return w_global.domain.window_attrs; } return NULL; @@ -689,7 +808,7 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac eventQLength = read(w_global.inotify.fd_event_queue, buff, sizeof(buff)); if (eventQLength < 0) { - WMLogWarning(_("read problem when trying to get INotify event: %s"), strerror(errno)); + WMLogWarning("read problem when trying to get INotify event: %s", strerror(errno)); return; } @@ -699,31 +818,30 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac domain = _domainForWatchDescriptor(pevent->wd); if (!domain) { - WMLogWarning(_("inotify: ignore event for domain that is not tracked anymore.")); + WMLogWarning("inotify [descriptor %i]: ignore event for domain that is not tracked anymore.", + pevent->wd); goto next_event; } if (pevent->mask & IN_MODIFY) { - WMLogWarning(_("inotify: defaults domain has been modified. Rereading defaults database.")); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been modified.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_MOVE_SELF) { - WMLogWarning(_("inotify: %i defaults domain has been moved."), pevent->wd); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been moved.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_DELETE_SELF) { - WMLogWarning(_("inotify: %i defaults domain has been deleted!"), pevent->wd); - /* _updateDomain(domain); */ + WMLogWarning("inotify [descriptor %i]: defaults domain has been deleted.", pevent->wd); wDefaultsUpdateDomainsIfNeeded(NULL); } if (pevent->mask & IN_UNMOUNT) { - WMLogWarning(_("inotify: the unit containing the defaults database has" - " been unmounted. Setting --static mode." " Any changes will not be saved.")); + WMLogWarning("inotify: the unit containing the defaults database has" + " been unmounted. Disabling tracking changes mode." + " Any changes will not be saved."); wDefaultsShouldTrackChanges(domain, false); wPreferences.flags.noupdates = 1; @@ -733,39 +851,50 @@ static void _processWatchEvents(CFFileDescriptorRef fdref, CFOptionFlags callBac /* move to next event in the buffer */ i += sizeof(struct inotify_event) + pevent->len; } - + CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); } +static Bool _initializeInotify() +{ + w_global.inotify.fd_event_queue = inotify_init(); + if (w_global.inotify.fd_event_queue < 0) { + WMLogWarning("** inotify ** could not initialise an inotify instance." + " Changes to the defaults database will require a restart to take effect."); + return False; + } else { // Add to runloop + CFFileDescriptorRef ifd = NULL; + CFRunLoopSourceRef ifd_source = NULL; + + ifd = CFFileDescriptorCreate(kCFAllocatorDefault, w_global.inotify.fd_event_queue, true, + _processWatchEvents, NULL); + CFFileDescriptorEnableCallBacks(ifd, kCFFileDescriptorReadCallBack); + + ifd_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, ifd, 0); + CFRunLoopAddSource(wm_runloop, ifd_source, kCFRunLoopDefaultMode); + CFRelease(ifd_source); + CFRelease(ifd); + } + + return True; +} + void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack) { CFStringRef domainPath = NULL; - const char *watchPath = NULL; + const char *watchPath = NULL; - if (!domain) + if (!domain) { return; + } - // Initialize inotify - if (w_global.inotify.fd_event_queue < 0) { - w_global.inotify.fd_event_queue = inotify_init(); - if (w_global.inotify.fd_event_queue < 0) { - WMLogWarning(_("** inotify ** could not initialise an inotify instance." - " Changes to the defaults database will require a restart to take effect.")); - return; - } - else { // Add to runloop - CFFileDescriptorRef ifd = NULL; - CFRunLoopSourceRef ifd_source = NULL; - - ifd = CFFileDescriptorCreate(kCFAllocatorDefault, w_global.inotify.fd_event_queue, true, - _processWatchEvents, NULL); - CFFileDescriptorEnableCallBacks(ifd, kCFFileDescriptorReadCallBack); + if (!wm_runloop) { + return; + } - ifd_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, ifd, 0); - CFRunLoopAddSource(wm_runloop, ifd_source, kCFRunLoopDefaultMode); - CFRelease(ifd_source); - CFRelease(ifd); - } + // Initialize inotify if needed + if ((w_global.inotify.fd_event_queue < 0) && (_initializeInotify() == False)) { + return; } // Create watcher @@ -779,32 +908,40 @@ void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack) domain->inotify_watch = inotify_add_watch(w_global.inotify.fd_event_queue, watchPath, mask); if (domain->inotify_watch < 0) { - WMLogWarning(_("** inotify ** could not add an inotify watch on path %s (error: %i %s)." - " Changes to the defaults database will require a restart to take effect."), + WMLogWarning("** inotify ** could not add an inotify watch on path %s (error: %i %s)." + " Changes to the defaults database will require a restart to take effect.", watchPath, errno, strerror(errno)); } CFRelease(domainPath); - } - else if (domain->inotify_watch >= 0) { + } else if (domain->inotify_watch >= 0) { WMLogError("inotify: will remove watch for %@.", domain->name); - - if (domain->inotify_watch >= 0) { - inotify_rm_watch(w_global.inotify.fd_event_queue, domain->inotify_watch); - } + inotify_rm_watch(w_global.inotify.fd_event_queue, domain->inotify_watch); domain->inotify_watch = -1; } + // else shouldTrack == false but domain is not tracked for changes - do nothing. } #endif /* HAVE_INOTIFY */ +static void _settingsObserver(CFNotificationCenterRef center, + void *observer, // NULL + CFNotificationName name, + const void *object, // object - ignored + CFDictionaryRef userInfo) +{ + wDefaultsUpdateDomainsIfNeeded(NULL); +} + // Called from startup.c +static Bool isOptionListsIntialized = false; +static Bool isObserverSet = false; WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) { WDDomain *domain; - static int inited = 0; + CFMutableDictionaryRef dict; - if (!inited) { - inited = 1; + if (isOptionListsIntialized == false) { + isOptionListsIntialized = true; _initializeOptionLists(); } @@ -814,23 +951,25 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) domain = wmalloc(sizeof(WDDomain)); domain->name = CFStringCreateWithCString(kCFAllocatorDefault, domain_name, kCFStringEncodingUTF8); domain->inotify_watch = -1; + domain->shouldTrackChanges = shouldTrackChanges; - domain->dictionary = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, true); - if (domain->dictionary) { - if ((CFGetTypeID(domain->dictionary) != CFDictionaryGetTypeID())) { - CFRelease(domain->dictionary); + // Initializing domain->dictionary + dict = (CFMutableDictionaryRef)WMUserDefaultsRead(domain->name, true); + if (dict) { + if ((CFGetTypeID(dict) != CFDictionaryGetTypeID())) { + CFRelease(dict); domain->dictionary = NULL; - WMLogError(_("domain %s (%s) of defaults database is corrupted!"), domain_name, - WMUserDefaultsGetCString(CFURLGetString(domain->path), kCFStringEncodingUTF8)); + WMLogError("domain %s (%@) of defaults database is corrupted!", domain_name, + CFURLGetString(domain->path)); } - } - else { + domain->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict); + CFRelease(dict); + } else { WMLogError("creating empty domain: %@", domain->name); - domain->dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + domain->dictionary = CFDictionaryCreateMutable( + kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } - + if (domain->dictionary && WMUserDefaultsWrite(domain->dictionary, domain->name)) { CFURLRef osURL; @@ -840,9 +979,14 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) domain->path = CFURLCreateCopyAppendingPathExtension(NULL, osURL, CFSTR("plist")); CFRelease(osURL); - if (wm_runloop) { - WMLogInfo("start tracking changes for domain: %@", domain->name); - wDefaultsShouldTrackChanges(domain, shouldTrackChanges); + wDefaultsShouldTrackChanges(domain, shouldTrackChanges); + + // first domain without tracking changes (inotify) + if ((shouldTrackChanges == false) && (isObserverSet == false)) { + WMLogError("Setting up `WMSettingsDidChangeNotification` observer..."); + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, _settingsObserver, + WMDidChangeAppearanceSettingsNotification, NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); } } @@ -851,7 +995,7 @@ WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges) // Called from startup.c // Apply `plvalue` from `dict` to appropriate `entry->addr` specified in `staticOptionList` -void wDefaultsReadStatic(CFMutableDictionaryRef dict) +void wDefaultsReadStaticPreferences(CFMutableDictionaryRef dict) { CFTypeRef plvalue; WDefaultEntry *entry; @@ -885,64 +1029,67 @@ void wDefaultsReadStatic(CFMutableDictionaryRef dict) } } -// Apply `plvalue` from `new_dict` to appropriate `entry->addr` specified in `optionList` -void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify) +// Propagates `optionList` values to `wPreferences`, `WScreen` or other global variable. +// If option exists in `new_dict` - use it instead. +// Usually `new_dict` is a `w_global.domain.wm_preferences->dictionary` which is the in-memory +// representation of WM.plist file. +// +// Function applies `plvalue` from `new_dict` to appropriate `entry->addr` specified in `optionList`. +// `entry->addr` is a wPreferences member or `NULL`. `NULL` means that `entry->update` callback +// sets value to appropriate structure (for example, WScreen) or global variable. +void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify) { + CFDictionaryRef old_dict = NULL; CFTypeRef plvalue = NULL; - CFTypeRef old_value = NULL; + CFTypeRef old_plvalue = NULL; WDefaultEntry *entry; unsigned int i; unsigned int needs_refresh = 0; void *tdata; - CFDictionaryRef old_dict = NULL; - if (w_global.domain.wm->dictionary != new_dict) - old_dict = w_global.domain.wm->dictionary; + WMLogWarning("Reading preferences from WM.plist...."); + + if (w_global.domain.wm_preferences->dictionary != new_dict) { + old_dict = w_global.domain.wm_preferences->dictionary; + } - needs_refresh = 0; + WMLogWarning("WindowTitleFont from new_dict %@", CFDictionaryGetValue(new_dict, CFSTR("WindowTitleFont"))); for (i = 0; i < wlengthof(optionList); i++) { entry = &optionList[i]; if (new_dict) { plvalue = CFDictionaryGetValue(new_dict, entry->plkey); - } - else { + } else { plvalue = NULL; } - - if (!old_dict) { - old_value = NULL; - } - else { - old_value = CFDictionaryGetValue(old_dict, entry->plkey); + + if (old_dict) { + old_plvalue = CFDictionaryGetValue(old_dict, entry->plkey); + } else { + old_plvalue = NULL; } // No need to hold default value in dictionary - /* WMLogError("Check if default exist: %@", entry->plkey); */ if (plvalue && CFEqual(plvalue, entry->plvalue)) { plvalue = NULL; - /* WMLogError("Removing setting equal to default: %@", entry->plkey); */ CFDictionaryRemoveValue(new_dict, entry->plkey); - /* WMLogError("Removed"); */ } if (!plvalue) { - /* value was deleted from DB. Keep current value */ + // value was deleted from DB. Keep current value plvalue = entry->plvalue; - /* continue; */ - } - else if (!old_value) { - /* set value for the 1st time */ - } - else if (CFEqual(plvalue, old_value)) { - /* value was not changed since last time */ + } else if (!old_plvalue) { + // set value for the 1st time + } else if (CFEqual(plvalue, old_plvalue)) { + // value was not changed since last time continue; } if (plvalue) { - /* convert data */ + // convert data if ((*entry->convert) (scr, entry, plvalue, entry->addr, &tdata)) { + // propagate converted value if (entry->update) { needs_refresh |= (*entry->update) (scr, entry, tdata, entry->extra_data); } @@ -950,7 +1097,7 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot } } - if (shouldNotify && needs_refresh != 0/* && !scr->flags.startup && !scr->flags.startup2*/) { + if (shouldNotify && needs_refresh != 0 /* && !scr->flags.startup && !scr->flags.startup2*/) { int foo; foo = 0; @@ -962,8 +1109,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeMenuTitleAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeMenuTitleAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } foo = 0; if (needs_refresh & REFRESH_MENU_TEXTURE) @@ -974,8 +1121,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeMenuAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeMenuAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } foo = 0; if (needs_refresh & REFRESH_WINDOW_FONT) @@ -986,8 +1133,8 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WColorSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeWindowAppearanceSettings, - (void *)(uintptr_t) foo, NULL, TRUE); + WMDidChangeWindowAppearanceSettings, + (void *)(uintptr_t)foo, NULL, TRUE); } if (!(needs_refresh & REFRESH_ICON_TILE)) { foo = 0; @@ -999,7 +1146,7 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot foo |= WTextureSettings; if (foo) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), - WMDidChangeIconAppearanceSettings, + WMDidChangeIconAppearanceSettings, (void *)(uintptr_t)foo, NULL, TRUE); } } @@ -1012,22 +1159,28 @@ void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNot } // Update in-memory representaion of user defaults. -// Also used as CFTimer callback. +// Also used as CFTimer callback - that's why argument exists. void wDefaultsUpdateDomainsIfNeeded(void* arg) { WScreen *scr; CFAbsoluteTime time = 0.0; - // ~/Library/Preferences/.NextSpace/WM - time = WMUserDefaultsFileModificationTime(w_global.domain.wm->name, 0); - if (w_global.domain.wm->timestamp < time) { - _updateDomain(w_global.domain.wm, True); + // ~/Library/Preferences/.NextSpace/WM.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.wm_preferences->name, 0); + if (w_global.domain.wm_preferences->timestamp < time) { + _updateDomain(w_global.domain.wm_preferences, True); } - // ~/Library/Preferences/.NextSpace/WMWindowAttributes - time = WMUserDefaultsFileModificationTime(w_global.domain.window_attr->name, 0); - if (w_global.domain.window_attr->timestamp < time) { - _updateDomain(w_global.domain.window_attr, False); + // ~/Library/Preferences/.NextSpace/WMState.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.wm_state->name, 0); + if (w_global.domain.wm_state->timestamp < time) { + _updateDomain(w_global.domain.wm_state, True); + } + + // ~/Library/Preferences/.NextSpace/WMWindowAttributes.plist + time = WMUserDefaultsFileModificationTime(w_global.domain.window_attrs->name, 0); + if (w_global.domain.window_attrs->timestamp < time) { + _updateDomain(w_global.domain.window_attrs, False); if ((scr = wDefaultScreen())) { _updateApplicationIcons(scr); } @@ -2478,6 +2631,19 @@ static int setLargeDisplayFont(WScreen *scr, WDefaultEntry *entry, void *tdata, return 0; } +static int setAntialiasedText(WScreen *scr, WDefaultEntry *entry, void *tdata, void *foo) +{ + char *flag = tdata; + + /* Parameter not used, but tell the compiler that it is ok */ + (void) entry; + (void) foo; + + scr->wmscreen->antialiasedText = *flag; + + return 0; +} + static int setHightlight(WScreen *scr, WDefaultEntry *entry, void *tdata, void *foo) { XColor *color = tdata; diff --git a/Applications/Workspace/WM/defaults.h b/Applications/Workspace/WM/defaults.h index 299125d68..e1c38e2ee 100644 --- a/Applications/Workspace/WM/defaults.h +++ b/Applications/Workspace/WM/defaults.h @@ -33,6 +33,7 @@ typedef struct WDDomain { CFMutableDictionaryRef dictionary; CFURLRef path; CFAbsoluteTime timestamp; + Bool shouldTrackChanges; #ifdef HAVE_INOTIFY int inotify_watch; #endif @@ -212,17 +213,17 @@ extern struct WPreferences { #ifdef USE_ICCCM_WMREPLACE unsigned int replace : 1; /* replace existing window manager */ #endif - unsigned int nodock : 1; /* don't display the dock */ - unsigned int noclip : 1; /* don't display the clip */ - unsigned int clip_merged_in_dock : 1; /* disable clip, switch workspaces with dock */ - unsigned int nodrawer : 1; /* don't use drawers */ + unsigned int nodock : 1; /* don't display the dock */ + unsigned int noclip : 1; /* don't display the clip */ + unsigned int clip_merged_in_dock : 1; /* disable clip, switch workspaces with dock */ + unsigned int nodrawer : 1; /* don't use drawers */ unsigned int wrap_appicons_in_dock : 1; /* Whether to wrap appicons when Dock is moved up and down */ - unsigned int noupdates : 1; /* don't require ~/GNUstep (-static) */ - unsigned int noautolaunch : 1; /* don't autolaunch apps */ - unsigned int norestore : 1; /* don't restore session */ - unsigned int restarting : 2; - } flags; /* internal flags */ + unsigned int noupdates : 1; /* don't require ~/GNUstep (-static) */ + unsigned int noautolaunch : 1; /* don't autolaunch apps */ + unsigned int norestore : 1; /* don't restore session */ + unsigned int restarting : 2; + } flags; /* internal flags */ /* Map table between w_cursor and actual X id */ Cursor cursor[WCUR_LAST]; @@ -230,8 +231,8 @@ extern struct WPreferences { } wPreferences; WDDomain *wDefaultsInitDomain(const char *domain_name, Bool shouldTrackChanges); -void wDefaultsReadStatic(CFMutableDictionaryRef dict); -void wDefaultsRead(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify); +void wDefaultsReadStaticPreferences(CFMutableDictionaryRef dict); +void wDefaultsReadPreferences(WScreen *scr, CFMutableDictionaryRef new_dict, Bool shouldNotify); void wDefaultsUpdateDomainsIfNeeded(void *arg); #ifdef HAVE_INOTIFY @@ -255,6 +256,8 @@ void wDefaultsShouldTrackChanges(WDDomain *domain, Bool shouldTrack); #define DEF_WINDOW_TITLE_EXTEND_SPACE "0" #define DEF_MENU_TITLE_EXTEND_SPACE "0" #define DEF_MENU_TEXT_EXTEND_SPACE "0" +#define DEF_ICON_BACK "(\"tpixmap\", \"/Library/Images/common_Tile.tiff\", \"#000000\")" +#define DEF_MINIWINDOW_BACK "(\"tpixmap\", \"/Library/Images/common_MiniWindowTile.tiff\", \"#000000\")" #ifndef HAVE_INOTIFY /* Check defaults database for changes every this many milliseconds */ diff --git a/Applications/Workspace/WM/dock.c b/Applications/Workspace/WM/dock.c index ef4ee9623..d953fdd4f 100644 --- a/Applications/Workspace/WM/dock.c +++ b/Applications/Workspace/WM/dock.c @@ -714,7 +714,7 @@ static WAppIcon *mainIconCreate(WScreen *scr, int type, const char *name) icon_desc = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(icon_desc, CFSTR("Icon"), CFSTR(APP_ICON)); - CFDictionarySetValue(w_global.domain.window_attr->dictionary, CFSTR("Workspace.GNUstep"), + CFDictionarySetValue(w_global.domain.window_attrs->dictionary, CFSTR("Workspace.GNUstep"), icon_desc); CFRelease(icon_desc); btn = wAppIconCreateForDock(scr, NULL, "Workspace", "GNUstep", TILE_NORMAL); diff --git a/Applications/Workspace/WM/event.c b/Applications/Workspace/WM/event.c index 5089618c3..c15b9e300 100644 --- a/Applications/Workspace/WM/event.c +++ b/Applications/Workspace/WM/event.c @@ -318,7 +318,7 @@ void WMRunLoop_V0() { XEvent event; - WMLogError("WMRunLoop0: handling events while run loop is warming up."); + WMLogError("WMRunLoop_V0: handling events while run loop is warming up."); while (wm_runloop == NULL) { WMNextEvent(dpy, &event); WMHandleEvent(&event); @@ -328,8 +328,7 @@ void WMRunLoop_V0() #ifdef HAVE_INOTIFY /* Track some defaults files for changes */ w_global.inotify.fd_event_queue = -1; - wDefaultsShouldTrackChanges(w_global.domain.wm, true); - wDefaultsShouldTrackChanges(w_global.domain.window_attr, true); + wDefaultsShouldTrackChanges(w_global.domain.window_attrs, true); #else /* Setup defaults files polling */ if (!wPreferences.flags.noupdates) { @@ -344,7 +343,7 @@ void WMRunLoop_V1() CFFileDescriptorRef xfd; CFRunLoopSourceRef xfd_source; - WMLogError("V1: Entering WM runloop with X connection: %i", ConnectionNumber(dpy)); + WMLogError("WMRunLoop_V1: Entering WM runloop with X connection: %i", ConnectionNumber(dpy)); // X connection file descriptor xfd = CFFileDescriptorCreate(kCFAllocatorDefault, ConnectionNumber(dpy), true, @@ -356,7 +355,7 @@ void WMRunLoop_V1() CFRelease(xfd_source); CFRelease(xfd); - WMLogError("V1: Going into CFRunLoop..."); + WMLogError("WMRunLoop_V1: Going into CFRunLoop..."); wm_runloop = run_loop; CFRunLoopRun(); diff --git a/Applications/Workspace/WM/screen.c b/Applications/Workspace/WM/screen.c index b11a85648..267250b80 100644 --- a/Applications/Workspace/WM/screen.c +++ b/Applications/Workspace/WM/screen.c @@ -624,6 +624,10 @@ static void createInternalWindows(WScreen *scr) scr->dock_shadow = XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs); + Atom data = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + Atom property = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + XChangeProperty(dpy, scr->dock_shadow, property, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&data, 1); /* workspace name */ vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel; @@ -796,7 +800,7 @@ WScreen *wScreenInit(int screen_number) allocGCs(scr); /* read defaults for this screen */ - wDefaultsRead(scr, w_global.domain.wm->dictionary, True); + wDefaultsReadPreferences(scr, w_global.domain.wm_preferences->dictionary, True); { XColor xcol; diff --git a/Applications/Workspace/WM/shutdown.c b/Applications/Workspace/WM/shutdown.c index 632146a66..b9da1d1f6 100644 --- a/Applications/Workspace/WM/shutdown.c +++ b/Applications/Workspace/WM/shutdown.c @@ -113,6 +113,7 @@ void wShutdown(WMShutdownMode mode) wScreenSaveState(scr); wNETWMCleanup(scr); /* Delete _NET_* Atoms */ PropCleanUp(scr->root_win); /* WM specific properties */ + XDeleteProperty(dpy, scr->root_win, XInternAtom(dpy, "_XROOTPMAP_ID", False)); RShutdown(); /* wraster clean exit */ #if HAVE_SYSLOG_H WMSyslogClose(); diff --git a/Applications/Workspace/WM/startup.c b/Applications/Workspace/WM/startup.c index c88b15fa3..f9b144a31 100644 --- a/Applications/Workspace/WM/startup.c +++ b/Applications/Workspace/WM/startup.c @@ -80,6 +80,7 @@ #include "xmodifier.h" #include "dock.h" #include "application.h" +#include "wmcomposer.h" /****** Global ******/ Display *dpy; @@ -114,9 +115,12 @@ CFStringRef WMDidChangeMenuTitleAppearanceSettings = CFSTR("WMDidChangeMenuTitleAppearanceSettings"); CFStringRef WMDidChangeKeyboardLayoutNotification = CFSTR("WMDidChangeKeyboardLayoutNotification"); -CFStringRef WMDidChangeDockContentNotification = CFSTR("WMDidChangeDockContentNotification"); -/* GNUstep applications notifications */ +/* GNUstep applications notifications. Public ObjC part resides in DesktopKit/NXTWorkspace.h */ +// WM.plist +CFStringRef WMDidChangeAppearanceSettingsNotification = CFSTR("WMDidChangeAppearanceSettingsNotification"); +// WMState.plist +CFStringRef WMDidChangeDockContentNotification = CFSTR("WMDidChangeDockContentNotification"); // Hide Others CFStringRef WMShouldHideOthersNotification = CFSTR("WMShouldHideOthersNotification"); CFStringRef WMDidHideOthersNotification = CFSTR("WMDidHideOthersNotification"); @@ -175,7 +179,10 @@ static int _catchXError(Display *dpy, XErrorEvent *error) */ || (error->request_code == X_InstallColormap))) { return 0; + } else if (wComposerErrorHandler(dpy, error)) { + return 0; } + FormatXError(dpy, error, buffer, MAXLINE); WMLogWarning(_("internal X error: %s"), buffer); return -1; @@ -646,29 +653,41 @@ void wStartUp(Bool defaultScreenOnly) /* set hook for out event dispatcher in WINGs event dispatcher */ WMHookEventHandler(DispatchEvent); - /* initialize defaults stuff */ - w_global.domain.wm = wDefaultsInitDomain("WMState", true); - if (!w_global.domain.wm->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMState"); + /* + Initialize defaults stuff + */ + // Read defaults from WM.plist file. This file may not exist - use hardcoded defults (defaults.c). + // Defaults are propagated into wPreferences, WScreen. + w_global.domain.wm_preferences = wDefaultsInitDomain("WM", false); + if (!w_global.domain.wm_preferences->dictionary) { + WMLogWarning("could not read domain \"WM\" from defaults database"); + } + + // Process defaults that don't change until a restart and are screen independent. + // Were read from WM.plist on previous step. + if (w_global.domain.wm_preferences) { + wDefaultsReadStaticPreferences(w_global.domain.wm_preferences->dictionary); + // WMUserDefaultsWrite(w_global.domain.wm_preferences->dictionary, w_global.domain.wm_preferences->name); + } else { + wDefaultsReadStaticPreferences(NULL); } - /* read defaults that don't change until a restart and are screen independent */ - wDefaultsReadStatic(w_global.domain.wm ? w_global.domain.wm->dictionary : NULL); - if (w_global.domain.wm) { - WMUserDefaultsWrite(w_global.domain.wm->dictionary, w_global.domain.wm->name); + w_global.domain.wm_state = wDefaultsInitDomain("WMState", true); + if (!w_global.domain.wm_state->dictionary) { + WMLogWarning("could not read domain \"WMState\" from defaults database"); } /* check sanity of some values */ if (wPreferences.icon_size < 64) { - WMLogWarning(_("Icon size is configured to %i, but it's too small. Using 64 instead"), + WMLogWarning("Icon size is configured to %i, but it's too small. Using 64 instead", wPreferences.icon_size); wPreferences.icon_size = 64; } /* init other domains */ - w_global.domain.window_attr = wDefaultsInitDomain("WMWindowAttributes", true); - if (!w_global.domain.window_attr->dictionary) { - WMLogWarning(_("could not read domain \"%s\" from defaults database"), "WMWindowAttributes"); + w_global.domain.window_attrs = wDefaultsInitDomain("WMWindowAttributes", true); + if (!w_global.domain.window_attrs->dictionary) { + WMLogWarning("could not read domain \"WMWindowAttributes\" from defaults database"); } wSetErrorHandler(); diff --git a/Applications/Workspace/WM/window_attributes.c b/Applications/Workspace/WM/window_attributes.c index ec6c6570b..f03710f72 100644 --- a/Applications/Workspace/WM/window_attributes.c +++ b/Applications/Workspace/WM/window_attributes.c @@ -167,8 +167,8 @@ static CFTypeRef get_value_from_instanceclass(const char *value) key = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8); - if (w_global.domain.window_attr->dictionary) - val = key ? CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key) : NULL; + if (w_global.domain.window_attrs->dictionary) + val = key ? CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key) : NULL; if (key) CFRelease(key); @@ -245,8 +245,8 @@ void wDefaultFillAttributes(const char *instance, const char *class, WWindowAttr dn = get_value_from_instanceclass(instance); dc = get_value_from_instanceclass(class); - if ((w_global.domain.window_attr->dictionary) && (useGlobalDefault)) - da = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, AnyWindow); + if ((w_global.domain.window_attrs->dictionary) && (useGlobalDefault)) + da = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, AnyWindow); /* get the data */ value = get_value(dw, dc, dn, da, ANoTitlebar, No, useGlobalDefault); @@ -338,7 +338,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt /* Search the icon name using class and instance */ if (class && instance) { key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%s"), instance, class); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) { @@ -350,7 +350,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt if (!value && instance) { key = CFStringCreateWithCString(kCFAllocatorDefault, instance, kCFStringEncodingUTF8); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) { @@ -362,7 +362,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt if (!value && class) { key = CFStringCreateWithCString(kCFAllocatorDefault, class, kCFStringEncodingUTF8); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); CFRelease(key); if (dict) @@ -372,7 +372,7 @@ static CFTypeRef get_generic_value(const char *instance, const char *class, CFSt /* Search the default icon name - See default_icon argument! */ if (!value && default_icon) { /* AnyWindow is "*" - see wdefaults.c */ - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, AnyWindow); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, AnyWindow); if (dict) value = CFDictionaryGetValue(dict, option); @@ -502,7 +502,7 @@ int wDefaultGetStartWorkspace(WScreen *scr, const char *instance, const char *cl int w; const char *tmp; - if (!w_global.domain.window_attr->dictionary) + if (!w_global.domain.window_attrs->dictionary) return -1; value = get_generic_value(instance, class, AStartWorkspace, True); @@ -527,7 +527,7 @@ const char *wDefaultGetIconFile(const char *instance, const char *class, Bool de CFTypeRef value; const char *tmp; - if (!w_global.domain.window_attr || !w_global.domain.window_attr->dictionary) + if (!w_global.domain.window_attrs || !w_global.domain.window_attrs->dictionary) return NULL; value = get_generic_value(instance, class, AIcon, default_icon); @@ -542,7 +542,7 @@ const char *wDefaultGetIconFile(const char *instance, const char *class, Bool de void wDefaultChangeIcon(const char *instance, const char *class, const char *file) { - WDDomain *db = w_global.domain.window_attr; + WDDomain *db = w_global.domain.window_attrs; CFMutableDictionaryRef dict = db->dictionary; CFMutableDictionaryRef icon_entry = NULL; CFMutableDictionaryRef attrs = NULL; @@ -629,11 +629,11 @@ void wDefaultPurgeInfo(const char *instance, const char *class) CFDictionaryRef dict; key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%s"), instance, class); - dict = CFDictionaryGetValue(w_global.domain.window_attr->dictionary, key); + dict = CFDictionaryGetValue(w_global.domain.window_attrs->dictionary, key); if (dict) { - CFDictionaryRemoveValue(w_global.domain.window_attr->dictionary, key); - WMUserDefaultsWrite(w_global.domain.window_attr->dictionary, w_global.domain.window_attr->name); + CFDictionaryRemoveValue(w_global.domain.window_attrs->dictionary, key); + WMUserDefaultsWrite(w_global.domain.window_attrs->dictionary, w_global.domain.window_attrs->name); } CFRelease(key); diff --git a/Applications/Workspace/WM/wmcomposer.c b/Applications/Workspace/WM/wmcomposer.c new file mode 100644 index 000000000..16fe0f577 --- /dev/null +++ b/Applications/Workspace/WM/wmcomposer.c @@ -0,0 +1,1943 @@ +/* + * Copyright © 2003 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* Modified by Matthew Hawn. I don't know what to say here so follow what it + says above. Not that I can really do anything about it +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _ignore { + struct _ignore *next; + unsigned long sequence; +} CMPIgnoreSequence; + +typedef struct _win { + struct _win *next; + Window id; + Pixmap pixmap; + XWindowAttributes a; + int mode; + int damaged; + Damage damage; + Picture picture; + Picture alphaPict; + Picture shadowPict; + XserverRegion borderSize; + XserverRegion extents; + Picture shadow; + int shadow_dx; + int shadow_dy; + int shadow_width; + int shadow_height; + unsigned int opacity; + Atom windowType; + unsigned long damage_sequence; /* sequence when damage was created */ + Bool shaped; + XRectangle shape_bounds; + + /* for drawing translucent windows */ + XserverRegion borderClip; + struct _win *prev_trans; +} CMPWindow; + +typedef struct _conv { + int size; + double *data; +} conv; + +typedef struct _fade { + struct _fade *next; + Display *dpy; + CMPWindow *w; + double cur; + double finish; + double step; + void (*callback)(Display *dpy, CMPWindow *w, Bool gone); + Bool gone; +} CMPFade; + +static Display *dpy; +static CMPWindow *list; +static CMPFade *fades; +static int scr; +static Window root_window; +static Picture root_picture; +static Picture root_picture_buffer; +static Picture root_picture_tile; +static Picture black_picture; +static Picture trans_black_picture; +static XserverRegion allDamage; +static Bool is_clip_changed; +static Bool has_name_pixmap; +static int root_height, root_width; +static CMPIgnoreSequence *ignore_head, **ignore_tail = &ignore_head; +static int xfixes_event, xfixes_error; +static int damage_event, damage_error; +static int composite_event, composite_error; +static int render_event, render_error; +static int xshape_event, xshape_error; +static Bool should_synchronize; +static int composite_opcode; + +/* find these once and be done with it */ +static Atom opacityAtom; +static Atom winTypeAtom; +static Atom winDesktopAtom; +static Atom winDockAtom; +static Atom winToolbarAtom; +static Atom winMenuAtom; +static Atom winUtilAtom; +static Atom winSplashAtom; +static Atom winDialogAtom; +static Atom winNormalAtom; + +#define TRANSLUCENT 0xe0000000 +#define OPAQUE 0xffffffff + +static conv *gaussianMap; + +#define WINDOW_SOLID 0 +#define WINDOW_TRANS 1 +#define WINDOW_ARGB 2 + +typedef enum _compMode { + CompSimple, /* looks like a regular X server */ + CompServerShadows, /* use window alpha for shadow; sharp, but precise */ + CompClientShadows, /* use window extents for shadow, blurred */ +} CompMode; + +static void determine_mode(Display *dpy, CMPWindow *w); + +static double get_window_opacity_value(Display *dpy, CMPWindow *w, double def); + +static unsigned int get_window_opacity_property(Display *dpy, CMPWindow *w, unsigned int def); + +static XserverRegion window_extents_region(Display *dpy, CMPWindow *w); +static XserverRegion window_border_size(Display *dpy, CMPWindow *w); + +static void wComposerDiscardEventIgnore(Display *dpy, unsigned long sequence); +static void wComposerSetEventIgnore(Display *dpy, unsigned long sequence); +static int wComposerShouldIgnoreEvent(Display *dpy, unsigned long sequence); + +static CompMode compMode = CompSimple; + +static int shadowRadius = 20; // 12; +static int shadowOffsetX = -30; // -15; +static int shadowOffsetY = -30; // -15; +static double shadowOpacity = .20; //.75; + +static Bool fadeWindows = False; +static Bool fadeTrans = False; +static double fade_in_step = 0.028; +static double fade_out_step = 0.03; +static int fade_delta = 10; +static int fade_time = 0; +static Bool excludeDockShadows = False; +static Bool autoRedirect = False; + +/* For shadow precomputation */ +static int Gsize = -1; +static unsigned char *shadowCorner = NULL; +static unsigned char *shadowTop = NULL; + +static int get_time_in_milliseconds(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +// ---------------------------------------------------------------------------------------------- +// Fading +// ---------------------------------------------------------------------------------------------- + +static CMPFade *find_fade(CMPWindow *w) +{ + CMPFade *f; + + for (f = fades; f; f = f->next) { + if (f->w == w) { + return f; + } + } + return NULL; +} + +static void dequeue_fade(Display *dpy, CMPFade *f) +{ + CMPFade **prev; + + for (prev = &fades; *prev; prev = &(*prev)->next) + if (*prev == f) { + *prev = f->next; + if (f->callback) { + (*f->callback)(dpy, f->w, f->gone); + } + free(f); + break; + } +} + +static void cleanup_fade(Display *dpy, CMPWindow *w) +{ + CMPFade *f = find_fade(w); + if (f) { + dequeue_fade(dpy, f); + } +} + +static void enqueue_fade(Display *dpy, CMPFade *f) +{ + if (!fades) { + fade_time = get_time_in_milliseconds() + fade_delta; + } + f->next = fades; + fades = f; +} + +static void set_fade(Display *dpy, CMPWindow *w, double start, double finish, double step, + void (*callback)(Display *dpy, CMPWindow *w, Bool gone), Bool gone, + Bool exec_callback, Bool override) +{ + CMPFade *f; + + f = find_fade(w); + if (!f) { + f = malloc(sizeof(CMPFade)); + f->next = NULL; + f->w = w; + f->cur = start; + enqueue_fade(dpy, f); + } else if (!override) { + return; + } else { + if (exec_callback) { + if (f->callback) { + (*f->callback)(dpy, f->w, f->gone); + } + } + } + + if (finish < 0) { + finish = 0; + } + if (finish > 1) { + finish = 1; + } + f->finish = finish; + if (f->cur < finish) { + f->step = step; + } else if (f->cur > finish) { + f->step = -step; + } + f->callback = callback; + f->gone = gone; + w->opacity = f->cur * OPAQUE; + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = window_extents_region(dpy, w); + } +} + +static int fade_timeout(void) +{ + int now; + int delta; + if (!fades) { + return -1; + } + now = get_time_in_milliseconds(); + delta = fade_time - now; + if (delta < 0) { + delta = 0; + } + return delta; +} + +static void run_fades(Display *dpy) +{ + int now = get_time_in_milliseconds(); + CMPFade *next = fades; + int steps; + Bool need_dequeue; + + if (fade_time - now > 0) + return; + steps = 1 + (now - fade_time) / fade_delta; + + while (next) { + CMPFade *f = next; + CMPWindow *w = f->w; + next = f->next; + f->cur += f->step * steps; + if (f->cur >= 1) { + f->cur = 1; + } else if (f->cur < 0) { + f->cur = 0; + } + w->opacity = f->cur * OPAQUE; + need_dequeue = False; + if (f->step > 0) { + if (f->cur >= f->finish) { + w->opacity = f->finish * OPAQUE; + need_dequeue = True; + } + } else { + if (f->cur <= f->finish) { + w->opacity = f->finish * OPAQUE; + need_dequeue = True; + } + } + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = window_extents_region(dpy, w); + } + /* Must do this last as it might destroy f->w in callbacks */ + if (need_dequeue) { + dequeue_fade(dpy, f); + } + } + fade_time = now + fade_delta; +} + +// ---------------------------------------------------------------------------------------------- +// Gaussian blur +// ---------------------------------------------------------------------------------------------- +static double gaussian(double r, double x, double y) +{ + return ((1 / (sqrt(2 * M_PI * r))) * exp((-(x * x + y * y)) / (2 * r * r))); +} + +static conv *make_gaussian_map(Display *dpy, double r) +{ + conv *c; + int size = ((int)ceil((r * 3)) + 1) & ~1; + int center = size / 2; + int x, y; + double t; + double g; + + c = malloc(sizeof(conv) + size * size * sizeof(double)); + c->size = size; + c->data = (double *)(c + 1); + t = 0.0; + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) { + g = gaussian(r, (double)(x - center), (double)(y - center)); + t += g; + c->data[y * size + x] = g; + } + for (y = 0; y < size; y++) { + for (x = 0; x < size; x++) { + c->data[y * size + x] /= t; + } + } + return c; +} + +/* + * A picture will help + * + * -center 0 width width+center + * -center +-----+-------------------+-----+ + * | | | | + * | | | | + * 0 +-----+-------------------+-----+ + * | | | | + * | | | | + * | | | | + * height +-----+-------------------+-----+ + * | | | | + * height+ | | | | + * center +-----+-------------------+-----+ + */ + +static unsigned char sum_gaussian(conv *map, double opacity, int x, int y, int width, int height) +{ + int fx, fy; + double *g_line = map->data; + int g_size = map->size; + int center = g_size / 2; + int fx_start, fx_end; + int fy_start, fy_end; + double v; + + /* + * Compute set of filter values which are "in range", + * that's the set with: + * 0 <= x + (fx-center) && x + (fx-center) < width && + * 0 <= y + (fy-center) && y + (fy-center) < height + * + * 0 <= x + (fx - center) x + fx - center < width + * center - x <= fx fx < width + center - x + */ + + fx_start = center - x; + if (fx_start < 0) { + fx_start = 0; + } + fx_end = width + center - x; + if (fx_end > g_size) { + fx_end = g_size; + } + + fy_start = center - y; + if (fy_start < 0) { + fy_start = 0; + } + fy_end = height + center - y; + if (fy_end > g_size) { + fy_end = g_size; + } + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0; + for (fy = fy_start; fy < fy_end; fy++) { + double *g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) { + v += *g_data++; + } + } + if (v > 1) { + v = 1; + } + + return ((unsigned char)(v * opacity * 255.0)); +} + +/* precompute shadow corners and sides to save time for large windows */ +static void presum_gaussian(conv *map) +{ + int center = map->size / 2; + int opacity, x, y; + + Gsize = map->size; + + if (shadowCorner) { + free(shadowCorner); + } + if (shadowTop) { + free(shadowTop); + } + + shadowCorner = malloc((Gsize + 1) * (Gsize + 1) * 26); + shadowTop = malloc((Gsize + 1) * 26); + + for (x = 0; x <= Gsize; x++) { + shadowTop[25 * (Gsize + 1) + x] = + sum_gaussian(map, 1, x - center, center, Gsize * 2, Gsize * 2); + for (opacity = 0; opacity < 25; opacity++) { + shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25; + } + for (y = 0; y <= x; y++) { + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] = + sum_gaussian(map, 1, x - center, y - center, Gsize * 2, Gsize * 2); + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] = + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; + for (opacity = 0; opacity < 25; opacity++) { + shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] = + shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] = + shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25; + } + } + } +} + +// ---------------------------------------------------------------------------------------------- +// Pictures, images and painting +// ---------------------------------------------------------------------------------------------- +static XImage *create_shadow_image(Display *dpy, double opacity, int width, int height) +{ + XImage *ximage; + unsigned char *data; + int gsize = gaussianMap->size; + int ylimit, xlimit; + int swidth = width + gsize; + int sheight = height + gsize; + int center = gsize / 2; + int x, y; + unsigned char d; + int x_diff; + int opacity_int = (int)(opacity * 25); + data = malloc(swidth * sheight * sizeof(unsigned char)); + if (!data) + return NULL; + ximage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8, ZPixmap, 0, (char *)data, + swidth, sheight, 8, swidth * sizeof(unsigned char)); + if (!ximage) { + free(data); + return NULL; + } + /* + * Build the gaussian in sections + */ + + /* + * center (fill the complete data array) + */ + if (Gsize > 0) + d = shadowTop[opacity_int * (Gsize + 1) + Gsize]; + else + d = sum_gaussian(gaussianMap, opacity, center, center, width, height); + memset(data, d, sheight * swidth); + + /* + * corners + */ + ylimit = gsize; + if (ylimit > sheight / 2) { + ylimit = (sheight + 1) / 2; + } + xlimit = gsize; + if (xlimit > swidth / 2) { + xlimit = (swidth + 1) / 2; + } + + for (y = 0; y < ylimit; y++) { + for (x = 0; x < xlimit; x++) { + if (xlimit == Gsize && ylimit == Gsize) { + d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; + } else { + d = sum_gaussian(gaussianMap, opacity, x - center, y - center, width, height); + } + data[y * swidth + x] = d; + data[(sheight - y - 1) * swidth + x] = d; + data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + /* + * top/bottom + */ + x_diff = swidth - (gsize * 2); + if (x_diff > 0 && ylimit > 0) { + for (y = 0; y < ylimit; y++) { + if (ylimit == Gsize) { + d = shadowTop[opacity_int * (Gsize + 1) + y]; + } else { + d = sum_gaussian(gaussianMap, opacity, center, y - center, width, height); + } + memset(&data[y * swidth + gsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + gsize], d, x_diff); + } + } + + /* + * sides + */ + + for (x = 0; x < xlimit; x++) { + if (xlimit == Gsize) { + d = shadowTop[opacity_int * (Gsize + 1) + x]; + } else { + d = sum_gaussian(gaussianMap, opacity, x - center, center, width, height); + } + for (y = gsize; y < sheight - gsize; y++) { + data[y * swidth + x] = d; + data[y * swidth + (swidth - x - 1)] = d; + } + } + + return ximage; +} + +static Picture create_shadow_picture(Display *dpy, double opacity, Picture alpha_pict, + int width, int height, int *wp, int *hp) +{ + XImage *shadowImage; + Pixmap shadowPixmap; + Picture shadowPicture; + GC gc; + + shadowImage = create_shadow_image(dpy, opacity, width, height); + if (!shadowImage) { + return None; + } + shadowPixmap = XCreatePixmap(dpy, root_window, shadowImage->width, shadowImage->height, 8); + if (!shadowPixmap) { + XDestroyImage(shadowImage); + return None; + } + + shadowPicture = XRenderCreatePicture(dpy, shadowPixmap, + XRenderFindStandardFormat(dpy, PictStandardA8), 0, NULL); + if (!shadowPicture) { + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + return (Picture)None; + } + + gc = XCreateGC(dpy, shadowPixmap, 0, NULL); + if (!gc) { + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + XRenderFreePicture(dpy, shadowPicture); + return (Picture)None; + } + + XPutImage(dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, shadowImage->width, + shadowImage->height); + *wp = shadowImage->width; + *hp = shadowImage->height; + XFreeGC(dpy, gc); + XDestroyImage(shadowImage); + XFreePixmap(dpy, shadowPixmap); + return shadowPicture; +} + +static Picture create_solid_picture(Display *dpy, Bool argb, double a, double r, double g, double b) +{ + Pixmap pixmap; + Picture picture; + XRenderPictureAttributes pa; + XRenderColor c; + XRenderPictFormat *pictureFormat; + + pixmap = XCreatePixmap(dpy, root_window, 1, 1, argb ? 32 : 8); + if (!pixmap) { + return None; + } + + pa.repeat = True; + pictureFormat = XRenderFindStandardFormat(dpy, argb ? PictStandardARGB32 : PictStandardA8); + picture = XRenderCreatePicture(dpy, pixmap, pictureFormat, CPRepeat, &pa); + if (!picture) { + XFreePixmap(dpy, pixmap); + return None; + } + + c.alpha = a * 0xffff; + c.red = r * 0xffff; + c.green = g * 0xffff; + c.blue = b * 0xffff; + XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + XFreePixmap(dpy, pixmap); + + return picture; +} + +static Picture root_tile_picture(Display *dpy) +{ + Picture picture; + Atom actual_type; + Pixmap pixmap = None; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop; + Bool shouldFill = False; + XRenderPictureAttributes pa; + + int result = XGetWindowProperty(dpy, root_window, XInternAtom(dpy, "_XROOTPMAP_ID", False), 0, 4, False, + AnyPropertyType, &actual_type, &actual_format, &nitems, + &bytes_after, &prop); + if (result == Success && actual_type == XInternAtom(dpy, "PIXMAP", False) && + actual_format == 32 && nitems == 1) { + memcpy(&pixmap, prop, 4); + XFree(prop); + } + + if (!pixmap) { + pixmap = XCreatePixmap(dpy, root_window, 1, 1, DefaultDepth(dpy, scr)); + shouldFill = True; + } + pa.repeat = True; + picture = XRenderCreatePicture(dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + CPRepeat, &pa); + if (shouldFill) { + XRenderColor c; + + // c.red = c.green = c.blue = 0x8080; + c.red = c.green = c.blue = 0x6363; + c.alpha = 0xffff; + XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + } + return picture; +} + +static void paint_root_window(Display *dpy) +{ + if (!root_picture_tile) { + root_picture_tile = root_tile_picture(dpy); + } + + XRenderComposite(dpy, PictOpSrc, root_picture_tile, None, root_picture_buffer, 0, 0, 0, 0, 0, 0, root_width, + root_height); +} + +static void paint_all(Display *dpy, XserverRegion region) +{ + CMPWindow *w; + CMPWindow *t = NULL; + + if (!region) { + XRectangle r; + r.x = 0; + r.y = 0; + r.width = root_width; + r.height = root_height; + region = XFixesCreateRegion(dpy, &r, 1); + } + if (!root_picture_buffer) { + Pixmap rootPixmap = XCreatePixmap(dpy, root_window, root_width, root_height, DefaultDepth(dpy, scr)); + root_picture_buffer = XRenderCreatePicture( + dpy, rootPixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), 0, NULL); + XFreePixmap(dpy, rootPixmap); + } + XFixesSetPictureClipRegion(dpy, root_picture, 0, 0, region); + for (w = list; w; w = w->next) { + /* never painted, ignore it */ + if (!w->damaged) { + continue; + } + /* if invisible, ignore it */ + if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 || w->a.x >= root_width || + w->a.y >= root_height) { + continue; + } + if (!w->picture) { + XRenderPictureAttributes pa; + XRenderPictFormat *format; + Drawable draw = w->id; + + if (has_name_pixmap && !w->pixmap) { + w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); + } + if (w->pixmap) { + draw = w->pixmap; + } + format = XRenderFindVisualFormat(dpy, w->a.visual); + pa.subwindow_mode = IncludeInferiors; + w->picture = XRenderCreatePicture(dpy, draw, format, CPSubwindowMode, &pa); + } + if (is_clip_changed) { + if (w->borderSize) { + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->borderSize); + w->borderSize = None; + } + if (w->extents) { + XFixesDestroyRegion(dpy, w->extents); + w->extents = None; + } + if (w->borderClip) { + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + } + if (!w->borderSize) { + w->borderSize = window_border_size(dpy, w); + } + if (!w->extents) { + w->extents = window_extents_region(dpy, w); + } + if (w->mode == WINDOW_SOLID) { + int x, y, wid, hei; + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, region); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XFixesSubtractRegion(dpy, region, region, w->borderSize); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpSrc, w->picture, None, root_picture_buffer, 0, 0, 0, 0, x, y, wid, hei); + } + if (!w->borderClip) { + w->borderClip = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, w->borderClip, region); + } + w->prev_trans = t; + t = w; + } + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, region); + paint_root_window(dpy); + for (w = t; w; w = w->prev_trans) { + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); + switch (compMode) { + case CompSimple: + break; + case CompServerShadows: + /* dont' bother drawing shadows on desktop windows */ + if (w->windowType == winDesktopAtom) + break; + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + if (w->opacity != OPAQUE && !w->shadowPict) + w->shadowPict = create_solid_picture(dpy, True, (double)w->opacity / OPAQUE * 0.3, 0, 0, 0); + XRenderComposite(dpy, PictOpOver, w->shadowPict ? w->shadowPict : trans_black_picture, + w->picture, root_picture_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, + w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); + break; + case CompClientShadows: + /* don't bother drawing shadows on desktop windows */ + if (w->shadow && w->windowType != winDesktopAtom) { + XRenderComposite(dpy, PictOpOver, black_picture, w->shadow, root_picture_buffer, 0, 0, 0, 0, + w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, + w->shadow_height); + } + break; + } + if (w->opacity != OPAQUE && !w->alphaPict) { + w->alphaPict = create_solid_picture(dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); + } + if (w->mode == WINDOW_TRANS) { + int x, y, wid, hei; + XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, root_picture_buffer, 0, 0, 0, 0, x, y, wid, + hei); + } else if (w->mode == WINDOW_ARGB) { + int x, y, wid, hei; + XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, w->borderClip); + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XRenderComposite(dpy, PictOpOver, w->picture, w->alphaPict, root_picture_buffer, 0, 0, 0, 0, x, y, wid, + hei); + } + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + XFixesDestroyRegion(dpy, region); + if (root_picture_buffer != root_picture) { + XFixesSetPictureClipRegion(dpy, root_picture_buffer, 0, 0, None); + XRenderComposite(dpy, PictOpSrc, root_picture_buffer, None, root_picture, 0, 0, 0, 0, 0, 0, root_width, + root_height); + } +} + +static void add_damage_region(Display *dpy, XserverRegion damage) +{ + if (allDamage) { + XFixesUnionRegion(dpy, allDamage, allDamage, damage); + XFixesDestroyRegion(dpy, damage); + } else { + allDamage = damage; + } +} + +// ---------------------------------------------------------------------------------------------- +// Windows +// ---------------------------------------------------------------------------------------------- +static CMPWindow *find_window(Display *dpy, Window id) +{ + CMPWindow *w; + + for (w = list; w; w = w->next) { + if (w->id == id) { + return w; + } + } + return NULL; +} + +static XserverRegion window_extents_region(Display *dpy, CMPWindow *w) +{ + XRectangle r; + + r.x = w->a.x; + r.y = w->a.y; + r.width = w->a.width + w->a.border_width * 2; + r.height = w->a.height + w->a.border_width * 2; + if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) { + if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) { + XRectangle sr; + + if (compMode == CompServerShadows) { + w->shadow_dx = 2; + w->shadow_dy = 7; + w->shadow_width = w->a.width; + w->shadow_height = w->a.height; + } else { + w->shadow_dx = shadowOffsetX; + w->shadow_dy = shadowOffsetY; + if (!w->shadow) { + double opacity = shadowOpacity; + if (w->mode == WINDOW_TRANS) { + opacity = opacity * ((double)w->opacity) / ((double)OPAQUE); + } + w->shadow = create_shadow_picture(dpy, opacity, w->alphaPict, w->a.width + w->a.border_width * 2, + w->a.height + w->a.border_width * 2, &w->shadow_width, + &w->shadow_height); + } + } + sr.x = w->a.x + w->shadow_dx; + sr.y = w->a.y + w->shadow_dy; + sr.width = w->shadow_width; + sr.height = w->shadow_height; + if (sr.x < r.x) { + r.width = (r.x + r.width) - sr.x; + r.x = sr.x; + } + if (sr.y < r.y) { + r.height = (r.y + r.height) - sr.y; + r.y = sr.y; + } + if (sr.x + sr.width > r.x + r.width) { + r.width = sr.x + sr.width - r.x; + } + if (sr.y + sr.height > r.y + r.height) { + r.height = sr.y + sr.height - r.y; + } + } + } + return XFixesCreateRegion(dpy, &r, 1); +} + +static XserverRegion window_border_size(Display *dpy, CMPWindow *w) +{ + XserverRegion border; + /* + * if window doesn't exist anymore, this will generate an error + * as well as not generate a region. Perhaps a better XFixes + * architecture would be to have a request that copies instead + * of creates, that way you'd just end up with an empty region + * instead of an invalid XID. + */ + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + border = XFixesCreateRegionFromWindow(dpy, w->id, WindowRegionBounding); + /* translate this */ + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XFixesTranslateRegion(dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + return border; +} + +static void repair_window(Display *dpy, CMPWindow *w) +{ + XserverRegion parts; + + if (!w->damaged) { + parts = window_extents_region(dpy, w); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, None); + } else { + parts = XFixesCreateRegion(dpy, NULL, 0); + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, parts); + XFixesTranslateRegion(dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + if (compMode == CompServerShadows) { + XserverRegion o = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, o, parts); + XFixesTranslateRegion(dpy, o, w->shadow_dx, w->shadow_dy); + XFixesUnionRegion(dpy, parts, parts, o); + XFixesDestroyRegion(dpy, o); + } + } + add_damage_region(dpy, parts); + w->damaged = 1; +} + +static void map_window(Display *dpy, Window id, unsigned long sequence, Bool doFade) +{ + CMPWindow *w = find_window(dpy, id); + + if (!w) { + return; + } + w->a.map_state = IsViewable; + + /* This needs to be here or else we lose transparency messages */ + XSelectInput(dpy, id, PropertyChangeMask); + + /* This needs to be here since we don't get PropertyNotify when unmapped */ + w->opacity = get_window_opacity_property(dpy, w, OPAQUE); + determine_mode(dpy, w); + + w->damaged = 0; + + if (doFade && fadeWindows) { + set_fade(dpy, w, 0, get_window_opacity_value(dpy, w, 1.0), fade_in_step, NULL, False, True, True); + } +} + +static void finish_unmap_window(Display *dpy, CMPWindow *w) +{ + w->damaged = 0; + if (w->extents != None) { + add_damage_region(dpy, w->extents); /* destroys region */ + w->extents = None; + } + + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + } + + if (w->picture) { + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + + /* don't care about properties anymore */ + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XSelectInput(dpy, w->id, 0); + + if (w->borderSize) { + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->borderSize); + w->borderSize = None; + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + if (w->borderClip) { + XFixesDestroyRegion(dpy, w->borderClip); + w->borderClip = None; + } + + is_clip_changed = True; +} + +static void unmap_window_callback(Display *dpy, CMPWindow *w, Bool gone) +{ + finish_unmap_window(dpy, w); +} +static void unmap_window(Display *dpy, Window id, Bool doFade) +{ + CMPWindow *w = find_window(dpy, id); + if (!w) { + return; + } + w->a.map_state = IsUnmapped; + if (w->pixmap && doFade && fadeWindows) { + set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, unmap_window_callback, False, False, + True); + } else { + finish_unmap_window(dpy, w); + } +} + +/* Get the opacity prop from window + not found: default + otherwise the value + */ +static unsigned int get_window_opacity_property(Display *dpy, CMPWindow *w, unsigned int def) +{ + Atom actual; + int format; + unsigned long n, left; + + unsigned char *data; + int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False, XA_CARDINAL, &actual, + &format, &n, &left, &data); + if (result == Success && data != NULL) { + unsigned int i; + memcpy(&i, data, sizeof(unsigned int)); + XFree((void *)data); + return i; + } + return def; +} + +/* Get the opacity property from the window in a percent format + not found: default + otherwise: the value +*/ +static double get_window_opacity_value(Display *dpy, CMPWindow *w, double def) +{ + unsigned int opacity = get_window_opacity_property(dpy, w, (unsigned int)(OPAQUE * def)); + + return opacity * 1.0 / OPAQUE; +} + +/* determine mode for window all in one place. + Future might check for menu flag and other cool things +*/ + +static void determine_mode(Display *dpy, CMPWindow *w) +{ + int mode; + XRenderPictFormat *format; + + /* if trans prop == -1 fall back on previous tests*/ + + if (w->alphaPict) { + XRenderFreePicture(dpy, w->alphaPict); + w->alphaPict = None; + } + if (w->shadowPict) { + XRenderFreePicture(dpy, w->shadowPict); + w->shadowPict = None; + } + + if (w->a.class == InputOnly) { + format = NULL; + } else { + format = XRenderFindVisualFormat(dpy, w->a.visual); + } + + if (format && format->type == PictTypeDirect && format->direct.alphaMask) { + mode = WINDOW_ARGB; + } else if (w->opacity != OPAQUE) { + mode = WINDOW_TRANS; + } else { + mode = WINDOW_SOLID; + } + w->mode = mode; + if (w->extents) { + XserverRegion damage; + damage = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, damage, w->extents); + add_damage_region(dpy, damage); + } +} + +static Atom get_window_type_property(Display *dpy, Window w) +{ + Atom actual; + int format; + unsigned long n, left; + + unsigned char *data; + int result = XGetWindowProperty(dpy, w, winTypeAtom, 0L, 1L, False, XA_ATOM, &actual, &format, &n, + &left, &data); + + if (result == Success && data != (unsigned char *)None) { + Atom a; + memcpy(&a, data, sizeof(Atom)); + XFree((void *)data); + return a; + } + return winNormalAtom; +} + +static Atom get_window_type(Display *dpy, Window window) +{ + Window root_return, parent_return; + Window *children = NULL; + unsigned int nchildren; + Atom type; + + type = get_window_type_property(dpy, window); + + if (type != winNormalAtom) + return type; + + if (!XQueryTree(dpy, window, &root_return, &parent_return, &children, &nchildren)) { + /* XQueryTree failed. */ + if (children) { + XFree((void *)children); + } + return winNormalAtom; + } + + for (unsigned int i = 0; i < nchildren; i++) { + type = get_window_type(dpy, children[i]); + if (type != winNormalAtom) { + return type; + } + } + + if (children) + XFree((void *)children); + + return winNormalAtom; +} + +static void add_window(Display *dpy, Window id, Window prev) +{ + CMPWindow *new = malloc(sizeof(CMPWindow)); + CMPWindow **p; + + if (!new) + return; + if (prev) { + for (p = &list; *p; p = &(*p)->next) { + if ((*p)->id == prev) { + break; + } + } + } else { + p = &list; + } + new->id = id; + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + if (!XGetWindowAttributes(dpy, id, &new->a)) { + free(new); + return; + } + new->shaped = False; + new->shape_bounds.x = new->a.x; + new->shape_bounds.y = new->a.y; + new->shape_bounds.width = new->a.width; + new->shape_bounds.height = new->a.height; + new->damaged = 0; + new->pixmap = None; + new->picture = None; + if (new->a.class == InputOnly) { + new->damage_sequence = 0; + new->damage = None; + } else { + new->damage_sequence = NextRequest(dpy); + new->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty); + XShapeSelectInput(dpy, id, ShapeNotifyMask); + } + new->alphaPict = None; + new->shadowPict = None; + new->borderSize = None; + new->extents = None; + new->shadow = None; + new->shadow_dx = 0; + new->shadow_dy = 0; + new->shadow_width = 0; + new->shadow_height = 0; + new->opacity = OPAQUE; + + new->borderClip = None; + new->prev_trans = NULL; + + new->windowType = get_window_type(dpy, new->id); + + new->next = *p; + *p = new; + if (new->a.map_state == IsViewable) { + map_window(dpy, id, new->damage_sequence - 1, True); + } +} + +static void restack_window(Display *dpy, CMPWindow *w, Window new_above) +{ + Window old_above; + + if (w->next) { + old_above = w->next->id; + } else { + old_above = None; + } + if (old_above != new_above) { + CMPWindow **prev; + + /* unhook */ + for (prev = &list; *prev; prev = &(*prev)->next) { + if ((*prev) == w) { + break; + } + } + *prev = w->next; + + /* rehook */ + for (prev = &list; *prev; prev = &(*prev)->next) { + if ((*prev)->id == new_above) { + break; + } + } + w->next = *prev; + *prev = w; + } +} + +static void configure_window(Display *dpy, XConfigureEvent *ce) +{ + CMPWindow *w = find_window(dpy, ce->window); + XserverRegion damage = None; + + if (!w) { + if (ce->window == root_window) { + if (root_picture_buffer) { + XRenderFreePicture(dpy, root_picture_buffer); + root_picture_buffer = None; + } + root_width = ce->width; + root_height = ce->height; + } + return; + } + damage = XFixesCreateRegion(dpy, NULL, 0); + if (w->extents != None) { + XFixesCopyRegion(dpy, damage, w->extents); + } + w->shape_bounds.x -= w->a.x; + w->shape_bounds.y -= w->a.y; + w->a.x = ce->x; + w->a.y = ce->y; + if (w->a.width != ce->width || w->a.height != ce->height) { + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + if (w->picture) { + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + } + w->a.width = ce->width; + w->a.height = ce->height; + w->a.border_width = ce->border_width; + w->a.override_redirect = ce->override_redirect; + restack_window(dpy, w, ce->above); + if (damage) { + XserverRegion extents = window_extents_region(dpy, w); + XFixesUnionRegion(dpy, damage, damage, extents); + XFixesDestroyRegion(dpy, extents); + add_damage_region(dpy, damage); + } + w->shape_bounds.x += w->a.x; + w->shape_bounds.y += w->a.y; + if (!w->shaped) { + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + is_clip_changed = True; +} + +static void circulate_windows(Display *dpy, XCirculateEvent *ce) +{ + CMPWindow *w = find_window(dpy, ce->window); + Window new_above; + + if (!w) { + return; + } + if (ce->place == PlaceOnTop) { + new_above = list->id; + } else { + new_above = None; + } + restack_window(dpy, w, new_above); + is_clip_changed = True; +} + +static void finish_destroy_window(Display *dpy, Window id, Bool gone) +{ + CMPWindow **prev, *w; + + for (prev = &list; (w = *prev); prev = &w->next) { + if (w->id == id) { + if (gone) { + finish_unmap_window(dpy, w); + } + *prev = w->next; + if (w->picture) { + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + if (w->alphaPict) { + XRenderFreePicture(dpy, w->alphaPict); + w->alphaPict = None; + } + if (w->shadowPict) { + XRenderFreePicture(dpy, w->shadowPict); + w->shadowPict = None; + } + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + } + if (w->damage != None) { + wComposerSetEventIgnore(dpy, NextRequest(dpy)); + XDamageDestroy(dpy, w->damage); + w->damage = None; + } + cleanup_fade(dpy, w); + free(w); + break; + } + } +} + +static void destroy_callback(Display *dpy, CMPWindow *w, Bool gone) +{ + finish_destroy_window(dpy, w->id, gone); +} + +static void destroy_window(Display *dpy, Window id, Bool gone, Bool doFade) +{ + CMPWindow *w = find_window(dpy, id); + if (w && w->pixmap && doFade && fadeWindows) { + set_fade(dpy, w, w->opacity * 1.0 / OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, + True); + } else { + finish_destroy_window(dpy, id, gone); + } +} + +// ---------------------------------------------------------------------------------------------- +// Events +// ---------------------------------------------------------------------------------------------- +static void wComposerDiscardEventIgnore(Display *dpy, unsigned long sequence) +{ + while (ignore_head) { + if ((long)(sequence - ignore_head->sequence) > 0) { + CMPIgnoreSequence *next = ignore_head->next; + free(ignore_head); + ignore_head = next; + if (!ignore_head) { + ignore_tail = &ignore_head; + } + } else { + break; + } + } +} + +static void wComposerSetEventIgnore(Display *dpy, unsigned long sequence) +{ + CMPIgnoreSequence *i = malloc(sizeof(CMPIgnoreSequence)); + + if (!i) { + return; + } + + i->sequence = sequence; + i->next = NULL; + *ignore_tail = i; + ignore_tail = &i->next; +} + +static int wComposerShouldIgnoreEvent(Display *dpy, unsigned long sequence) +{ + wComposerDiscardEventIgnore(dpy, sequence); + return ignore_head && ignore_head->sequence == sequence; +} + +Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev) +{ + int o; + const char *name = NULL; + static char buffer[256]; + + if (wComposerShouldIgnoreEvent(dpy, ev->serial)) { + return True; + } + + if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { + fprintf(stderr, "Another composite manager is already running\n"); + return False; + } + + o = ev->error_code - xfixes_error; + switch (o) { + case BadRegion: + name = "BadRegion"; + break; + default: + break; + } + o = ev->error_code - damage_error; + switch (o) { + case BadDamage: + name = "BadDamage"; + break; + default: + break; + } + o = ev->error_code - render_error; + switch (o) { + case BadPictFormat: + name = "BadPictFormat"; + break; + case BadPicture: + name = "BadPicture"; + break; + case BadPictOp: + name = "BadPictOp"; + break; + case BadGlyphSet: + name = "BadGlyphSet"; + break; + case BadGlyph: + name = "BadGlyph"; + break; + default: + break; + } + + if (name == NULL) { + return False; + } else { + buffer[0] = '\0'; + XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer)); + name = buffer; + + fprintf(stderr, "error %d: %s request %d minor %d serial %lu\n", ev->error_code, + (strlen(name) > 0) ? name : "unknown", ev->request_code, ev->minor_code, ev->serial); + } + + return True; +} + +static void wComposerProcessDamageEvent(Display *dpy, XDamageNotifyEvent *de) +{ + CMPWindow *w = find_window(dpy, de->drawable); + + if (!w) { + return; + } + repair_window(dpy, w); +} + +static void wComposerProcessShapeEvent(Display *dpy, XShapeEvent *se) +{ + CMPWindow *w = find_window(dpy, se->window); + + if (!w) { + return; + } + if (se->kind == ShapeClip || se->kind == ShapeBounding) { + XserverRegion region0; + XserverRegion region1; + + is_clip_changed = True; + + region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + + if (se->shaped == True) { + w->shaped = True; + w->shape_bounds.x = w->a.x + se->x; + w->shape_bounds.y = w->a.y + se->y; + w->shape_bounds.width = se->width; + w->shape_bounds.height = se->height; + } else { + w->shaped = False; + w->shape_bounds.x = w->a.x; + w->shape_bounds.y = w->a.y; + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + region1 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + XFixesUnionRegion(dpy, region0, region0, region1); + XFixesDestroyRegion(dpy, region1); + + /* ask for repaint of the old and new region */ + paint_all(dpy, region0); + } +} + +static XRectangle *expose_rects = NULL; +static int size_expose = 0; +static int n_expose = 0; +void wComposerProcessEvent(Display *dpy, XEvent ev) +{ + if (!autoRedirect) { + switch (ev.type) { + case CreateNotify: + add_window(dpy, ev.xcreatewindow.window, 0); + break; + case ConfigureNotify: + configure_window(dpy, &ev.xconfigure); + break; + case DestroyNotify: + destroy_window(dpy, ev.xdestroywindow.window, True, True); + break; + case MapNotify: + map_window(dpy, ev.xmap.window, ev.xmap.serial, True); + break; + case UnmapNotify: + unmap_window(dpy, ev.xunmap.window, True); + break; + case ReparentNotify: + if (ev.xreparent.parent == root_window) { + add_window(dpy, ev.xreparent.window, 0); + } else { + destroy_window(dpy, ev.xreparent.window, False, True); + } + break; + case CirculateNotify: + circulate_windows(dpy, &ev.xcirculate); + break; + case Expose: + if (ev.xexpose.window == root_window) { + int more = ev.xexpose.count + 1; + if (n_expose == size_expose) { + if (expose_rects) { + expose_rects = realloc(expose_rects, (size_expose + more) * sizeof(XRectangle)); + size_expose += more; + } else { + expose_rects = malloc(more * sizeof(XRectangle)); + size_expose = more; + } + } + expose_rects[n_expose].x = ev.xexpose.x; + expose_rects[n_expose].y = ev.xexpose.y; + expose_rects[n_expose].width = ev.xexpose.width; + expose_rects[n_expose].height = ev.xexpose.height; + n_expose++; + if (ev.xexpose.count == 0) { + add_damage_region(dpy, XFixesCreateRegion(dpy, expose_rects, n_expose)); + n_expose = 0; + } + } + break; + case PropertyNotify: + if (ev.xproperty.atom == XInternAtom(dpy, "_XROOTPMAP_ID", False)) { + if (root_picture_tile) { + XClearArea(dpy, root_window, 0, 0, 0, 0, True); + XRenderFreePicture(dpy, root_picture_tile); + root_picture_tile = None; + break; + } + } + /* check if Trans property was changed */ + if (ev.xproperty.atom == opacityAtom) { + /* reset mode and redraw window */ + CMPWindow *w = find_window(dpy, ev.xproperty.window); + if (w) { + if (fadeTrans) { + double start, finish, step; + start = w->opacity * 1.0 / OPAQUE; + finish = get_window_opacity_value(dpy, w, 1.0); + if (start > finish) + step = fade_in_step; + else + step = fade_out_step; + set_fade(dpy, w, start, finish, step, NULL, False, True, False); + } else { + w->opacity = get_window_opacity_property(dpy, w, OPAQUE); + determine_mode(dpy, w); + if (w->shadow) { + XRenderFreePicture(dpy, w->shadow); + w->shadow = None; + w->extents = window_extents_region(dpy, w); + } + } + } + } + break; + default: + if (ev.type == damage_event + XDamageNotify) { + wComposerProcessDamageEvent(dpy, (XDamageNotifyEvent *)&ev); + } else if (ev.type == xshape_event + ShapeNotify) { + wComposerProcessShapeEvent(dpy, (XShapeEvent *)&ev); + } + break; + } + } +} + +#include "core/log_utils.h" +void wComposerRunLoop() +{ + struct pollfd ufd; + XEvent ev; + // XRectangle *expose_rects = NULL; + // int size_expose = 0; + // int n_expose = 0; + // int p; + + WMLogError("Composer: Entering runloop with X connection: %i", ConnectionNumber(dpy)); + + ufd.fd = ConnectionNumber(dpy); + ufd.events = POLLIN; + if (!autoRedirect) { + paint_all(dpy, None); + } + + for (;;) { + do { + if (autoRedirect) { + XFlush(dpy); + } + if (!QLength(dpy)) { + if (poll(&ufd, 1, fade_timeout()) == 0) { + run_fades(dpy); + break; + } + } + XNextEvent(dpy, &ev); + if ((ev.type & 0x7f) != KeymapNotify) { + wComposerDiscardEventIgnore(dpy, ev.xany.serial); + } + wComposerProcessEvent(dpy, ev); + } while (QLength(dpy)); + + if (allDamage && !autoRedirect) { + static int paint; + paint_all(dpy, allDamage); + paint++; + XSync(dpy, False); + allDamage = None; + is_clip_changed = False; + } + } +} + +//------------------------------------------------------------------------------------------------ +// Composer intialization +//------------------------------------------------------------------------------------------------ + +static Bool wComposerRegister(Display *dpy) +{ + Window window; + Atom atom; + static char net_wm_cm[] = "_NET_WM_CM_Sxx"; + + // EWMH 1.4.draft-2 + snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", scr); + atom = XInternAtom(dpy, net_wm_cm, False); + + window = XGetSelectionOwner(dpy, atom); + if (window != None) { + XTextProperty tp; + char **strs; + int count; + Atom winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", False); + + if (!XGetTextProperty(dpy, window, &tp, winNameAtom) && !XGetTextProperty(dpy, window, &tp, XA_WM_NAME)) { + fprintf(stderr, "Another composite manager is already running (0x%lx)\n", (unsigned long)window); + return False; + } + if (XmbTextPropertyToTextList(dpy, &tp, &strs, &count) == Success) { + fprintf(stderr, "Another composite manager is already running (%s)\n", strs[0]); + + XFreeStringList(strs); + } + + XFree(tp.value); + + return False; + } + + window = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 1, 1, 0, None, None); + + Xutf8SetWMProperties(dpy, window, "Workspace Composer", "xcompmgr", NULL, 0, NULL, NULL, NULL); + + XSetSelectionOwner(dpy, atom, window, 0); + + return True; +} + +static void wComposerAtomsCreate(Display *dpy) +{ + opacityAtom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False); + winTypeAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + winDesktopAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + winDockAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + winToolbarAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); + winMenuAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False); + winUtilAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); + winSplashAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); + winDialogAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + winNormalAtom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); +} + +static Bool wComposerExtensionsCheck(Display *dpy) +{ + // int composite_major, composite_minor; + + if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { + fprintf(stderr, "No Render extension\n"); + return False; + } + if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &composite_event, + &composite_error)) { + fprintf(stderr, "No Composite extension\n"); + return False; + } + // XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + has_name_pixmap = True; + if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { + fprintf(stderr, "No Damage extension\n"); + return False; + } + if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { + fprintf(stderr, "No XFixes extension\n"); + return False; + } + if (!XShapeQueryExtension(dpy, &xshape_event, &xshape_error)) { + fprintf(stderr, "No XShape extension\n"); + return False; + } + + return True; +} + +// int compose_main(int argc, char **argv) +// { + // Specifies the time between steps in a fade in milliseconds. (default 10) + // case 'D': + // fade_delta = atoi(optarg); + // if (fade_delta < 1) { + // fade_delta = 10; + // } + // Specifies the opacity change between steps while fading in. (default 0.028) + // case 'I': + // fade_in_step = atof(optarg); + // if (fade_in_step <= 0) { + // fade_in_step = 0.01; + // } + // Specifies the opacity change between steps while fading out. (default 0.03) + // case 'O': + // fade_out_step = atof(optarg); + // if (fade_out_step <= 0) { + // fade_out_step = 0.01; + // } + // Draw server-side shadows with sharp edges. + // case 's': + // compMode = CompServerShadows; + // Draw client-side shadows with fuzzy edges. + // case 'c': + // compMode = CompClientShadows; + // Avoid drawing shadows on dock/panel windows. + // case 'C': + // excludeDockShadows = True; + // Normal client-side compositing with transparency support + // case 'n': + // compMode = CompSimple; + // Fade windows in/out when opening/closing. + // case 'f': + // fadeWindows = True; + // Fade windows during opacity changes. + // case 'F': + // fadeTrans = True; + // Use automatic server-side compositing. Faster, but no special effects. + // case 'a': + // autoRedirect = True; + // Enable synchronous operation (for debugging). + // case 'S': + // synchronize = True; + // Specifies the blur radius for client-side shadows. (default 12) + // case 'r': + // shadowRadius = atoi(optarg); + // Specifies the translucency for client-side shadows. (default .75) + // case 'o': + // shadowOpacity = atof(optarg); + // Specifies the left offset for client-side shadows. (default -15) + // case 'l': + // shadowOffsetX = atoi(optarg); + // Specifies the top offset for clinet-side shadows. (default -15) + // case 't': + // shadowOffsetY = atoi(optarg); +// } +Bool wComposerInitialize() +{ + // Display *dpy; + char *display = NULL; + Window root_return, parent_return; + Window *children; + unsigned int nchildren; + XRenderPictureAttributes pa; + + // True - CompositeRedirectAutomatic + // False - CompositeRedirectManual + autoRedirect = False; + // CompSimple - looks like a regular X server + // CompServerShadows - use window alpha for shadow; sharp, but precise + // CompClientShadows - use window extents for shadow, blurred + compMode = CompSimple; + + dpy = XOpenDisplay(display); + if (!dpy) { + fprintf(stderr, "Can't open display\n"); + return False; + } + + XSetErrorHandler(wComposerErrorHandler); + + if (should_synchronize) { + XSynchronize(dpy, 1); + } + scr = DefaultScreen(dpy); + root_window = RootWindow(dpy, scr); + + if (wComposerExtensionsCheck(dpy) == False) { + return False; + } + + if (wComposerRegister(dpy) == False) { + return False; + } + + wComposerAtomsCreate(dpy); + + pa.subwindow_mode = IncludeInferiors; + + if (compMode == CompClientShadows) { + gaussianMap = make_gaussian_map(dpy, shadowRadius); + presum_gaussian(gaussianMap); + } + + root_width = DisplayWidth(dpy, scr); + root_height = DisplayHeight(dpy, scr); + + root_picture = XRenderCreatePicture( + dpy, root_window, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), CPSubwindowMode, &pa); + black_picture = create_solid_picture(dpy, True, 1, 0, 0, 0); + if (compMode == CompServerShadows) { + trans_black_picture = create_solid_picture(dpy, True, 0.3, 0, 0, 0); + } + allDamage = None; + is_clip_changed = True; + + XGrabServer(dpy); + if (autoRedirect) { + XCompositeRedirectSubwindows(dpy, root_window, CompositeRedirectAutomatic); + } else { + XCompositeRedirectSubwindows(dpy, root_window, CompositeRedirectManual); + XSelectInput(dpy, root_window, + SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); + XShapeSelectInput(dpy, root_window, ShapeNotifyMask); + XQueryTree(dpy, root_window, &root_return, &parent_return, &children, &nchildren); + for (unsigned int i = 0; i < nchildren; i++) + add_window(dpy, children[i], i ? children[i - 1] : None); + XFree(children); + } + XUngrabServer(dpy); + + return True; +} + +void wComposerShutdown() +{ + + } diff --git a/Applications/Workspace/WM/wmcomposer.h b/Applications/Workspace/WM/wmcomposer.h new file mode 100644 index 000000000..1a678f9f6 --- /dev/null +++ b/Applications/Workspace/WM/wmcomposer.h @@ -0,0 +1,6 @@ +#include + +Bool wComposerInitialize(); +void wComposerRunLoop(); +void wComposerProcessEvent(XEvent ev); +Bool wComposerErrorHandler(Display *dpy, XErrorEvent *ev); \ No newline at end of file diff --git a/Applications/Workspace/WM/wmspec.c b/Applications/Workspace/WM/wmspec.c index 2bc2d90ff..9846c19dd 100644 --- a/Applications/Workspace/WM/wmspec.c +++ b/Applications/Workspace/WM/wmspec.c @@ -1089,7 +1089,9 @@ static int getWindowLayer(WWindow *wwin) } else if (wwin->type == net_wm_window_type_menu) { layer = NSSubmenuWindowLevel; } else if (wwin->type == net_wm_window_type_utility) { + layer = NSFloatingWindowLevel; } else if (wwin->type == net_wm_window_type_splash) { + layer = NSPopUpMenuWindowLevel; } else if (wwin->type == net_wm_window_type_dialog) { if (wwin->transient_for) { WWindow *parent = wWindowFor(wwin->transient_for); @@ -1107,7 +1109,9 @@ static int getWindowLayer(WWindow *wwin) } else if (wwin->type == net_wm_window_type_combo) { layer = NSSubmenuWindowLevel; } else if (wwin->type == net_wm_window_type_dnd) { + layer = NSPopUpMenuWindowLevel; } else if (wwin->type == net_wm_window_type_normal) { + layer = NSNormalWindowLevel; } if (wwin->client_flags.sunken && NSSunkenWindowLevel < layer) @@ -1280,6 +1284,7 @@ static Bool _getAttributesForWindowType(Atom type, WWindowAttributes *window_att window_attrs->no_miniaturizable = 1; window_attrs->no_resizebar = 1; window_attrs->no_shadeable = 1; + window_attrs->omnipresent = 1; window_attrs->skip_window_list = 1; window_attrs->skip_switchpanel = 1; window_attrs->dont_move_off = 1; diff --git a/Applications/Workspace/WMNotificationCenter.m b/Applications/Workspace/WMNotificationCenter.m index cc0334e9a..5f3a0c970 100644 --- a/Applications/Workspace/WMNotificationCenter.m +++ b/Applications/Workspace/WMNotificationCenter.m @@ -61,7 +61,7 @@ @implementation CFObject // Workspace notification center //----------------------------------------------------------------------------- -static WMNotificationCenter *_workspaceCenter = nil; +static WMNotificationCenter *_windowManagerCenter = nil; typedef enum NotificationSource { LocalNC, DistributedNC, CoreFoundationNC } NotificationSource; @@ -79,7 +79,7 @@ - (void)_postCFNotification:(NSString *)name userInfo:(NSDictionary *)info // userInfo cfUserInfo = convertNStoCFDictionary(info); - WMLogWarning("[WMNC] post CF notification: %@ - %@", cfName, cfUserInfo); + // WMLogWarning("post CF notification: %@", cfName); CFNotificationCenterPostNotification(_coreFoundationCenter, cfName, self, cfUserInfo, TRUE); @@ -103,8 +103,8 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer NSDictionary *nsUserInfo = nil; // This is the mirrored notification sent by us - if (object == _workspaceCenter) { - WMLogWarning("_handleCFNotification: Received mirrored notification from CF. Ignoring..."); + if (object == _windowManagerCenter) { + WMLogWarning("handle CF notification: Received mirrored notification from CF. Ignoring..."); return; } @@ -116,10 +116,9 @@ static void _handleCFNotification(CFNotificationCenterRef center, void *observer nsUserInfo = convertCFtoNSDictionary(userInfo); } - WMLogWarning("[WMNC] _handleCFNotificaition: dispatching CF notification %@ - %@", name, - userInfo); + WMLogWarning("handle CF notificaition: Dispatching %@ - %@", name, userInfo); - [_workspaceCenter postNotificationName:nsName object:nsObject userInfo:nsUserInfo]; + [_windowManagerCenter postNotificationName:nsName object:nsObject userInfo:nsUserInfo]; [nsObject release]; [nsUserInfo release]; @@ -142,18 +141,21 @@ - (void)_handleRemoteNotification:(NSNotification *)aNotification objectName = object; } - if ([name isEqualToString:@"NSApplicationDidResignActiveNotification"] || - [name isEqualToString:@"NSApplicationDidBecomeActiveNotification"]) { + if ([name hasPrefix:@"NSApplication"]) { NSString *appName = [aNotification userInfo][@"NSApplicationName"]; - WMLogWarning("[WMNC] %s - %s", [aNotification name].cString, appName.cString); + WMLogWarning("handle remote notification: %s - %s", [aNotification name].cString, appName.cString); } else { - WMLogWarning("[WMNC] handle remote notification: %@ - %@", convertNStoCFString(name), + WMLogWarning("handle remote notification: %@ - %@", convertNStoCFString(name), convertNStoCFString(objectName)); } - if ([name hasPrefix:@"WMShould"]) { - [self _postCFNotification:name userInfo:[aNotification userInfo]]; - } else { + // Post all notifications to CFNotificationCenter + [self _postCFNotification:name userInfo:[aNotification userInfo]]; + + // if ([name hasPrefix:@"WM"]) { + // [self _postCFNotification:name userInfo:[aNotification userInfo]]; + // } else { + if ([name hasPrefix:@"WM"] == NO) { // Examples: // NSWorkspaceWillLaunchApplicationNotification - by Controller+NSWorkspace // NSWorkspaceDidLaunchApplicationNotification - by AppKit @@ -168,10 +170,10 @@ @implementation WMNotificationCenter + (instancetype)defaultCenter { - if (!_workspaceCenter) { + if (!_windowManagerCenter) { [[WMNotificationCenter alloc] init]; } - return _workspaceCenter; + return _windowManagerCenter; } - (void)dealloc @@ -190,7 +192,7 @@ - (id)init self = [super init]; if (self != nil) { - _workspaceCenter = self; + _windowManagerCenter = self; _remoteCenter = [[NSDistributedNotificationCenter defaultCenter] retain]; @try { diff --git a/Applications/Workspace/Workspace+WM.h b/Applications/Workspace/Workspace+WM.h index b616672e4..809aa6734 100644 --- a/Applications/Workspace/Workspace+WM.h +++ b/Applications/Workspace/Workspace+WM.h @@ -42,8 +42,6 @@ extern WorkspaceExitCode ws_quit_code; //----------------------------------------------------------------------------- #ifdef __OBJC__ -#undef _ - #include #include diff --git a/Applications/Workspace/Workspace_main.m b/Applications/Workspace/Workspace_main.m index 01a2f583a..a78ec09ee 100644 --- a/Applications/Workspace/Workspace_main.m +++ b/Applications/Workspace/Workspace_main.m @@ -23,11 +23,14 @@ #import #import +#import #import "Application.h" #import "Recycler.h" #import "Workspace+WM.h" +#include "WM/wmcomposer.h" + // Global - set in WM/event.c - WMRunLoop() CFRunLoopRef wm_runloop = NULL; @@ -136,15 +139,14 @@ int main(int argc, const char **argv) fprintf(stderr, "=== Starting Workspace ===\n"); workspace_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); - - //--- Window Manager thread queue ------------------------------------- { - dispatch_queue_t wm_q; - + // DISPATCH_QUEUE_CONCURRENT is mandatory for CFRunLoop run. - wm_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_t window_manager_q = dispatch_queue_create("ns.workspace.wm", DISPATCH_QUEUE_CONCURRENT); + + //--- Initialize Window Manager fprintf(stderr, "=== Initializing Window Manager ===\n"); - dispatch_sync(wm_q, ^{ + dispatch_sync(window_manager_q, ^{ @autoreleasepool { // Restore display layout [[[OSEScreen new] autorelease] applySavedDisplayLayout]; @@ -157,11 +159,29 @@ int main(int argc, const char **argv) }); fprintf(stderr, "=== Window Manager initialized! ===\n"); + //--- Composer + NXTDefaults *defs = [[NXTDefaults alloc] initDefaultsWithPath:NSUserDomainMask + domain:@"Workspace"]; + if ([defs boolForKey:@"ComposerEnabled"] != NO) { + dispatch_queue_t composer_q = dispatch_queue_create("ns.workspace.composer", DISPATCH_QUEUE_CONCURRENT); + dispatch_async(composer_q, ^{ + fprintf(stderr, "=== Initializing Composer ===\n"); + if (wComposerInitialize() == True) { + fprintf(stderr, "=== Composer initialized ===\n"); + wComposerRunLoop(); + fprintf(stderr, "=== Composer completed it's execution ===\n"); + } else { + fprintf(stderr, "=== Failed to initialize Composer ===\n"); + } + }); + } + [defs release]; + // Start WM run loop V0 to catch events while V1 is warming up. - dispatch_async(wm_q, ^{ + dispatch_async(window_manager_q, ^{ WMRunLoop_V0(); }); - dispatch_async(wm_q, ^{ + dispatch_async(window_manager_q, ^{ WMRunLoop_V1(); }); } diff --git a/Applications/nextspace-applications.spec b/Applications/nextspace-applications.spec index bd4fb41fe..686d0efe5 100644 --- a/Applications/nextspace-applications.spec +++ b/Applications/nextspace-applications.spec @@ -24,6 +24,7 @@ BuildRequires: nextspace-frameworks-devel BuildRequires: pam-devel # Workspace BuildRequires: libcorefoundation-devel +BuildRequires: fontconfig-devel BuildRequires: giflib-devel BuildRequires: libjpeg-turbo-devel BuildRequires: libpng-devel @@ -34,7 +35,9 @@ BuildRequires: libXpm-devel BuildRequires: libXmu-devel BuildRequires: libexif-devel BuildRequires: libXfixes-devel -BuildRequires: fontconfig-devel +BuildRequires: libXcomposite-devel +BuildRequires: libXrender-devel +BuildRequires: libXdamage-devel # Requires: nextspace-frameworks Requires: libcorefoundation @@ -44,6 +47,9 @@ Requires: libXinerama Requires: libXpm Requires: libXmu Requires: libXfixes +Requires: libXcomposite +Requires: libXrender +Requires: libXdamage Requires: libexif Requires: xorg-x11-drv-evdev Requires: xorg-x11-drv-intel diff --git a/Frameworks/DesktopKit/GNUmakefile b/Frameworks/DesktopKit/GNUmakefile index bc1b08d72..58bb7f2b0 100644 --- a/Frameworks/DesktopKit/GNUmakefile +++ b/Frameworks/DesktopKit/GNUmakefile @@ -34,6 +34,7 @@ $(FRAMEWORK_NAME)_OBJC_FILES = \ NXTOpenPanel.m \ NXTHelpPanel.m \ NXTListView.m \ + NXTWorkspace.m \ \ Utilities.m @@ -60,6 +61,7 @@ $(FRAMEWORK_NAME)_HEADER_FILES = \ NXTOpenPanel.h \ NXTHelpPanel.h \ NXTListView.h \ + NXTWorkspace.h \ \ Utilities.h diff --git a/Frameworks/DesktopKit/NXTDefaults.m b/Frameworks/DesktopKit/NXTDefaults.m index 3542774c5..941777930 100644 --- a/Frameworks/DesktopKit/NXTDefaults.m +++ b/Frameworks/DesktopKit/NXTDefaults.m @@ -146,10 +146,11 @@ - (NXTDefaults *)initWithGlobalUserDefaults - (void)dealloc { - NSLog(@"[NXTDefaults] - dealloc"); [self synchronize]; - - if (syncTimer) [syncTimer release]; + + if (syncTimer) { + [syncTimer release]; + } [defaultsDict release]; [filePath release]; [syncLock release]; diff --git a/Frameworks/DesktopKit/NXTWorkspace.h b/Frameworks/DesktopKit/NXTWorkspace.h new file mode 100644 index 000000000..34b0758fe --- /dev/null +++ b/Frameworks/DesktopKit/NXTWorkspace.h @@ -0,0 +1,71 @@ +/* -*- mode: objc -*- */ +// +// Project: NEXTSPACE - DesktopKit framework +// +// Copyright (C) 2014-present Sergii Stoian +// +// This application is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This application is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this library; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +// + +#import + +/* + Notifications to communicate with applications. Manadatory prefixes in + notification names are: + - WMShould for notification from application to perform some action + - WMDid to notify application about action completion + Every WMDid should complement WMShould notification. + + All notifications object must be set to @"GSWorkspaceNotification". + Otherwise Workspace Manager will ignore this notification. +*/ +// WM.plist +extern NSString* WMDidChangeAppearanceSettingsNotification; +// WMState.plist +extern NSString* WMDidChangeDockContentNotification; + +/* + All WMShould and WMDid notifications must contain in userInfo: + "WindowID" = CFNumber; + "ApplicationName" = CFString; + */ +// Hide All +extern NSString* WMShouldHideOthersNotification; +extern NSString* WMDidHideOthersNotification; +// Quit or Force Quit +extern NSString* WMShouldTerminateApplicationNotification; +extern NSString* WMDidTerminateApplicationNotification; +// Zoom Window +/* additional userInfo element: + "ZoomType" = "Vertical" | "Horizontal" | "Maximize"; */ +extern NSString* WMShouldZoomWindowNotification; +extern NSString* WMDidZoomWindowNotification; +// Tile Window +/* additional userInfo element: + "TileDirection" = "Left" | "Right" | "Top" | "Bottom"; */ +extern NSString* WMShouldTileWindowNotification; +extern NSString* WMDidTileWindowNotification; +// Shade Window +extern NSString* WMShouldShadeWindowNotification; +extern NSString* WMDidShadeWindowNotification; +// Arrange in Front +extern NSString* WMShouldArrangeWindowsNotification; +extern NSString* WMDidArrangeWindowsNotification; +// Miniaturize Window +extern NSString* WMShouldMinmizeWindowNotification; +extern NSString* WMDidMinmizeWindowNotification; +// Close Window +extern NSString* WMShouldCloseWindowNotification; +extern NSString* WMDidCloseWindowNotification; \ No newline at end of file diff --git a/Frameworks/DesktopKit/NXTWorkspace.m b/Frameworks/DesktopKit/NXTWorkspace.m new file mode 100644 index 000000000..bbb10cadb --- /dev/null +++ b/Frameworks/DesktopKit/NXTWorkspace.m @@ -0,0 +1,51 @@ +/* -*- mode: objc -*- */ +// +// Project: NEXTSPACE - DesktopKit framework +// +// Copyright (C) 2014-present Sergii Stoian +// +// This application is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This application is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this library; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +// + +#import "NXTWorkspace.h" + +// WM.plist +NSString* WMDidChangeAppearanceSettingsNotification = @"WMDidChangeAppearanceSettingsNotification"; +// WMState.plist +NSString* WMDidChangeDockContentNotification = @"WMDidChangeDockContentNotification"; +// Hide Others +NSString* WMShouldHideOthersNotification = @"WMShouldHideOthersNotification"; +NSString* WMDidHideOthersNotification = @"WMDidHideOthersNotification"; +// Quit or Force Quit +NSString* WMShouldTerminateApplicationNotification = @"WMShouldTerminateApplicationNotification"; +NSString* WMDidTerminateApplicationNotification = @"WMDidTerminateApplicationNotification"; +// Windows -> Zoom Window +NSString* WMShouldZoomWindowNotification = @"WMShouldZoomWindowNotification"; +NSString* WMDidZoomWindowNotification = @"WMDidZoomWindowNotification"; +// Windows -> Tile Window -> Left | Right | Top | Bottom +NSString* WMShouldTileWindowNotification = @"WMShouldTileWindowNotification"; +NSString* WMDidTileWindowNotification = @"WMDidTileWindowNotification"; +// Windows -> Shade Window +NSString* WMShouldShadeWindowNotification = @"WMShouldShadeWindowNotification"; +NSString* WMDidShadeWindowNotification = @"WMDidShadeWindowNotification"; +// Windows -> Arrange in Front +NSString* WMShouldArrangeWindowsNotification = @"WMShouldArrangeWindowsNotification"; +NSString* WMDidArrangeWindowsNotification = @"WMDidArrangeWindowsNotification"; +// Windows -> Miniaturize Window +NSString * WMShouldMinmizeWindowNotification = @"WMShouldMinmizeWindowNotification"; +NSString* WMDidMinmizeWindowNotification = @"WMDidMinmizeWindowNotification"; +// Windows -> Close Window +NSString* WMShouldCloseWindowNotification = @"WMShouldCloseWindowNotification"; +NSString* WMDidCloseWindowNotification = @"WMDidCloseWindowNotification"; diff --git a/Frameworks/DesktopKit/compile_flags.txt b/Frameworks/DesktopKit/compile_flags.txt new file mode 120000 index 000000000..7a643aa9f --- /dev/null +++ b/Frameworks/DesktopKit/compile_flags.txt @@ -0,0 +1 @@ +../../compile_flags.txt \ No newline at end of file diff --git a/Frameworks/SystemKit/OSEScreen.h b/Frameworks/SystemKit/OSEScreen.h index eb66b5f94..049fe4833 100644 --- a/Frameworks/SystemKit/OSEScreen.h +++ b/Frameworks/SystemKit/OSEScreen.h @@ -71,17 +71,19 @@ @interface OSEScreen : NSObject { - Display *xDisplay; - Window xRootWindow; + @private + Display *xDisplay; + Window xRootWindow; - BOOL useAutosave; + Pixmap background_pixmap; + GC background_gc; + XGCValues background_gc_values; + id backgroundPixmapOwner; + BOOL useAutosave; NSLock *updateScreenLock; - XRRScreenResources *screen_resources; - NSMutableArray *systemDisplays; - NSSize sizeInPixels, sizeInMilimeters; } diff --git a/Frameworks/SystemKit/OSEScreen.m b/Frameworks/SystemKit/OSEScreen.m index 5e9342ff8..4f1741a6a 100644 --- a/Frameworks/SystemKit/OSEScreen.m +++ b/Frameworks/SystemKit/OSEScreen.m @@ -34,6 +34,8 @@ */ #import +#include +#include #import #import #include @@ -304,6 +306,8 @@ - (id)init } useAutosave = NO; + background_pixmap = None; + background_gc = None; // Workspace Manager notification sent as a reaction to XRRScreenChangeNotify [[NSDistributedNotificationCenter defaultCenter] @@ -327,7 +331,13 @@ - (void)dealloc [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; XRRFreeScreenResources(screen_resources); - + if (background_pixmap != None && backgroundPixmapOwner == self) { + XFree(&background_pixmap); + } + if (background_gc != None) { + XFreeGC(xDisplay, background_gc); + } + XCloseDisplay(xDisplay); [systemDisplays release]; @@ -530,6 +540,44 @@ - (BOOL)backgroundColorRed:(CGFloat *)redComponent return success; } +- (void)_setBackgroundXColor:(XColor)xColor + forXScreen:(Screen *)xScreen +{ + Atom rootpmap_id = XInternAtom(xDisplay, "_XROOTPMAP_ID", False); + + if (background_pixmap == None) { + // Try to get existing _XROOTPMAP_ID property + Atom type; + int format; + unsigned long length, after; + unsigned char *data = 0; + int result = XGetWindowProperty(xDisplay, xRootWindow, rootpmap_id, 0, 1, True, AnyPropertyType, + &type, &format, &length, &after, &data); + + if (result == Success && data && type == XA_PIXMAP && format == 32 && length == 1) { + // Do not clear out - owner may still exist (Login.app) + // XKillClient(xDisplay, *((Pixmap *)data)); + // XFree(data); + background_pixmap = *((Pixmap *)data); + } else { + background_pixmap = XCreatePixmap(xDisplay, xRootWindow, 1, 1, DefaultDepth(xDisplay, 0)); + backgroundPixmapOwner = self; + } + background_gc_values.foreground = xColor.pixel; + background_gc = XCreateGC(xDisplay, xRootWindow, GCForeground, &background_gc_values); + } + + // Set new _XROOTPMAP_ID property + if (background_pixmap != None) { + background_gc_values.foreground = xColor.pixel; + XChangeGC(xDisplay, background_gc, GCForeground, &background_gc_values); + + XFillRectangle(xDisplay, background_pixmap, background_gc, 0, 0, 1, 1); + XChangeProperty(xDisplay, xRootWindow, rootpmap_id, XA_PIXMAP, 32, PropModeReplace, + (unsigned char *)&background_pixmap, 1); + } +} + - (BOOL)setBackgroundColorRed:(CGFloat)redComponent green:(CGFloat)greenComponent blue:(CGFloat)blueComponent @@ -558,10 +606,14 @@ - (BOOL)setBackgroundColorRed:(CGFloat)redComponent x_color_spec); return NO; } - + + // Set background for non-compositor sessions XSetWindowBackground(xDisplay, xRootWindow, xColor.pixel); XClearWindow(xDisplay, xRootWindow); + // Set background for sessions with compositor + [self _setBackgroundXColor:xColor forXScreen:xScreen]; XSync(xDisplay, False); + return YES; } diff --git a/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m b/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m index abd6c156b..3550da1cb 100644 --- a/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m +++ b/Libraries/gnustep/back-art/Source/x11/XGServerWindow.m @@ -2906,7 +2906,7 @@ - (void)setwindowlevel:(int)level :(int)win { data[0] = generic._NET_WM_WINDOW_TYPE_NORMAL_ATOM; skipTaskbar = YES; } else if (level == NSMainMenuWindowLevel) { - data[0] = generic._NET_WM_WINDOW_TYPE_DOCK_ATOM; + data[0] = generic._NET_WM_WINDOW_TYPE_TOOLBAR_ATOM; skipTaskbar = YES; } else if (level == NSSubmenuWindowLevel || level == NSTornOffMenuWindowLevel) { diff --git a/README.md b/README.md index b89e3d4cf..94afcb03d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Unlike other 'real' and 'serious' projects, I have not yet defined a target audi * Porting to other Linux distributions and operating systems. For now, I want a fast, accurate, and stable version for RedHat-based Linux distributions. Currently these are CentOS 7, CentOS Stream and Fedora. However, NEXTSPACE was designed to be portable and thus this point may be changed in future. * GNOME, KDE, macOS rival in terms of visual effects, modern design principles, look and feel. * Implementing a macOS-like desktop paradigm. There is another good place for this -- see [Étoilé](http://etoileos.com). +* Creating a OpenStep 4.0 pr1-like desktop. ## Installing Installation is based off CentOS 7's minimal install, you can find [full directions in the installation guide](https://github.com/trunkmaster/nextspace/wiki/Install-Guide). diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 000000000..6e01e7ebd --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,33 @@ +-xobjective-c +-MMD +-MP +-DGNUSTEP +-DGNUSTEP_BASE_LIBRARY=1 +-DGNU_GUI_LIBRARY=1 +-DGNUSTEP_RUNTIME=1 +-D_NONFRAGILE_ABI=1 +-DGNUSTEP_BASE_LIBRARY=1 +-fno-strict-aliasing +-fexceptions +-fobjc-exceptions +-D_NATIVE_OBJC_EXCEPTIONS +-DHAVE_CONFIG_H +-DWITH_GNUSTEP +-D_XOPEN_SOURCE=600 +-D_GNU_SOURCE +-pthread +-fPIC +-DDEBUG +-fno-omit-frame-pointer +-Wall +-Wno-import +-Wno-unused-variable +-Wno-typedef-redefinition +-g +-fobjc-runtime=gnustep-2.0 +-fblocks +-fconstant-string-class=NSConstantString +-I. +-I/Users/me/Library/Headers +-I/Developer/Headers +-I/usr/NextSpace/include