This guide covers development practices for macwmfx using the new modular, import-based architecture. The system uses runtime module loading instead of compile-time feature flags, providing better separation of concerns, runtime flexibility, and cleaner code organization.
- Import-Based Loading: Features are loaded only when explicitly imported or configured
- Runtime Flexibility: Enable/disable features without recompilation
- Clean Separation: Each feature is self-contained in its own module
- Dependency Management: Automatic dependency resolution between modules
- Performance: Only load features that are actually used
src/
βββ main/ # Core orchestrator (macwmfx)
β βββ macwmfx.m # Main orchestrator
β βββ macwmfx.h # Main header
β βββ module_loader.h # Dynamic module loading
βββ modules/ # Feature modules
β βββ windows/
β β βββ WindowManager.m
β β βββ WindowManager.h
β β βββ features/
β β βββ borders/
β β β βββ WindowBorderModule.h
β β β βββ WindowBorderModule.m
β β βββ shadows/
β β βββ transparency/
β β βββ blur/
β β βββ titlebar/
β β βββ trafficLights/
β βββ dock/
β β βββ DockManager.m
β β βββ DockManager.h
β βββ menubar/
β β βββ MenubarManager.m
β β βββ MenubarManager.h
β βββ spaces/
β βββ SpacesManager.m
β βββ SpacesManager.h
βββ core/ # Shared utilities
β βββ config/
β β βββ ConfigManager.m
β β βββ ConfigManager.h
β βββ utils/
β β βββ ColorUtils.m
β β βββ WindowUtils.m
β βββ types/
β βββ macwmfx_types.h
βββ shared/ # Common libraries
βββ headers/
βββ ZKSwizzle/
Every feature module implements the macwmfx_module protocol:
@protocol macwmfx_module <NSObject>
@required
+ (NSString *)moduleName;
+ (NSString *)moduleVersion;
+ (BOOL)loadModule;
+ (void)unloadModule;
+ (BOOL)isLoaded;
@optional
+ (NSArray<NSString *> *)dependencies;
+ (NSDictionary *)defaultConfiguration;
@endModules are automatically registered using the convenience macro:
@implementation WindowBorderModule
+ (NSString *)moduleName {
return @"window.borders";
}
+ (NSString *)moduleVersion {
return @"1.0.0";
}
+ (BOOL)loadModule {
// Initialize border system
return YES;
}
+ (void)unloadModule {
// Cleanup border system
}
+ (BOOL)isLoaded {
return YES; // Track loading state
}
@end
MACWMFX_MODULE_REGISTER(WindowBorderModule)Modules can declare dependencies on other modules:
+ (NSArray<NSString *> *)dependencies {
return @[@"window.core", @"config.manager"];
}# Debug build
make debug
# Release build
make release
# Clean build
make cleanModules are loaded based on JSON configuration:
{
"window": {
"outline": {
"enabled": true,
"width": 2,
"cornerRadius": 8
},
"blur": {
"enabled": false
}
},
"dock": {
"enabled": true,
"autohide": true
}
}Only modules with "enabled": true are loaded at runtime.
-
Create module directory structure:
src/modules/windows/features/yourFeature/ βββ YourFeatureModule.h βββ YourFeatureModule.m -
Implement the module protocol:
@interface YourFeatureModule : NSObject <macwmfx_module> // Your interface @end @implementation YourFeatureModule // Implementation with MACWMFX_MODULE_REGISTER @end
-
Add to configuration schema:
{ "window": { "yourFeature": { "enabled": false, "setting1": "value1" } } } -
Register with manager:
// In WindowManager.m - (void)loadYourFeature { if ([self.moduleLoader isModuleLoaded:@"window.yourFeature"]) { YourFeatureModule *module = [YourFeatureModule sharedInstance]; [module setupFeature]; } }
// YourFeatureModule.h
@interface YourFeatureModule : NSObject <macwmfx_module>
// Module protocol methods
+ (NSString *)moduleName;
+ (NSString *)moduleVersion;
+ (BOOL)loadModule;
+ (void)unloadModule;
+ (BOOL)isLoaded;
// Feature-specific methods
- (void)setupFeature;
- (void)teardownFeature;
- (void)updateConfiguration:(NSDictionary *)config;
@end
// YourFeatureModule.m
@implementation YourFeatureModule
+ (NSString *)moduleName {
return @"window.yourFeature";
}
+ (BOOL)loadModule {
// Initialize your feature
// Set up hooks, observers, etc.
return YES;
}
+ (void)unloadModule {
// Clean up your feature
// Remove hooks, observers, etc.
}
- (void)setupFeature {
// Feature-specific setup
}
@end
MACWMFX_MODULE_REGISTER(YourFeatureModule)// Test individual module
- (void)testYourFeatureModule {
YourFeatureModule *module = [[YourFeatureModule alloc] init];
XCTAssertTrue([YourFeatureModule loadModule]);
XCTAssertTrue([YourFeatureModule isLoaded]);
[YourFeatureModule unloadModule];
}
// Test module integration
- (void)testModuleIntegration {
WindowManager *manager = [[WindowManager alloc] init];
[manager loadModulesFromConfiguration:testConfig];
XCTAssertTrue([manager isModuleLoaded:@"window.yourFeature"]);
}{
"hotload": {
"enabled": true,
"interval": 1
},
"window": {
"outline": {
"enabled": true,
"width": 2,
"cornerRadius": 8,
"colors": {
"active": "#fbf1c7",
"inactive": "#d5c4a1"
}
},
"blur": {
"enabled": false,
"radius": 10,
"passes": 1
}
},
"dock": {
"enabled": true,
"autohide": true,
"position": "bottom"
}
}Configuration changes are automatically detected and applied:
// In ConfigManager.m
- (void)startHotReload {
// Monitor config file for changes
// Automatically reload modules when config changes
}src/modules/category/features/featureName/
βββ FeatureNameModule.h # Module interface
βββ FeatureNameModule.m # Module implementation
βββ FeatureNameManager.h # Feature-specific manager (if needed)
βββ FeatureNameManager.m # Manager implementation
βββ README.md # Module documentation
- Modules:
FeatureNameModule(e.g.,WindowBorderModule) - Managers:
CategoryManager(e.g.,WindowManager) - Module names:
category.feature(e.g.,window.borders) - Files:
FeatureNameModule.h/m
// Standard import order
#import "FeatureNameModule.h"
#import "../core/config/ConfigManager.h"
#import "../shared/headers/CommonTypes.h"
#import <Cocoa/Cocoa.h>// Test individual modules
- (void)testModuleLifecycle {
XCTAssertTrue([TestModule loadModule]);
XCTAssertTrue([TestModule isLoaded]);
[TestModule unloadModule];
XCTAssertFalse([TestModule isLoaded]);
}
// Test configuration loading
- (void)testConfigurationLoading {
NSDictionary *config = @{@"feature": @{@"enabled": @YES}};
[moduleLoader loadModulesFromConfiguration:config];
XCTAssertTrue([moduleLoader isModuleLoaded:@"feature"]);
}// Test module interactions
- (void)testModuleDependencies {
[moduleLoader loadModuleWithDependencies:@"window.borders"];
XCTAssertTrue([moduleLoader isModuleLoaded:@"window.core"]);
XCTAssertTrue([moduleLoader isModuleLoaded:@"window.borders"]);
}Modules are loaded only when needed:
- (void)applyFeatureToWindow:(NSWindow *)window {
if (![self.moduleLoader isModuleLoaded:@"window.feature"]) {
return; // Skip if module not loaded
}
FeatureModule *module = [FeatureModule sharedInstance];
[module applyToWindow:window];
}+ (void)unloadModule {
// Clean up resources
[self removeObservers];
[self cleanupHooks];
[self releaseResources];
}- Follow modular architecture - Create self-contained modules
- Use dependency injection - Pass dependencies through constructors
- Implement proper lifecycle - Handle load/unload correctly
- Test thoroughly - Unit test each module
- Document clearly - Include README for each module
- Module implements
macwmfx_moduleprotocol - Proper error handling and logging
- Clean separation of concerns
- Configuration-driven behavior
- Proper resource cleanup
- Unit tests included
- Documentation updated
- Familiarize yourself with the module system
- Study existing modules for patterns
- Create small modules first to understand the system
- Test thoroughly before submitting PRs
- Ask questions if unsure about architecture
- Configuration: See
src/config/config_example.jsonfor configuration format - Module Examples: See
src/modules/windows/features/borders/for module implementation - Core System: See
src/main/for orchestrator and module loader - Build System: See
Makefilefor build options
- Core orchestrator (
macwmfx) - Module loader system
- Configuration manager
- Basic module structure
- Window feature modules
- Dock and menubar modules
- Spaces modules
- Build system updates
- Remove old feature flag system
- Update documentation
- Performance optimization
- Comprehensive testing suite
This modular architecture provides a clean, maintainable foundation for macwmfx while enabling runtime flexibility and better code organization.