diff --git a/Applications/Preferences/Modules/Expert/Expert.h b/Applications/Preferences/Modules/Expert/Expert.h index c0f10551c..15aad8274 100644 --- a/Applications/Preferences/Modules/Expert/Expert.h +++ b/Applications/Preferences/Modules/Expert/Expert.h @@ -34,6 +34,8 @@ id privateWindowServerBtn; id privateSoundServerBtn; + id permissionsView; + OSEDefaults *defaults; NSImage *image; } diff --git a/Applications/Preferences/Modules/Expert/Expert.m b/Applications/Preferences/Modules/Expert/Expert.m index e9954b66a..6cdd339c5 100644 --- a/Applications/Preferences/Modules/Expert/Expert.m +++ b/Applications/Preferences/Modules/Expert/Expert.m @@ -20,9 +20,27 @@ // #import +#import #import +#import +#import + #import "Expert.h" +#import "WMPermissions.h" + +// Global defaults key holding the file-creation umask (octal), e.g. 022. +// The value is the POSIX umask -- the complement of the permission bits +// granted to newly created files and folders. Workspace (the session +// leader) applies it with umask() at startup and again, live, whenever +// this module posts FileCreationMaskDidChangeNotification, so the setting +// takes effect immediately without re-logging in. +static NSString * const FileCreationMaskKey = @"NXFileCreationMask"; + +// Posted (distributed) when the user edits the mask so Workspace re-applies +// it to the running session. Mirrors the Font module's live-apply pattern. +static NSString * const FileCreationMaskDidChangeNotification = + @"NXFileCreationMaskDidChangeNotification"; @implementation Expert @@ -62,6 +80,57 @@ - (void)awakeFromNib selectItemWithTag:[[OSEFileManager defaultManager] sortFilesBy]]; [showHiddenFilesBtn setState:[[OSEFileManager defaultManager] isShowHiddenFiles]]; + + // The "File Creation Mask" control is a WMPermissions custom view placed + // in the NIB. It is not wired to a Gorm connection, so locate it in the + // loaded view hierarchy and finish its setup here. + permissionsView = [self permissionsViewInView:view]; + if (permissionsView != nil) { + unsigned long grantedMode; + mode_t mask; + + // Show all three permission rows (Read/Write/Execute) to match the + // Owner/Group/Others x Read/Write/Execute layout of the panel. + [permissionsView setDisplaysExecute:YES]; + [permissionsView setEditable:YES]; + [permissionsView setTarget:self]; + [permissionsView setAction:@selector(setFileCreationMask:)]; + + // Seed the matrix from the saved default; fall back to the current + // process umask when the key is absent (objectForKey: nil-check, since + // a "default present" semantics cannot be expressed with boolForKey:). + if ([defaults objectForKey:FileCreationMaskKey] != nil) { + mask = (mode_t)[defaults integerForKey:FileCreationMaskKey]; + } else { + mask = umask(0); // read current umask ... + umask(mask); // ... and restore it immediately + } + // WMPermissions displays *granted* permission bits, i.e. the complement + // of the umask, limited to the rwxrwxrwx (0777) range. + grantedMode = (~mask) & 0777; + [permissionsView setMode:grantedMode]; + } +} + +// Depth-first search for the WMPermissions view loaded from the NIB. +- (id)permissionsViewInView:(NSView *)aView +{ + NSArray *subviews = [aView subviews]; + NSUInteger i, count = [subviews count]; + + for (i = 0; i < count; i++) { + NSView *subview = [subviews objectAtIndex:i]; + id found; + + if ([subview isKindOfClass:[WMPermissions class]]) { + return subview; + } + found = [self permissionsViewInView:subview]; + if (found != nil) { + return found; + } + } + return nil; } - (NSView *)view @@ -102,5 +171,20 @@ - (void)setShowHiddenFiles:(id)sender [[OSEFileManager defaultManager] setShowHiddenFiles:[sender state]]; } +- (void)setFileCreationMask:(id)sender +{ + unsigned long grantedMode = [(WMPermissions *)sender mode] & 0777; + mode_t mask = (mode_t)((~grantedMode) & 0777); + + // Persist as the POSIX umask, then notify Workspace so it re-applies the + // mask to the running session immediately (no re-login required). + [defaults setInteger:(NSInteger)mask forKey:FileCreationMaskKey]; + [defaults synchronize]; + + [[NSDistributedNotificationCenter defaultCenter] + postNotificationName:FileCreationMaskDidChangeNotification + object:@"Preferences"]; +} + @end diff --git a/Applications/Preferences/Modules/Expert/GNUmakefile b/Applications/Preferences/Modules/Expert/GNUmakefile index 829c79f66..96224a7ab 100644 --- a/Applications/Preferences/Modules/Expert/GNUmakefile +++ b/Applications/Preferences/Modules/Expert/GNUmakefile @@ -18,7 +18,10 @@ $(BUNDLE_NAME)_HEADERS= \ $(BUNDLE_NAME)_RESOURCE_FILES = \ Resources/Expert.tiff \ - Resources/bundle.registry + Resources/bundle.registry \ + Resources/PermYes.tiff \ + Resources/PermNo.tiff \ + Resources/PermNoChange.tiff $(BUNDLE_NAME)_LANGUAGES = \ English diff --git a/Applications/Preferences/Modules/Expert/Resources/PermNo.tiff b/Applications/Preferences/Modules/Expert/Resources/PermNo.tiff new file mode 100644 index 000000000..a1e10e908 Binary files /dev/null and b/Applications/Preferences/Modules/Expert/Resources/PermNo.tiff differ diff --git a/Applications/Preferences/Modules/Expert/Resources/PermNoChange.tiff b/Applications/Preferences/Modules/Expert/Resources/PermNoChange.tiff new file mode 100644 index 000000000..4c194746a Binary files /dev/null and b/Applications/Preferences/Modules/Expert/Resources/PermNoChange.tiff differ diff --git a/Applications/Preferences/Modules/Expert/Resources/PermYes.tiff b/Applications/Preferences/Modules/Expert/Resources/PermYes.tiff new file mode 100644 index 000000000..698099aa5 Binary files /dev/null and b/Applications/Preferences/Modules/Expert/Resources/PermYes.tiff differ diff --git a/Applications/Workspace/Controller.m b/Applications/Workspace/Controller.m index 75ea4d1f0..6289ea7ba 100644 --- a/Applications/Workspace/Controller.m +++ b/Applications/Workspace/Controller.m @@ -21,9 +21,11 @@ #import #import #import +#import #import #import +#import #include #include @@ -674,6 +676,34 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notif selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp]; + + // File creation mask (umask): apply the saved value to this session leader + // now, and re-apply it live whenever the Preferences Expert module changes + // it, so the setting takes effect without re-logging in. + [self applyFileCreationMask]; + [[NSDistributedNotificationCenter defaultCenter] + addObserver:self + selector:@selector(fileCreationMaskDidChange:) + name:@"NXFileCreationMaskDidChangeNotification" + object:@"Preferences"]; +} + +// Read the saved file-creation umask from the global defaults and apply it to +// the Workspace process. Folders/files created by the File Viewer and every +// application Workspace launches afterwards inherit this umask. Already +// running applications keep the umask they inherited at their own launch. +- (void)applyFileCreationMask +{ + OSEDefaults *defs = [OSEDefaults globalUserDefaults]; + + if ([defs objectForKey:@"NXFileCreationMask"] != nil) { + umask((mode_t)[defs integerForKey:@"NXFileCreationMask"]); + } +} + +- (void)fileCreationMaskDidChange:(NSNotification *)aNotif +{ + [self applyFileCreationMask]; } - (void)applicationDidFinishLaunching:(NSNotification *)notif