├── src ├── core │ ├── utils │ │ ├── frida-tracer.py │ │ ├── Icon.icns │ │ ├── Info.plist │ │ ├── SymRezUtils.h │ │ ├── generate_shadow_image.py │ │ └── SymRezUtils.m │ └── config │ │ └── ConfigManager.h ├── shared │ ├── headers │ │ ├── configParser.h │ │ └── macwmfx_globals.h │ ├── macwmfx_logging.m │ ├── macwmfx_logging.h │ └── ZKSwizzle │ │ └── ZKSwizzle.h ├── SymRez │ ├── module.modulemap │ ├── SymRez.h │ ├── Base.h │ ├── Package.swift │ ├── README.md │ ├── SymRez.hpp │ └── Core.h ├── modules │ ├── menubar │ │ └── features │ │ │ ├── ribbonbar │ │ │ ├── RibbonBarShared.h │ │ │ ├── RibbonBar.h │ │ │ ├── RibbonBar.m │ │ │ └── HookUtil.m │ │ │ └── NoMenubar.m │ ├── spaces │ │ └── features │ │ │ ├── SpacesBehavior.m │ │ │ ├── DisableSpaces.m │ │ │ ├── RenameSpaces.m │ │ │ └── InstantFullscreenTransition.m │ ├── dock │ │ └── features │ │ │ └── DisableDock.m │ ├── windows │ │ ├── features │ │ │ ├── windowShadow │ │ │ │ ├── ShadowColor.mm │ │ │ │ └── DisableWindowShadow.m │ │ │ ├── windowBehavior │ │ │ │ ├── AlwaysOnTopController.m │ │ │ │ └── GoodbyeForGood.m │ │ │ ├── windowAnimations │ │ │ │ └── windowRotation.m │ │ │ ├── borders │ │ │ │ ├── WindowBorderModule.h │ │ │ │ └── WindowBorderModule.m │ │ │ ├── windowMaskShapes │ │ │ │ └── WindowStar.m │ │ │ ├── windowTrafficLights │ │ │ │ └── disableTrafficLights.m │ │ │ ├── windowTransparency │ │ │ │ └── OpacityController.m │ │ │ ├── window_example.m │ │ │ ├── windowSizeContraints │ │ │ │ └── DisableResizeConstraints.m │ │ │ ├── windowOutline │ │ │ │ ├── WindowBordersCenterline.m │ │ │ │ ├── WindowBordersOutline.mm │ │ │ │ ├── WindowBordersInline.mm │ │ │ │ └── DisableWindowCornerRadiusMask.m │ │ │ ├── windowTitlebar │ │ │ │ ├── ForceCustomTitle.m │ │ │ │ ├── ForceClassicTitlebars.m │ │ │ │ ├── TitlebarAesthetics.m │ │ │ │ └── DisableTitleBars.m │ │ │ └── windowBlur │ │ │ │ └── BlurController.m │ │ └── WindowManager.h │ └── objc_hook.m ├── config │ ├── defineGlobals.m │ └── config_example.json ├── main │ ├── macwmfx.h │ ├── module_loader.h │ ├── macwmfx.m │ └── module_loader.m ├── client │ ├── macwmfx_client.h │ └── macwmfx_client.m └── server │ └── macwmfx_server.h ├── Preview.png ├── .gitattributes ├── .gitignore ├── .github └── FUNDING.yml ├── LICENSE ├── libmacwmfx.dylib.blacklist ├── libmacwmfx_server.dylib.blacklist ├── AppleGraphicsInternals.md ├── LOGGING_TRANSITION.md └── README.md /src/core/utils/frida-tracer.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aspauldingcode/macwmfx/HEAD/Preview.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/shared/headers/configParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "macwmfx_globals.h" -------------------------------------------------------------------------------- /src/SymRez/module.modulemap: -------------------------------------------------------------------------------- 1 | module SymRez [system] { 2 | header "SymRez.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /src/core/utils/Icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aspauldingcode/macwmfx/HEAD/src/core/utils/Icon.icns -------------------------------------------------------------------------------- /src/modules/menubar/features/ribbonbar/RibbonBarShared.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ContextualMenuButton : NSButton 4 | @property (retain) NSMenu *associatedMenu; 5 | - (void)displayAssociatedMenu:(id)sender; 6 | @end 7 | -------------------------------------------------------------------------------- /src/modules/spaces/features/SpacesBehavior.m: -------------------------------------------------------------------------------- 1 | // Changes behavior of spaces on macOS. 2 | 3 | #import 4 | #import "../headers/macwmfx_globals.h" 5 | 6 | // @interface SpacesBehavior : NSObject 7 | 8 | // @end 9 | 10 | // @implementation SpacesBehavior 11 | 12 | // @end -------------------------------------------------------------------------------- /src/modules/spaces/features/DisableSpaces.m: -------------------------------------------------------------------------------- 1 | // Disables macOS workspaces. Not really useful. 2 | 3 | #import 4 | #import "../headers/macwmfx_globals.h" 5 | 6 | // @interface DisableSpaces : NSObject 7 | 8 | // @end 9 | 10 | // @implementation DisableSpaces 11 | 12 | // @end -------------------------------------------------------------------------------- /src/modules/spaces/features/RenameSpaces.m: -------------------------------------------------------------------------------- 1 | // This file renames the spaces to the names specified in the config file 2 | 3 | #import 4 | #import "../headers/macwmfx_globals.h" 5 | 6 | // @interface RenameSpaces : NSObject 7 | 8 | // @end 9 | 10 | // @implementation RenameSpaces 11 | 12 | // @end -------------------------------------------------------------------------------- /src/modules/dock/features/DisableDock.m: -------------------------------------------------------------------------------- 1 | // Disable Dock only hides the dock since macOS requires it for core functionality 2 | 3 | #import 4 | #import "../headers/macwmfx_globals.h" 5 | 6 | // @interface DisableDock : NSObject 7 | 8 | // @end 9 | 10 | // @implementation DisableDock 11 | 12 | // @end 13 | -------------------------------------------------------------------------------- /src/SymRez/SymRez.h: -------------------------------------------------------------------------------- 1 | // 2 | // SymRez.h 3 | // SymRez 4 | // 5 | // Created by Jeremy Legendre on 4/14/20. 6 | // Copyright © 2020 Jeremy Legendre. All rights reserved. 7 | // 8 | 9 | #ifndef SymRez_h 10 | #define SymRez_h 11 | 12 | #include 13 | #include 14 | #include "Base.h" 15 | #include "Core.h" 16 | #include "SymRez.hpp" 17 | 18 | #endif /* SymRez_h */ 19 | -------------------------------------------------------------------------------- /src/modules/spaces/features/InstantFullscreenTransition.m: -------------------------------------------------------------------------------- 1 | // 2 | // InstantFullscreenTransition.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../headers/macwmfx_globals.h" 11 | 12 | // @interface InstantFullscreenTransition : NSObject 13 | 14 | // @end 15 | 16 | // @implementation InstantFullscreenTransition 17 | 18 | // @end -------------------------------------------------------------------------------- /src/core/utils/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.aspauldingcode.macwmfx 7 | CFBundleName 8 | macwmfx 9 | CFBundleVersion 10 | 1.0.0 11 | CFBundleShortVersionString 12 | 1.0.0 13 | CFBundlePackageType 14 | DYLIB 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowShadow/ShadowColor.mm: -------------------------------------------------------------------------------- 1 | // // 2 | // // ShadowColor.mm 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | #include "macwmfx_globals.h" 14 | #include 15 | #include 16 | 17 | // Global shadow config 18 | extern ShadowConfig gShadowConfig; 19 | CFDictionaryRef (*OriginalShadowDataFunc)(int windowID); 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Makefile outputs 2 | build/ 3 | 4 | # Nix build outputs 5 | result* 6 | .direnv/ 7 | 8 | # C/C++ Language Server Cache 9 | .ccls-cache/ 10 | .ccls-cache/@* 11 | 12 | # macOS system files 13 | .DS_Store 14 | **/.DS_Store 15 | 16 | # Log files and temporary outputs 17 | *.log 18 | *.info 19 | *_output.log 20 | *_classdump.log 21 | windowserver.info 22 | test_output.log 23 | 24 | # IDE and editor files 25 | .vscode/ 26 | .idea/ 27 | *.swp 28 | *.swo 29 | *~ 30 | 31 | # Xcode build files 32 | DerivedData/ 33 | *.xcuserstate 34 | *.xcuserdatad 35 | 36 | # Compiled object files 37 | *.o 38 | *.obj 39 | *.so 40 | *.dylib 41 | *.a 42 | 43 | # Debug symbols 44 | *.dSYM/ 45 | -------------------------------------------------------------------------------- /src/SymRez/Base.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYMREZ_BASE__ 2 | #define __SYMREZ_BASE__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if __has_feature(nullability) 9 | #define SR_NULLABLE _Nullable 10 | #define SR_NONNULL _Nonnull 11 | #else 12 | #define SR_NULLABLE 13 | #define SR_NONNULL 14 | #endif 15 | 16 | #ifndef SR_INLINE 17 | #define SR_INLINE OS_INLINE OS_ALWAYS_INLINE 18 | #endif 19 | 20 | typedef const struct mach_header_64* mach_header_t; 21 | typedef struct symrez* symrez_t; 22 | typedef struct sr_iterator* sr_iterator_t; 23 | typedef struct sr_iter_result * SR_NULLABLE sr_iter_result_t; 24 | typedef void * SR_NULLABLE sr_ptr_t; 25 | typedef char* sr_symbol_t; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/modules/menubar/features/ribbonbar/RibbonBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // RibbonBar.h 3 | // RibbonBar 4 | // 5 | // Created by bedtime on 5/17/25. 6 | // 7 | 8 | #ifndef RibbonBar_h 9 | #define RibbonBar_h 10 | 11 | #import 12 | 13 | extern void * gHook; 14 | 15 | typedef void (*GumInterceptorReplaceFuncType)(void *, void *, void *, void *, void * *); 16 | typedef void (*GumInterceptorBeginTransactionFuncType)(void *); 17 | typedef void (*GumInterceptorEndTransactionFuncType)(void *); 18 | 19 | extern GumInterceptorReplaceFuncType GumInterceptorReplaceFunc; 20 | extern GumInterceptorBeginTransactionFuncType GumInterceptorBeginTransactionFunc; 21 | extern GumInterceptorEndTransactionFuncType GumInterceptorEndTransactionFunc; 22 | 23 | #endif /* RibbonBar_h */ 24 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowBehavior/AlwaysOnTopController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlwaysOnTopController.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "macwmfx_globals.h" 10 | 11 | // @interface AlwaysOnTopController : NSObject 12 | // @end 13 | 14 | // @implementation AlwaysOnTopController 15 | 16 | // // + (void)load { 17 | // // // Nothing needed here since we just want the swizzle 18 | // // } 19 | 20 | // @end 21 | 22 | // ZKSwizzleInterface(BS_NSWindow_AlwaysOnTop, NSWindow, NSWindow) 23 | 24 | // @implementation BS_NSWindow_AlwaysOnTop 25 | 26 | // - (void)makeKeyAndOrderFront:(id)sender { 27 | // ZKOrig(void, sender); 28 | 29 | // NSWindow *window = (NSWindow *)self; 30 | // window.level = NSFloatingWindowLevel; // Set window to float above others 31 | // } 32 | 33 | // @end 34 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowAnimations/windowRotation.m: -------------------------------------------------------------------------------- 1 | // #import "../../headers/macwmfx_globals.h" 2 | // #import 3 | // #import 4 | 5 | // ZKSwizzleInterface(BS_NSWindow_Spin, NSWindow, NSWindow) 6 | 7 | // @implementation BS_NSWindow_Spin 8 | 9 | // - (void)makeKeyAndOrderFront:(id)sender { 10 | // ZKOrig(void, sender); 11 | 12 | // NSView *windowFrame = self.contentView.superview; 13 | // windowFrame.wantsLayer = YES; 14 | 15 | // CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 16 | // spinAnimation.fromValue = @(0.0); 17 | // spinAnimation.toValue = @(2 * M_PI); 18 | // spinAnimation.duration = 2.0; 19 | // spinAnimation.repeatCount = HUGE_VALF; 20 | 21 | // windowFrame.layer.anchorPoint = CGPointMake(0.5, 0.5); 22 | // [windowFrame.layer addAnimation:spinAnimation forKey:@"spinAnimation"]; 23 | // } 24 | 25 | // @end 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: aspauldingcode # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Alex (aspauldingcode) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/SymRez/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SymRez", 8 | platforms: [ 9 | .macOS(.v10_10), 10 | ], 11 | products: [ 12 | .library( 13 | name: "SymRez", 14 | targets: ["SymRez"]), 15 | ], 16 | targets: [ 17 | .target( 18 | name: "SymRez", 19 | dependencies: [], 20 | path: ".", 21 | exclude: ["README.md", "Tests"], 22 | publicHeadersPath: ".", 23 | cSettings: [ 24 | .headerSearchPath("."), 25 | .unsafeFlags(["-Os", 26 | "-momit-leaf-frame-pointer", 27 | "-foptimize-sibling-calls", 28 | "-fno-stack-protector", 29 | "-fno-stack-check"], 30 | .when(configuration: .release)), 31 | ] 32 | ), 33 | .testTarget( 34 | name: "SymRezTests", 35 | dependencies: ["SymRez"], 36 | path: "Tests"), 37 | ], 38 | cLanguageStandard: .c17, 39 | cxxLanguageStandard: .cxx17 40 | ) 41 | -------------------------------------------------------------------------------- /src/modules/windows/features/borders/WindowBorderModule.h: -------------------------------------------------------------------------------- 1 | // 2 | // WindowBorderModule.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "main/module_loader.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /** 16 | * Window Border Module 17 | * 18 | * Handles window border customization including: 19 | * - Border width and corner radius 20 | * - Custom colors for active/inactive/stacked states 21 | * - Border type (inline, outline, etc.) 22 | */ 23 | @interface WindowBorderModule : NSObject 24 | 25 | // Configuration properties 26 | @property (nonatomic, assign) BOOL enabled; 27 | @property (nonatomic, assign) float width; 28 | @property (nonatomic, assign) float cornerRadius; 29 | @property (nonatomic, strong, nullable) NSColor *customColor; 30 | 31 | // Border type 32 | @property (nonatomic, assign) NSInteger borderType; // 0 = inline, 1 = outline 33 | 34 | // Singleton access 35 | + (instancetype)sharedInstance; 36 | 37 | // Window management 38 | - (void)updateWindow:(NSWindow *)window; 39 | - (void)updateAllWindows; 40 | 41 | // Configuration 42 | - (void)loadConfiguration; 43 | - (void)saveConfiguration; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /src/modules/menubar/features/NoMenubar.m: -------------------------------------------------------------------------------- 1 | // // 2 | // // NoMenubar.m 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | // #import "../headers/macwmfx_globals.h" 10 | 11 | // ZKSwizzleInterface(BS_NSMenu_NoMenubar, NSMenu, NSMenu) 12 | 13 | // @implementation BS_NSMenu_NoMenubar 14 | 15 | // - (void)setMenuBarVisible:(BOOL)visible { 16 | // // Always set menubar to invisible 17 | // ZKOrig(void, NO); 18 | // } 19 | 20 | // - (BOOL)menuBarVisible { 21 | // // Always return NO to indicate menubar is not visible 22 | // return NO; 23 | // } 24 | 25 | // @end 26 | 27 | // ZKSwizzleInterface(BS_NSApplication_NoMenubar, NSApplication, NSApplication) 28 | 29 | // @implementation BS_NSApplication_NoMenubar 30 | 31 | // - (void)setPresentationOptions:(NSApplicationPresentationOptions)options { 32 | // // Add the auto-hide menu bar option to whatever options are being set 33 | // options |= NSApplicationPresentationAutoHideMenuBar; 34 | // ZKOrig(void, options); 35 | // } 36 | 37 | // - (NSApplicationPresentationOptions)presentationOptions { 38 | // // Add auto-hide menu bar to the current presentation options 39 | // NSApplicationPresentationOptions options = ZKOrig(NSApplicationPresentationOptions); 40 | // return options | NSApplicationPresentationAutoHideMenuBar; 41 | // } 42 | 43 | // @end 44 | -------------------------------------------------------------------------------- /src/shared/macwmfx_logging.m: -------------------------------------------------------------------------------- 1 | #import "macwmfx_logging.h" 2 | 3 | // Define the logging categories 4 | os_log_t macwmfx_log_server; 5 | os_log_t macwmfx_log_client; 6 | os_log_t macwmfx_log_config; 7 | os_log_t macwmfx_log_window; 8 | os_log_t macwmfx_log_hook; 9 | os_log_t macwmfx_log_cli; 10 | os_log_t macwmfx_log_general; 11 | os_log_t macwmfx_log_titlebar; 12 | os_log_t macwmfx_log_traffic_lights; 13 | os_log_t macwmfx_log_shadow; 14 | os_log_t macwmfx_log_outline; 15 | 16 | void macwmfx_logging_init(void) { 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | // Initialize all logging categories 20 | macwmfx_log_server = os_log_create(MACWMFX_SUBSYSTEM, "server"); 21 | macwmfx_log_client = os_log_create(MACWMFX_SUBSYSTEM, "client"); 22 | macwmfx_log_config = os_log_create(MACWMFX_SUBSYSTEM, "config"); 23 | macwmfx_log_window = os_log_create(MACWMFX_SUBSYSTEM, "window"); 24 | macwmfx_log_hook = os_log_create(MACWMFX_SUBSYSTEM, "hook"); 25 | macwmfx_log_cli = os_log_create(MACWMFX_SUBSYSTEM, "cli"); 26 | macwmfx_log_general = os_log_create(MACWMFX_SUBSYSTEM, "general"); 27 | macwmfx_log_titlebar = os_log_create(MACWMFX_SUBSYSTEM, "titlebar"); 28 | macwmfx_log_traffic_lights = os_log_create(MACWMFX_SUBSYSTEM, "traffic_lights"); 29 | macwmfx_log_shadow = os_log_create(MACWMFX_SUBSYSTEM, "shadow"); 30 | macwmfx_log_outline = os_log_create(MACWMFX_SUBSYSTEM, "outline"); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/config/defineGlobals.m: -------------------------------------------------------------------------------- 1 | // 2 | // defineGlobals.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../headers/macwmfx_globals.h" 11 | 12 | // Global Configuration Variables 13 | BOOL gIsEnabled = YES; 14 | HotloadConfig gHotloadConfig = {NO, 1}; // Disabled by default, 1 second interval 15 | BlurConfig gBlurConfig = {NO, 20, 20.0}; 16 | TitlebarConfig gTitlebarConfig = {0}; 17 | CustomTitleConfig gCustomTitleConfig = {0}; 18 | TrafficLightsConfig gTrafficLightsConfig = { 19 | .enabled = NO, 20 | .style = nil, 21 | .shape = nil, 22 | .order = nil, 23 | .position = nil, 24 | .size = 0, 25 | .padding = 0, 26 | .customColor = { 27 | .enabled = NO, 28 | .active = { 29 | .stop = nil, 30 | .yield = nil, 31 | .go = nil 32 | }, 33 | .inactive = { 34 | .stop = nil, 35 | .yield = nil, 36 | .go = nil 37 | }, 38 | .hover = { 39 | .stop = nil, 40 | .yield = nil, 41 | .go = nil 42 | } 43 | } 44 | }; 45 | ShadowConfig gShadowConfig = {0}; 46 | WindowSizeConstraintsConfig gWindowSizeConstraintsConfig = {0}; 47 | OutlineConfig gOutlineConfig = {0}; 48 | TransparencyConfig gTransparencyConfig = {0}; 49 | SystemColorConfig gSystemColorConfig = {0}; 50 | 51 | // CLI flag 52 | BOOL gRunningFromCLI = NO; 53 | -------------------------------------------------------------------------------- /src/shared/macwmfx_logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Logging subsystem and categories 6 | #define MACWMFX_SUBSYSTEM "com.aspauldingcode.macwmfx" 7 | 8 | // Global logging categories 9 | extern os_log_t macwmfx_log_server; 10 | extern os_log_t macwmfx_log_client; 11 | extern os_log_t macwmfx_log_config; 12 | extern os_log_t macwmfx_log_window; 13 | extern os_log_t macwmfx_log_hook; 14 | extern os_log_t macwmfx_log_cli; 15 | extern os_log_t macwmfx_log_general; 16 | extern os_log_t macwmfx_log_titlebar; 17 | extern os_log_t macwmfx_log_traffic_lights; 18 | extern os_log_t macwmfx_log_shadow; 19 | extern os_log_t macwmfx_log_outline; 20 | 21 | // Convenience macros for common log levels 22 | #define MACWMFX_LOG_INFO(category, ...) os_log_info(category, __VA_ARGS__) 23 | #define MACWMFX_LOG_ERROR(category, ...) os_log_error(category, __VA_ARGS__) 24 | #define MACWMFX_LOG_DEBUG(category, ...) os_log_debug(category, __VA_ARGS__) 25 | #define MACWMFX_LOG_FAULT(category, ...) os_log_fault(category, __VA_ARGS__) 26 | #define MACWMFX_LOG_WARNING(category, ...) os_log(category, __VA_ARGS__) 27 | #define MACWMFX_LOG(category, ...) os_log(category, __VA_ARGS__) 28 | 29 | // Legacy macros for backward compatibility - these will use os_log 30 | #ifdef MACWMFX_DEBUG 31 | #define DLog(...) MACWMFX_LOG_INFO(macwmfx_log_general, __VA_ARGS__) 32 | #define VLog(...) MACWMFX_LOG_DEBUG(macwmfx_log_general, __VA_ARGS__) 33 | #else 34 | #define DLog(...) do {} while(0) 35 | #define VLog(...) do {} while(0) 36 | #endif 37 | 38 | // Initialize logging - should be called once at startup 39 | void macwmfx_logging_init(void); 40 | -------------------------------------------------------------------------------- /src/modules/menubar/features/ribbonbar/RibbonBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // RibbonBar.m 3 | // RibbonBar 4 | // 5 | // Created by bedtime on 5/17/25. 6 | // 7 | 8 | #import "RibbonBar.h" 9 | #import "RibbonBarShared.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #import "NSThemeFrame.h" 20 | 21 | #define kRibbonInset 5.0 22 | #define kRibbonHeight 22.0 23 | #define kRibbonPadding 10.0 24 | 25 | // Extern declarations for ribbon bar symbols implemented in macwmfx_server.m 26 | extern void DisplayMenuAsContextual(NSMenu *menu, NSView *view, NSPoint location); 27 | extern CGFloat FindVisualEffectViewSecondOrHighestX(NSView *parentView); 28 | extern void ForceTitlebar(id self, SEL _cmd, NSWindowStyleMask style); 29 | extern NSView* TitlebarContainerView(NSView *self, SEL _cmd); 30 | 31 | void (*_ForceTitlebarOld)(id self, SEL _cmd, NSWindowStyleMask styleMask); 32 | NSView * (*_TitlebarContainerViewOld)(id self, SEL _cmd); 33 | 34 | // Remove the implementations of these functions - they are now in macwmfx_server.m 35 | // Only keep the function pointer declarations above 36 | 37 | void * gHook; 38 | 39 | GumInterceptorReplaceFuncType GumInterceptorReplaceFunc; 40 | GumInterceptorBeginTransactionFuncType GumInterceptorBeginTransactionFunc; 41 | GumInterceptorEndTransactionFuncType GumInterceptorEndTransactionFunc; 42 | 43 | extern 44 | void AddHook(Class class, SEL originalSelector, SEL swizzledSelector, IMP implementation, Method *originalMethodStorage, BOOL isClassMethod); 45 | -------------------------------------------------------------------------------- /src/modules/windows/WindowManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // WindowManager.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @class ConfigManager; 15 | 16 | /** 17 | * WindowManager - Manages all window-related features 18 | * 19 | * This class coordinates all window modifications including: 20 | * - Window borders and outlines 21 | * - Window shadows 22 | * - Window transparency 23 | * - Window blur effects 24 | * - Titlebar modifications 25 | * - Traffic light customization 26 | * - Size constraints 27 | */ 28 | @interface WindowManager : NSObject 29 | 30 | // Initialization 31 | - (instancetype)initWithConfigManager:(ConfigManager *)configManager; 32 | 33 | // Lifecycle management 34 | - (void)start; 35 | - (void)stop; 36 | - (void)reloadConfiguration; 37 | 38 | // Feature control 39 | - (void)enableFeature:(NSString *)featureName; 40 | - (void)disableFeature:(NSString *)featureName; 41 | - (BOOL)isFeatureEnabled:(NSString *)featureName; 42 | 43 | // Window management 44 | - (void)updateWindow:(NSWindow *)window; 45 | - (void)updateAllWindows; 46 | - (void)handleWindowUpdate:(NSNotification *)notification; 47 | 48 | // Feature-specific methods 49 | - (void)applyBorderToWindow:(NSWindow *)window; 50 | - (void)applyShadowToWindow:(NSWindow *)window; 51 | - (void)applyTransparencyToWindow:(NSWindow *)window; 52 | - (void)applyBlurToWindow:(NSWindow *)window; 53 | - (void)modifyTitlebarForWindow:(NSWindow *)window; 54 | - (void)modifyTrafficLightsForWindow:(NSWindow *)window; 55 | 56 | // Configuration access 57 | - (NSDictionary *)getWindowConfiguration; 58 | - (id)getWindowValueForKey:(NSString *)key; 59 | 60 | @end 61 | 62 | NS_ASSUME_NONNULL_END 63 | -------------------------------------------------------------------------------- /src/core/utils/SymRezUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // SymRezUtils.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../../SymRez/SymRez.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** 15 | * SymRezUtils - Utility functions for SymRez integration 16 | * 17 | * Provides convenient wrappers around SymRez functionality for 18 | * resolving private symbols and accessing internal macOS APIs. 19 | */ 20 | @interface SymRezUtils : NSObject 21 | 22 | // Framework symbol resolution 23 | + (void * _Nullable)resolveSymbol:(const char *)symbolName inFramework:(const char *)frameworkName; 24 | + (void * _Nullable)resolveSymbol:(const char *)symbolName inImage:(const char *)imageName; 25 | 26 | // System framework shortcuts 27 | + (void * _Nullable)resolveSymbolInAppKit:(const char *)symbolName; 28 | + (void * _Nullable)resolveSymbolInCoreGraphics:(const char *)symbolName; 29 | + (void * _Nullable)resolveSymbolInQuartzCore:(const char *)symbolName; 30 | 31 | // Global variable access 32 | + (void * _Nullable)resolveGlobalVariable:(const char *)variableName inFramework:(const char *)frameworkName; 33 | 34 | // Utility methods 35 | + (BOOL)isSymbolAvailable:(const char *)symbolName inFramework:(const char *)frameworkName; 36 | + (NSArray *)listSymbolsInFramework:(const char *)frameworkName; 37 | 38 | @end 39 | 40 | // Convenience macros 41 | #define SYMREZ_RESOLVE(framework, symbol) [SymRezUtils resolveSymbol:symbol inFramework:framework] 42 | #define SYMREZ_APPKIT(symbol) [SymRezUtils resolveSymbolInAppKit:symbol] 43 | #define SYMREZ_COREGRAPHICS(symbol) [SymRezUtils resolveSymbolInCoreGraphics:symbol] 44 | #define SYMREZ_QUARTZCORE(symbol) [SymRezUtils resolveSymbolInQuartzCore:symbol] 45 | 46 | NS_ASSUME_NONNULL_END 47 | -------------------------------------------------------------------------------- /src/core/config/ConfigManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigManager.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /** 14 | * ConfigManager - Centralized configuration management 15 | * 16 | * This class handles all configuration loading, parsing, and hot-reloading 17 | * for the macwmfx system. It replaces the old ConfigParser with a cleaner 18 | * interface and better separation of concerns. 19 | */ 20 | @interface ConfigManager : NSObject 21 | 22 | // Configuration access 23 | @property (nonatomic, strong, readonly) NSDictionary *configuration; 24 | @property (nonatomic, strong, readonly) NSString *configPath; 25 | 26 | // Hot-reload support 27 | @property (nonatomic, assign) BOOL hotReloadEnabled; 28 | @property (nonatomic, assign) NSTimeInterval hotReloadInterval; 29 | 30 | // Initialization 31 | - (instancetype)init; 32 | - (instancetype)initWithConfigPath:(NSString *)configPath; 33 | 34 | // Configuration loading 35 | - (BOOL)loadConfiguration; 36 | - (BOOL)loadConfigurationFromPath:(NSString *)path; 37 | - (BOOL)saveConfiguration:(NSDictionary *)config; 38 | 39 | // Configuration access 40 | - (NSDictionary *)getConfiguration; 41 | - (id)getValueForKey:(NSString *)key; 42 | - (id)getValueForKeyPath:(NSString *)keyPath; 43 | 44 | // Hot-reload management 45 | - (void)startHotReload; 46 | - (void)stopHotReload; 47 | - (void)setHotReloadCallback:(void (^)(NSDictionary *newConfig))callback; 48 | 49 | // Configuration validation 50 | - (BOOL)validateConfiguration:(NSDictionary *)config; 51 | - (NSDictionary *)getDefaultConfiguration; 52 | 53 | // Utility methods 54 | - (void)resetToDefaults; 55 | - (BOOL)backupConfiguration; 56 | - (BOOL)restoreConfiguration; 57 | 58 | @end 59 | 60 | NS_ASSUME_NONNULL_END 61 | -------------------------------------------------------------------------------- /src/main/macwmfx.h: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol macwmfxModule; 15 | @class ConfigManager; 16 | @class WindowManager; 17 | @class DockManager; 18 | @class MenubarManager; 19 | @class SpacesManager; 20 | 21 | /** 22 | * macwmfx - Main orchestrator class 23 | * 24 | * This is the main entry point for the macwmfx tweak. 25 | * It manages the lifecycle of all modules and handles 26 | * the overall coordination of window management effects. 27 | * 28 | * The class is designed to be a singleton that can be 29 | * accessed from anywhere in the tweak to manage modules 30 | * and configuration. 31 | */ 32 | @interface macwmfx : NSObject 33 | 34 | // Singleton access 35 | + (instancetype)sharedInstance; 36 | 37 | // Core managers 38 | @property (nonatomic, strong, readonly) ConfigManager *configManager; 39 | @property (nonatomic, strong, readonly) WindowManager *windowManager; 40 | @property (nonatomic, strong, readonly) DockManager *dockManager; 41 | @property (nonatomic, strong, readonly) MenubarManager *menubarManager; 42 | @property (nonatomic, strong, readonly) SpacesManager *spacesManager; 43 | 44 | // Lifecycle management 45 | - (void)start; 46 | - (void)stop; 47 | 48 | // Module management 49 | - (void)loadModules; 50 | - (void)unloadModules; 51 | - (NSArray *)getLoadedModules; 52 | 53 | // Configuration 54 | - (void)loadConfiguration; 55 | - (void)reloadConfiguration; 56 | - (void)saveConfiguration; 57 | 58 | // Window management 59 | - (void)updateAllWindows; 60 | - (void)updateWindow:(NSWindow *)window; 61 | 62 | // Feature control 63 | - (void)enableFeature:(NSString *)featureName; 64 | - (void)disableFeature:(NSString *)featureName; 65 | - (BOOL)isFeatureEnabled:(NSString *)featureName; 66 | 67 | // System integration 68 | - (void)setupSystemHooks; 69 | - (void)removeSystemHooks; 70 | 71 | @end 72 | 73 | NS_ASSUME_NONNULL_END 74 | -------------------------------------------------------------------------------- /src/modules/windows/features/borders/WindowBorderModule.m: -------------------------------------------------------------------------------- 1 | #import "WindowBorderModule.h" 2 | #import "macwmfx_globals.h" 3 | 4 | @implementation WindowBorderModule 5 | 6 | + (instancetype)sharedInstance { 7 | static WindowBorderModule *sharedInstance = nil; 8 | static dispatch_once_t onceToken; 9 | dispatch_once(&onceToken, ^{ 10 | sharedInstance = [[WindowBorderModule alloc] init]; 11 | }); 12 | return sharedInstance; 13 | } 14 | 15 | - (instancetype)init { 16 | self = [super init]; 17 | if (self) { 18 | _enabled = NO; 19 | _width = 1.0f; 20 | _cornerRadius = 0.0f; 21 | _customColor = nil; 22 | _borderType = 0; 23 | } 24 | return self; 25 | } 26 | 27 | - (BOOL)isEnabled { 28 | return _enabled; 29 | } 30 | 31 | - (void)start { 32 | if (_enabled) return; 33 | _enabled = YES; 34 | [self loadConfiguration]; 35 | [self updateAllWindows]; 36 | } 37 | 38 | - (void)stop { 39 | if (!_enabled) return; 40 | _enabled = NO; 41 | } 42 | 43 | - (void)updateWindow:(NSWindow *)window { 44 | if (!_enabled || !window) return; 45 | // Minimal window border update implementation 46 | } 47 | 48 | - (void)updateAllWindows { 49 | if (!_enabled) return; 50 | for (NSWindow *window in [NSApplication sharedApplication].windows) { 51 | [self updateWindow:window]; 52 | } 53 | } 54 | 55 | - (void)loadConfiguration { 56 | if (gOutlineConfig.enabled) { 57 | _enabled = YES; 58 | _width = gOutlineConfig.width; 59 | _cornerRadius = gOutlineConfig.cornerRadius; 60 | _customColor = gOutlineConfig.customColor.active; 61 | _borderType = 0; // Default type 62 | } 63 | } 64 | 65 | - (void)saveConfiguration { 66 | // Minimal configuration save - update globals 67 | gOutlineConfig.enabled = _enabled; 68 | gOutlineConfig.width = _width; 69 | gOutlineConfig.cornerRadius = _cornerRadius; 70 | if (_customColor) { 71 | gOutlineConfig.customColor.active = _customColor; 72 | gOutlineConfig.customColor.inactive = _customColor; 73 | gOutlineConfig.customColor.stacked = _customColor; 74 | } 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /src/core/utils/generate_shadow_image.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw, ImageFilter 2 | import os 3 | 4 | def generate_shadow(): 5 | # Create a new RGBA image (transparent background) 6 | width = 3 7 | height = 3 8 | image = Image.new('RGBA', (width, height), (0, 0, 0, 0)) 9 | draw = ImageDraw.Draw(image) 10 | 11 | # Define shadow properties 12 | shadow_color = (255, 0, 0, 32) # Light red shadow 13 | border_color = (139, 0, 0, 255) # Dark red border 14 | 15 | # Draw the base shadow 16 | draw.point([(1, 1)], fill=shadow_color) 17 | 18 | # Draw the border 19 | for x in range(3): 20 | for y in range(3): 21 | if x == 0 or x == 2 or y == 0 or y == 2: 22 | draw.point([(x, y)], fill=border_color) 23 | 24 | # Create a new RGBA image (transparent background) 25 | width = 27 26 | height = 27 27 | shadow_image = Image.new('RGBA', (width, height), (0, 0, 0, 0)) 28 | border_image = Image.new('RGBA', (width, height), (0, 0, 0, 0)) 29 | draw_shadow = ImageDraw.Draw(shadow_image) 30 | draw_border = ImageDraw.Draw(border_image) 31 | 32 | # Define shadow properties 33 | shadow_color = (255, 0, 0, 128) # More visible red shadow 34 | border_color = (139, 0, 0, 255) # Dark red, fully opaque 35 | 36 | # Draw the shadow on separate image 37 | draw_shadow.rectangle( 38 | [(3, 3), (width-3, height-3)], 39 | fill=shadow_color 40 | ) 41 | 42 | # Blur only the shadow 43 | shadow_image = shadow_image.filter(ImageFilter.GaussianBlur(radius=1.5)) 44 | 45 | # Draw the border on separate image 46 | draw_border.rectangle( 47 | [(3, 3), (width-3, height-3)], 48 | outline=border_color, 49 | width=1 50 | ) 51 | 52 | # Combine the images 53 | image = Image.alpha_composite(shadow_image, border_image) 54 | 55 | # Save the image, overwriting if exists 56 | shadow_path = "/Library/wsfun/shadow.png" 57 | 58 | # Create directory if it doesn't exist 59 | os.makedirs(os.path.dirname(shadow_path), exist_ok=True) 60 | 61 | image.save(shadow_path, "PNG") 62 | 63 | if __name__ == "__main__": 64 | generate_shadow() 65 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowMaskShapes/WindowStar.m: -------------------------------------------------------------------------------- 1 | // 2 | // WindowStar.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "macwmfx_globals.h" 10 | #import 11 | #import 12 | 13 | // @interface NSWindow (Private) 14 | // - (id)_cornerMask; 15 | // @end 16 | 17 | // @interface WindowStarController : NSObject 18 | // @end 19 | 20 | // @implementation WindowStarController 21 | 22 | // + (void)load { 23 | // Method maskMethod = class_getInstanceMethod(NSClassFromString(@"NSWindow"), @selector(_cornerMask)); 24 | // if (!maskMethod) return; 25 | 26 | // IMP maskIMP = imp_implementationWithBlock(^id(NSWindow *self) { 27 | // // Get window size 28 | // NSRect frame = [self frame]; 29 | // CGFloat size = MIN(frame.size.width, frame.size.height); 30 | 31 | // // Create star shape 32 | // NSBezierPath *starPath = [NSBezierPath bezierPath]; 33 | // CGFloat centerX = frame.size.width / 2; 34 | // CGFloat centerY = frame.size.height / 2; 35 | // CGFloat outerRadius = size / 2; 36 | // CGFloat innerRadius = outerRadius * 0.382; // Golden ratio 37 | 38 | // for (int i = 0; i < 10; i++) { 39 | // CGFloat radius = (i % 2 == 0) ? outerRadius : innerRadius; 40 | // CGFloat angle = i * M_PI / 5 - M_PI / 2; // Start from top point 41 | 42 | // CGFloat x = centerX + radius * cos(angle); 43 | // CGFloat y = centerY + radius * sin(angle); 44 | 45 | // if (i == 0) { 46 | // [starPath moveToPoint:NSMakePoint(x, y)]; 47 | // } else { 48 | // [starPath lineToPoint:NSMakePoint(x, y)]; 49 | // } 50 | // } 51 | // [starPath closePath]; 52 | 53 | // // Create mask image 54 | // NSImage *maskImage = [[NSImage alloc] initWithSize:frame.size]; 55 | // [maskImage lockFocus]; 56 | // [[NSColor whiteColor] set]; 57 | // [starPath fill]; 58 | // [maskImage unlockFocus]; 59 | 60 | // return maskImage; 61 | // }); 62 | 63 | // method_setImplementation(maskMethod, maskIMP); 64 | // } 65 | 66 | // @end 67 | -------------------------------------------------------------------------------- /src/client/macwmfx_client.h: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx_client.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | // Forward declarations 15 | @class macwmfxServerResponse; 16 | 17 | // Client completion block 18 | typedef void (^macwmfxClientCompletionBlock)(macwmfxServerResponse * _Nullable response, NSError * _Nullable error); 19 | 20 | // Client class for communicating with the macwmfx server 21 | @interface macwmfxClient : NSObject 22 | 23 | // Singleton access 24 | + (instancetype)sharedClient; 25 | 26 | // Connection management 27 | - (void)connectWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 28 | - (void)disconnect; 29 | - (BOOL)isConnected; 30 | 31 | // Server commands 32 | - (void)reloadWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 33 | - (void)startServerWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 34 | - (void)stopServerWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 35 | - (void)enableBordersWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 36 | - (void)disableBordersWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 37 | - (void)setBorderWidth:(float)width completion:(nullable macwmfxClientCompletionBlock)completion; 38 | - (void)setBorderRadius:(float)radius completion:(nullable macwmfxClientCompletionBlock)completion; 39 | - (void)enableResizeWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 40 | - (void)disableResizeWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 41 | - (void)getStatusWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 42 | 43 | // Module management commands 44 | - (void)enableModule:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion; 45 | - (void)disableModule:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion; 46 | - (void)getModuleInfo:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion; 47 | - (void)listModulesWithCompletion:(nullable macwmfxClientCompletionBlock)completion; 48 | 49 | // Generic command method 50 | - (void)sendCommand:(NSInteger)command withData:(nullable id)data completion:(nullable macwmfxClientCompletionBlock)completion; 51 | 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /src/main/module_loader.h: -------------------------------------------------------------------------------- 1 | // 2 | // module_loader.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** 15 | * ModuleLoader - Dynamic module loading system 16 | * 17 | * This system replaces feature flags with import-based module loading. 18 | * Features are loaded only when explicitly imported, similar to how 19 | * Nix handles optional dependencies. 20 | */ 21 | 22 | /** 23 | * Module protocol that all macwmfx modules must implement 24 | */ 25 | @protocol macwmfxModule 26 | 27 | // Required methods 28 | - (void)start; 29 | - (void)stop; 30 | - (BOOL)isEnabled; 31 | 32 | @optional 33 | // Optional methods 34 | - (void)reloadConfiguration; 35 | - (void)updateConfiguration:(NSDictionary *)config; 36 | - (void)updateWindow:(NSWindow *)window; 37 | 38 | @end 39 | 40 | // Module loader interface 41 | @interface ModuleLoader : NSObject 42 | 43 | // Singleton access 44 | + (instancetype)sharedLoader; 45 | 46 | // Module management 47 | - (BOOL)loadModule:(NSString *)moduleName; 48 | - (BOOL)unloadModule:(NSString *)moduleName; 49 | - (BOOL)isModuleLoaded:(NSString *)moduleName; 50 | - (NSArray *)getLoadedModules; 51 | - (NSArray *)getAvailableModules; 52 | 53 | // Dependency resolution 54 | - (BOOL)loadModuleWithDependencies:(NSString *)moduleName; 55 | - (NSArray *)resolveDependencies:(NSString *)moduleName; 56 | 57 | // Module discovery 58 | - (NSArray *)discoverAvailableModules; 59 | - (NSDictionary *)getModuleInfo:(NSString *)moduleName; 60 | 61 | // Configuration integration 62 | - (void)loadModulesFromConfiguration:(NSDictionary *)config; 63 | - (NSDictionary *)getModuleConfigurations; 64 | 65 | // Runtime control 66 | - (BOOL)enableModule:(NSString *)moduleName; 67 | - (BOOL)disableModule:(NSString *)moduleName; 68 | - (void)reloadAllModules; 69 | - (void)updateAllWindows; 70 | 71 | @end 72 | 73 | // Convenience macros for module registration 74 | #define MACWMFX_MODULE_REGISTER(ModuleClass) \ 75 | + (void)load { \ 76 | [[ModuleLoader sharedLoader] registerModule:[ModuleClass class]]; \ 77 | } 78 | 79 | #define MACWMFX_MODULE_DEPENDENCY(ModuleName) \ 80 | + (NSArray *)moduleDependencies { \ 81 | return @[ModuleName]; \ 82 | } 83 | 84 | NS_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /src/modules/menubar/features/ribbonbar/HookUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // HookUtil.m 3 | // RibbonBar 4 | // 5 | // Created by bedtime on 5/18/25. 6 | // 7 | 8 | #import "RibbonBar.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | void HookFunc(void* func, void* newFunc, void** oldFunc) { 18 | if (func != 0x55) { 19 | GumInterceptorBeginTransactionFunc(gHook); 20 | GumInterceptorReplaceFunc(gHook, (void *)(func), newFunc, NULL, oldFunc); 21 | GumInterceptorEndTransactionFunc(gHook); 22 | } 23 | } 24 | 25 | void SwizzleMethod(Class cls, SEL originalSelector, SEL swizzledSelector, id (**originalImplementation)(id, SEL)) { 26 | Method originalMethod = class_getInstanceMethod(cls, originalSelector); 27 | Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); 28 | 29 | BOOL didAddMethod = class_addMethod(cls, 30 | originalSelector, 31 | method_getImplementation(swizzledMethod), 32 | method_getTypeEncoding(swizzledMethod)); 33 | 34 | if (didAddMethod) { 35 | class_replaceMethod(cls, 36 | swizzledSelector, 37 | method_getImplementation(originalMethod), 38 | method_getTypeEncoding(originalMethod)); 39 | } else { 40 | // Store the original implementation in the appropriate function pointer 41 | if (originalImplementation) { 42 | *originalImplementation = (id (*)(id, SEL))method_getImplementation(originalMethod); 43 | } 44 | 45 | // Swap implementations 46 | method_exchangeImplementations(originalMethod, swizzledMethod); 47 | } 48 | } 49 | 50 | void AddHook(Class class, SEL originalSelector, SEL swizzledSelector, IMP implementation, Method *originalMethodStorage, BOOL isClassMethod) { 51 | if (class) { 52 | Method originalMethod = isClassMethod ? class_getClassMethod(class, originalSelector) : class_getInstanceMethod(class, originalSelector); 53 | if (originalMethod) { 54 | Class targetClass = isClassMethod ? object_getClass(class) : class; 55 | class_addMethod(targetClass, 56 | swizzledSelector, 57 | implementation, 58 | method_getTypeEncoding(originalMethod)); 59 | SwizzleMethod(targetClass, originalSelector, swizzledSelector, originalMethodStorage); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowTrafficLights/disableTrafficLights.m: -------------------------------------------------------------------------------- 1 | // 2 | // disableTrafficLights.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/10/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../../../../shared/headers/macwmfx_globals.h" 11 | #import "../../../../shared/macwmfx_logging.h" 12 | 13 | ZKSwizzleInterface(BS_NSWindow_DisableTrafficLights, NSWindow, NSWindow) 14 | 15 | @implementation BS_NSWindow_DisableTrafficLights 16 | 17 | + (void)load { 18 | [[NSNotificationCenter defaultCenter] addObserver:self 19 | selector:@selector(configChanged:) 20 | name:@"com.aspauldingcode.macwmfx.configChanged" 21 | object:nil]; 22 | MACWMFX_LOG_INFO(macwmfx_log_traffic_lights, "Traffic lights visibility controller initialized"); 23 | } 24 | 25 | + (void)handleConfigChange:(NSNotification *)notification { 26 | dispatch_async(dispatch_get_main_queue(), ^{ 27 | [self updateAllWindowTrafficLights]; 28 | }); 29 | } 30 | 31 | + (void)updateAllWindowTrafficLights { 32 | MACWMFX_LOG_INFO(macwmfx_log_traffic_lights, "Updating all traffic lights visibility. Enabled=%d", gTrafficLightsConfig.enabled); 33 | 34 | for (NSWindow *window in [NSApp windows]) { 35 | if (![window isKindOfClass:[NSWindow class]]) continue; 36 | if (!(window.styleMask & NSWindowStyleMaskTitled)) continue; 37 | 38 | [self updateTrafficLightsForWindow:window]; 39 | } 40 | } 41 | 42 | + (void)updateTrafficLightsForWindow:(NSWindow *)window { 43 | NSButton *closeButton = [window standardWindowButton:NSWindowCloseButton]; 44 | NSButton *minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton]; 45 | NSButton *zoomButton = [window standardWindowButton:NSWindowZoomButton]; 46 | 47 | BOOL shouldHide = !gTrafficLightsConfig.enabled; 48 | 49 | for (NSButton *button in @[closeButton, minimizeButton, zoomButton]) { 50 | if (button) { 51 | [button setHidden:shouldHide]; 52 | } 53 | } 54 | } 55 | 56 | - (void)makeKeyAndOrderFront:(id)sender { 57 | ZKOrig(void, sender); 58 | 59 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 60 | 61 | [BS_NSWindow_DisableTrafficLights updateTrafficLightsForWindow:(NSWindow *)self]; 62 | } 63 | 64 | - (void)orderFront:(id)sender { 65 | ZKOrig(void, sender); 66 | 67 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 68 | 69 | [BS_NSWindow_DisableTrafficLights updateTrafficLightsForWindow:(NSWindow *)self]; 70 | } 71 | 72 | + (void)dealloc { 73 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 74 | [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowBehavior/GoodbyeForGood.m: -------------------------------------------------------------------------------- 1 | // 2 | // GoodbyeForGood.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "macwmfx_globals.h" 10 | 11 | // // Apps that should never be terminated 12 | // static NSSet *excludedBundleIDs; 13 | 14 | // ZKSwizzleInterface(BS_NSWindow_GoodbyeForGood, NSObject, NSObject) 15 | // @implementation BS_NSWindow_GoodbyeForGood 16 | 17 | // + (void)initialize { 18 | // excludedBundleIDs = [NSSet setWithArray:@[ 19 | // @"com.apple.dock", 20 | // @"com.apple.systemuiserver", 21 | // @"com.apple.WindowManager", 22 | // @"com.apple.mail", 23 | // @"com.apple.iCal", 24 | // @"org.m0k.transmission", 25 | // @"com.viscosityvpn.Viscosity", 26 | // @"com.apple.ScreenSharing", 27 | // @"org.mozilla.firefox", 28 | // @"com.apple.launchpad.launcher" 29 | // ]]; 30 | 31 | // [[NSNotificationCenter defaultCenter] addObserver:self 32 | // selector:@selector(windowWillClose:) 33 | // name:NSWindowWillCloseNotification 34 | // object:nil]; 35 | // } 36 | 37 | // + (void)windowWillClose:(NSNotification *)notification { 38 | // dispatch_async(dispatch_get_main_queue(), ^{ 39 | // NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; 40 | // if ([excludedBundleIDs containsObject:bundleID]) return; 41 | 42 | // NSUInteger visibleWindows = 0; 43 | // for (NSWindow *window in [NSApp windows]) { 44 | // if (!window || !(window.styleMask & NSWindowStyleMaskTitled)) continue; 45 | // if (window.level != NSNormalWindowLevel) continue; 46 | 47 | // NSString *className = NSStringFromClass([window class]); 48 | // if ([className containsString:@"Panel"] || 49 | // [className containsString:@"Sheet"] || 50 | // [className containsString:@"Popover"] || 51 | // [className containsString:@"HUD"] || 52 | // [className containsString:@"Helper"]) continue; 53 | 54 | // if ([window isVisible]) visibleWindows++; 55 | // } 56 | 57 | // static NSMutableSet *appsWithWindows; 58 | // static dispatch_once_t onceToken; 59 | // dispatch_once(&onceToken, ^{ 60 | // appsWithWindows = [NSMutableSet new]; 61 | // }); 62 | 63 | // if (visibleWindows > 0) { 64 | // [appsWithWindows addObject:bundleID]; 65 | // } else if ([appsWithWindows containsObject:bundleID] && [NSApp isActive]) { 66 | // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), 67 | // dispatch_get_main_queue(), ^{ 68 | // [NSApp terminate:nil]; 69 | // }); 70 | // } 71 | // }); 72 | // } 73 | 74 | // @end 75 | -------------------------------------------------------------------------------- /src/core/utils/SymRezUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // SymRezUtils.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "SymRezUtils.h" 10 | #import 11 | #import "../../shared/macwmfx_logging.h" 12 | #import "../../SymRez/SymRez.h" 13 | 14 | // Static callback for sr_for_each 15 | static bool symbolCallback(sr_symbol_t symbol, sr_ptr_t ptr, void *context) { 16 | NSMutableArray *symbolArray = (__bridge NSMutableArray *)context; 17 | [symbolArray addObject:@(symbol)]; 18 | return false; // Continue iteration 19 | } 20 | 21 | @implementation SymRezUtils 22 | 23 | + (void *)resolveSymbol:(const char *)symbolName inFramework:(const char *)frameworkName { 24 | symrez_t symrez = symrez_new(frameworkName); 25 | if (!symrez) { 26 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Failed to create SymRez for framework: %s", frameworkName); 27 | return NULL; 28 | } 29 | 30 | void *symbol = sr_resolve_symbol(symrez, symbolName); 31 | if (!symbol) { 32 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Failed to resolve symbol %s in framework %s", symbolName, frameworkName); 33 | } else { 34 | MACWMFX_LOG_DEBUG(macwmfx_log_general, "Successfully resolved symbol %s in framework %s", symbolName, frameworkName); 35 | } 36 | 37 | sr_free(symrez); 38 | return symbol; 39 | } 40 | 41 | + (void *)resolveSymbol:(const char *)symbolName inImage:(const char *)imageName { 42 | return symrez_resolve_once(imageName, symbolName); 43 | } 44 | 45 | + (void *)resolveSymbolInAppKit:(const char *)symbolName { 46 | return [self resolveSymbol:symbolName inFramework:"AppKit"]; 47 | } 48 | 49 | + (void *)resolveSymbolInCoreGraphics:(const char *)symbolName { 50 | return [self resolveSymbol:symbolName inFramework:"CoreGraphics"]; 51 | } 52 | 53 | + (void *)resolveSymbolInQuartzCore:(const char *)symbolName { 54 | return [self resolveSymbol:symbolName inFramework:"QuartzCore"]; 55 | } 56 | 57 | + (void *)resolveGlobalVariable:(const char *)variableName inFramework:(const char *)frameworkName { 58 | // For global variables, we need to resolve the symbol and dereference it 59 | void *symbol = [self resolveSymbol:variableName inFramework:frameworkName]; 60 | if (symbol) { 61 | return *(void **)symbol; 62 | } 63 | return NULL; 64 | } 65 | 66 | + (BOOL)isSymbolAvailable:(const char *)symbolName inFramework:(const char *)frameworkName { 67 | void *symbol = [self resolveSymbol:symbolName inFramework:frameworkName]; 68 | return symbol != NULL; 69 | } 70 | 71 | + (NSArray *)listSymbolsInFramework:(const char *)frameworkName { 72 | NSMutableArray *symbols = [NSMutableArray array]; 73 | 74 | symrez_t symrez = symrez_new(frameworkName); 75 | if (!symrez) { 76 | return symbols; 77 | } 78 | 79 | sr_for_each(symrez, (__bridge void *)symbols, symbolCallback); 80 | 81 | sr_free(symrez); 82 | return [symbols copy]; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowShadow/DisableWindowShadow.m: -------------------------------------------------------------------------------- 1 | // 2 | // DisableWindowShadow.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../../../../shared/headers/macwmfx_globals.h" 11 | #import "../../../../shared/macwmfx_logging.h" 12 | 13 | ZKSwizzleInterface(BS_NSWindow_Shadow, NSWindow, NSWindow) 14 | 15 | @implementation BS_NSWindow_Shadow 16 | 17 | + (void)load { 18 | [[NSNotificationCenter defaultCenter] addObserver:self 19 | selector:@selector(configChanged:) 20 | name:@"com.aspauldingcode.macwmfx.configChanged" 21 | object:nil]; 22 | MACWMFX_LOG_INFO(macwmfx_log_shadow, "Shadow controller initialized - listening for config changes"); 23 | } 24 | 25 | + (void)updateAllWindowShadows { 26 | MACWMFX_LOG_INFO(macwmfx_log_shadow, "Updating all window shadows. Shadow enabled=%d", gShadowConfig.enabled); 27 | 28 | dispatch_async(dispatch_get_main_queue(), ^{ 29 | for (NSWindow *window in [NSApp windows]) { 30 | if (![window isKindOfClass:[NSWindow class]]) continue; 31 | if (!(window.styleMask & NSWindowStyleMaskTitled)) continue; 32 | 33 | // Force update the shadow state 34 | [window setHasShadow:NO]; // Reset state 35 | [window setHasShadow:gShadowConfig.enabled]; // Apply new state 36 | 37 | // Force window to update 38 | [window displayIfNeeded]; 39 | 40 | MACWMFX_LOG_DEBUG(macwmfx_log_shadow, "Updated window shadow: %{public}@", window); 41 | } 42 | }); 43 | } 44 | 45 | - (void)makeKeyAndOrderFront:(id)sender { 46 | ZKOrig(void, sender); 47 | 48 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 49 | 50 | // Force update shadow state when window becomes key 51 | [(NSWindow *)self setHasShadow:NO]; // Reset state 52 | [(NSWindow *)self setHasShadow:gShadowConfig.enabled]; // Apply new state 53 | [(NSWindow *)self displayIfNeeded]; 54 | } 55 | 56 | - (void)setHasShadow:(BOOL)hasShadow { 57 | if (!(self.styleMask & NSWindowStyleMaskTitled)) { 58 | ZKOrig(void, hasShadow); 59 | return; 60 | } 61 | 62 | // Always respect the global shadow config 63 | BOOL finalState = gShadowConfig.enabled ? hasShadow : NO; 64 | ZKOrig(void, finalState); 65 | } 66 | 67 | + (void)dealloc { 68 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 69 | [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 70 | } 71 | 72 | + (void)configChanged:(NSNotification *)notification { 73 | MACWMFX_LOG_INFO(macwmfx_log_shadow, "Config changed, updating all window shadows. Shadow enabled=%d", gShadowConfig.enabled); 74 | 75 | // Update all windows 76 | NSArray *windows = [NSApp windows]; 77 | for (NSWindow *window in windows) { 78 | [window setHasShadow:gShadowConfig.enabled]; 79 | MACWMFX_LOG_DEBUG(macwmfx_log_shadow, "Updated window shadow: %{public}@", window); 80 | } 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /src/config/config_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "hotload": { 3 | "enabled": true, 4 | "interval": 1 5 | }, 6 | "spaces": { 7 | "enabled": true, 8 | "instantFullscreen": false, 9 | "behavior": "default", 10 | "names": ["1", "2", "3", "4"] 11 | }, 12 | "window": { 13 | "blur": { 14 | "enabled": false, 15 | "passes": 1, 16 | "radius": 10 17 | }, 18 | "titlebar": { 19 | "enabled": true, 20 | "forceClassic": false, 21 | "customTitle": { 22 | "enabled": true, 23 | "title": "My Custom Window Title" 24 | }, 25 | "customColor": { 26 | "enabled": false, 27 | "activeBackground": "32302f", 28 | "activeForeground": "fbf1c7", 29 | "inactiveBackground": "32302f", 30 | "inactiveForeground": "fbf1c7" 31 | }, 32 | "style": "modern", 33 | "size": 22 34 | }, 35 | "trafficLights": { 36 | "enabled": true, 37 | "customColor": { 38 | "enabled": true, 39 | "active": { 40 | "stop": "fb4934", 41 | "yield": "fabd2f", 42 | "go": "b8bb26" 43 | }, 44 | "inactive": { 45 | "stop": "d5c4a1", 46 | "yield": "ebdbb2", 47 | "go": "fbf1c7" 48 | }, 49 | "hover": { 50 | "stop": "fb4934", 51 | "yield": "fabd2f", 52 | "go": "b8bb26" 53 | } 54 | }, 55 | "style": "macOS", 56 | "shape": "circle", 57 | "order": "stop-yield-go", 58 | "size": 12, 59 | "padding": 4, 60 | "position": "top-right" 61 | }, 62 | "shadow": { 63 | "enabled": true, 64 | "customColor": { 65 | "enabled": false, 66 | "active": "32302f", 67 | "inactive": "00302f" 68 | } 69 | }, 70 | "sizeConstraints": { 71 | "enabled": true 72 | }, 73 | "outline": { 74 | "enabled": false, 75 | "customColor": { 76 | "enabled": true, 77 | "active": "fbf1c7", 78 | "inactive": "d5c4a1", 79 | "stacked": "fb4934" 80 | }, 81 | "cornerRadius": 40, 82 | "type": "inline", 83 | "width": 2 84 | }, 85 | "transparency": { 86 | "enabled": false, 87 | "value": 0.5 88 | } 89 | }, 90 | "menubar": { 91 | "enabled": true, 92 | "autohide": false, 93 | "transparency": 0.8 94 | }, 95 | "dock": { 96 | "enabled": true, 97 | "autohide": true, 98 | "position": "bottom", 99 | "size": 48 100 | }, 101 | "customSystemColorScheme": { 102 | "enabled": true, 103 | "variant": "dark", 104 | "slug": "gruvbox-dark-soft", 105 | "colors": { 106 | "base00": "32302f", 107 | "base01": "3c3836", 108 | "base02": "504945", 109 | "base03": "665c54", 110 | "base04": "bdae93", 111 | "base05": "d5c4a1", 112 | "base06": "ebdbb2", 113 | "base07": "fbf1c7", 114 | "base08": "fb4934", 115 | "base09": "fe8019", 116 | "base0A": "fabd2f", 117 | "base0B": "b8bb26", 118 | "base0C": "8ec07c", 119 | "base0D": "83a598", 120 | "base0E": "d3869b", 121 | "base0F": "d65d0e" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /libmacwmfx.dylib.blacklist: -------------------------------------------------------------------------------- 1 | launchd 2 | logd 3 | smd 4 | UserEventAgent 5 | uninstalld 6 | iconservicesagent 7 | IconChamp 8 | com.apple.iconservices 9 | com.macenhance.IChelper.plist 10 | com.sindresorhus.Plain-Text-Editor 11 | StepTwo 12 | BasiliskII 13 | fseventsd 14 | mediaremoted 15 | systemstats 16 | Broadcasts 17 | configd 18 | endpointsecurityd 19 | powerd 20 | IOMFB_bics_daemon 21 | biomed 22 | amfid 23 | remoted 24 | keybagd 25 | DiskUnmountWatcher 26 | softwareupdated 27 | watchdogd 28 | mds 29 | iconservicesd 30 | kernelmanagerd 31 | diskarbitrationd 32 | coreduetd 33 | syslogd 34 | thermalmonitord 35 | opendirectoryd 36 | apsd 37 | launchservicesd 38 | timed 39 | usbmuxd 40 | securityd 41 | locationd 42 | autofsd 43 | dasd 44 | distnoted 45 | AppleCredentialManagerDaemon 46 | PerfPowerServices 47 | dirhelper 48 | logind 49 | revisiond 50 | KernelEventAgent 51 | usermanagerd 52 | bluetoothd 53 | notifyd 54 | sandboxd 55 | corebrightnessd 56 | AirPlayXPCHelper 57 | com.apple.cmio.registerassistantservice 58 | cfprefsd 59 | tccd 60 | aslmanager 61 | loginwindow 62 | contextstored 63 | coreservicesd 64 | runningboardd 65 | lsd 66 | coreaudiod 67 | trustd 68 | csnameddatad 69 | PowerUIAgent 70 | airportd 71 | com.apple.ifdreader 72 | distnoted 73 | apfsd 74 | nehelper 75 | nsurlsessiond 76 | usbd 77 | mDNSResponder 78 | VDCAssistant 79 | biometrickitd 80 | logd_helper 81 | analyticsd 82 | cryptexd 83 | mobileassetd 84 | symptomsd 85 | authd 86 | PlugInLibraryService 87 | trustdFileHelper 88 | AudioComponentRegistrar 89 | systemstatusd 90 | mDNSResponderHelper 91 | com.apple.audio.SandboxHelper 92 | distnoted 93 | containermanagerd_system 94 | hidd 95 | distnoted 96 | secinitd 97 | findmydeviced 98 | securityd_system 99 | WirelessRadioManagerd 100 | com.apple.geod 101 | com.apple.audio.DriverHelper 102 | distnoted 103 | findmybeaconingd 104 | syspolicyd 105 | backupd 106 | countryd 107 | storagekitd 108 | backgroundtaskmanagementd 109 | secinitd 110 | cfprefsd 111 | distnoted 112 | trustd 113 | sysextd 114 | vbcableagent 115 | ZhuGeService 116 | com.apple.CodeSigningHelper 117 | containermanagerd 118 | colorsync.displayservices 119 | com.apple.ColorSyncXPCAgent 120 | wifip2pd 121 | colorsyncd 122 | appleh13camerad 123 | UVCAssistant 124 | appleeventsd 125 | searchpartyd 126 | audioclocksyncd 127 | bootinstalld 128 | com.apple.DriverKit-IOUserDockChannelSerial 129 | com.apple.AppleUserHIDDrivers 130 | mds_stores 131 | WiFiCloudAssetsXPCService 132 | distnoted 133 | Wallpaper 134 | symptomsd-diag 135 | com.apple.AccountPolicyHelper 136 | coreauthd 137 | distnoted 138 | wifianalyticsd 139 | captiveagent 140 | distnoted 141 | ctkahp 142 | com.apple.MobileSoftwareUpdate.CleanupPreparePathService 143 | ctkd 144 | XProtectPluginService 145 | systemsoundserverd 146 | netbiosd 147 | ioupsd 148 | sysmond 149 | com.apple.MobileSoftwareUpdate.UpdateBrainService 150 | xpcroleaccountd 151 | systemstats 152 | backupd-helper 153 | com.apple.AmbientDisplayAgent 154 | com.apple.ColorSyncXPCAgent 155 | IOUserBluetoothSerialDriver 156 | siriinferenced 157 | distnoted 158 | cfprefsd 159 | lsd 160 | csnameddatad 161 | secd 162 | mdbulkimport 163 | mdbulkimport 164 | pkd 165 | trustd 166 | containermanagerd 167 | distnoted 168 | GSSCred 169 | securityd_service 170 | nesessionmanager 171 | corekdld 172 | UserEventAgent 173 | gamecontrollerd 174 | seld 175 | CoreServicesUIAgent 176 | universalaccessd 177 | com.apple.sbd 178 | cloudd 179 | usernotificationsd 180 | accountsd 181 | pboard 182 | CommCenter 183 | distnoted 184 | usernoted 185 | APFSUserAgent 186 | rapportd 187 | nsurlsessiond 188 | routined 189 | ContextStoreAgent 190 | com.apple.hiservices-xpcservice 191 | talagent 192 | Console 193 | -------------------------------------------------------------------------------- /libmacwmfx_server.dylib.blacklist: -------------------------------------------------------------------------------- 1 | launchd 2 | logd 3 | smd 4 | UserEventAgent 5 | uninstalld 6 | iconservicesagent 7 | IconChamp 8 | com.apple.iconservices 9 | com.macenhance.IChelper.plist 10 | com.sindresorhus.Plain-Text-Editor 11 | StepTwo 12 | BasiliskII 13 | fseventsd 14 | mediaremoted 15 | systemstats 16 | Broadcasts 17 | configd 18 | endpointsecurityd 19 | powerd 20 | IOMFB_bics_daemon 21 | biomed 22 | amfid 23 | remoted 24 | keybagd 25 | DiskUnmountWatcher 26 | softwareupdated 27 | watchdogd 28 | mds 29 | iconservicesd 30 | kernelmanagerd 31 | diskarbitrationd 32 | coreduetd 33 | syslogd 34 | thermalmonitord 35 | opendirectoryd 36 | apsd 37 | launchservicesd 38 | timed 39 | usbmuxd 40 | securityd 41 | locationd 42 | autofsd 43 | dasd 44 | distnoted 45 | AppleCredentialManagerDaemon 46 | PerfPowerServices 47 | dirhelper 48 | logind 49 | revisiond 50 | KernelEventAgent 51 | usermanagerd 52 | bluetoothd 53 | notifyd 54 | sandboxd 55 | corebrightnessd 56 | AirPlayXPCHelper 57 | com.apple.cmio.registerassistantservice 58 | cfprefsd 59 | tccd 60 | aslmanager 61 | loginwindow 62 | contextstored 63 | coreservicesd 64 | runningboardd 65 | lsd 66 | coreaudiod 67 | trustd 68 | csnameddatad 69 | PowerUIAgent 70 | airportd 71 | com.apple.ifdreader 72 | distnoted 73 | apfsd 74 | nehelper 75 | nsurlsessiond 76 | usbd 77 | mDNSResponder 78 | VDCAssistant 79 | biometrickitd 80 | logd_helper 81 | analyticsd 82 | cryptexd 83 | mobileassetd 84 | symptomsd 85 | authd 86 | PlugInLibraryService 87 | trustdFileHelper 88 | AudioComponentRegistrar 89 | systemstatusd 90 | mDNSResponderHelper 91 | com.apple.audio.SandboxHelper 92 | distnoted 93 | containermanagerd_system 94 | hidd 95 | distnoted 96 | secinitd 97 | findmydeviced 98 | securityd_system 99 | WirelessRadioManagerd 100 | com.apple.geod 101 | com.apple.audio.DriverHelper 102 | distnoted 103 | findmybeaconingd 104 | syspolicyd 105 | backupd 106 | countryd 107 | storagekitd 108 | backgroundtaskmanagementd 109 | secinitd 110 | cfprefsd 111 | distnoted 112 | trustd 113 | sysextd 114 | vbcableagent 115 | ZhuGeService 116 | com.apple.CodeSigningHelper 117 | containermanagerd 118 | colorsync.displayservices 119 | com.apple.ColorSyncXPCAgent 120 | wifip2pd 121 | colorsyncd 122 | appleh13camerad 123 | UVCAssistant 124 | appleeventsd 125 | searchpartyd 126 | audioclocksyncd 127 | bootinstalld 128 | com.apple.DriverKit-IOUserDockChannelSerial 129 | com.apple.AppleUserHIDDrivers 130 | mds_stores 131 | WiFiCloudAssetsXPCService 132 | distnoted 133 | Wallpaper 134 | symptomsd-diag 135 | com.apple.AccountPolicyHelper 136 | coreauthd 137 | distnoted 138 | wifianalyticsd 139 | captiveagent 140 | distnoted 141 | ctkahp 142 | com.apple.MobileSoftwareUpdate.CleanupPreparePathService 143 | ctkd 144 | XProtectPluginService 145 | systemsoundserverd 146 | netbiosd 147 | ioupsd 148 | sysmond 149 | com.apple.MobileSoftwareUpdate.UpdateBrainService 150 | xpcroleaccountd 151 | systemstats 152 | backupd-helper 153 | com.apple.AmbientDisplayAgent 154 | com.apple.ColorSyncXPCAgent 155 | IOUserBluetoothSerialDriver 156 | siriinferenced 157 | distnoted 158 | cfprefsd 159 | lsd 160 | csnameddatad 161 | secd 162 | mdbulkimport 163 | mdbulkimport 164 | pkd 165 | trustd 166 | containermanagerd 167 | distnoted 168 | GSSCred 169 | securityd_service 170 | nesessionmanager 171 | corekdld 172 | UserEventAgent 173 | gamecontrollerd 174 | seld 175 | CoreServicesUIAgent 176 | universalaccessd 177 | com.apple.sbd 178 | cloudd 179 | usernotificationsd 180 | accountsd 181 | pboard 182 | CommCenter 183 | distnoted 184 | usernoted 185 | APFSUserAgent 186 | rapportd 187 | nsurlsessiond 188 | routined 189 | ContextStoreAgent 190 | com.apple.hiservices-xpcservice 191 | talagent 192 | Console 193 | -------------------------------------------------------------------------------- /src/server/macwmfx_server.h: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx_server.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | // Server command types 17 | typedef NS_ENUM(NSInteger, macwmfxServerCommand) { 18 | macwmfxServerCommandReload = 1, 19 | macwmfxServerCommandStart = 2, 20 | macwmfxServerCommandStop = 3, 21 | macwmfxServerCommandEnableBorders = 4, 22 | macwmfxServerCommandDisableBorders = 5, 23 | macwmfxServerCommandSetBorderWidth = 6, 24 | macwmfxServerCommandSetBorderRadius = 7, 25 | macwmfxServerCommandEnableResize = 8, 26 | macwmfxServerCommandDisableResize = 9, 27 | macwmfxServerCommandUpdateConfig = 10, 28 | macwmfxServerCommandGetStatus = 11, 29 | macwmfxServerCommandEnableModule = 12, 30 | macwmfxServerCommandDisableModule = 13, 31 | macwmfxServerCommandGetModuleInfo = 14, 32 | macwmfxServerCommandListModules = 15 33 | }; 34 | 35 | // Server response types 36 | typedef NS_ENUM(NSInteger, macwmfxServerResponseType) { 37 | macwmfxServerResponseTypeSuccess = 1, 38 | macwmfxServerResponseTypeError = 2, 39 | macwmfxServerResponseTypeStatus = 3 40 | }; 41 | 42 | // Server message structure 43 | @interface macwmfxServerMessage : NSObject 44 | @property (nonatomic, assign) macwmfxServerCommand command; 45 | @property (nonatomic, strong, nullable) id data; 46 | @property (nonatomic, strong, nullable) NSString *errorMessage; 47 | @end 48 | 49 | // Server response structure 50 | @interface macwmfxServerResponse : NSObject 51 | @property (nonatomic, assign) macwmfxServerResponseType type; 52 | @property (nonatomic, strong, nullable) id data; 53 | @property (nonatomic, strong, nullable) NSString *errorMessage; 54 | @end 55 | 56 | // Main server class 57 | @interface macwmfxServer : NSObject 58 | 59 | // Singleton access 60 | + (instancetype)sharedServer; 61 | 62 | // Lifecycle management 63 | - (void)startServer; 64 | - (void)stopServer; 65 | - (BOOL)isServerRunning; 66 | 67 | // Configuration management 68 | - (void)loadConfiguration; 69 | - (void)reloadConfiguration; 70 | - (void)updateConfiguration:(NSDictionary *)config; 71 | 72 | // Window management 73 | - (void)updateAllWindows; 74 | - (void)updateWindow:(NSWindow *)window; 75 | 76 | // App lifecycle management 77 | - (void)reloadAllApplications; 78 | - (void)killAllApplications; 79 | - (NSArray *)getRunningApplications; 80 | - (NSArray *)getRunningGUIApplications; 81 | - (BOOL)shouldSkipApplication:(NSRunningApplication *)app; 82 | - (void)restartApplications:(NSArray *)appsToRestart; 83 | 84 | // Command handling 85 | - (macwmfxServerResponse *)handleCommand:(macwmfxServerCommand)command withData:(nullable id)data; 86 | 87 | // Module management 88 | - (BOOL)enableModule:(NSString *)moduleName; 89 | - (BOOL)disableModule:(NSString *)moduleName; 90 | - (BOOL)isModuleEnabled:(NSString *)moduleName; 91 | - (NSDictionary *)getModuleInfo:(NSString *)moduleName; 92 | - (NSArray *)getAvailableModules; 93 | - (NSArray *)getLoadedModules; 94 | - (NSDictionary *)getAllModuleInfo; 95 | 96 | // XPC connection management 97 | - (void)handleClientConnection:(xpc_connection_t)connection; 98 | - (void)sendResponse:(macwmfxServerResponse *)response toConnection:(xpc_connection_t)connection; 99 | 100 | @end 101 | 102 | // Global server instance 103 | extern macwmfxServer *gmacwmfxServer; 104 | 105 | NS_ASSUME_NONNULL_END 106 | -------------------------------------------------------------------------------- /src/SymRez/README.md: -------------------------------------------------------------------------------- 1 | # SymRez 2 | 3 | When dlsym isn't enough 4 | 5 | ## When to use? 6 | 7 | Although dlsym is very powerful, it usually plays by the rules and will not 8 | resolve non-exported symbols. This is where SymRez comes into play. SymRez works 9 | by manually resolving symbol names to their pointer locations in the symbol 10 | table inside Mach-O files. Works especially well for hooking symbolicated global 11 | variables, which dlsym will not :) 12 | 13 | Note: SymRez does not demangle symbols. The raw symbol name is required for this 14 | to work. 15 | 16 | ## API 17 | 18 | ``` 19 | #ifndef SymRez_h 20 | #define SymRez_h 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | 27 | #include 28 | #include 29 | 30 | #define SR_DYLD_HDR ((void *) -1) 31 | 32 | typedef const struct mach_header_64 mach_header; 33 | typedef const struct mach_header_64* mach_header_t; 34 | 35 | // return true to stop loop 36 | typedef bool (*symrez_function_t)(char *symbol, void *ptr); 37 | 38 | typedef struct symrez* symrez_t; 39 | 40 | /*! @function symrez_new 41 | @abstract Create new symrez object. Caller must free. 42 | @param image_name Name or full path of the library to symbolicate. Pass NULL for current executable */ 43 | symrez_t symrez_new(const char *image_name); 44 | 45 | /*! @function symrez_new 46 | @abstract Create new symrez object. Caller must free. 47 | @param header Pointer to the mach_header_64 to symbolicate. Pass NULL for current executable */ 48 | symrez_t symrez_new_mh(mach_header_t header); 49 | 50 | /*! @function sr_resolve_symbol 51 | @abstract Find symbol address 52 | @param symrez symrez object created by symrez_new 53 | @param symbol Mangled symbol name 54 | @return Pointer to symbol location or NULL if not found */ 55 | void * sr_resolve_symbol(symrez_t symrez, const char *symbol); 56 | 57 | /*! @function sr_for_each 58 | @abstract Loop through all symbols with a callback 59 | @param symrez symrez object created by symrez_new 60 | @param callback callback for processing each iteration. Return true to stop loop. 61 | @discussion String passed to 'callback' may be ephemeral . */ 62 | void sr_for_each(symrez_t symrez, symrez_function_t callback); 63 | 64 | /*! @function symrez_free 65 | @abstract Release all resources allocated for this symrez object */ 66 | void symrez_free(symrez_t); 67 | 68 | /*! @function symrez_resolve_once 69 | @abstract Lookup a single symbol. Does not allocate memory but not recommended for multiple lookups 70 | @param image_name Name or full path of the library to symbolicate. Pass NULL for current executable 71 | @return Pointer to symbol location or NULL if not found */ 72 | void * symrez_resolve_once(const char *image_name, const char *symbol); 73 | 74 | /*! @function symrez_resolve_once_mh 75 | @abstract Lookup a single symbol. Does not allocate memory but not recommended for multiple lookups 76 | @param header Pointer to the mach_header_64 to symbolicate. Pass NULL for current executable 77 | @return Pointer to symbol location or NULL if not found */ 78 | void * symrez_resolve_once_mh(mach_header_t header, const char *symbol); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | #endif /* SymRez_h */ 84 | ``` 85 | 86 | ## Example 87 | 88 | ``` 89 | // Example: Resolving a symbol from a system framework 90 | symrez_t framework = symrez_new("SomeFramework"); 91 | if(framework != NULL) { 92 | void* symbol = sr_resolve_symbol(framework, "_SomePrivateFunction"); 93 | if(symbol != NULL) { 94 | // Use the resolved symbol 95 | printf("Symbol resolved successfully\n"); 96 | } 97 | symrez_free(framework); 98 | } 99 | ``` 100 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowTransparency/OpacityController.m: -------------------------------------------------------------------------------- 1 | // // 2 | // // OpacityController.m 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | // #import 10 | // #import "../../headers/macwmfx_globals.h" 11 | 12 | // @interface OpacityController : NSObject 13 | // @end 14 | 15 | // @implementation OpacityController 16 | 17 | // + (void)load { 18 | // // Nothing needed here since we just want the swizzle 19 | // } 20 | 21 | // @end 22 | 23 | // ZKSwizzleInterface(BS_NSWindow_Opacity, NSWindow, NSWindow) 24 | 25 | // @implementation BS_NSWindow_Opacity 26 | 27 | // - (void)makeKeyAndOrderFront:(id)sender { 28 | // ZKOrig(void, sender); 29 | 30 | // // Skip if this is not a regular window 31 | // if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 32 | 33 | // // Skip if window is in fullscreen 34 | // if (self.styleMask & NSWindowStyleMaskFullScreen) { 35 | // // Reset opacity and remove background when entering fullscreen 36 | // [self resetWindowOpacity]; 37 | // return; 38 | // } 39 | 40 | // // Check if transparency is enabled and has a valid value 41 | // if (gTransparencyConfig.enabled && gTransparencyConfig.value >= 0.0) { 42 | // [self updateWindowOpacity]; 43 | // } else { 44 | // [self resetWindowOpacity]; 45 | // } 46 | // } 47 | 48 | // - (void)resetWindowOpacity { 49 | // NSView *contentView = self.contentView; 50 | // if (!contentView) return; 51 | 52 | // // Reset opacity for all subviews 53 | // for (NSView *subview in [contentView.subviews copy]) { 54 | // if (CGColorEqualToColor(subview.layer.backgroundColor, [[NSColor redColor] CGColor])) { 55 | // [subview removeFromSuperview]; 56 | // } else { 57 | // subview.alphaValue = 1.0; 58 | // } 59 | // } 60 | 61 | // // Reset window properties 62 | // self.backgroundColor = [NSColor windowBackgroundColor]; 63 | // self.opaque = YES; 64 | // } 65 | 66 | // - (void)updateWindowOpacity { 67 | // NSView *contentView = self.contentView; 68 | // if (!contentView) return; 69 | 70 | // // Clamp opacity between 0.1 and 1.0 to prevent completely invisible windows 71 | // CGFloat opacity = MAX(0.1, MIN(1.0, gTransparencyConfig.value)); 72 | 73 | // // Apply opacity to all subviews 74 | // NSArray *subviews = [contentView.subviews copy]; 75 | 76 | // // Find and remove any existing red background 77 | // NSView *existingBackground = nil; 78 | // for (NSView *view in subviews) { 79 | // if (CGColorEqualToColor(view.layer.backgroundColor, [[NSColor redColor] CGColor])) { 80 | // existingBackground = view; 81 | // [view removeFromSuperview]; 82 | // break; 83 | // } 84 | // } 85 | 86 | // // Create or update red background 87 | // NSView *redBackgroundView = existingBackground ?: [[NSView alloc] initWithFrame:contentView.bounds]; 88 | // redBackgroundView.wantsLayer = YES; 89 | // redBackgroundView.layer.backgroundColor = [[NSColor redColor] CGColor]; 90 | // redBackgroundView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; 91 | 92 | // // Add background at the bottom 93 | // [contentView addSubview:redBackgroundView positioned:NSWindowBelow relativeTo:nil]; 94 | 95 | // // Update opacity for other views 96 | // for (NSView *subview in subviews) { 97 | // if (subview != existingBackground) { 98 | // subview.alphaValue = opacity; 99 | // } 100 | // } 101 | 102 | // // Update window properties 103 | // self.backgroundColor = [NSColor clearColor]; 104 | // self.opaque = NO; 105 | // } 106 | 107 | // @end -------------------------------------------------------------------------------- /src/modules/windows/features/window_example.m: -------------------------------------------------------------------------------- 1 | // 2 | // window_example.m 3 | // macwmfx 4 | // 5 | // Example of using conditional compilation for feature management 6 | // 7 | 8 | #import "../headers/macwmfx_globals.h" 9 | 10 | @interface WindowExample : NSObject 11 | - (void)setupWindowFeatures:(NSWindow *)window; 12 | @end 13 | 14 | @implementation WindowExample 15 | 16 | - (void)setupWindowFeatures:(NSWindow *)window { 17 | MACWMFX_LOG_INFO(macwmfx_log_window, "Setting up window features for: %{public}@", window); 18 | 19 | #if MACWMFX_ENABLE_WINDOW_BORDERS 20 | // Window border code - only compiled if feature is enabled 21 | [self setupWindowBorders:window]; 22 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Window borders configured"); 23 | #endif 24 | 25 | #if MACWMFX_ENABLE_WINDOW_SHADOWS 26 | // Window shadow code 27 | [self setupWindowShadows:window]; 28 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Window shadows configured"); 29 | #endif 30 | 31 | #if MACWMFX_ENABLE_WINDOW_TRANSPARENCY 32 | // Transparency code 33 | [self setupWindowTransparency:window]; 34 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Window transparency configured"); 35 | #endif 36 | 37 | #if MACWMFX_ENABLE_WINDOW_BLUR 38 | // Blur effects - might be problematic, easy to disable 39 | [self setupWindowBlur:window]; 40 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Window blur configured"); 41 | #endif 42 | 43 | #if MACWMFX_ENABLE_TITLEBAR_TWEAKS 44 | // Titlebar modifications 45 | [self setupTitlebarTweaks:window]; 46 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Titlebar tweaks configured"); 47 | #endif 48 | 49 | #if MACWMFX_ENABLE_ADVANCED_SHADOWS 50 | // Experimental shadow features - disabled by default 51 | [self setupAdvancedShadows:window]; 52 | MACWMFX_LOG_DEBUG(macwmfx_log_shadow, "Advanced shadows configured (experimental)"); 53 | #endif 54 | 55 | #if MACWMFX_ENABLE_CUSTOM_ANIMATIONS 56 | // Custom animations - might conflict with system 57 | [self setupCustomAnimations:window]; 58 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Custom animations configured (experimental)"); 59 | #endif 60 | 61 | MACWMFX_LOG_INFO(macwmfx_log_window, "Window feature setup complete"); 62 | } 63 | 64 | #if MACWMFX_ENABLE_WINDOW_BORDERS 65 | - (void)setupWindowBorders:(NSWindow *)window { 66 | // Border implementation here 67 | // This entire method is excluded from compilation if feature is disabled 68 | MACWMFX_LOG_INFO(macwmfx_log_window, "Setting up window borders"); 69 | } 70 | #endif 71 | 72 | #if MACWMFX_ENABLE_WINDOW_SHADOWS 73 | - (void)setupWindowShadows:(NSWindow *)window { 74 | // Shadow implementation here 75 | MACWMFX_LOG_INFO(macwmfx_log_shadow, "Setting up window shadows"); 76 | } 77 | #endif 78 | 79 | #if MACWMFX_ENABLE_WINDOW_TRANSPARENCY 80 | - (void)setupWindowTransparency:(NSWindow *)window { 81 | // Transparency implementation here 82 | MACWMFX_LOG_INFO(macwmfx_log_window, "Setting up window transparency"); 83 | } 84 | #endif 85 | 86 | #if MACWMFX_ENABLE_WINDOW_BLUR 87 | - (void)setupWindowBlur:(NSWindow *)window { 88 | // Blur implementation here - might be problematic 89 | MACWMFX_LOG_INFO(macwmfx_log_window, "Setting up window blur"); 90 | } 91 | #endif 92 | 93 | #if MACWMFX_ENABLE_TITLEBAR_TWEAKS 94 | - (void)setupTitlebarTweaks:(NSWindow *)window { 95 | // Titlebar implementation here 96 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Setting up titlebar tweaks"); 97 | } 98 | #endif 99 | 100 | #if MACWMFX_ENABLE_ADVANCED_SHADOWS 101 | - (void)setupAdvancedShadows:(NSWindow *)window { 102 | // Advanced shadow implementation here - experimental 103 | MACWMFX_LOG_INFO(macwmfx_log_shadow, "Setting up advanced shadows (experimental)"); 104 | } 105 | #endif 106 | 107 | #if MACWMFX_ENABLE_CUSTOM_ANIMATIONS 108 | - (void)setupCustomAnimations:(NSWindow *)window { 109 | // Custom animation implementation here - experimental 110 | MACWMFX_LOG_INFO(macwmfx_log_window, "Setting up custom animations (experimental)"); 111 | } 112 | #endif 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /src/modules/objc_hook.m: -------------------------------------------------------------------------------- 1 | // #include 2 | // #include 3 | // #include 4 | // #include 5 | // #include 6 | // #include 7 | 8 | // // Objective-C hook storage 9 | // CALayer* (*_old_layer)(id self, SEL _cmd); 10 | 11 | // // C hook storage 12 | // void (*printf_old)(const char *, ...); 13 | 14 | // // Frida/Gum function pointers for C hooks 15 | // void (*GumInterceptorReplaceFunc)(void * self, void * function_address, void * replacement_function, void * replacement_data, void ** original_function); 16 | // void *(*GumModuleFindExportByNameFunc)(const char * module_name, const char * symbol_name); 17 | // void (*GumInterceptorBeginTransactionFunc)(void * self); 18 | // void (*GumInterceptorEndTransactionFunc)(void * self); 19 | 20 | // void * magic; 21 | 22 | // // Objective-C hook replacement functions 23 | // CALayer* replacement_layer(id self, SEL _cmd) { 24 | // CALayer *orig = _old_layer(self, _cmd); 25 | // [orig setBackgroundColor:NSColor.redColor.CGColor]; 26 | // return orig; 27 | // } 28 | 29 | // // C hook replacement functions 30 | // void printf_hook(const char *format, ...) { 31 | // va_list args; 32 | // va_start(args, format); 33 | 34 | // printf_old("[HOOKED] "); 35 | // vprintf(format, args); 36 | 37 | // va_end(args); 38 | // } 39 | 40 | // // Helper function to hook Objective-C methods 41 | // void HookObjcMethod(Class class, SEL selector, IMP replacement, IMP *original) { 42 | // Method method = class_getInstanceMethod(class, selector); 43 | // if (method != NULL) { 44 | // *original = method_setImplementation(method, replacement); 45 | // NSLog(@"[HOOKED] Successfully hooked %@ method on %@", 46 | // NSStringFromSelector(selector), 47 | // NSStringFromClass(class)); 48 | // } else { 49 | // NSLog(@"[ERROR] Failed to find method %@ in class %@", 50 | // NSStringFromSelector(selector), 51 | // NSStringFromClass(class)); 52 | // } 53 | // } 54 | 55 | // // Helper function to hook C functions using Frida/Gum 56 | // void HookCFunction(void * func, void * new, void ** old) { 57 | // if (func != NULL) { 58 | // GumInterceptorBeginTransactionFunc(magic); 59 | // GumInterceptorReplaceFunc(magic, func, new, NULL, old); 60 | // GumInterceptorEndTransactionFunc(magic); 61 | // } 62 | // } 63 | 64 | // // Ammonia entry point - unified hook loader 65 | // __attribute__((visibility("default"))) void LoadFunction(void *interceptor) { 66 | // NSLog(@"[INFO] macwmfx LoadFunction called - initializing hooks"); 67 | 68 | // // Setup C function hooking via Frida/Gum 69 | // magic = interceptor; 70 | // void *hooking = dlopen("/usr/local/bin/ammonia/fridagum.dylib", RTLD_NOW | RTLD_GLOBAL); 71 | // if (hooking != NULL) { 72 | // GumInterceptorReplaceFunc = dlsym(hooking, "gum_interceptor_replace"); 73 | // GumModuleFindExportByNameFunc = dlsym(hooking, "gum_module_find_export_by_name"); 74 | // GumInterceptorBeginTransactionFunc = dlsym(hooking, "gum_interceptor_begin_transaction"); 75 | // GumInterceptorEndTransactionFunc = dlsym(hooking, "gum_interceptor_end_transaction"); 76 | 77 | // // Hook C functions (example: printf) 78 | // HookCFunction(printf, printf_hook, (void **)&printf_old); 79 | // NSLog(@"[INFO] C function hooks initialized"); 80 | // } else { 81 | // NSLog(@"[WARNING] Failed to load fridagum.dylib - C hooks disabled"); 82 | // } 83 | 84 | // // Setup Objective-C method hooking 85 | // Class viewClass = NSClassFromString(@"NSView"); 86 | // if (viewClass != nil) { 87 | // // Hook the layer method for red background example 88 | // HookObjcMethod(viewClass, @selector(layer), (IMP)replacement_layer, (void **)&_old_layer); 89 | // NSLog(@"[INFO] NSView layer hooks installed"); 90 | // } else { 91 | // NSLog(@"[ERROR] Failed to find NSView class"); 92 | // } 93 | 94 | // NSLog(@"[INFO] macwmfx hook initialization complete"); 95 | // } 96 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowSizeContraints/DisableResizeConstraints.m: -------------------------------------------------------------------------------- 1 | // 2 | // DisableResizeConstraints.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "macwmfx_globals.h" 11 | 12 | ZKSwizzleInterface(BS_NSWindow_Resize, NSWindow, NSWindow) 13 | 14 | @implementation BS_NSWindow_Resize 15 | 16 | - (void)makeKeyAndOrderFront:(id)sender { 17 | ZKOrig(void, sender); 18 | 19 | // Skip if this is not a regular window (e.g., menu, tooltip, etc.) 20 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 21 | 22 | // Skip if window is a panel, sheet, or other special window type 23 | if (self.styleMask & (NSWindowStyleMaskHUDWindow | 24 | NSWindowStyleMaskNonactivatingPanel | 25 | NSWindowStyleMaskUtilityWindow)) return; 26 | 27 | // Skip if window doesn't want to be resizable (check original style mask) 28 | if (!(self.styleMask & NSWindowStyleMaskResizable)) return; 29 | 30 | // Skip if window has a fixed aspect ratio 31 | if ([self respondsToSelector:@selector(aspectRatio)] && !NSEqualSizes([self aspectRatio], NSZeroSize)) return; 32 | 33 | // Skip if window has content size constraints 34 | NSSize minContentSize = [self contentMinSize]; 35 | NSSize maxContentSize = [self contentMaxSize]; 36 | if (!NSEqualSizes(minContentSize, NSZeroSize) && !NSEqualSizes(maxContentSize, NSZeroSize) && 37 | NSEqualSizes(minContentSize, maxContentSize)) return; 38 | 39 | // Only disable resize constraints if the config has constraints disabled 40 | if (!gWindowSizeConstraintsConfig.enabled) { 41 | [self disableResizeConstraints]; 42 | } 43 | } 44 | 45 | - (void)disableResizeConstraints { 46 | // Skip if this is not a regular window (e.g., menu, tooltip, etc.) 47 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 48 | 49 | // Skip if window is a panel, sheet, or other special window type 50 | if (self.styleMask & (NSWindowStyleMaskHUDWindow | 51 | NSWindowStyleMaskNonactivatingPanel | 52 | NSWindowStyleMaskUtilityWindow)) return; 53 | 54 | // Skip if window doesn't want to be resizable (check original style mask) 55 | if (!(self.styleMask & NSWindowStyleMaskResizable)) return; 56 | 57 | // Skip if window has a fixed aspect ratio 58 | if ([self respondsToSelector:@selector(aspectRatio)] && !NSEqualSizes([self aspectRatio], NSZeroSize)) return; 59 | 60 | // Skip if window has content size constraints 61 | NSSize minContentSize = [self contentMinSize]; 62 | NSSize maxContentSize = [self contentMaxSize]; 63 | if (!NSEqualSizes(minContentSize, NSZeroSize) && !NSEqualSizes(maxContentSize, NSZeroSize) && 64 | NSEqualSizes(minContentSize, maxContentSize)) return; 65 | 66 | // Directly use self as NSWindow instead of accessing a private ivar 67 | NSWindow *window = (NSWindow *)self; 68 | 69 | // Ensure window exists and can be resized 70 | if (!window || ![window respondsToSelector:@selector(setMinSize:)] || 71 | ![window respondsToSelector:@selector(setMaxSize:)]) return; 72 | 73 | // Get current window size 74 | NSSize currentSize = window.frame.size; 75 | 76 | // Try to modify constraints within a @try block to catch any exceptions 77 | @try { 78 | // Enable resizing and remove constraints while preserving current size 79 | window.styleMask |= NSWindowStyleMaskResizable; 80 | [window setMinSize:NSMakeSize(currentSize.width * 0.5, currentSize.height * 0.5)]; // Allow 50% smaller 81 | [window setMaxSize:NSMakeSize(currentSize.width * 2.0, currentSize.height * 2.0)]; // Allow 200% larger 82 | 83 | // Ensure window stays at current size after removing constraints 84 | [window setFrame:NSMakeRect(window.frame.origin.x, 85 | window.frame.origin.y, 86 | currentSize.width, 87 | currentSize.height) 88 | display:YES]; 89 | } @catch (NSException *exception) { 90 | // If anything goes wrong, restore original state and skip this window 91 | window.styleMask &= ~NSWindowStyleMaskResizable; 92 | return; 93 | } 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowOutline/WindowBordersCenterline.m: -------------------------------------------------------------------------------- 1 | // // 2 | // // WindowBordersCenterline.m 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | // #import 10 | // #import "../../headers/macwmfx_globals.h" 11 | // #import 12 | 13 | // ZKSwizzleInterface(BS_NSWindow_BordersCenterline, NSWindow, NSWindow) 14 | 15 | // @interface BSCenterlineBorderWindow : NSPanel 16 | // @property (nonatomic, weak) NSWindow *targetWindow; 17 | // @end 18 | 19 | // @implementation BSCenterlineBorderWindow 20 | 21 | // - (instancetype)initWithTargetWindow:(NSWindow *)window { 22 | // self = [super initWithContentRect:NSZeroRect 23 | // styleMask:NSWindowStyleMaskBorderless 24 | // backing:NSBackingStoreBuffered 25 | // defer:NO]; 26 | // if (self) { 27 | // self.targetWindow = window; 28 | // self.backgroundColor = [NSColor clearColor]; 29 | // self.opaque = NO; 30 | // self.hasShadow = NO; 31 | // self.level = NSFloatingWindowLevel; 32 | // self.ignoresMouseEvents = YES; 33 | // self.releasedWhenClosed = NO; 34 | // } 35 | // return self; 36 | // } 37 | 38 | // - (void)updateBorderFrame { 39 | // if (!self.targetWindow) return; 40 | 41 | // NSRect targetFrame = self.targetWindow.frame; 42 | // CGFloat borderWidth = gOutlineConfig.width; 43 | 44 | // // For centerline, position border to overlap window edge 45 | // NSRect borderFrame = NSInsetRect(targetFrame, -borderWidth/2, -borderWidth/2); 46 | // [self setFrame:borderFrame display:YES]; 47 | // } 48 | 49 | // @end 50 | 51 | // @implementation BS_NSWindow_BordersCenterline { 52 | // BSCenterlineBorderWindow *_borderWindow; 53 | // } 54 | 55 | // + (void)initialize { 56 | // if (self == [BS_NSWindow_BordersCenterline class]) { 57 | // NSLog(@"[macwmfx] Window centerline border controller initialized"); 58 | // } 59 | // } 60 | 61 | // - (void)updateBorder { 62 | // @try { 63 | // // Skip if disabled or wrong type 64 | // if (!gOutlineConfig.enabled || 65 | // ![gOutlineConfig.type isEqualToString:@"centerline"]) { 66 | // [self clearBorder]; 67 | // return; 68 | // } 69 | 70 | // // Skip non-standard windows 71 | // if (![self isKindOfClass:[NSWindow class]] || 72 | // [self isKindOfClass:[NSPanel class]] || 73 | // !(self.styleMask & NSWindowStyleMaskTitled) || 74 | // (self.styleMask & NSWindowStyleMaskFullScreen)) { 75 | // [self clearBorder]; 76 | // return; 77 | // } 78 | 79 | // NSView *frameView = [self.contentView superview]; 80 | // if (!frameView) return; 81 | 82 | // frameView.wantsLayer = YES; 83 | 84 | // [CATransaction begin]; 85 | // [CATransaction setDisableActions:YES]; 86 | 87 | // frameView.layer.borderWidth = gOutlineConfig.width; 88 | // frameView.layer.cornerRadius = gOutlineConfig.cornerRadius; 89 | 90 | // NSColor *borderColor = self.isKeyWindow ? 91 | // [NSColor colorWithDeviceWhite:0.0 alpha:0.3] : 92 | // [NSColor colorWithDeviceWhite:0.5 alpha:0.3]; 93 | 94 | // if (gOutlineConfig.customColor.enabled) { 95 | // borderColor = self.isKeyWindow ? 96 | // gOutlineConfig.customColor.active : 97 | // gOutlineConfig.customColor.inactive; 98 | // } 99 | 100 | // frameView.layer.borderColor = borderColor.CGColor; 101 | 102 | // [CATransaction commit]; 103 | // } @catch (NSException *e) { 104 | // NSLog(@"[macwmfx] Error updating centerline border: %@", e); 105 | // [self clearBorder]; 106 | // } 107 | // } 108 | 109 | // - (void)clearBorder { 110 | // @try { 111 | // NSView *frameView = [self.contentView superview]; 112 | // if (frameView && frameView.layer) { 113 | // frameView.layer.borderWidth = 0; 114 | // frameView.layer.borderColor = nil; 115 | // } 116 | // } @catch (NSException *e) { 117 | // NSLog(@"[macwmfx] Error clearing centerline border: %@", e); 118 | // } 119 | // } 120 | 121 | // - (void)makeKeyAndOrderFront:(id)sender { 122 | // ZKOrig(void, sender); 123 | // [self updateBorder]; 124 | // } 125 | 126 | // - (void)becomeKeyWindow { 127 | // ZKOrig(void); 128 | // [self updateBorder]; 129 | // } 130 | 131 | // - (void)resignKeyWindow { 132 | // ZKOrig(void); 133 | // [self updateBorder]; 134 | // } 135 | 136 | // - (void)windowDidEnterFullScreen:(NSNotification *)notification { 137 | // [self clearBorder]; 138 | // } 139 | 140 | // - (void)windowDidExitFullScreen:(NSNotification *)notification { 141 | // [self updateBorder]; 142 | // } 143 | 144 | // @end -------------------------------------------------------------------------------- /src/modules/windows/features/windowOutline/WindowBordersOutline.mm: -------------------------------------------------------------------------------- 1 | // // 2 | // // WindowBordersOutline.m 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | // #import "../../headers/macwmfx_globals.h" 10 | // #import 11 | 12 | // Hey I couldn't figure this out. How did you do this? 13 | // — Today at 1:58 PM 14 | // C++ hook 15 | // — Today at 1:58 PM 16 | // OH 17 | // — Today at 2:02 PM 18 | // force the inactive shadow, hook the data function for the shadow and bam 19 | 20 | 21 | // @interface BSOutlineBorderWindow : NSPanel 22 | // @property (nonatomic, weak) NSWindow *targetWindow; 23 | // @end 24 | 25 | // @implementation BSOutlineBorderWindow 26 | 27 | // - (instancetype)initWithTargetWindow:(NSWindow *)window { 28 | // self = [super initWithContentRect:window.frame 29 | // styleMask:NSWindowStyleMaskBorderless 30 | // backing:NSBackingStoreBuffered 31 | // defer:YES]; 32 | // if (self) { 33 | // self.targetWindow = window; 34 | // self.backgroundColor = [NSColor clearColor]; 35 | // self.opaque = NO; 36 | // self.hasShadow = NO; 37 | // self.level = NSNormalWindowLevel - 1; 38 | // self.ignoresMouseEvents = YES; 39 | 40 | // NSView *contentView = self.contentView; 41 | // contentView.wantsLayer = YES; 42 | // contentView.layer = [CALayer layer]; 43 | // } 44 | // return self; 45 | // } 46 | 47 | // - (void)updateBorderFrame { 48 | // if (!self.targetWindow) return; 49 | 50 | // NSRect targetFrame = self.targetWindow.frame; 51 | // CGFloat borderWidth = MIN(MAX(gOutlineConfig.width, 1), 10); 52 | // NSRect borderFrame = NSInsetRect(targetFrame, -borderWidth, -borderWidth); 53 | 54 | // [self setFrame:borderFrame display:YES]; 55 | 56 | // CALayer *borderLayer = self.contentView.layer; 57 | // borderLayer.frame = self.contentView.bounds; 58 | // borderLayer.borderWidth = borderWidth; 59 | // borderLayer.cornerRadius = MIN(gOutlineConfig.cornerRadius, 40); 60 | 61 | // NSColor *borderColor = self.targetWindow.isKeyWindow ? 62 | // [NSColor colorWithDeviceWhite:0.0 alpha:0.3] : 63 | // [NSColor colorWithDeviceWhite:0.5 alpha:0.3]; 64 | 65 | // if (gOutlineConfig.customColor.enabled) { 66 | // borderColor = self.targetWindow.isKeyWindow ? 67 | // gOutlineConfig.customColor.active : 68 | // gOutlineConfig.customColor.inactive; 69 | // } 70 | 71 | // borderLayer.borderColor = borderColor.CGColor; 72 | // } 73 | 74 | // @end 75 | 76 | // ZKSwizzleInterface(BS_NSWindow_BordersOutline, NSWindow, NSWindow) 77 | 78 | // @implementation BS_NSWindow_BordersOutline { 79 | // BSOutlineBorderWindow * __weak _borderWindow; 80 | // } 81 | 82 | // + (void)initialize { 83 | // if (self == [BS_NSWindow_BordersOutline class]) { 84 | // NSLog(@"[macwmfx] Window outline controller initialized"); 85 | // } 86 | // } 87 | 88 | // - (void)updateBorder { 89 | // @try { 90 | // // Skip if disabled or wrong type 91 | // if (!gOutlineConfig.enabled || 92 | // ![gOutlineConfig.type isEqualToString:@"outline"]) { 93 | // [self clearBorder]; 94 | // return; 95 | // } 96 | 97 | // // Skip non-standard windows 98 | // if (![self isKindOfClass:[NSWindow class]] || 99 | // [self isKindOfClass:[NSPanel class]] || 100 | // !(self.styleMask & NSWindowStyleMaskTitled) || 101 | // (self.styleMask & NSWindowStyleMaskFullScreen)) { 102 | // [self clearBorder]; 103 | // return; 104 | // } 105 | 106 | // if (!_borderWindow) { 107 | // _borderWindow = [[BSOutlineBorderWindow alloc] initWithTargetWindow:self]; 108 | // } 109 | 110 | // [_borderWindow updateBorderFrame]; 111 | // [_borderWindow orderFront:nil]; 112 | // } @catch (NSException *e) { 113 | // NSLog(@"[macwmfx] Error updating outline border: %@", e); 114 | // [self clearBorder]; 115 | // } 116 | // } 117 | 118 | // - (void)clearBorder { 119 | // if (_borderWindow) { 120 | // [_borderWindow orderOut:nil]; 121 | // _borderWindow = nil; 122 | // } 123 | // } 124 | 125 | // - (void)makeKeyAndOrderFront:(id)sender { 126 | // ZKOrig(void, sender); 127 | // [self updateBorder]; 128 | // } 129 | 130 | // - (void)becomeKeyWindow { 131 | // ZKOrig(void); 132 | // [self updateBorder]; 133 | // } 134 | 135 | // - (void)resignKeyWindow { 136 | // ZKOrig(void); 137 | // [self updateBorder]; 138 | // } 139 | 140 | // - (void)close { 141 | // [self clearBorder]; 142 | // ZKOrig(void); 143 | // } 144 | 145 | // - (void)windowDidEnterFullScreen:(NSNotification *)notification { 146 | // [self clearBorder]; 147 | // } 148 | 149 | // - (void)windowDidExitFullScreen:(NSNotification *)notification { 150 | // [self updateBorder]; 151 | // } 152 | 153 | // @end -------------------------------------------------------------------------------- /src/modules/windows/features/windowTitlebar/ForceCustomTitle.m: -------------------------------------------------------------------------------- 1 | // 2 | // ForceCustomTitle.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "macwmfx_globals.h" 11 | 12 | ZKSwizzleInterface(BS_NSWindow_CustomTitle, NSWindow, NSWindow) 13 | 14 | @implementation BS_NSWindow_CustomTitle 15 | 16 | + (void)load { 17 | // Register for config change notifications 18 | [[NSDistributedNotificationCenter defaultCenter] addObserver:self 19 | selector:@selector(handleConfigChange:) 20 | name:@"com.aspauldingcode.macwmfx.configChanged" 21 | object:nil]; 22 | } 23 | 24 | + (void)handleConfigChange:(NSNotification *)notification { 25 | // Only update titles if custom titles are enabled 26 | if (!gCustomTitleConfig.enabled) { 27 | return; 28 | } 29 | 30 | dispatch_async(dispatch_get_main_queue(), ^{ 31 | // Update all window titles 32 | for (NSWindow *window in [NSApp windows]) { 33 | @try { 34 | if ([window isKindOfClass:[NSWindow class]] && (window.styleMask & NSWindowStyleMaskTitled)) { 35 | // Store original title before any custom title was applied 36 | NSString *originalTitle = window.representedFilename ?: window.title; 37 | if (originalTitle) { 38 | // Trigger our swizzled setTitle: method to update based on new config 39 | [window setTitle:originalTitle]; 40 | } 41 | } 42 | } @catch (NSException *exception) { 43 | MACWMFX_LOG_ERROR(macwmfx_log_titlebar, "Error updating window title: %{public}@", exception); 44 | } 45 | } 46 | }); 47 | } 48 | 49 | // Helper method that retrieves a custom title via Key-Value Coding. 50 | // This avoids direct use of the undeclared "titlebar" property. 51 | - (NSString *)customTitleFromTitlebar { 52 | NSString *customTitle = nil; 53 | @try { 54 | id titlebar = [self valueForKey:@"titlebar"]; 55 | if (titlebar) { 56 | id customTitleObj = [titlebar valueForKey:@"customTitle"]; 57 | if (customTitleObj) { 58 | customTitle = [customTitleObj valueForKey:@"title"]; 59 | } 60 | } 61 | } @catch (NSException *exception) { 62 | // If the key is undefined, just ignore and fall back. 63 | } 64 | return customTitle; 65 | } 66 | 67 | - (void)makeKeyAndOrderFront:(id)sender { 68 | @try { 69 | ZKOrig(void, sender); 70 | 71 | if (!(self.styleMask & NSWindowStyleMaskTitled)) 72 | return; 73 | 74 | // Force update title state when the window becomes key. 75 | NSString *currentTitle = self.title; 76 | if (currentTitle) { 77 | [self setTitle:currentTitle]; 78 | [self displayIfNeeded]; 79 | } 80 | } @catch (NSException *exception) { 81 | MACWMFX_LOG_ERROR(macwmfx_log_titlebar, "Error in makeKeyAndOrderFront: %{public}@", exception); 82 | } 83 | } 84 | 85 | - (void)setTitle:(NSString *)title { 86 | @try { 87 | if (!(self.styleMask & NSWindowStyleMaskTitled)) { 88 | ZKOrig(void, title); 89 | return; 90 | } 91 | 92 | NSString *finalTitle = title; 93 | 94 | // Only modify title if custom titles are enabled 95 | if (gCustomTitleConfig.enabled && gCustomTitleConfig.title) { 96 | finalTitle = @(gCustomTitleConfig.title); 97 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Applying custom title: %{public}@", finalTitle); 98 | } 99 | 100 | if (finalTitle) { 101 | ZKOrig(void, finalTitle); 102 | } 103 | } @catch (NSException *exception) { 104 | MACWMFX_LOG_ERROR(macwmfx_log_titlebar, "Error setting title: %{public}@", exception); 105 | // Fallback to original title if there's an error 106 | if (title) { 107 | ZKOrig(void, title); 108 | } 109 | } 110 | } 111 | 112 | - (void)setTitleWithRepresentedFilename:(NSString *)filename { 113 | @try { 114 | if (!(self.styleMask & NSWindowStyleMaskTitled)) { 115 | ZKOrig(void, filename); 116 | return; 117 | } 118 | 119 | NSString *finalTitle = filename; 120 | 121 | // Only modify title if custom titles are enabled 122 | if (gCustomTitleConfig.enabled && gCustomTitleConfig.title) { 123 | finalTitle = @(gCustomTitleConfig.title); 124 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Applying custom title: %{public}@", finalTitle); 125 | } 126 | 127 | if (finalTitle) { 128 | ZKOrig(void, finalTitle); 129 | } 130 | } @catch (NSException *exception) { 131 | MACWMFX_LOG_ERROR(macwmfx_log_titlebar, "Error setting title with filename: %{public}@", exception); 132 | // Fallback to original filename if there's an error 133 | if (filename) { 134 | ZKOrig(void, filename); 135 | } 136 | } 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /AppleGraphicsInternals.md: -------------------------------------------------------------------------------- 1 | # Apple Graphics Internals: Key Types and Structures 2 | 3 | > **Note:** This documentation (@AppleGraphicsInternals.md) is based on a dump of internal type definitions extracted from macOS Ventura. It provides insight into the private structures used by Apple's graphics and windowing systems on that OS version. 4 | 5 | This document summarizes and organizes the most developer-relevant types and structures found in the internal Apple graphics/windowing system dump (`windowserver.info`). It focuses on types from Core Animation (CA), Core Graphics (CG), and related frameworks, providing a reference for reverse engineers and advanced developers. 6 | 7 | --- 8 | 9 | ## Core Animation (CA) Types 10 | 11 | ### Layers 12 | - **CALayer**: The base class for all layer types. Represents a renderable region in a layer tree. 13 | - **CAEmitterLayer, CATiledLayer, CATransformLayer, CAReplicatorLayer, CAShapeLayer, CAProxyLayer, CAChameleonLayer, CABoxLayoutManager, CAScrollLayer, CATableLayoutManager, CAWrappedLayoutManager, CACloningTerminatorLayer, CABackdropLayer, CADistanceFieldLayer, CAPluginLayer, CAOpenGLLayer, CAEAGLLayer, CAMetalLayer, CAPortalLayer, CALayerHost, CAStateControllerLayer, CAStateElement, CAStateAddElement, CAStateRemoveElement, CAStateSetValue, CAStateTransitionElement, CAStateRemoveAnimation, CAStateAddAnimation**: Specialized layer types for various rendering, effects, and layout purposes. 14 | 15 | ### Animation 16 | - **CAAnimation**: Base struct for animations. 17 | - **CAPropertyAnimation, CABasicAnimation, CAKeyframeAnimation, CASpringAnimation, CAMatchMoveAnimation, CAMatchPropertyAnimation, CATransition, CAAnimationGroup, CAExternalAnimation**: Animation types for property changes, keyframes, transitions, and groups. 18 | - **CAMediaTimingFunction, CAMediaTimingFunctionPrivate, CAMediaTimingFunctionBuiltin**: Timing functions for animation pacing. 19 | 20 | ### Rendering and Contexts 21 | - **CARenderer**: Represents a rendering context for drawing layer trees. 22 | - **CAContext**: Encapsulates a rendering context for remote or local drawing. 23 | - **CAContentStream, CAContentStreamOptions, CAContentStreamFrame**: Types for streaming content to displays or remote contexts. 24 | 25 | ### Display and Timing 26 | - **CADisplay, CADisplayMode, CADisplayAttributes, CADisplayPreferences, CADisplayLink, CADisplayPowerAssertion, CADisplayWallGroup, CADisplayWallConfiguration, CADisplayProperties, CADisplayPersistedData, CADisplayPersistedLatency, CADisplayPersistedPreferredMode, CAFrameRateRange, CAFrameIntervalRange, DynamicFrameRateSource, CADynamicFrameRateSource**: Types for display management, modes, and timing. 27 | - **CATimingFramePacingLatency**: Frame pacing and latency info. 28 | 29 | ### Metal and OpenGL 30 | - **CAMetalLayer, CAMetalDrawable, CAMetalDisplayLink, CAMetalDisplayLinkUpdate, CAOpenGLLayer, CAEAGLLayer, CAEAGLBuffer, _CAEAGLNativeWindow**: Types for Metal and OpenGL-backed layers and drawables. 31 | 32 | ### Miscellaneous 33 | - **CAFilter, CAValueFunction, CAStateController, CAStateControllerTransition, CAStateControllerUndo, CAState, CAStateTransition, CAStateControllerAnimation, CAStateControllerDelegate, CAStateControllerData, CAStateControllerLayer, CAStateElement, CAStateAddElement, CAStateRemoveElement, CAStateSetValue, CAStateTransitionElement, CAStateRemoveAnimation, CAStateAddAnimation**: State management and filtering. 34 | - **CAFrameRateRangeGroup, CAFrameRateRange, CAFrameIntervalRange, CAFrameRateRangeGroup, CAFrameRateRange, CAFrameIntervalRange**: Frame rate and timing. 35 | 36 | --- 37 | 38 | ## Core Graphics (CG) Types 39 | 40 | ### Geometry and Transforms 41 | - **CGPoint, CGSize, CGRect, CGAffineTransform, CATransform3D, CAPoint3D, CACornerRadii, CAColorMatrix**: Fundamental geometric and transformation types. 42 | 43 | ### Drawing and Rendering 44 | - **CGPath, CGPathElement, CGPattern, CGColor, CGImage, CGContext**: Types for paths, patterns, colors, images, and drawing contexts. 45 | - **CGColorSpace, CGColorTRC, CGColorTRCParametric, CGColorTRCTable, CGColorTRCBoundaryExtension**: Color management and transfer curve types. 46 | 47 | --- 48 | 49 | ## Window Server and Display Management 50 | - **CAWindowServer, CAWindowServerImpl, CAWindowServerDisplay, CAWindowServerDisplayImpl, CAWindowServerVirtualDisplay, CAWindowServerDisplayManager**: Types for managing the window server and displays. 51 | - **CABrightnessTransaction**: Manages display brightness transactions. 52 | 53 | --- 54 | 55 | ## Objective-C Runtime Integration 56 | - **objc_object, NSObject, NSString, NSArray, NSDictionary, NSMutableArray, NSMutableSet, NSTimer**: Core Objective-C types referenced by many structures. 57 | - **__objc2_class, __objc2_class_ro, __objc2_class_rw, __objc2_class_rw1, __objc2_class_rw1_ext, __objc2_category, __objc2_meth, __objc2_meth_list, __objc2_ivar, __objc2_ivar_list, __objc2_prop, __objc2_prop_list, __objc2_prot, __objc2_prot_list**: Internal Objective-C runtime structures. 58 | 59 | --- 60 | 61 | ## Synchronization and Low-Level Types 62 | - **Mutex, SpinLock, pthread_mutex_t, pthread_cond_t, mach_msg_header_t, mach_port_t, mach_vm_size_t, vm_address_t, vm_size_t, audit_token_t**: Synchronization, Mach IPC, and memory management types. 63 | 64 | --- 65 | 66 | ## Notes 67 | - Many types are internal and not documented by Apple. Use with caution. 68 | - This document omits purely internal, low-level, or irrelevant types for clarity. 69 | - For more details, refer to the original `windowserver.info` dump. -------------------------------------------------------------------------------- /LOGGING_TRANSITION.md: -------------------------------------------------------------------------------- 1 | # macwmfx Logging System Transition 2 | 3 | ## Overview 4 | 5 | Successfully completed the transition from NSLog to Apple's modern os_log system for better performance, categorization, and system integration. 6 | 7 | ## Changes Made 8 | 9 | ### 1. Enhanced Logging System (`src/shared/macwmfx_logging.h/m`) 10 | 11 | - **New Categories Added:** 12 | - `macwmfx_log_titlebar` - For titlebar-related operations 13 | - `macwmfx_log_traffic_lights` - For traffic light controls 14 | - `macwmfx_log_shadow` - For window shadow operations 15 | - `macwmfx_log_outline` - For window outline/border operations 16 | - Existing: `macwmfx_log_server`, `macwmfx_log_client`, `macwmfx_log_config`, `macwmfx_log_window`, `macwmfx_log_hook`, `macwmfx_log_cli`, `macwmfx_log_general` 17 | 18 | - **Convenience Macros:** 19 | - `MACWMFX_LOG_INFO(category, ...)` - For informational messages 20 | - `MACWMFX_LOG_ERROR(category, ...)` - For error messages 21 | - `MACWMFX_LOG_DEBUG(category, ...)` - For debug messages 22 | - `MACWMFX_LOG_WARNING(category, ...)` - For warnings 23 | - `MACWMFX_LOG_FAULT(category, ...)` - For critical faults 24 | 25 | - **Legacy Compatibility:** 26 | - `DLog()` and `VLog()` macros now use os_log instead of NSLog 27 | - Maintains backward compatibility for existing code 28 | 29 | ### 2. Updated Files with os_log Implementation 30 | 31 | #### Core Components 32 | 33 | - **CLI Tool** (`src/modules/CLITool.m`) 34 | - Replaced NSLog with `MACWMFX_LOG_ERROR` for pipe errors 35 | - Added logging initialization in main() 36 | 37 | - **Main Module** (`src/main/macwmfx.m`) 38 | - Added comprehensive logging for module lifecycle 39 | - Initialization, start/stop, configuration loading 40 | - Module loading/unloading tracking 41 | 42 | - **Client** (`src/client/macwmfx_client.m`) 43 | - Added logging initialization 44 | - Client connection and response logging 45 | 46 | #### Window Features 47 | 48 | - **Window Example** (`src/modules/windows/features/window_example.m`) 49 | - Converted all NSLog calls to appropriate os_log categories 50 | - Used `macwmfx_log_window`, `macwmfx_log_shadow`, `macwmfx_log_titlebar` 51 | 52 | - **Custom Title** (`src/modules/windows/features/windowTitlebar/ForceCustomTitle.m`) 53 | - Error handling with `MACWMFX_LOG_ERROR` 54 | - Info logging with `MACWMFX_LOG_INFO` 55 | - Used privacy-aware format strings (`%{public}@`) 56 | 57 | - **Titlebar Controls** (`src/modules/windows/features/windowTitlebar/DisableTitleBars.m`, `TitlebarAesthetics.m`) 58 | - Initialization and state change logging 59 | - Proper categorization with `macwmfx_log_titlebar` 60 | 61 | - **Traffic Lights** (`src/modules/windows/features/windowTrafficLights/disableTrafficLights.m`) 62 | - Visibility state changes 63 | - Used `macwmfx_log_traffic_lights` category 64 | 65 | - **Window Shadows** (`src/modules/windows/features/windowShadow/DisableWindowShadow.m`) 66 | - Shadow state management logging 67 | - Configuration change tracking 68 | - Used `macwmfx_log_shadow` category 69 | 70 | ### 3. Updated Global Headers 71 | 72 | - **macwmfx_globals.h** 73 | - Removed NSLog-based DLog/VLog macros 74 | - Added reference to new os_log system 75 | - Fixed include path for logging header 76 | 77 | ## Benefits of os_log vs NSLog 78 | 79 | ### Performance 80 | 81 | - **Lazy Evaluation:** os_log only formats strings when logs are actually collected 82 | - **Efficient Storage:** Binary format reduces disk I/O 83 | - **Lower CPU Overhead:** Especially for debug/verbose logging 84 | 85 | ### System Integration 86 | 87 | - **Console.app Integration:** Logs appear properly categorized in Console 88 | - **Unified Logging:** Integrates with system-wide logging infrastructure 89 | - **Log Streaming:** Works with `log stream` command for real-time monitoring 90 | 91 | ### Privacy & Security 92 | 93 | - **Privacy-Aware Formatting:** `%{public}@` vs `%@` for sensitive data 94 | - **Automatic Redaction:** Private data automatically redacted in logs 95 | - **Structured Logging:** Better parsing and analysis capabilities 96 | 97 | ### Debugging & Monitoring 98 | 99 | - **Categorized Logging:** Easy filtering by subsystem and category 100 | - **Log Levels:** Proper debug, info, error, fault level separation 101 | - **Persistence:** Logs persist across reboots and crashes 102 | 103 | ## Usage Examples 104 | 105 | ### Basic Logging 106 | 107 | ```objc 108 | MACWMFX_LOG_INFO(macwmfx_log_window, "Window updated successfully"); 109 | MACWMFX_LOG_ERROR(macwmfx_log_config, "Failed to load configuration: %{public}@", error); 110 | ``` 111 | 112 | ### Legacy Compatibility 113 | 114 | ```objc 115 | DLog(@"Debug message"); // Now uses os_log_info 116 | VLog(@"Verbose message"); // Now uses os_log_debug 117 | ``` 118 | 119 | ### Viewing Logs 120 | 121 | ```bash 122 | # Real-time log streaming 123 | log stream --predicate 'subsystem == "com.aspauldingcode.macwmfx"' 124 | 125 | # Filter by category 126 | log stream --predicate 'subsystem == "com.aspauldingcode.macwmfx" AND category == "window"' 127 | 128 | # CLI tool log observation 129 | macwmfx --observe-logs 130 | ``` 131 | 132 | ## Migration Status 133 | 134 | ✅ **Complete** - All NSLog calls converted to os_log 135 | ✅ **Tested** - Compilation successful across all updated files 136 | ✅ **Backward Compatible** - Existing DLog/VLog macros still work 137 | ✅ **Categorized** - Proper logging categories for different subsystems 138 | ✅ **Initialized** - Logging system properly initialized in all entry points 139 | 140 | ## Next Steps 141 | 142 | - Monitor log output during runtime testing 143 | - Adjust log levels as needed for production vs debug builds 144 | - Consider adding more specific categories for new features 145 | - Implement log rotation/cleanup policies if needed 146 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowBlur/BlurController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BlurController.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import "macwmfx_globals.h" 11 | #import 12 | #import 13 | #import 14 | 15 | // #import 16 | // #import 17 | // #import 18 | 19 | // static void *BlurViewKey = &BlurViewKey; 20 | // static void *BackdropViewKey = &BackdropViewKey; 21 | 22 | // // This controller adds blur effects to windows 23 | // ZKSwizzleInterface(BS_NSWindow_Blur, NSWindow, NSWindow) 24 | 25 | // @implementation BS_NSWindow_Blur 26 | 27 | // - (void)makeKeyAndOrderFront:(id)sender { 28 | // ZKOrig(void, sender); 29 | 30 | // // Skip if this is not a regular window (e.g., menu, tooltip, etc.) 31 | // if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 32 | 33 | // // Skip if window is in fullscreen 34 | // if (self.styleMask & NSWindowStyleMaskFullScreen) { 35 | // // Remove blur when entering fullscreen 36 | // [self removeBlurEffect]; 37 | // return; 38 | // } 39 | 40 | // // Subscribe to window resize notifications 41 | // [[NSNotificationCenter defaultCenter] addObserver:self 42 | // selector:@selector(windowDidResize:) 43 | // name:NSWindowDidResizeNotification 44 | // object:self]; 45 | 46 | // [self setupBlurEffect]; 47 | // } 48 | 49 | // - (void)windowDidResize:(NSNotification *)notification { 50 | // // Skip if in fullscreen 51 | // if (self.styleMask & NSWindowStyleMaskFullScreen) return; 52 | 53 | // // Update blur effect on resize 54 | // [self setupBlurEffect]; 55 | // } 56 | 57 | // - (void)removeBlurEffect { 58 | // NSVisualEffectView *existingBlur = objc_getAssociatedObject(self, BlurViewKey); 59 | // NSView *existingBackdrop = objc_getAssociatedObject(self, BackdropViewKey); 60 | 61 | // if (existingBlur) { 62 | // [existingBlur removeFromSuperview]; 63 | // objc_setAssociatedObject(self, BlurViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 64 | // } 65 | 66 | // if (existingBackdrop) { 67 | // [existingBackdrop removeFromSuperview]; 68 | // objc_setAssociatedObject(self, BackdropViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 69 | // } 70 | 71 | // // Reset window properties 72 | // self.backgroundColor = [NSColor windowBackgroundColor]; 73 | // self.opaque = YES; 74 | // } 75 | 76 | // - (void)makeViewTransparent:(NSView *)view { 77 | // view.wantsLayer = YES; 78 | // view.layer.backgroundColor = [NSColor clearColor].CGColor; 79 | 80 | // // Recursively make all subviews transparent 81 | // for (NSView *subview in view.subviews) { 82 | // [self makeViewTransparent:subview]; 83 | // } 84 | // } 85 | 86 | // - (void)setupBlurEffect { 87 | // if (!gBlurConfig.enabled) return; 88 | 89 | // // Skip if this is not a regular window 90 | // if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 91 | 92 | // // Skip if in fullscreen 93 | // if (self.styleMask & NSWindowStyleMaskFullScreen) { 94 | // [self removeBlurEffect]; 95 | // return; 96 | // } 97 | 98 | // NSView *contentView = [self contentView]; 99 | // if (!contentView) return; 100 | 101 | // // Make all existing views transparent 102 | // [self makeViewTransparent:contentView]; 103 | 104 | // // Create backdrop view 105 | // NSView *backdropView = [[NSView alloc] initWithFrame:contentView.bounds]; 106 | // backdropView.wantsLayer = YES; 107 | // backdropView.layer.backgroundColor = [NSColor clearColor].CGColor; 108 | // backdropView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; 109 | 110 | // // Add backdrop at the very bottom 111 | // [contentView addSubview:backdropView positioned:NSWindowBelow relativeTo:nil]; 112 | // objc_setAssociatedObject(self, BackdropViewKey, backdropView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 113 | 114 | // // Create the main blur effect view 115 | // NSVisualEffectView *blurView = [[NSVisualEffectView alloc] initWithFrame:contentView.bounds]; 116 | // blurView.blendingMode = NSVisualEffectBlendingModeBehindWindow; 117 | // blurView.material = NSVisualEffectMaterialWindowBackground; 118 | // blurView.state = NSVisualEffectStateActive; 119 | // blurView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; 120 | 121 | // // Add blur effect above backdrop but below other content 122 | // [contentView addSubview:blurView positioned:NSWindowBelow relativeTo:nil]; 123 | // objc_setAssociatedObject(self, BlurViewKey, blurView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 124 | 125 | // // Make window transparent 126 | // self.backgroundColor = [NSColor clearColor]; 127 | // self.opaque = NO; 128 | 129 | // // Apply blur effect to all content subviews 130 | // for (NSView *subview in [contentView.subviews copy]) { 131 | // if (subview != blurView && subview != backdropView) { 132 | // NSVisualEffectView *subBlur = [[NSVisualEffectView alloc] initWithFrame:subview.bounds]; 133 | // subBlur.blendingMode = NSVisualEffectBlendingModeBehindWindow; 134 | // subBlur.material = NSVisualEffectMaterialWindowBackground; 135 | // subBlur.state = NSVisualEffectStateActive; 136 | // subBlur.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; 137 | // [subview addSubview:subBlur positioned:NSWindowBelow relativeTo:nil]; 138 | // } 139 | // } 140 | // } 141 | 142 | // @end 143 | -------------------------------------------------------------------------------- /src/SymRez/SymRez.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SYMREZ_HPP__ 2 | #define __SYMREZ_HPP__ 3 | #if defined(__cplusplus) 4 | #include "Core.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef _LIBCPP_CONSTEXPR_SINCE_CXX14 12 | #if _LIBCPP_STD_VER >= 14 13 | #define _LIBCPP_CONSTEXPR_SINCE_CXX14 constexpr 14 | #else 15 | #define _LIBCPP_CONSTEXPR_SINCE_CXX14 16 | #endif 17 | #endif 18 | 19 | #ifndef sr_contexpr_14 20 | #define sr_contexpr_14 _LIBCPP_CONSTEXPR_SINCE_CXX14 21 | #endif 22 | 23 | namespace { 24 | struct SymRez { 25 | public: 26 | struct iterator { 27 | public: 28 | struct IteratorEntry { 29 | public: 30 | inline const std::string_view &name() const { return name_; } 31 | 32 | inline void *address() const { return address_; } 33 | 34 | private: 35 | friend SymRez::iterator; 36 | inline IteratorEntry(sr_iterator_t i) { 37 | if (i == nullptr) [[unlikely]] { 38 | name_ = ""; 39 | address_ = nullptr; 40 | return; 41 | } 42 | setName(i); 43 | address_ = sr_iter_get_ptr(i); 44 | } 45 | 46 | #if _LIBCPP_STD_VER >= 17 47 | IteratorEntry(const IteratorEntry &) = delete; 48 | IteratorEntry &operator=(const IteratorEntry &) = delete; 49 | #endif 50 | 51 | inline sr_contexpr_14 void setName(std::string_view name) { 52 | name_ = name; 53 | } 54 | 55 | inline sr_contexpr_14 void setName(sr_iterator_t it) { 56 | sr_symbol_t n = sr_iter_get_symbol(it); 57 | name_ = n ? n : ""; 58 | } 59 | 60 | inline sr_contexpr_14 void setAddress(void *address) { 61 | address_ = address; 62 | } 63 | 64 | inline sr_contexpr_14 void setAddress(sr_iterator_t it) { 65 | void *a = sr_iter_get_ptr(it); 66 | setAddress(a); 67 | } 68 | 69 | inline sr_contexpr_14 void update(sr_iterator_t it) { 70 | setName(it); 71 | setAddress(it); 72 | } 73 | 74 | std::string_view name_; 75 | void *address_; 76 | }; 77 | 78 | using iterator_category = std::forward_iterator_tag; 79 | using value_type = IteratorEntry; 80 | using difference_type = std::ptrdiff_t; 81 | using pointer = IteratorEntry *; 82 | using reference = IteratorEntry &; 83 | using const_pointer = const IteratorEntry *; 84 | using const_reference = const IteratorEntry &; 85 | 86 | inline iterator(sr_iterator_t iter) : iter_(iter), current_(iter) {} 87 | 88 | inline iterator(symrez_t sr) 89 | : iter_(sr_get_iterator(sr)), current_(nullptr) { 90 | sr_iter_reset(iter_); 91 | sr_iter_get_next(iter_); 92 | current_.update(iter_); 93 | } 94 | 95 | #if _LIBCPP_STD_VER >= 17 96 | iterator(const iterator &) = delete; 97 | iterator &operator=(const iterator &) = delete; 98 | #endif 99 | 100 | inline constexpr const_pointer operator->() const { return ¤t_; } 101 | 102 | inline constexpr const_reference &operator*() const { return current_; } 103 | 104 | inline constexpr bool operator==(const iterator &other) const { 105 | return current_.address() == other.current_.address(); 106 | } 107 | 108 | inline constexpr bool operator!=(const iterator &other) const { 109 | return !(*this == other); 110 | } 111 | 112 | inline sr_contexpr_14 iterator &operator++() { 113 | sr_iter_get_next(iter_); 114 | current_.update(iter_); 115 | return *this; 116 | } 117 | 118 | inline void reset() { 119 | sr_iter_reset(iter_); 120 | (void)++(*this); 121 | } 122 | 123 | private: 124 | sr_iterator_t iter_; 125 | IteratorEntry current_; 126 | }; 127 | 128 | using IteratorEntry = SymRez::iterator::IteratorEntry; 129 | 130 | inline SymRez(const std::string_view &image_name) 131 | : symrez_(symrez_new(image_name.data()), sr_free) {} 132 | 133 | inline SymRez(mach_header_t &header) 134 | : symrez_(symrez_new_mh(header), sr_free) {} 135 | 136 | SymRez(const SymRez &) = delete; 137 | SymRez &operator=(const SymRez &) = delete; 138 | 139 | inline explicit operator bool() const { return bool(symrez_); } 140 | 141 | static inline void *ResolveOnce(const std::string_view &image_name, 142 | const std::string_view &symbol) { 143 | return symrez_resolve_once(image_name.data(), symbol.data()); 144 | } 145 | 146 | static inline void *ResolveOnce(mach_header_t &image, 147 | const std::string_view &symbol) { 148 | return symrez_resolve_once_mh(image, symbol.data()); 149 | } 150 | 151 | template 153 | inline FunctionType resolveSymbol(const std::string_view &symbol) const { 154 | return reinterpret_cast( 155 | sr_resolve_symbol(symrez_.get(), symbol.data())); 156 | } 157 | 158 | template 160 | inline FunctionType 161 | resolveExportedSymbol(const std::string_view &symbol) const { 162 | return reinterpret_cast( 163 | sr_resolve_exported(symrez_.get(), symbol.data())); 164 | } 165 | 166 | inline iterator begin() const { 167 | sr_iterator_t it = sr_get_iterator(symrez_.get()); 168 | sr_iter_reset(it); 169 | sr_iter_get_next(it); 170 | return iterator(it); 171 | } 172 | 173 | inline iterator end() const { return iterator((sr_iterator_t) nullptr); } 174 | 175 | inline sr_contexpr_14 void setSlide(intptr_t slide) const { 176 | sr_set_slide(symrez_.get(), slide); 177 | } 178 | 179 | inline constexpr intptr_t getSlide() const { 180 | return sr_get_slide(symrez_.get()); 181 | } 182 | 183 | private: 184 | std::unique_ptr symrez_; 185 | // symrez_t symrez_; 186 | }; 187 | } // namespace 188 | 189 | #endif //__cplusplus 190 | #endif 191 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowTitlebar/ForceClassicTitlebars.m: -------------------------------------------------------------------------------- 1 | // // 2 | // // ForceClassicTitlebars.m 3 | // // macwmfx 4 | // // 5 | // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // 8 | 9 | // #import 10 | // #import 11 | // #import "../../headers/macwmfx_globals.h" 12 | 13 | // ZKSwizzleInterface(BS_NSWindow_TitleBar_Classic, NSWindow, NSWindow) 14 | 15 | // @implementation BS_NSWindow_TitleBar_Classic 16 | 17 | // static const CGFloat kForcedTitlebarHeight = 50.0; 18 | 19 | // - (void)makeKeyAndOrderFront:(id)sender { 20 | // ZKOrig(void, sender); 21 | 22 | // // Skip if this is not a regular window 23 | // if ([self isKindOfClass:[NSPanel class]] || [self isKindOfClass:[NSMenu class]]) return; 24 | 25 | // // Force classic titlebar if the config has classic titlebars enabled 26 | // if (gTitlebarConfig.forceClassic) { 27 | // [self forceClassicTitleBar]; 28 | // } 29 | // } 30 | 31 | // - (void)forceClassicTitleBar { 32 | // NSWindow *window = (NSWindow *)self; 33 | // window.titlebarAppearsTransparent = NO; 34 | // window.titleVisibility = NSWindowTitleVisible; 35 | // window.styleMask = (window.styleMask & ~(NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskUnifiedTitleAndToolbar)) | 36 | // (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable); 37 | // window.toolbarStyle = NSWindowToolbarStyleExpanded; 38 | 39 | // NSView *titlebarView = [window standardWindowButton:NSWindowCloseButton].superview.superview; 40 | // if (titlebarView) { 41 | // titlebarView.frame = (NSRect){.origin = {titlebarView.frame.origin.x, window.frame.size.height - kForcedTitlebarHeight}, .size = {titlebarView.frame.size.width, kForcedTitlebarHeight}}; 42 | // NSView *contentView = window.contentView; 43 | // contentView.frame = (NSRect){.origin = {contentView.frame.origin.x, 0}, .size = {contentView.frame.size.width, window.frame.size.height - kForcedTitlebarHeight}}; 44 | // titlebarView.autoresizingMask = NSViewNotSizable; 45 | // contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; 46 | 47 | // for (NSButton *button in @[[window standardWindowButton:NSWindowCloseButton], [window standardWindowButton:NSWindowMiniaturizeButton], [window standardWindowButton:NSWindowZoomButton]]) { 48 | // if (button) { 49 | // button.frame = (NSRect){.origin = {button.frame.origin.x, (kForcedTitlebarHeight - button.frame.size.height) / 2}, .size = button.frame.size}; 50 | // } 51 | // } 52 | // } 53 | 54 | // if (window.delegate != (id)self) { 55 | // window.delegate = (id)self; 56 | // } 57 | 58 | // [self swizzleTitlebarMethods]; 59 | // } 60 | 61 | // - (void)windowDidResize:(NSNotification *)notification { 62 | // NSWindow *window = notification.object; 63 | // if (![window isKindOfClass:[NSPanel class]] && ![window isKindOfClass:[NSMenu class]]) { 64 | // [self enforceTitlebarConstraints:window]; 65 | // } 66 | // } 67 | 68 | // - (void)enforceTitlebarConstraints:(NSWindow *)window { 69 | // [self forceClassicTitleBar]; 70 | // } 71 | 72 | // - (void)swizzleTitlebarMethods { 73 | // static dispatch_once_t onceToken; 74 | // dispatch_once(&onceToken, ^{ 75 | // [self swizzleOriginalSelector:@selector(setTitlebarAppearsTransparent:) withSwizzledSelector:@selector(swizzled_setTitlebarAppearsTransparent:)]; 76 | // [self swizzleOriginalSelector:@selector(setTitleVisibility:) withSwizzledSelector:@selector(swizzled_setTitleVisibility:)]; 77 | // [self swizzleOriginalSelector:@selector(setStyleMask:) withSwizzledSelector:@selector(swizzled_setStyleMask:)]; 78 | // [self swizzleOriginalSelector:@selector(setToolbarStyle:) withSwizzledSelector:@selector(swizzled_setToolbarStyle:)]; 79 | // [self swizzleOriginalSelector:@selector(setContentView:) withSwizzledSelector:@selector(swizzled_setContentView:)]; 80 | // [self swizzleOriginalSelector:@selector(setFrame:display:) withSwizzledSelector:@selector(swizzled_setFrame:display:)]; 81 | // }); 82 | // } 83 | 84 | // - (void)swizzleOriginalSelector:(SEL)originalSelector withSwizzledSelector:(SEL)swizzledSelector { 85 | // Method originalMethod = class_getInstanceMethod([self class], originalSelector); 86 | // Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector); 87 | // if (class_addMethod([self class], originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) { 88 | // class_replaceMethod([self class], swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 89 | // } else { 90 | // method_exchangeImplementations(originalMethod, swizzledMethod); 91 | // } 92 | // } 93 | 94 | // - (void)swizzled_setTitlebarAppearsTransparent:(BOOL)flag { 95 | // [self swizzled_setTitlebarAppearsTransparent:NO]; 96 | // } 97 | 98 | // - (void)swizzled_setTitleVisibility:(NSWindowTitleVisibility)visibility { 99 | // [self swizzled_setTitleVisibility:NSWindowTitleVisible]; 100 | // } 101 | 102 | // - (void)swizzled_setStyleMask:(NSWindowStyleMask)styleMask { 103 | // [self swizzled_setStyleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)]; 104 | // } 105 | 106 | // - (void)swizzled_setToolbarStyle:(NSWindowToolbarStyle)toolbarStyle { 107 | // [self swizzled_setToolbarStyle:NSWindowToolbarStyleExpanded]; 108 | // } 109 | 110 | // - (void)swizzled_setContentView:(NSView *)contentView { 111 | // [self swizzled_setContentView:contentView]; 112 | // [self forceClassicTitleBar]; 113 | // } 114 | 115 | // - (void)swizzled_setFrame:(NSRect)frameRect display:(BOOL)flag { 116 | // [self swizzled_setFrame:frameRect display:flag]; 117 | // [self enforceTitlebarConstraints:(NSWindow *)self]; 118 | // } 119 | 120 | // @end -------------------------------------------------------------------------------- /src/modules/windows/features/windowTitlebar/TitlebarAesthetics.m: -------------------------------------------------------------------------------- 1 | // 2 | // TitlebarAesthetics.m 3 | // macwmfx 4 | // 5 | // Modified to resolve compilation errors 6 | // 7 | 8 | #import 9 | #import "macwmfx_globals.h" 10 | 11 | // Removed duplicate forward declarations for NSTextField and NSColor 12 | 13 | // Compatibility macros for different SDK versions 14 | #ifndef NSWindowStyleMaskFullSizeContentView 15 | #define NSWindowStyleMaskFullSizeContentView (1 << 15) 16 | #endif 17 | 18 | ZKSwizzleInterface(BS_NSWindow_TitleColor, NSWindow, NSWindow) 19 | 20 | @implementation BS_NSWindow_TitleColor 21 | 22 | - (instancetype)init { 23 | self = [super init]; 24 | if (self) { 25 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Titlebar aesthetics controller initialized"); 26 | } 27 | return self; 28 | } 29 | 30 | + (void)initialize { 31 | if (self == [BS_NSWindow_TitleColor class]) { 32 | [[NSNotificationCenter defaultCenter] addObserver:self 33 | selector:@selector(updateAllTitlebarColors) 34 | name:@"com.aspauldingcode.macwmfx.configChanged" 35 | object:nil]; 36 | 37 | [[NSDistributedNotificationCenter defaultCenter] addObserver:self 38 | selector:@selector(updateAllTitlebarColors) 39 | name:@"com.aspauldingcode.macwmfx.configChanged" 40 | object:nil 41 | suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 42 | 43 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Titlebar aesthetics controller class initialized"); 44 | } 45 | } 46 | 47 | + (void)updateAllTitlebarColors { 48 | dispatch_async(dispatch_get_main_queue(), ^{ 49 | for (NSWindow *window in [NSApp windows]) { 50 | if ([window isKindOfClass:ZKClass(BS_NSWindow_TitleColor)]) { 51 | [(BS_NSWindow_TitleColor *)window updateTitlebarColor]; 52 | } 53 | } 54 | }); 55 | } 56 | 57 | - (NSTextField *)findOriginalTitleTextField { 58 | NSView *themeFrame = [self contentView].superview; 59 | 60 | for (NSView *view in themeFrame.subviews) { 61 | NSString *className = NSStringFromClass([view class]); 62 | if ([className containsString:@"NSTitlebar"]) { 63 | for (NSView *subview in view.subviews) { 64 | if ([subview isKindOfClass:[NSTextField class]] && 65 | [(NSTextField *)subview stringValue] == self.title) { 66 | return (NSTextField *)subview; 67 | } 68 | } 69 | } 70 | } 71 | return nil; 72 | } 73 | 74 | - (NSColor *)calculateForegroundColor { 75 | // Implement your color calculation logic 76 | if (gTitlebarConfig.customColor.enabled) { 77 | return self.isKeyWindow 78 | ? gTitlebarConfig.customColor.activeForeground 79 | : gTitlebarConfig.customColor.inactiveForeground; 80 | } 81 | return self.isKeyWindow ? [NSColor labelColor] : [NSColor secondaryLabelColor]; 82 | } 83 | 84 | - (NSColor *)calculateBackgroundColor { 85 | // Implement your background color calculation 86 | if (gTitlebarConfig.customColor.enabled) { 87 | return self.isKeyWindow 88 | ? gTitlebarConfig.customColor.activeBackground 89 | : gTitlebarConfig.customColor.inactiveBackground; 90 | } 91 | return gTitlebarConfig.aesthetics.activeColor; 92 | } 93 | 94 | - (void)updateTitlebarColor { 95 | // Skip for panels 96 | if ([self isKindOfClass:[NSPanel class]]) return; 97 | 98 | // Access styleMask through cast to NSWindow 99 | NSWindow *window = (NSWindow *)self; 100 | 101 | if (!gTitlebarConfig.enabled) { 102 | // If titlebar is disabled, make it transparent and hide title 103 | window.titlebarAppearsTransparent = YES; 104 | window.titleVisibility = NSWindowTitleHidden; 105 | window.styleMask |= NSWindowStyleMaskFullSizeContentView; 106 | return; 107 | } 108 | 109 | // Titlebar is enabled, show it normally 110 | window.titlebarAppearsTransparent = NO; 111 | window.titleVisibility = NSWindowTitleVisible; 112 | window.styleMask &= ~NSWindowStyleMaskFullSizeContentView; 113 | 114 | // Apply custom colors if enabled 115 | if (gTitlebarConfig.customColor.enabled) { 116 | NSTextField *titleField = [self findOriginalTitleTextField]; 117 | NSColor *foregroundColor = [self calculateForegroundColor]; 118 | NSColor *backgroundColor = [self calculateBackgroundColor]; 119 | 120 | if (titleField) { 121 | titleField.textColor = foregroundColor; 122 | titleField.font = [NSFont systemFontOfSize:13 weight:NSFontWeightSemibold]; 123 | } 124 | 125 | [self modifyTitlebarBackground:backgroundColor]; 126 | } 127 | } 128 | 129 | - (void)modifyTitlebarBackground:(NSColor *)color { 130 | NSView *themeFrame = [self contentView].superview; 131 | 132 | for (NSView *view in themeFrame.subviews) { 133 | NSString *className = NSStringFromClass([view class]); 134 | if ([className containsString:@"NSTitlebar"] && 135 | [view respondsToSelector:@selector(layer)] && 136 | view.frame.size.height <= 28) { 137 | 138 | view.wantsLayer = YES; 139 | view.layer.backgroundColor = color.CGColor; 140 | break; 141 | } 142 | } 143 | } 144 | 145 | - (void)makeKeyAndOrderFront:(id)sender { 146 | ZKOrig(void, sender); 147 | [self updateTitlebarColor]; 148 | } 149 | 150 | - (void)becomeKeyWindow { 151 | ZKOrig(void); 152 | [self updateTitlebarColor]; 153 | } 154 | 155 | - (void)resignKeyWindow { 156 | ZKOrig(void); 157 | [self updateTitlebarColor]; 158 | } 159 | 160 | + (void)dealloc { 161 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 162 | [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 163 | } 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowOutline/WindowBordersInline.mm: -------------------------------------------------------------------------------- 1 | // // // 2 | // // // WindowBordersInline.m 3 | // // // macwmfx 4 | // // // 5 | // // // Created by Alex "aspauldingcode" on 11/13/24. 6 | // // // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // // // 8 | 9 | // #import 10 | // #import "../../headers/macwmfx_globals.h" 11 | // #import 12 | 13 | // Hey I couldn't figure this out. How did you do this? 14 | // — Today at 1:58 PM 15 | // C++ hook 16 | // — Today at 1:58 PM 17 | // OH 18 | // — Today at 2:02 PM 19 | // force the inactive shadow, hook the data function for the shadow and bam 20 | 21 | 22 | 23 | // @interface NSWindow (Private) 24 | // - (BOOL)_getCornerRadius:(CGFloat *)radius; 25 | // @end 26 | 27 | // ZKSwizzleInterface(BS_NSWindow_BordersInline, NSWindow, NSWindow) 28 | 29 | // @implementation BS_NSWindow_BordersInline { 30 | // BOOL _isExitingFullscreen; 31 | // } 32 | 33 | // + (void)initialize { 34 | // if (self == [BS_NSWindow_BordersInline class]) { 35 | // // Only log if outlines are enabled 36 | // if (gOutlineConfig.enabled) { 37 | // NSLog(@"[macwmfx] Window inline border controller initialized"); 38 | // } 39 | // } 40 | // } 41 | 42 | // - (BOOL)shouldProcessWindowEvents { 43 | // return gOutlineConfig.enabled && 44 | // [gOutlineConfig.type isEqualToString:@"inline"] && 45 | // [self isKindOfClass:[NSWindow class]] && 46 | // ![self isKindOfClass:[NSPanel class]] && 47 | // (self.styleMask & NSWindowStyleMaskTitled); 48 | // } 49 | 50 | // - (void)updateBorder { 51 | // @try { 52 | // // Skip if window is invalid or in transition 53 | // if (!self.contentView || 54 | // self.isReleasedWhenClosed || 55 | // _isExitingFullscreen) { 56 | // return; 57 | // } 58 | 59 | // // Get frame view before proceeding 60 | // NSView *frameView = [self.contentView superview]; 61 | // if (!frameView) return; 62 | 63 | // // Skip if disabled or wrong type 64 | // if (!gOutlineConfig.enabled || 65 | // ![gOutlineConfig.type isEqualToString:@"inline"]) { 66 | // [self clearBorder]; 67 | // return; 68 | // } 69 | 70 | // // Skip non-standard windows 71 | // if (![self isKindOfClass:[NSWindow class]] || 72 | // [self isKindOfClass:[NSPanel class]] || 73 | // !(self.styleMask & NSWindowStyleMaskTitled) || 74 | // (self.styleMask & NSWindowStyleMaskFullScreen)) { 75 | // [self clearBorder]; 76 | // return; 77 | // } 78 | 79 | // frameView.wantsLayer = YES; 80 | 81 | // [CATransaction begin]; 82 | // [CATransaction setDisableActions:YES]; 83 | 84 | // frameView.layer.borderWidth = gOutlineConfig.width; 85 | // frameView.layer.cornerRadius = gOutlineConfig.cornerRadius; 86 | 87 | // NSColor *borderColor = self.isKeyWindow ? 88 | // [NSColor colorWithDeviceWhite:0.0 alpha:0.3] : 89 | // [NSColor colorWithDeviceWhite:0.5 alpha:0.3]; 90 | 91 | // if (gOutlineConfig.customColor.enabled) { 92 | // borderColor = self.isKeyWindow ? 93 | // gOutlineConfig.customColor.active : 94 | // gOutlineConfig.customColor.inactive; 95 | // } 96 | 97 | // frameView.layer.borderColor = borderColor.CGColor; 98 | 99 | // [CATransaction commit]; 100 | // } @catch (NSException *e) { 101 | // NSLog(@"[macwmfx] Error updating inline border: %@", e); 102 | // [self clearBorder]; 103 | // } 104 | // } 105 | 106 | // - (void)clearBorder { 107 | // @try { 108 | // NSView *frameView = [self.contentView superview]; 109 | // if (!frameView) return; 110 | 111 | // frameView.wantsLayer = YES; 112 | // [CATransaction begin]; 113 | // [CATransaction setDisableActions:YES]; 114 | 115 | // // Reset all layer properties 116 | // frameView.layer.borderWidth = 0; 117 | // frameView.layer.borderColor = nil; 118 | // frameView.layer.cornerRadius = 0; 119 | 120 | // [CATransaction commit]; 121 | // } @catch (NSException *e) { 122 | // NSLog(@"[macwmfx] Error clearing inline border: %@", e); 123 | // } 124 | // } 125 | 126 | // - (void)makeKeyAndOrderFront:(id)sender { 127 | // ZKOrig(void, sender); 128 | // if ([self shouldProcessWindowEvents]) { 129 | // [self updateBorder]; 130 | // } 131 | // } 132 | 133 | // - (void)becomeKeyWindow { 134 | // ZKOrig(void); 135 | // if ([self shouldProcessWindowEvents]) { 136 | // [self updateBorder]; 137 | // } 138 | // } 139 | 140 | // - (void)resignKeyWindow { 141 | // ZKOrig(void); 142 | // if ([self shouldProcessWindowEvents]) { 143 | // [self updateBorder]; 144 | // } 145 | // } 146 | 147 | // - (void)windowWillEnterFullScreen:(NSNotification *)notification { 148 | // if ([self shouldProcessWindowEvents]) { 149 | // [self clearBorder]; 150 | // } 151 | // } 152 | 153 | // - (void)windowDidEnterFullScreen:(NSNotification *)notification { 154 | // if ([self shouldProcessWindowEvents]) { 155 | // [self clearBorder]; 156 | // } 157 | // } 158 | 159 | // - (void)windowWillExitFullScreen:(NSNotification *)notification { 160 | // if ([self shouldProcessWindowEvents]) { 161 | // _isExitingFullscreen = YES; 162 | // [self clearBorder]; 163 | // } 164 | // } 165 | 166 | // - (void)windowDidExitFullScreen:(NSNotification *)notification { 167 | // if ([self shouldProcessWindowEvents]) { 168 | // _isExitingFullscreen = NO; 169 | // dispatch_async(dispatch_get_main_queue(), ^{ 170 | // [self updateBorder]; 171 | // }); 172 | // } 173 | // } 174 | 175 | // - (void)setFrame:(NSRect)frameRect display:(BOOL)flag { 176 | // ZKOrig(void, frameRect, flag); 177 | // if ([self shouldProcessWindowEvents] && !_isExitingFullscreen) { 178 | // [self updateBorder]; 179 | // } 180 | // } 181 | 182 | // @end -------------------------------------------------------------------------------- /src/shared/ZKSwizzle/ZKSwizzle.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKSwizzle.h 3 | // ZKSwizzle 4 | // 5 | // Created by Alexander S Zielenski on 7/24/14. 6 | // Copyright (c) 2014 Alexander S Zielenski. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | // This is a class for streamlining swizzling. Simply create a new class of any name you want and 14 | // Example: 15 | /* 16 | @interface ZKHookClass : NSObject 17 | - (NSString *)description; // hooks -description on NSObject 18 | - (void)addedMethod; // all subclasses of NSObject now respond to -addedMethod 19 | @end 20 | 21 | @implementation ZKHookClass 22 | ... 23 | @end 24 | 25 | [ZKSwizzle swizzleClass:ZKClass(ZKHookClass) forClass:ZKClass(destination)]; 26 | */ 27 | 28 | #ifndef ZKSWIZZLE_DEFS 29 | #define ZKSWIZZLE_DEFS 30 | 31 | // CRAZY MACROS FOR DYNAMIC PROTOTYPE CREATION 32 | #define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(0, ## __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5 ,4 ,3 ,2, 1, 0) 33 | #define VA_NUM_ARGS_IMPL(_0, _1,_2,_3,_4,_5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 ,N,...) N 34 | 35 | #define WRAP0() 36 | #define WRAP1(VARIABLE) , typeof ( VARIABLE ) 37 | #define WRAP2(VARIABLE, ...) WRAP1(VARIABLE) WRAP1(__VA_ARGS__) 38 | #define WRAP3(VARIABLE, ...) WRAP1(VARIABLE) WRAP2(__VA_ARGS__) 39 | #define WRAP4(VARIABLE, ...) WRAP1(VARIABLE) WRAP3(__VA_ARGS__) 40 | #define WRAP5(VARIABLE, ...) WRAP1(VARIABLE) WRAP4(__VA_ARGS__) 41 | #define WRAP6(VARIABLE, ...) WRAP1(VARIABLE) WRAP5(__VA_ARGS__) 42 | #define WRAP7(VARIABLE, ...) WRAP1(VARIABLE) WRAP6(__VA_ARGS__) 43 | #define WRAP8(VARIABLE, ...) WRAP1(VARIABLE) WRAP7(__VA_ARGS__) 44 | #define WRAP9(VARIABLE, ...) WRAP1(VARIABLE) WRAP8(__VA_ARGS__) 45 | #define WRAP10(VARIABLE, ...) WRAP1(VARIABLE) WRAP9(__VA_ARGS__) 46 | #define WRAP11(VARIABLE, ...) WRAP1(VARIABLE) WRAP10(__VA_ARGS__) 47 | #define WRAP12(VARIABLE, ...) WRAP1(VARIABLE) WRAP11(__VA_ARGS__) 48 | #define WRAP13(VARIABLE, ...) WRAP1(VARIABLE) WRAP12(__VA_ARGS__) 49 | #define WRAP14(VARIABLE, ...) WRAP1(VARIABLE) WRAP13(__VA_ARGS__) 50 | #define WRAP15(VARIABLE, ...) WRAP1(VARIABLE) WRAP14(__VA_ARGS__) 51 | #define WRAP16(VARIABLE, ...) WRAP1(VARIABLE) WRAP15(__VA_ARGS__) 52 | #define WRAP17(VARIABLE, ...) WRAP1(VARIABLE) WRAP16(__VA_ARGS__) 53 | #define WRAP18(VARIABLE, ...) WRAP1(VARIABLE) WRAP17(__VA_ARGS__) 54 | #define WRAP19(VARIABLE, ...) WRAP1(VARIABLE) WRAP18(__VA_ARGS__) 55 | #define WRAP20(VARIABLE, ...) WRAP1(VARIABLE) WRAP19(__VA_ARGS__) 56 | 57 | #define CAT(A, B) A ## B 58 | #define INVOKE(MACRO, NUMBER, ...) CAT(MACRO, NUMBER)(__VA_ARGS__) 59 | #define WRAP_LIST(...) INVOKE(WRAP, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__) 60 | 61 | // Gets the a class with the name CLASS 62 | #define ZKClass(CLASS) objc_getClass(#CLASS) 63 | 64 | // returns the value of an instance variable. 65 | #if !__has_feature(objc_arc) 66 | #define ZKHookIvar(OBJECT, TYPE, NAME) (*(TYPE *)ZKIvarPointer(OBJECT, NAME)) 67 | #else 68 | #define ZKHookIvar(OBJECT, TYPE, NAME) \ 69 | _Pragma("clang diagnostic push") \ 70 | _Pragma("clang diagnostic ignored \"-Wignored-attributes\"") \ 71 | (*(__unsafe_unretained TYPE *)ZKIvarPointer(OBJECT, NAME)) \ 72 | _Pragma("clang diagnostic pop") 73 | #endif 74 | // returns the original implementation of the swizzled function or null or not found 75 | #define ZKOrig(TYPE, ...) ((TYPE (*)(id, SEL WRAP_LIST(__VA_ARGS__)))(ZKOriginalImplementation(self, _cmd, __PRETTY_FUNCTION__)))(self, _cmd, ##__VA_ARGS__) 76 | 77 | // returns the original implementation of the superclass of the object swizzled 78 | #define ZKSuper(TYPE, ...) ((TYPE (*)(id, SEL WRAP_LIST(__VA_ARGS__)))(ZKSuperImplementation(self, _cmd, __PRETTY_FUNCTION__)))(self, _cmd, ##__VA_ARGS__) 79 | 80 | #define _ZKSwizzleInterfaceConditionally(CLASS_NAME, TARGET_CLASS, SUPERCLASS, GROUP, IMMEDIATELY) \ 81 | @interface _$ ## CLASS_NAME : SUPERCLASS @end \ 82 | @implementation _$ ## CLASS_NAME \ 83 | + (void)initialize {} \ 84 | @end \ 85 | @interface CLASS_NAME : _$ ## CLASS_NAME @end \ 86 | @implementation CLASS_NAME (ZKSWIZZLE) \ 87 | + (void)load { \ 88 | _$ZKRegisterInterface(self, #GROUP);\ 89 | if (IMMEDIATELY) { \ 90 | [self _ZK_unconditionallySwizzle]; \ 91 | } \ 92 | } \ 93 | + (void)_ZK_unconditionallySwizzle { \ 94 | ZKSwizzle(CLASS_NAME, TARGET_CLASS); \ 95 | } \ 96 | @end 97 | 98 | // Bootstraps your swizzling class so that it requires no setup 99 | // outside of this macro call 100 | // If you override +load you must call ZKSwizzle(CLASS_NAME, TARGET_CLASS) 101 | // yourself, otherwise the swizzling would not take place 102 | #define ZKSwizzleInterface(CLASS_NAME, TARGET_CLASS, SUPERCLASS) \ 103 | _ZKSwizzleInterfaceConditionally(CLASS_NAME, TARGET_CLASS, SUPERCLASS, ZK_UNGROUPED, YES) 104 | 105 | // Same as ZKSwizzleInterface, except 106 | #define ZKSwizzleInterfaceGroup(CLASS_NAME, TARGET_CLASS, SUPER_CLASS, GROUP) \ 107 | _ZKSwizzleInterfaceConditionally(CLASS_NAME, TARGET_CLASS, SUPER_CLASS, GROUP, NO) 108 | 109 | __BEGIN_DECLS 110 | 111 | // Make sure to cast this before you use it 112 | typedef id (*ZKIMP)(id, SEL, ...); 113 | 114 | // returns a pointer to the instance variable "name" on the object 115 | void *ZKIvarPointer(id self, const char *name); 116 | // returns the original implementation of a method with selector "sel" of an object hooked by the methods below 117 | ZKIMP ZKOriginalImplementation(id self, SEL sel, const char *info); 118 | // returns the implementation of a method with selector "sel" of the superclass of object 119 | ZKIMP ZKSuperImplementation(id object, SEL sel, const char *info); 120 | 121 | // hooks all the implemented methods of source with destination 122 | // adds any methods that arent implemented on destination to destination that are implemented in source 123 | #define ZKSwizzle(src, dst) _ZKSwizzle(ZKClass(src), ZKClass(dst)) 124 | BOOL _ZKSwizzle(Class src, Class dest); 125 | 126 | #define ZKSwizzleGroup(NAME) _ZKSwizzleGroup(#NAME) 127 | void _$ZKRegisterInterface(Class cls, const char *groupName); 128 | BOOL _ZKSwizzleGroup(const char *groupName); 129 | 130 | // Calls above method with the superclass of source for desination 131 | #define ZKSwizzleClass(src) _ZKSwizzleClass(ZKClass(src)) 132 | BOOL _ZKSwizzleClass(Class cls); 133 | 134 | __END_DECLS 135 | #endif 136 | 137 | -------------------------------------------------------------------------------- /src/SymRez/Core.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYMREZ_CORE__ 2 | #define __SYMREZ_CORE__ 3 | 4 | __BEGIN_DECLS 5 | #include "Base.h" 6 | OS_ASSUME_NONNULL_BEGIN 7 | 8 | /*! 9 | * @define SR_EXEC_HDR 10 | * 11 | * @abstract Can be used with symrez_new_mh() to get the main executable 12 | */ 13 | #define SR_EXEC_HDR ((mach_header_t)(void *) -1) 14 | 15 | /*! 16 | * @define SR_DYLD_HDR 17 | * 18 | * @abstract Can be used with symrez_new_mh() to get dyld header 19 | */ 20 | #define SR_DYLD_HDR ((mach_header_t)(void *) -2) 21 | 22 | // return true to stop loop 23 | typedef bool (*symrez_function_t)(sr_symbol_t symbol, sr_ptr_t ptr, void * SR_NULLABLE context); 24 | 25 | /*! 26 | * @function symrez_new 27 | * 28 | * @abstract Create new symrez object. Caller must free. 29 | * 30 | * @param image_name Name or full path of the library to symbolicate. Pass NULL for current executable 31 | */ 32 | symrez_t SR_NULLABLE OS_MALLOC OS_WARN_RESULT 33 | symrez_new(const char *image_name); 34 | 35 | /*! 36 | * @function symrez_new 37 | * 38 | * @abstract Create new symrez object. Caller must free. 39 | * 40 | * @param header Pointer to the mach_header_64 to symbolicate. Pass NULL for current executable 41 | */ 42 | symrez_t SR_NULLABLE OS_MALLOC OS_WARN_RESULT 43 | symrez_new_mh(mach_header_t header); 44 | 45 | /*! 46 | * @function sr_resolve_symbol 47 | * 48 | * @abstract Find symbol address 49 | * 50 | * @param symrez symrez object created by symrez_new 51 | * 52 | * @param symbol Mangled symbol name 53 | * 54 | * @return Pointer to symbol location or NULL if not found 55 | * */ 56 | sr_ptr_t sr_resolve_symbol(symrez_t symrez, const char *symbol); 57 | 58 | /*! 59 | * @function sr_resolve_exported 60 | * 61 | * @abstract Find symbol address of public symbol 62 | * 63 | * @param symrez symrez object created by symrez_new 64 | * 65 | * @param symbol Mangled symbol name 66 | * 67 | * @return Pointer to symbol location or NULL if not found 68 | * 69 | * @discussion 70 | * Use this instead of `sr_resolve_symbol` if you want to search for ONLY 71 | * public symbols. This is the same behavior as `dlsym` 72 | * */ 73 | sr_ptr_t sr_resolve_exported(symrez_t symrez, const char *symbol); 74 | 75 | /*! 76 | * @function sr_for_each 77 | * 78 | * @abstract Loop through all symbols with a callback 79 | * 80 | * @param symrez symrez object created by symrez_new 81 | * 82 | * @param context user context for callback 83 | * 84 | * @param callback callback for processing each iteration. Return true to stop loop. 85 | * 86 | * @discussion More performant and efficient than `sr_iterator`, but less convenient. String passed to 'callback' should be considered ephemeral. 87 | * */ 88 | void sr_for_each(symrez_t symrez, void * SR_NULLABLE context, symrez_function_t callback); 89 | 90 | /*! 91 | * @function sr_get_iterator 92 | * 93 | * @abstract Get iterator from symrez object 94 | * 95 | * @param symrez symrez object created by symrez_new 96 | * 97 | * @return iterator reference 98 | * 99 | * @discussion First call to `sr_get_iterator` will allocate more memory. Consider using 'sr_for_each' for more performance. 100 | * */ 101 | sr_iterator_t sr_get_iterator(symrez_t symrez); 102 | 103 | /*! 104 | * @function sr_set_slide 105 | * 106 | * @abstract Set custom slide value 107 | * 108 | * @param symrez symrez object created by symrez_new 109 | * 110 | * @param slide new slide value 111 | * 112 | * @discussion Useful for static analysis tools. i.e. disassemblers. 113 | */ 114 | void sr_set_slide(symrez_t symrez, intptr_t slide); 115 | 116 | /*! 117 | * @function sr_get_slide 118 | * 119 | * @abstract Get mach-o image slide 120 | * 121 | * @param symrez symrez object created by symrez_new 122 | * 123 | * @return slide value 124 | */ 125 | intptr_t sr_get_slide(symrez_t symrez); 126 | 127 | /*! 128 | * @function sr_free 129 | * 130 | * @abstract Release all resources allocated for this symrez object 131 | * */ 132 | void sr_free(symrez_t); 133 | 134 | /*! 135 | * @function symrez_resolve_once 136 | * 137 | * @abstract Lookup a single symbol. Does not allocate memory but not recommended for multiple lookups 138 | * 139 | * @param image_name Name or full path of the library to symbolicate. Pass NULL for current executable 140 | * 141 | * @return Pointer to symbol location or NULL if not found 142 | */ 143 | sr_ptr_t symrez_resolve_once(const char *image_name, const char *symbol); 144 | 145 | /*! 146 | * @function symrez_resolve_once_mh 147 | * 148 | * @abstract Lookup a single symbol. Does not allocate memory but not recommended for multiple lookups 149 | * 150 | * @param header Pointer to the mach_header_64 to symbolicate. Pass NULL for current executable 151 | * 152 | * @return Pointer to symbol location or NULL if not found 153 | * */ 154 | sr_ptr_t symrez_resolve_once_mh(mach_header_t header, const char *symbol); 155 | 156 | /*! 157 | * @function sr_iter_get_next 158 | * 159 | * @abstract Increment iterator 160 | * 161 | * @param iterator iterator 162 | * 163 | * @return Opaque sr_iter_result_t reference or NULL if done 164 | * 165 | * @discussion Use the `sr_iter_*` functions below to get the symbol 166 | * */ 167 | sr_iter_result_t sr_iter_get_next(sr_iterator_t iterator); 168 | 169 | /*! 170 | * @function sr_iter_reset 171 | * 172 | * @abstract Reset iterator back to start 173 | * 174 | * @param iterator iterator 175 | * */ 176 | void sr_iter_reset(sr_iterator_t iterator); 177 | 178 | /*! 179 | * @function sr_iter_get_ptr 180 | * 181 | * @abstract Get current symbol address 182 | * 183 | * @param iterator iterator 184 | * 185 | * @return Pointer to symbol location or NULL if not found. 186 | * */ 187 | sr_ptr_t sr_iter_get_ptr(sr_iterator_t iterator); 188 | 189 | /*! 190 | * @function sr_iter_get_symbol 191 | * 192 | * @abstract Get current symbol name 193 | * 194 | * @param iterator iterator 195 | * 196 | * @return volatile string reference to symbol name 197 | * 198 | * @discussion Use strdup or `sr_iter_copy_symbol` if you need to cache or save the symbol name. 199 | * */ 200 | sr_symbol_t sr_iter_get_symbol(sr_iterator_t iterator); 201 | 202 | /*! 203 | * @function sr_iter_copy_symbol 204 | * 205 | * @abstract Copy-out current symbol name 206 | * 207 | * @param iterator iterator 208 | * 209 | * @param dest Copy destination or NULL to only get strlen 210 | * 211 | * @return strlen of symbol 212 | * */ 213 | size_t sr_iter_copy_symbol(sr_iterator_t iterator, char *dest); 214 | 215 | /*! 216 | * @function sr_iter_next_symbol 217 | * 218 | * @abstract Convenience function for iterating symbol names 219 | * 220 | * @param iterator iterator 221 | * 222 | * @return volatile string reference to symbol name 223 | * */ 224 | SR_INLINE sr_symbol_t 225 | sr_iter_next_symbol(sr_iterator_t iterator) { 226 | sr_iter_get_next(iterator); 227 | return sr_iter_get_symbol(iterator); 228 | } 229 | 230 | OS_ASSUME_NONNULL_END 231 | __END_DECLS 232 | #endif 233 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macwmfx 2 | 3 | ![Preview](Preview.png) 4 | 5 | ## Information 6 | 7 | macwmfx is a macOS tweak for ammonia injector that enables configurable WindowManager Effects to macOS, similar to what swayfx does for sway on linux. 8 | 9 | - **Author**: [aspauldingcode](https://github.com/aspauldingcode) 10 | - **Status**: Work in progress - actively being refactored 11 | - **Inspired by**: 12 | - [INTrafficLightsDisabler](https://github.com/indragiek/INTrafficLightsDisabler) 13 | - [StopStoplightLight](https://github.com/shishkabibal/StopStoplightLight) 14 | - [AfloatX](https://github.com/jslegendre/AfloatX) 15 | - [Goodbye](https://github.com/MacEnhance/Goodbye) 16 | - yabai 17 | 18 | ## NOTICE: this is work-in-progress. I'm working on refactoring, and I promise this product will be complete at some point. macOS users will finally have some configurable window management ricing features. For now, please sit tight. Feel free to contribute if you'd like, although prs may not be merged, until I find a repo layout I'm happy with 19 | 20 | ## Features 21 | 22 | - Configurable window effects via JSON configuration 23 | - Window border customization (width, corner radius, colors) 24 | - Window transparency and blur effects 25 | - Titlebar modifications and traffic light customization 26 | - Window shadow control 27 | - Resize constraint removal 28 | - Dock and menubar tweaks 29 | - Application whitelist/blacklist support 30 | - **Background server architecture** for reliable app management 31 | - **One-command app reloading** with `macwmfx --reload` 32 | 33 | ## Architecture 34 | 35 | macwmfx uses a **client-server architecture** for reliable operation: 36 | 37 | - **Background Server** (`libmacwmfx_server.dylib`): Runs as an ammonia tweak, handles all window management operations and app lifecycle management 38 | - **Client CLI Tool** (`macwmfx`): Communicates with the server via XPC messaging 39 | - **Main Tweak** (`libmacwmfx.dylib`): Injected into applications to apply window effects 40 | 41 | This architecture ensures that: 42 | 43 | - The server can kill and restart all applications without being terminated itself 44 | - Commands are processed reliably through XPC communication 45 | - Configuration changes can be applied system-wide 46 | 47 | ## Installation 48 | 49 | 1. Download and install [ammonia](https://github.com/CoreBedtime/ammonia/releases/latest) from bedtime 50 | 2. Disable SIP, library validation, and enable preview arm64e abi 51 | 3. Clone and build: 52 | 53 | ```bash 54 | git clone https://github.com/aspauldingcode/macwmfx && cd macwmfx 55 | make help 56 | ``` 57 | 58 | > **Note:** In the future, `macwmfx` will be packaged for [Nixpkgs](https://nixos.org/) and [Homebrew](https://brew.sh/). 59 | > This will allow installation with: 60 | > 61 | > - `nix profile install github:aspauldingcode/macwmfx` (or via flakes) 62 | > - `brew install macwmfx` 63 | > 64 | > Stay tuned for official package availability! 65 | 66 | ## Configuration Setup 67 | 68 | macwmfx uses a JSON configuration file. To get started: 69 | 70 | 1. **Create default configuration:** 71 | 72 | ```bash 73 | ./build/macwmfx --generate-config 74 | ``` 75 | 76 | This will automatically: 77 | - Create the user config directory: `~/.config/macwmfx/` 78 | - Create the system config directory: `/Library/Application Support/macwmfx/` (with elevated privileges if needed) 79 | - Generate a default configuration at `~/.config/macwmfx/config.json` 80 | - Create a symlink from the system location to your user config 81 | - Handle all permission requirements seamlessly 82 | 83 | 2. **Edit your configuration:** 84 | 85 | ```bash 86 | # Edit the user config (recommended) 87 | nano ~/.config/macwmfx/config.json 88 | 89 | # Or edit the system config (same file due to symlink) 90 | sudo nano "/Library/Application Support/macwmfx/config.json" 91 | ``` 92 | 93 | 3. **Apply changes:** 94 | 95 | ```bash 96 | # Restart all open apps to apply changes 97 | macwmfx --reload 98 | ``` 99 | 100 | ## Building 101 | 102 | ### Using Makefile 103 | 104 | ```bash 105 | # Show all available build commands and options 106 | make help 107 | ``` 108 | 109 | The build system supports multiple configurations and targets. Run `make help` to see all available commands and their descriptions. 110 | 111 | ## CLI Tool Usage 112 | 113 | The macwmfx CLI tool provides several useful commands and handles all permission requirements automatically: 114 | 115 | ```bash 116 | # Show all available commands 117 | ./build/macwmfx 118 | 119 | # Create default configuration (handles sudo automatically) 120 | ./build/macwmfx --generate-config 121 | 122 | # Restart all open apps (kills them and restarts) 123 | ./build/macwmfx --reload 124 | 125 | # Server management 126 | ./build/macwmfx --start # Start the background server 127 | ./build/macwmfx --stop # Stop the background server 128 | ./build/macwmfx --status # Show server status 129 | 130 | # Observe macwmfx logs 131 | ./build/macwmfx --observe-logs 132 | 133 | # Runtime configuration changes 134 | ./build/macwmfx enable-borders 135 | ./build/macwmfx disable-borders 136 | ./build/macwmfx set-border-width 3.0 137 | ./build/macwmfx set-border-radius 10.0 138 | ./build/macwmfx enable-resize 139 | ./build/macwmfx disable-resize 140 | ``` 141 | 142 | **Note:** The CLI tool automatically requests elevated privileges when needed (e.g., for system-level configuration). No manual `sudo` commands are required. 143 | 144 | ## Key Features 145 | 146 | ### `macwmfx --reload` Command 147 | 148 | The `macwmfx --reload` command is a powerful feature that: 149 | 150 | 1. **Kills all open applications** (except system processes) 151 | 2. **Reloads the configuration** from disk 152 | 3. **Restarts applications** with the new configuration applied 153 | 154 | This ensures that configuration changes take effect immediately across all applications. The background server architecture allows this to work reliably without the command being terminated mid-process. 155 | 156 | ### Background Server 157 | 158 | The background server (`libmacwmfx_server.dylib`) runs as an ammonia tweak and: 159 | 160 | - Handles all window management operations 161 | - Manages application lifecycle 162 | - Processes commands via XPC messaging 163 | - Remains active even when applications are killed/restarted 164 | 165 | ### XPC Communication 166 | 167 | All commands are sent to the server via XPC messaging, ensuring: 168 | 169 | - Reliable communication between client and server 170 | - Proper error handling and response codes 171 | - Asynchronous command processing 172 | - System-level integration 173 | 174 | ## Development 175 | 176 | For detailed development information, architecture overview, and contribution guidelines, see [Dev_Guide.md](Dev_Guide.md). 177 | 178 | ## Contributing 179 | 180 | Feel free to contribute! However, please note that this project is actively being refactored, so PRs may not be merged until the new architecture is finalized. Please provide appropriate attribution rather than simply rebranding the code. 181 | 182 | ## License 183 | 184 | This project is open source. Please be respectful of the open source community and provide appropriate attribution for any adaptations. 185 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowOutline/DisableWindowCornerRadiusMask.m: -------------------------------------------------------------------------------- 1 | // #import "../../headers/macwmfx_globals.h" 2 | // #import "../../headers/ZKSwizzle.h" 3 | // #import 4 | // #import 5 | 6 | // // Swizzle NSWindow to enforce custom corner radius 7 | // ZKSwizzleInterface(AS_NSWindow_CornerRadius, NSWindow, NSWindow) 8 | // @implementation AS_NSWindow_CornerRadius 9 | 10 | // - (void)setFrame:(NSRect)frameRect display:(BOOL)flag { 11 | // ZKOrig(void, frameRect, flag); 12 | // [self updateCornerRadius]; 13 | // } 14 | 15 | // - (void)setStyleMask:(NSWindowStyleMask)styleMask { 16 | // ZKOrig(void, styleMask); 17 | // [self updateCornerRadius]; 18 | // } 19 | 20 | // - (void)updateCornerRadius { 21 | // // Skip if window is in fullscreen mode 22 | // if (self.styleMask & NSWindowStyleMaskFullScreen) { 23 | // return; 24 | // } 25 | 26 | // // Only modify windows that are titled (application windows) 27 | // if (!(self.styleMask & NSWindowStyleMaskTitled)) { 28 | // return; 29 | // } 30 | 31 | // // Get the frame view (contentView's superview) 32 | // NSView *frameView = [self.contentView superview]; 33 | // if (!frameView) return; 34 | 35 | // // Enable layer backing 36 | // frameView.wantsLayer = YES; 37 | // frameView.layer.masksToBounds = YES; 38 | 39 | // // Apply corner radius based on the config 40 | // if (gOutlineConfig.enabled) { 41 | // frameView.layer.cornerRadius = gOutlineConfig.cornerRadius; 42 | // } else { 43 | // frameView.layer.cornerRadius = 0; // Reset to default 44 | // } 45 | // } 46 | 47 | // @end 48 | 49 | // // Swizzle the titlebar decoration view to prevent rounded corners 50 | // ZKSwizzleInterface(AS_TitlebarDecorationView, _NSTitlebarDecorationView, NSView) 51 | // @implementation AS_TitlebarDecorationView 52 | 53 | // - (void)viewDidMoveToWindow { 54 | // ZKOrig(void); 55 | // // Only hide decoration for windows that are titled (application windows) and not in fullscreen 56 | // if ((self.window.styleMask & NSWindowStyleMaskTitled) && 57 | // !(self.window.styleMask & NSWindowStyleMaskFullScreen)) { 58 | // self.hidden = gOutlineConfig.enabled; // Hide the decoration view when outline is enabled 59 | // } 60 | // } 61 | 62 | // - (void)drawRect:(NSRect)dirtyRect { 63 | // // Only prevent drawing for titled windows when outline is enabled and not in fullscreen 64 | // if ((self.window.styleMask & NSWindowStyleMaskTitled) && 65 | // !(self.window.styleMask & NSWindowStyleMaskFullScreen) && 66 | // gOutlineConfig.enabled) { 67 | // return; // No-op to prevent any drawing 68 | // } 69 | // ZKOrig(void, dirtyRect); 70 | // } 71 | 72 | // @end 73 | 74 | // // Define a class to manage window outline updates 75 | // @interface WindowOutlineManager : NSObject 76 | // + (void)updateBorderForWindow:(NSWindow *)window; 77 | // + (void)updateCornerRadiusForWindow:(NSWindow *)window; 78 | // + (void)handleConfigChange:(NSNotification *)notification; 79 | // @end 80 | 81 | // @implementation WindowOutlineManager 82 | 83 | // + (void)updateBorderForWindow:(NSWindow *)window { 84 | // // Only process windows that are titled and at normal window level. 85 | // if (!(window.styleMask & NSWindowStyleMaskTitled) || 86 | // (window.level != NSNormalWindowLevel)) 87 | // return; 88 | 89 | // NSView *frameView = [window.contentView superview]; 90 | // if (!frameView) return; 91 | 92 | // // Force window update 93 | // [(id)window invalidateShadow]; 94 | // [window.contentView setNeedsDisplay:YES]; 95 | // [window displayIfNeeded]; 96 | 97 | // // Update the titlebar decoration view if available. 98 | // NSView *titlebarView = [window standardWindowButton:NSWindowCloseButton].superview.superview; 99 | // if ([titlebarView isKindOfClass:NSClassFromString(@"_NSTitlebarDecorationView")]) { 100 | // if (window.styleMask & NSWindowStyleMaskFullScreen) { 101 | // // In fullscreen, revert to system default by showing the decoration. 102 | // titlebarView.hidden = NO; 103 | // } else { 104 | // titlebarView.hidden = gOutlineConfig.enabled; 105 | // } 106 | // [titlebarView setNeedsDisplay:YES]; 107 | // } 108 | // } 109 | 110 | // + (void)updateCornerRadiusForWindow:(NSWindow *)window { 111 | // // Only process windows that are titled and at normal window level. 112 | // if (!(window.styleMask & NSWindowStyleMaskTitled) || 113 | // (window.level != NSNormalWindowLevel)) 114 | // return; 115 | 116 | // NSView *frameView = [window.contentView superview]; 117 | // if (!frameView) return; 118 | 119 | // frameView.wantsLayer = YES; 120 | // [CATransaction begin]; 121 | // [CATransaction setDisableActions:YES]; 122 | 123 | // if (window.styleMask & NSWindowStyleMaskFullScreen) { 124 | // // In fullscreen, always reset to the default corner radius. 125 | // frameView.layer.cornerRadius = 0; 126 | // } else { 127 | // // For non-fullscreen windows, apply the corner radius from the config if outline is enabled. 128 | // if (gOutlineConfig.enabled) { 129 | // frameView.layer.cornerRadius = gOutlineConfig.cornerRadius; 130 | // } else { 131 | // // Reset to default corner radius when outline is disabled. 132 | // frameView.layer.cornerRadius = 0; // or macOS default value 133 | // } 134 | // } 135 | 136 | // [CATransaction commit]; 137 | // } 138 | 139 | // + (void)handleConfigChange:(NSNotification *)notification { 140 | // dispatch_async(dispatch_get_main_queue(), ^{ 141 | // // Iterate through all windows and update the border and corner radius accordingly. 142 | // for (NSWindow *window in [NSApp windows]) { 143 | // if (![window isKindOfClass:[NSWindow class]]) continue; 144 | // [self updateBorderForWindow:window]; 145 | // [self updateCornerRadiusForWindow:window]; 146 | // } 147 | // }); 148 | // } 149 | 150 | // @end 151 | 152 | // // Initialize the WindowOutlineManager when the module loads 153 | // __attribute__((constructor)) 154 | // static void initializeWindowOutlineManager() { 155 | // // Register for config change notifications 156 | // [[NSDistributedNotificationCenter defaultCenter] addObserver:[WindowOutlineManager class] 157 | // selector:@selector(handleConfigChange:) 158 | // name:@"com.aspauldingcode.macwmfx.configChanged" 159 | // object:nil 160 | // suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 161 | 162 | // [[NSNotificationCenter defaultCenter] addObserver:[WindowOutlineManager class] 163 | // selector:@selector(handleConfigChange:) 164 | // name:@"com.aspauldingcode.macwmfx.configChanged" 165 | // object:nil]; 166 | 167 | // NSLog(@"[macwmfx] Window outline manager initialized"); 168 | // } 169 | -------------------------------------------------------------------------------- /src/shared/headers/macwmfx_globals.h: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx_globals.h 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | #ifndef MACWMFX_GLOBALS_H 9 | #define MACWMFX_GLOBALS_H 10 | 11 | #import 12 | #import "../ZKSwizzle/ZKSwizzle.h" 13 | #import 14 | 15 | #include "../macwmfx_logging.h" 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | // ============================================================================= 22 | // FEATURE FLAGS - Enable/Disable specific features during development 23 | // ============================================================================= 24 | 25 | // Debug and development flags 26 | #ifdef DEBUG 27 | #define MACWMFX_DEBUG 1 28 | #define MACWMFX_VERBOSE_LOGGING 1 29 | #else 30 | #define MACWMFX_DEBUG 0 31 | #define MACWMFX_VERBOSE_LOGGING 0 32 | #endif 33 | 34 | // Core feature flags - set to 0 to disable problematic features 35 | #define MACWMFX_ENABLE_WINDOW_BORDERS 1 36 | #define MACWMFX_ENABLE_WINDOW_SHADOWS 1 37 | #define MACWMFX_ENABLE_WINDOW_TRANSPARENCY 1 38 | #define MACWMFX_ENABLE_WINDOW_BLUR 1 39 | #define MACWMFX_ENABLE_TITLEBAR_TWEAKS 1 40 | #define MACWMFX_ENABLE_TRAFFIC_LIGHTS 1 41 | #define MACWMFX_ENABLE_RESIZE_LIMITS 1 42 | 43 | // Experimental features - easily disable if causing issues 44 | #define MACWMFX_ENABLE_DOCK_TWEAKS 1 45 | #define MACWMFX_ENABLE_MENUBAR_TWEAKS 1 46 | #define MACWMFX_ENABLE_SPACES_TWEAKS 1 47 | 48 | // Specific problematic features - can be disabled individually 49 | #define MACWMFX_ENABLE_ADVANCED_SHADOWS 0 // Disabled by default - experimental 50 | #define MACWMFX_ENABLE_CUSTOM_ANIMATIONS 0 // Disabled by default - may conflict 51 | 52 | // ============================================================================= 53 | // DEBUG MACROS 54 | // ============================================================================= 55 | 56 | // Note: DLog and VLog are now defined in macwmfx_logging.h 57 | // They use os_log instead of NSLog for better system integration 58 | 59 | // ============================================================================= 60 | // CONFIGURATION CONSTANTS 61 | // ============================================================================= 62 | 63 | // Simple configuration constants - hardcoded defaults 64 | static const BOOL kmacwmfxEnabled = YES; 65 | static const CGFloat kDefaultBorderWidth = 2.0; 66 | static const CGFloat kDefaultCornerRadius = 8.0; 67 | static const CGFloat kDefaultTransparency = 0.95; 68 | 69 | // Core window behavior flags 70 | extern bool WindowDecorations; 71 | extern bool WindowHideShadow; 72 | 73 | // Global configuration for menubar height 74 | extern int menubarHeight; 75 | 76 | // Shared memory structure for IPC 77 | typedef struct { 78 | BOOL outlineEnabled; 79 | CGFloat outlineWidth; 80 | CGFloat outlineCornerRadius; 81 | BOOL updateNeeded; 82 | } SharedMemory; 83 | 84 | // Path for shared memory 85 | #define SHARED_MEMORY_PATH "/tmp/macwmfx_shared" 86 | 87 | // Function to get shared memory 88 | SharedMemory* getSharedMemory(void); 89 | 90 | // Configuration Structures 91 | typedef struct { 92 | BOOL enabled; 93 | NSInteger passes; 94 | CGFloat radius; 95 | } BlurConfig; 96 | 97 | typedef struct { 98 | BOOL enabled; 99 | NSColor *activeColor; 100 | NSColor *inactiveColor; 101 | } TitlebarAesthetics; 102 | 103 | typedef struct { 104 | BOOL enabled; 105 | NSColor *activeBackground; // For active window 106 | NSColor *activeForeground; // For active window 107 | NSColor *inactiveBackground; // For inactive window 108 | NSColor *inactiveForeground; // For inactive window 109 | } TitlebarCustomColor; 110 | 111 | typedef struct { 112 | BOOL enabled; 113 | BOOL forceClassic; 114 | TitlebarAesthetics aesthetics; 115 | NSString *style; 116 | CGFloat size; 117 | TitlebarCustomColor customColor; 118 | } TitlebarConfig; 119 | 120 | typedef struct { 121 | BOOL enabled; 122 | const char *title; 123 | } CustomTitleConfig; 124 | 125 | // Traffic Lights Color State Config 126 | typedef struct { 127 | NSString *stop; 128 | NSString *yield; 129 | NSString *go; 130 | } TrafficLightsColorState; 131 | 132 | // Traffic Lights Custom Color Config 133 | typedef struct { 134 | BOOL enabled; 135 | TrafficLightsColorState active; 136 | TrafficLightsColorState inactive; 137 | TrafficLightsColorState hover; 138 | } TrafficLightsColorConfig; 139 | 140 | // Traffic Lights Config 141 | typedef struct { 142 | BOOL enabled; 143 | NSString *style; 144 | NSString *shape; 145 | NSString *order; 146 | NSString *position; 147 | CGFloat size; 148 | CGFloat padding; 149 | TrafficLightsColorConfig customColor; 150 | } TrafficLightsConfig; 151 | 152 | typedef struct { 153 | BOOL enabled; 154 | struct { 155 | BOOL enabled; 156 | NSString *active; 157 | NSString *inactive; 158 | } customColor; 159 | } ShadowConfig; 160 | 161 | typedef struct { 162 | BOOL enabled; 163 | } WindowSizeConstraintsConfig; 164 | 165 | typedef struct { 166 | BOOL enabled; 167 | NSString *type; 168 | CGFloat width; 169 | CGFloat cornerRadius; 170 | struct { 171 | BOOL enabled; 172 | NSColor *active; 173 | NSColor *inactive; 174 | NSColor *stacked; 175 | } customColor; 176 | } OutlineConfig; 177 | 178 | typedef struct { 179 | BOOL enabled; 180 | CGFloat value; 181 | } TransparencyConfig; 182 | 183 | typedef struct { 184 | NSColor *base00; 185 | NSColor *base01; 186 | NSColor *base02; 187 | NSColor *base03; 188 | NSColor *base04; 189 | NSColor *base05; 190 | NSColor *base06; 191 | NSColor *base07; 192 | NSColor *base08; 193 | NSColor *base09; 194 | NSColor *base0A; 195 | NSColor *base0B; 196 | NSColor *base0C; 197 | NSColor *base0D; 198 | NSColor *base0E; 199 | NSColor *base0F; 200 | } SystemColors; 201 | 202 | typedef struct { 203 | NSString *variant; 204 | NSString *slug; 205 | SystemColors colors; 206 | } SystemColorConfig; 207 | 208 | typedef struct { 209 | BOOL enabled; 210 | NSInteger interval; // Interval in seconds to check for changes 211 | } HotloadConfig; 212 | 213 | // Global Configuration Variables 214 | __attribute__((visibility("default"))) extern BOOL gIsEnabled; 215 | __attribute__((visibility("default"))) extern HotloadConfig gHotloadConfig; 216 | __attribute__((visibility("default"))) extern BlurConfig gBlurConfig; 217 | __attribute__((visibility("default"))) extern TitlebarConfig gTitlebarConfig; 218 | __attribute__((visibility("default"))) extern CustomTitleConfig gCustomTitleConfig; 219 | __attribute__((visibility("default"))) extern TrafficLightsConfig gTrafficLightsConfig; 220 | __attribute__((visibility("default"))) extern ShadowConfig gShadowConfig; 221 | __attribute__((visibility("default"))) extern WindowSizeConstraintsConfig gWindowSizeConstraintsConfig; 222 | __attribute__((visibility("default"))) extern OutlineConfig gOutlineConfig; 223 | __attribute__((visibility("default"))) extern TransparencyConfig gTransparencyConfig; 224 | __attribute__((visibility("default"))) extern SystemColorConfig gSystemColorConfig; 225 | 226 | // Flag to indicate if we're running from CLI 227 | extern BOOL gRunningFromCLI; 228 | 229 | // ConfigParser interface 230 | @interface ConfigParser : NSObject 231 | + (instancetype)sharedInstance; 232 | - (void)loadConfig; 233 | - (NSColor *)colorFromHexString:(NSString *)hexString; 234 | @end 235 | 236 | #ifdef __cplusplus 237 | } 238 | #endif 239 | 240 | #endif /* MACWMFX_GLOBALS_H */ 241 | -------------------------------------------------------------------------------- /src/modules/windows/features/windowTitlebar/DisableTitleBars.m: -------------------------------------------------------------------------------- 1 | // 2 | // DisableTitleBars.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 11/13/24. 6 | // Copyright (c) 2024 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "macwmfx_globals.h" 12 | 13 | ZKSwizzleInterface(BS_NSWindow_TitleBar, NSWindow, NSWindow) 14 | 15 | @implementation BS_NSWindow_TitleBar 16 | 17 | - (instancetype)init { 18 | self = [super init]; 19 | if (self) { 20 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Titlebar controller initialized"); 21 | } 22 | return self; 23 | } 24 | 25 | + (void)initialize { 26 | if (self == [BS_NSWindow_TitleBar class]) { 27 | // Register for config changes 28 | [[NSDistributedNotificationCenter defaultCenter] addObserver:self 29 | selector:@selector(handleConfigChange:) 30 | name:@"com.aspauldingcode.macwmfx.configChanged" 31 | object:nil 32 | suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 33 | 34 | [[NSNotificationCenter defaultCenter] addObserver:self 35 | selector:@selector(handleConfigChange:) 36 | name:@"com.aspauldingcode.macwmfx.configChanged" 37 | object:nil]; 38 | 39 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Titlebar controller class initialized"); 40 | } 41 | } 42 | 43 | + (void)handleConfigChange:(NSNotification *)notification { 44 | dispatch_async(dispatch_get_main_queue(), ^{ 45 | [self updateAllWindowTitlebars]; 46 | }); 47 | } 48 | 49 | + (void)updateAllWindowTitlebars { 50 | MACWMFX_LOG_INFO(macwmfx_log_titlebar, "Updating all window titlebars. Enabled=%d", gTitlebarConfig.enabled); 51 | 52 | for (NSWindow *window in [NSApp windows]) { 53 | if (![window isKindOfClass:[NSWindow class]]) continue; 54 | if (!(window.styleMask & NSWindowStyleMaskTitled)) continue; 55 | 56 | [self updateTitlebarForWindow:window]; 57 | } 58 | } 59 | 60 | + (void)updateTitlebarForWindow:(NSWindow *)window { 61 | if ([self isAppWhitelisted]) { 62 | [self disableTitlebarAlternativeForWindow:window]; 63 | } else { 64 | [self disableTitlebarNormalForWindow:window]; 65 | } 66 | } 67 | 68 | + (BOOL)isAppWhitelisted { 69 | NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; 70 | // Modify this whitelist as needed. 71 | return (bundleID && [bundleID isEqualToString:@"org.libreoffice.script"]); 72 | } 73 | 74 | + (void)disableTitlebarNormalForWindow:(NSWindow *)window { 75 | if (!gTitlebarConfig.enabled) { 76 | // Disable titlebar in the normal way, even in fullscreen. 77 | window.titlebarAppearsTransparent = YES; 78 | window.titleVisibility = NSWindowTitleHidden; 79 | window.styleMask |= NSWindowStyleMaskFullSizeContentView; 80 | window.contentView.wantsLayer = YES; 81 | 82 | // Additional fix for fullscreen: hide the titlebar container view if present. 83 | if (window.styleMask & NSWindowStyleMaskFullScreen) { 84 | NSView *container = window.contentView.superview; 85 | for (NSView *subview in container.subviews) { 86 | if ([[NSStringFromClass([subview class]) lowercaseString] containsString:@"titlebar"]) { 87 | subview.hidden = YES; 88 | } 89 | } 90 | } 91 | } else { 92 | // Restore default appearance. 93 | window.titlebarAppearsTransparent = NO; 94 | window.titleVisibility = NSWindowTitleVisible; 95 | window.styleMask &= ~NSWindowStyleMaskFullSizeContentView; 96 | 97 | // If in fullscreen, ensure the titlebar container view is shown. 98 | if (window.styleMask & NSWindowStyleMaskFullScreen) { 99 | NSView *container = window.contentView.superview; 100 | for (NSView *subview in container.subviews) { 101 | if ([[NSStringFromClass([subview class]) lowercaseString] containsString:@"titlebar"]) { 102 | subview.hidden = NO; 103 | } 104 | } 105 | } 106 | } 107 | // Remove any cropping mask left from alternative method. 108 | if (window.contentView.layer.mask) { 109 | window.contentView.layer.mask = nil; 110 | } 111 | [window displayIfNeeded]; 112 | } 113 | 114 | + (void)disableTitlebarAlternativeForWindow:(NSWindow *)window { 115 | if (!gTitlebarConfig.enabled) { 116 | // Hide the titlebar without shifting the content. 117 | window.titlebarAppearsTransparent = YES; 118 | window.titleVisibility = NSWindowTitleHidden; 119 | window.styleMask |= NSWindowStyleMaskFullSizeContentView; 120 | window.contentView.wantsLayer = YES; 121 | 122 | if (window.contentView) { 123 | NSRect expectedFrame = [window contentLayoutRect]; 124 | NSRect currentFrame = window.contentView.frame; 125 | // Determine the vertical offset that would have been removed by the titlebar. 126 | CGFloat offset = currentFrame.size.height - expectedFrame.size.height; 127 | if (offset > 0) { 128 | // Instead of moving the content, apply a mask to crop the top region. 129 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 130 | maskLayer.frame = window.contentView.bounds; 131 | CGRect cropRect = CGRectMake(0, 0, window.contentView.bounds.size.width, window.contentView.bounds.size.height - offset); 132 | CGMutablePathRef path = CGPathCreateMutable(); 133 | CGPathAddRect(path, NULL, cropRect); 134 | maskLayer.path = path; 135 | CGPathRelease(path); 136 | window.contentView.layer.mask = maskLayer; 137 | } else { 138 | window.contentView.layer.mask = nil; 139 | } 140 | } 141 | 142 | // Additional fix for fullscreen: hide the titlebar container view if present. 143 | if (window.styleMask & NSWindowStyleMaskFullScreen) { 144 | NSView *container = window.contentView.superview; 145 | for (NSView *subview in container.subviews) { 146 | if ([[NSStringFromClass([subview class]) lowercaseString] containsString:@"titlebar"]) { 147 | subview.hidden = YES; 148 | } 149 | } 150 | } 151 | 152 | // Ensure the alternative update is applied even during live resize. 153 | if (window.inLiveResize) { 154 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), 155 | dispatch_get_main_queue(), ^{ 156 | [self disableTitlebarAlternativeForWindow:window]; 157 | }); 158 | } 159 | } else { 160 | // Restore default appearance. 161 | window.titlebarAppearsTransparent = NO; 162 | window.titleVisibility = NSWindowTitleVisible; 163 | window.styleMask &= ~NSWindowStyleMaskFullSizeContentView; 164 | if (window.contentView.layer.mask) { 165 | window.contentView.layer.mask = nil; 166 | } 167 | 168 | // If in fullscreen, ensure the titlebar container view is shown. 169 | if (window.styleMask & NSWindowStyleMaskFullScreen) { 170 | NSView *container = window.contentView.superview; 171 | for (NSView *subview in container.subviews) { 172 | if ([[NSStringFromClass([subview class]) lowercaseString] containsString:@"titlebar"]) { 173 | subview.hidden = NO; 174 | } 175 | } 176 | } 177 | } 178 | 179 | [window displayIfNeeded]; 180 | } 181 | 182 | - (void)makeKeyAndOrderFront:(id)sender { 183 | ZKOrig(void, sender); 184 | 185 | // Skip if this is not a regular window. 186 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 187 | 188 | [BS_NSWindow_TitleBar updateTitlebarForWindow:(NSWindow *)self]; 189 | } 190 | 191 | - (void)orderFront:(id)sender { 192 | ZKOrig(void, sender); 193 | 194 | if (!(self.styleMask & NSWindowStyleMaskTitled)) return; 195 | 196 | [BS_NSWindow_TitleBar updateTitlebarForWindow:(NSWindow *)self]; 197 | } 198 | 199 | + (void)dealloc { 200 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 201 | [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /src/main/macwmfx.m: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "macwmfx.h" 10 | #import "../shared/headers/configParser.h" 11 | #import "../shared/headers/macwmfx_globals.h" 12 | #import "../shared/macwmfx_logging.h" 13 | #import "module_loader.h" 14 | 15 | // ============================================================================= 16 | // MODULE IMPORTS - Control which modules are compiled 17 | // ============================================================================= 18 | // Comment/uncomment these imports to enable/disable modules at compile time 19 | // Similar to Nix: imports = [ module1.nix module2.nix #unused.nix ]; 20 | // 21 | // DEVELOPMENT MODE: All modules disabled by default 22 | // Uncomment modules one-by-one as you develop and test them 23 | 24 | // Window Management Modules 25 | // #import "../modules/windows/features/borders/WindowBorderModule.h" 26 | // #import "../modules/windows/features/windowShadow/DisableWindowShadow.m" 27 | // #import "../modules/windows/features/windowTrafficLights/disableTrafficLights.m" 28 | // #import "../modules/windows/features/windowTitlebar/DisableTitleBars.m" 29 | // #import "../modules/windows/features/windowTitlebar/TitlebarAesthetics.m" 30 | // #import "../modules/windows/features/windowTitlebar/ForceCustomTitle.m" 31 | // #import "../modules/windows/features/windowSizeContraints/DisableResizeConstraints.m" 32 | 33 | // Menubar Modules 34 | // #import "../modules/menubar/features/NoMenubar.m" 35 | // #import "../modules/menubar/features/ribbonbar/RibbonBar.m" 36 | 37 | // Dock Modules 38 | // #import "../modules/dock/features/DisableDock.m" 39 | 40 | // Spaces Modules 41 | // #import "../modules/spaces/features/DisableSpaces.m" 42 | // #import "../modules/spaces/features/RenameSpaces.m" 43 | // #import "../modules/spaces/features/InstantFullscreenTransition.m" 44 | 45 | // Additional Window Modules (currently disabled) 46 | // #import "../modules/windows/features/windowBlur/BlurController.m" 47 | // #import "../modules/windows/features/windowTransparency/OpacityController.m" 48 | // #import "../modules/windows/features/windowBehavior/AlwaysOnTopController.m" 49 | // #import "../modules/windows/features/windowBehavior/GoodbyeForGood.m" 50 | // #import "../modules/windows/features/windowAnimations/windowRotation.m" 51 | // #import "../modules/windows/features/windowMaskShapes/WindowStar.m" 52 | // #import "../modules/windows/features/windowOutline/WindowBordersCenterline.m" 53 | // #import "../modules/windows/features/windowOutline/WindowBordersInline.mm" 54 | // #import "../modules/windows/features/windowOutline/WindowBordersOutline.mm" 55 | // #import "../modules/windows/features/windowOutline/DisableWindowCornerRadiusMask.m" 56 | // #import "../modules/windows/features/windowShadow/ShadowColor.mm" 57 | // #import "../modules/windows/features/windowTitlebar/DisableTitleBars.m" 58 | // #import "../modules/windows/features/windowTitlebar/ForceClassicTitlebars.m" 59 | // #import "../modules/windows/features/windowTrafficLights/TrafficLightsController.m" 60 | // #import "../modules/windows/features/windowTransparency/OpacityController.m" 61 | 62 | // ============================================================================= 63 | 64 | @interface macwmfx () 65 | @property (nonatomic, strong) ModuleLoader *moduleLoader; 66 | @property (nonatomic, assign) BOOL isRunning; 67 | @end 68 | 69 | @implementation macwmfx 70 | 71 | + (instancetype)sharedInstance { 72 | static macwmfx *sharedInstance = nil; 73 | static dispatch_once_t onceToken; 74 | dispatch_once(&onceToken, ^{ 75 | sharedInstance = [[macwmfx alloc] init]; 76 | }); 77 | return sharedInstance; 78 | } 79 | 80 | - (instancetype)init { 81 | self = [super init]; 82 | if (self) { 83 | // Initialize logging system 84 | macwmfx_logging_init(); 85 | 86 | self.moduleLoader = [ModuleLoader sharedLoader]; 87 | self.isRunning = NO; 88 | 89 | MACWMFX_LOG_INFO(macwmfx_log_general, "macwmfx main module initialized"); 90 | } 91 | return self; 92 | } 93 | 94 | - (void)start { 95 | if (self.isRunning) return; 96 | 97 | MACWMFX_LOG_INFO(macwmfx_log_general, "Starting macwmfx"); 98 | [self loadConfiguration]; 99 | [self loadModules]; 100 | self.isRunning = YES; 101 | MACWMFX_LOG_INFO(macwmfx_log_general, "macwmfx started successfully"); 102 | } 103 | 104 | - (void)stop { 105 | if (!self.isRunning) return; 106 | 107 | MACWMFX_LOG_INFO(macwmfx_log_general, "Stopping macwmfx"); 108 | [self unloadModules]; 109 | self.isRunning = NO; 110 | MACWMFX_LOG_INFO(macwmfx_log_general, "macwmfx stopped"); 111 | } 112 | 113 | - (BOOL)isRunning { return self.isRunning; } 114 | 115 | - (void)loadModules { 116 | MACWMFX_LOG_INFO(macwmfx_log_general, "Loading modules via ModuleLoader"); 117 | 118 | // DEVELOPMENT MODE: All modules are disabled by default 119 | // Uncomment module imports above to enable specific modules 120 | 121 | // Get available modules (those that were compiled in) 122 | NSArray *availableModules = [self.moduleLoader getAvailableModules]; 123 | MACWMFX_LOG_INFO(macwmfx_log_general, "Available modules: %@", availableModules); 124 | 125 | // Load modules based on configuration 126 | [self.moduleLoader loadModulesFromConfiguration:[self getCurrentConfig]]; 127 | 128 | NSArray *loadedModules = [self.moduleLoader getLoadedModules]; 129 | MACWMFX_LOG_INFO(macwmfx_log_general, "Loaded %lu modules: %@", (unsigned long)loadedModules.count, loadedModules); 130 | } 131 | 132 | - (void)unloadModules { 133 | NSArray *loadedModules = [self.moduleLoader getLoadedModules]; 134 | MACWMFX_LOG_INFO(macwmfx_log_general, "Unloading %lu modules", (unsigned long)loadedModules.count); 135 | 136 | for (NSString *moduleName in loadedModules) { 137 | [self.moduleLoader unloadModule:moduleName]; 138 | } 139 | 140 | MACWMFX_LOG_INFO(macwmfx_log_general, "All modules unloaded"); 141 | } 142 | 143 | - (NSArray *)getLoadedModules { 144 | return [self.moduleLoader getLoadedModules]; 145 | } 146 | 147 | - (NSArray *)getAvailableModules { 148 | return [self.moduleLoader getAvailableModules]; 149 | } 150 | 151 | - (void)loadConfiguration { 152 | MACWMFX_LOG_INFO(macwmfx_log_config, "Loading configuration"); 153 | [[ConfigParser sharedInstance] loadConfig]; 154 | } 155 | 156 | - (NSDictionary *)getCurrentConfig { 157 | // Convert global config variables to dictionary format 158 | return @{ 159 | @"window": @{ 160 | @"shadow": @{@"enabled": @(gShadowConfig.enabled)}, 161 | @"trafficLights": @{@"enabled": @(gTrafficLightsConfig.enabled)}, 162 | @"titlebar": @{@"enabled": @(gTitlebarConfig.enabled)}, 163 | @"outline": @{@"enabled": @(gOutlineConfig.enabled)} 164 | }, 165 | @"menubar": @{ 166 | @"noMenubar": @{@"enabled": @NO}, // Add to globals if needed 167 | @"ribbonbar": @{@"enabled": @NO} // Add to globals if needed 168 | }, 169 | @"dock": @{ 170 | @"disableDock": @{@"enabled": @NO} // Add to globals if needed 171 | }, 172 | @"spaces": @{ 173 | @"disableSpaces": @{@"enabled": @NO}, // Add to globals if needed 174 | @"renameSpaces": @{@"enabled": @NO} // Add to globals if needed 175 | } 176 | }; 177 | } 178 | 179 | - (void)reloadConfiguration { 180 | MACWMFX_LOG_INFO(macwmfx_log_config, "Reloading configuration"); 181 | [self loadConfiguration]; 182 | [self.moduleLoader reloadAllModules]; 183 | [self updateAllWindows]; 184 | } 185 | 186 | - (void)saveConfiguration { /* no-op */ } 187 | 188 | - (void)updateAllWindows { 189 | dispatch_async(dispatch_get_main_queue(), ^{ 190 | MACWMFX_LOG_DEBUG(macwmfx_log_window, "Updating all windows"); 191 | for (NSWindow *window in [NSApp windows]) [self updateWindow:window]; 192 | }); 193 | } 194 | 195 | - (void)updateWindow:(NSWindow *)window { 196 | [self.moduleLoader updateAllWindows]; 197 | } 198 | 199 | #pragma mark - Runtime Module Control 200 | 201 | - (BOOL)enableModule:(NSString *)moduleName { 202 | return [self.moduleLoader enableModule:moduleName]; 203 | } 204 | 205 | - (BOOL)disableModule:(NSString *)moduleName { 206 | return [self.moduleLoader disableModule:moduleName]; 207 | } 208 | 209 | - (BOOL)isModuleEnabled:(NSString *)moduleName { 210 | return [self.moduleLoader isModuleLoaded:moduleName]; 211 | } 212 | 213 | - (NSDictionary *)getModuleInfo:(NSString *)moduleName { 214 | return [self.moduleLoader getModuleInfo:moduleName]; 215 | } 216 | 217 | - (NSDictionary *)getAllModuleInfo { 218 | return [self.moduleLoader getModuleConfigurations]; 219 | } 220 | 221 | #pragma mark - Legacy Feature Methods (for compatibility) 222 | 223 | - (void)enableFeature:(NSString *)featureName { 224 | [self enableModule:featureName]; 225 | } 226 | 227 | - (void)disableFeature:(NSString *)featureName { 228 | [self disableModule:featureName]; 229 | } 230 | 231 | - (BOOL)isFeatureEnabled:(NSString *)featureName { 232 | return [self isModuleEnabled:featureName]; 233 | } 234 | 235 | - (void)setupSystemHooks { 236 | MACWMFX_LOG_INFO(macwmfx_log_general, "Setting up system hooks"); 237 | // This would be implemented if needed for legacy compatibility 238 | } 239 | 240 | - (void)removeSystemHooks { 241 | MACWMFX_LOG_INFO(macwmfx_log_general, "Removing system hooks"); 242 | // This would be implemented if needed for legacy compatibility 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /src/main/module_loader.m: -------------------------------------------------------------------------------- 1 | // 2 | // module_loader.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "module_loader.h" 10 | #import "../shared/macwmfx_logging.h" 11 | 12 | @interface ModuleLoader () 13 | @property (nonatomic, strong) NSMutableDictionary> *loadedModules; 14 | @property (nonatomic, strong) NSMutableDictionary *availableModules; 15 | @property (nonatomic, strong) NSMutableDictionary *> *moduleDependencies; 16 | @end 17 | 18 | @implementation ModuleLoader 19 | 20 | + (instancetype)sharedLoader { 21 | static ModuleLoader *sharedInstance = nil; 22 | static dispatch_once_t onceToken; 23 | dispatch_once(&onceToken, ^{ 24 | sharedInstance = [[self alloc] init]; 25 | }); 26 | return sharedInstance; 27 | } 28 | 29 | - (instancetype)init { 30 | self = [super init]; 31 | if (self) { 32 | _loadedModules = [NSMutableDictionary dictionary]; 33 | _availableModules = [NSMutableDictionary dictionary]; 34 | _moduleDependencies = [NSMutableDictionary dictionary]; 35 | 36 | MACWMFX_LOG_INFO(macwmfx_log_general, "ModuleLoader initialized"); 37 | } 38 | return self; 39 | } 40 | 41 | #pragma mark - Module Registration 42 | 43 | - (void)registerModule:(Class)moduleClass { 44 | if (![moduleClass conformsToProtocol:@protocol(macwmfxModule)]) { 45 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Module class %@ does not conform to macwmfxModule protocol", NSStringFromClass(moduleClass)); 46 | return; 47 | } 48 | 49 | NSString *moduleName = NSStringFromClass(moduleClass); 50 | self.availableModules[moduleName] = moduleClass; 51 | 52 | // Check for dependencies 53 | if ([moduleClass respondsToSelector:@selector(moduleDependencies)]) { 54 | NSArray *dependencies = (NSArray *)[moduleClass moduleDependencies]; 55 | if (dependencies.count > 0) { 56 | self.moduleDependencies[moduleName] = dependencies; 57 | MACWMFX_LOG_INFO(macwmfx_log_general, "Registered module %@ with dependencies: %@", moduleName, dependencies); 58 | } 59 | } 60 | 61 | MACWMFX_LOG_INFO(macwmfx_log_general, "Registered module: %@", moduleName); 62 | } 63 | 64 | #pragma mark - Module Management 65 | 66 | - (BOOL)loadModule:(NSString *)moduleName { 67 | if ([self isModuleLoaded:moduleName]) { 68 | MACWMFX_LOG_INFO(macwmfx_log_general, "Module %@ is already loaded", moduleName); 69 | return YES; 70 | } 71 | 72 | Class moduleClass = self.availableModules[moduleName]; 73 | if (!moduleClass) { 74 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Module %@ is not available (not compiled in)", moduleName); 75 | return NO; 76 | } 77 | 78 | // Check dependencies first 79 | if (![self loadModuleDependencies:moduleName]) { 80 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Failed to load dependencies for module %@", moduleName); 81 | return NO; 82 | } 83 | 84 | // Create and start the module 85 | id module = [[moduleClass alloc] init]; 86 | if (!module) { 87 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Failed to create instance of module %@", moduleName); 88 | return NO; 89 | } 90 | 91 | [module start]; 92 | self.loadedModules[moduleName] = module; 93 | 94 | MACWMFX_LOG_INFO(macwmfx_log_general, "Successfully loaded module: %@", moduleName); 95 | return YES; 96 | } 97 | 98 | - (BOOL)unloadModule:(NSString *)moduleName { 99 | id module = self.loadedModules[moduleName]; 100 | if (!module) { 101 | MACWMFX_LOG_INFO(macwmfx_log_general, "Module %@ is not loaded", moduleName); 102 | return YES; 103 | } 104 | 105 | [module stop]; 106 | [self.loadedModules removeObjectForKey:moduleName]; 107 | 108 | MACWMFX_LOG_INFO(macwmfx_log_general, "Successfully unloaded module: %@", moduleName); 109 | return YES; 110 | } 111 | 112 | - (BOOL)isModuleLoaded:(NSString *)moduleName { 113 | return self.loadedModules[moduleName] != nil; 114 | } 115 | 116 | - (NSArray *)getLoadedModules { 117 | return [self.loadedModules allKeys]; 118 | } 119 | 120 | - (NSArray *)getAvailableModules { 121 | return [self.availableModules allKeys]; 122 | } 123 | 124 | #pragma mark - Dependency Management 125 | 126 | - (BOOL)loadModuleWithDependencies:(NSString *)moduleName { 127 | return [self loadModule:moduleName]; 128 | } 129 | 130 | - (NSArray *)resolveDependencies:(NSString *)moduleName { 131 | return self.moduleDependencies[moduleName] ?: @[]; 132 | } 133 | 134 | - (BOOL)loadModuleDependencies:(NSString *)moduleName { 135 | NSArray *dependencies = [self resolveDependencies:moduleName]; 136 | 137 | for (NSString *dependency in dependencies) { 138 | if (![self loadModule:dependency]) { 139 | return NO; 140 | } 141 | } 142 | 143 | return YES; 144 | } 145 | 146 | #pragma mark - Module Discovery 147 | 148 | - (NSArray *)discoverAvailableModules { 149 | return [self getAvailableModules]; 150 | } 151 | 152 | - (NSDictionary *)getModuleInfo:(NSString *)moduleName { 153 | Class moduleClass = self.availableModules[moduleName]; 154 | if (!moduleClass) { 155 | return nil; 156 | } 157 | 158 | id module = self.loadedModules[moduleName]; 159 | 160 | return @{ 161 | @"name": moduleName, 162 | @"class": NSStringFromClass(moduleClass), 163 | @"loaded": @(module != nil), 164 | @"enabled": @(module ? [module isEnabled] : NO), 165 | @"dependencies": [self resolveDependencies:moduleName] 166 | }; 167 | } 168 | 169 | #pragma mark - Configuration Integration 170 | 171 | - (void)loadModulesFromConfiguration:(NSDictionary *)config { 172 | MACWMFX_LOG_INFO(macwmfx_log_general, "Loading modules from configuration"); 173 | 174 | // Load window modules based on config 175 | NSDictionary *windowConfig = config[@"window"]; 176 | if (windowConfig) { 177 | [self loadModuleIfAvailable:@"window.shadow" enabled:[windowConfig[@"shadow"][@"enabled"] boolValue]]; 178 | [self loadModuleIfAvailable:@"window.trafficLights" enabled:[windowConfig[@"trafficLights"][@"enabled"] boolValue]]; 179 | [self loadModuleIfAvailable:@"window.titlebar" enabled:[windowConfig[@"titlebar"][@"enabled"] boolValue]]; 180 | [self loadModuleIfAvailable:@"window.outline" enabled:[windowConfig[@"outline"][@"enabled"] boolValue]]; 181 | } 182 | 183 | // Load other module types 184 | NSDictionary *menubarConfig = config[@"menubar"]; 185 | if (menubarConfig) { 186 | [self loadModuleIfAvailable:@"menubar.noMenubar" enabled:[menubarConfig[@"noMenubar"][@"enabled"] boolValue]]; 187 | [self loadModuleIfAvailable:@"menubar.ribbonbar" enabled:[menubarConfig[@"ribbonbar"][@"enabled"] boolValue]]; 188 | } 189 | 190 | NSDictionary *dockConfig = config[@"dock"]; 191 | if (dockConfig) { 192 | [self loadModuleIfAvailable:@"dock.disableDock" enabled:[dockConfig[@"disableDock"][@"enabled"] boolValue]]; 193 | } 194 | 195 | NSDictionary *spacesConfig = config[@"spaces"]; 196 | if (spacesConfig) { 197 | [self loadModuleIfAvailable:@"spaces.disableSpaces" enabled:[spacesConfig[@"disableSpaces"][@"enabled"] boolValue]]; 198 | [self loadModuleIfAvailable:@"spaces.renameSpaces" enabled:[spacesConfig[@"renameSpaces"][@"enabled"] boolValue]]; 199 | } 200 | } 201 | 202 | - (void)loadModuleIfAvailable:(NSString *)moduleName enabled:(BOOL)enabled { 203 | if (enabled && [self.availableModules objectForKey:moduleName]) { 204 | [self loadModule:moduleName]; 205 | } else if (!enabled && [self isModuleLoaded:moduleName]) { 206 | [self unloadModule:moduleName]; 207 | } 208 | } 209 | 210 | - (NSDictionary *)getModuleConfigurations { 211 | NSMutableDictionary *configs = [NSMutableDictionary dictionary]; 212 | 213 | for (NSString *moduleName in [self getAvailableModules]) { 214 | NSDictionary *info = [self getModuleInfo:moduleName]; 215 | if (info) { 216 | configs[moduleName] = info; 217 | } 218 | } 219 | 220 | return [configs copy]; 221 | } 222 | 223 | #pragma mark - Runtime Control 224 | 225 | - (BOOL)enableModule:(NSString *)moduleName { 226 | if (![self.availableModules objectForKey:moduleName]) { 227 | MACWMFX_LOG_ERROR(macwmfx_log_general, "Cannot enable module %@ - not compiled in", moduleName); 228 | return NO; 229 | } 230 | 231 | return [self loadModule:moduleName]; 232 | } 233 | 234 | - (BOOL)disableModule:(NSString *)moduleName { 235 | return [self unloadModule:moduleName]; 236 | } 237 | 238 | - (void)reloadAllModules { 239 | MACWMFX_LOG_INFO(macwmfx_log_general, "Reloading all loaded modules"); 240 | 241 | NSArray *loadedModules = [self getLoadedModules]; 242 | for (NSString *moduleName in loadedModules) { 243 | id module = self.loadedModules[moduleName]; 244 | if ([module respondsToSelector:@selector(reloadConfiguration)]) { 245 | [module reloadConfiguration]; 246 | } 247 | } 248 | } 249 | 250 | - (void)updateAllWindows { 251 | MACWMFX_LOG_INFO(macwmfx_log_general, "Updating all windows through loaded modules"); 252 | 253 | for (id module in [self.loadedModules allValues]) { 254 | if ([module respondsToSelector:@selector(updateWindow:)]) { 255 | // This would need to be called with actual window instances 256 | // For now, just log that the module supports window updates 257 | MACWMFX_LOG_DEBUG(macwmfx_log_general, "Module %@ supports window updates", NSStringFromClass([module class])); 258 | } 259 | } 260 | } 261 | 262 | @end 263 | -------------------------------------------------------------------------------- /src/client/macwmfx_client.m: -------------------------------------------------------------------------------- 1 | // 2 | // macwmfx_client.m 3 | // macwmfx 4 | // 5 | // Created by Alex "aspauldingcode" on 01/09/25. 6 | // Copyright (c) 2025 Alex "aspauldingcode". All rights reserved. 7 | // 8 | 9 | #import "macwmfx_client.h" 10 | #import "../server/macwmfx_server.h" 11 | #import "../shared/macwmfx_logging.h" 12 | 13 | // XPC service name 14 | static const char *kmacwmfxServiceName = "com.aspauldingcode.macwmfx.server"; 15 | 16 | @implementation macwmfxClient { 17 | xpc_connection_t _connection; 18 | dispatch_queue_t _clientQueue; 19 | BOOL _isConnected; 20 | macwmfxClientCompletionBlock _pendingConnectCompletion; 21 | } 22 | 23 | + (instancetype)sharedClient { 24 | static macwmfxClient *sharedInstance = nil; 25 | static dispatch_once_t onceToken; 26 | dispatch_once(&onceToken, ^{ 27 | sharedInstance = [[self alloc] init]; 28 | }); 29 | return sharedInstance; 30 | } 31 | 32 | - (instancetype)init { 33 | self = [super init]; 34 | if (self) { 35 | // Initialize logging system 36 | macwmfx_logging_init(); 37 | 38 | _clientQueue = dispatch_queue_create("com.aspauldingcode.macwmfx.client", DISPATCH_QUEUE_SERIAL); 39 | _isConnected = NO; 40 | 41 | MACWMFX_LOG_INFO(macwmfx_log_client, "macwmfx client initialized"); 42 | } 43 | return self; 44 | } 45 | 46 | - (void)connectWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 47 | if (_isConnected) { 48 | if (completion) { 49 | completion(nil, [NSError errorWithDomain:@"com.aspauldingcode.macwmfx.client" code:1 userInfo:@{NSLocalizedDescriptionKey: @"Already connected"}]); 50 | } 51 | return; 52 | } 53 | 54 | dispatch_async(_clientQueue, ^{ 55 | // Create XPC connection 56 | self->_connection = xpc_connection_create_mach_service(kmacwmfxServiceName, self->_clientQueue, 0); 57 | 58 | if (!self->_connection) { 59 | if (completion) { 60 | NSError *error = [NSError errorWithDomain:@"com.aspauldingcode.macwmfx.client" code:2 userInfo:@{NSLocalizedDescriptionKey: @"Failed to create XPC connection - service not available"}]; 61 | completion(nil, error); 62 | } 63 | return; 64 | } 65 | 66 | // Store the completion block for error handling 67 | self->_pendingConnectCompletion = [completion copy]; 68 | 69 | // Set up event handler 70 | xpc_connection_set_event_handler(self->_connection, ^(xpc_object_t event) { 71 | [self handleXPCEvent:event]; 72 | }); 73 | 74 | // Activate the connection 75 | xpc_connection_activate(self->_connection); 76 | 77 | // If we get here, assume connection is in progress; completion will be called on first event or error 78 | self->_isConnected = YES; 79 | if (completion) { 80 | // Call completion optimistically, but if an error event comes in, we'll call it again with error 81 | completion(nil, nil); 82 | } 83 | }); 84 | } 85 | 86 | - (void)disconnect { 87 | if (!_isConnected) { 88 | return; 89 | } 90 | 91 | dispatch_async(_clientQueue, ^{ 92 | if (self->_connection) { 93 | xpc_connection_cancel(self->_connection); 94 | self->_connection = NULL; 95 | } 96 | self->_isConnected = NO; 97 | }); 98 | } 99 | 100 | - (BOOL)isConnected { 101 | return _isConnected; 102 | } 103 | 104 | - (void)handleXPCEvent:(xpc_object_t)event { 105 | xpc_type_t type = xpc_get_type(event); 106 | 107 | if (type == XPC_TYPE_DICTIONARY) { 108 | [self handleServerResponse:event]; 109 | } else if (type == XPC_TYPE_ERROR) { 110 | _isConnected = NO; 111 | NSString *errMsg = @"Unknown XPC error"; 112 | if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { 113 | errMsg = @"XPC connection interrupted"; 114 | } else if (event == XPC_ERROR_CONNECTION_INVALID) { 115 | errMsg = @"XPC connection invalid (server not running)"; 116 | } 117 | MACWMFX_LOG_ERROR(macwmfx_log_client, "%s", [errMsg UTF8String]); 118 | if (_pendingConnectCompletion) { 119 | NSError *error = [NSError errorWithDomain:@"com.aspauldingcode.macwmfx.client" 120 | code:4 121 | userInfo:@{NSLocalizedDescriptionKey: errMsg}]; 122 | _pendingConnectCompletion(nil, error); 123 | _pendingConnectCompletion = nil; 124 | } 125 | } 126 | } 127 | 128 | - (void)handleServerResponse:(xpc_object_t)response { 129 | // Parse response 130 | int64_t typeValue = xpc_dictionary_get_int64(response, "type"); 131 | macwmfxServerResponse *serverResponse = [[macwmfxServerResponse alloc] init]; 132 | serverResponse.type = (macwmfxServerResponseType)typeValue; 133 | 134 | // Extract data 135 | xpc_object_t dataObject = xpc_dictionary_get_value(response, "data"); 136 | if (dataObject && xpc_get_type(dataObject) == XPC_TYPE_DATA) { 137 | size_t dataSize = xpc_data_get_length(dataObject); 138 | const void *dataBytes = xpc_data_get_bytes_ptr(dataObject); 139 | if (dataSize > 0 && dataBytes) { 140 | serverResponse.data = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:[NSData dataWithBytes:dataBytes length:dataSize] error:nil]; 141 | } 142 | } 143 | 144 | // Extract error message 145 | const char *errorString = xpc_dictionary_get_string(response, "error"); 146 | if (errorString) { 147 | serverResponse.errorMessage = @(errorString); 148 | } 149 | 150 | // Handle the response (this would typically be passed to a completion block) 151 | MACWMFX_LOG_INFO(macwmfx_log_client, "Received server response: type=%ld, data=%@, error=%@", 152 | (long)serverResponse.type, serverResponse.data, serverResponse.errorMessage); 153 | } 154 | 155 | - (void)sendCommand:(NSInteger)command withData:(nullable id)data completion:(nullable macwmfxClientCompletionBlock)completion { 156 | if (!_isConnected) { 157 | if (completion) { 158 | NSError *error = [NSError errorWithDomain:@"com.aspauldingcode.macwmfx.client" code:3 userInfo:@{NSLocalizedDescriptionKey: @"Not connected to server"}]; 159 | completion(nil, error); 160 | } 161 | return; 162 | } 163 | 164 | dispatch_async(_clientQueue, ^{ 165 | // Create message 166 | xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); 167 | xpc_dictionary_set_int64(message, "command", command); 168 | 169 | // Add data if provided 170 | if (data) { 171 | NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:data requiringSecureCoding:NO error:nil]; 172 | if (archivedData) { 173 | xpc_dictionary_set_data(message, "data", archivedData.bytes, archivedData.length); 174 | } 175 | } 176 | 177 | // Send message 178 | xpc_connection_send_message(self->_connection, message); 179 | 180 | // For now, we'll just log the command 181 | // In a real implementation, you'd store the completion block and call it when the response arrives 182 | MACWMFX_LOG_DEBUG(macwmfx_log_client, "Sent command: %ld", (long)command); 183 | 184 | if (completion) { 185 | // For simplicity, we'll call completion immediately 186 | // In a real implementation, this would be called when the response arrives 187 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 188 | macwmfxServerResponse *response = [[macwmfxServerResponse alloc] init]; 189 | response.type = macwmfxServerResponseTypeSuccess; 190 | response.data = @{@"message": @"Command sent successfully"}; 191 | completion(response, nil); 192 | }); 193 | } 194 | }); 195 | } 196 | 197 | #pragma mark - Convenience Methods 198 | 199 | - (void)reloadWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 200 | [self sendCommand:macwmfxServerCommandReload withData:nil completion:completion]; 201 | } 202 | 203 | - (void)startServerWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 204 | [self sendCommand:macwmfxServerCommandStart withData:nil completion:completion]; 205 | } 206 | 207 | - (void)stopServerWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 208 | [self sendCommand:macwmfxServerCommandStop withData:nil completion:completion]; 209 | } 210 | 211 | - (void)enableBordersWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 212 | [self sendCommand:macwmfxServerCommandEnableBorders withData:nil completion:completion]; 213 | } 214 | 215 | - (void)disableBordersWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 216 | [self sendCommand:macwmfxServerCommandDisableBorders withData:nil completion:completion]; 217 | } 218 | 219 | - (void)setBorderWidth:(float)width completion:(nullable macwmfxClientCompletionBlock)completion { 220 | [self sendCommand:macwmfxServerCommandSetBorderWidth withData:@(width) completion:completion]; 221 | } 222 | 223 | - (void)setBorderRadius:(float)radius completion:(nullable macwmfxClientCompletionBlock)completion { 224 | [self sendCommand:macwmfxServerCommandSetBorderRadius withData:@(radius) completion:completion]; 225 | } 226 | 227 | - (void)enableResizeWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 228 | [self sendCommand:macwmfxServerCommandEnableResize withData:nil completion:completion]; 229 | } 230 | 231 | - (void)disableResizeWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 232 | [self sendCommand:macwmfxServerCommandDisableResize withData:nil completion:completion]; 233 | } 234 | 235 | - (void)getStatusWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 236 | [self sendCommand:macwmfxServerCommandGetStatus withData:nil completion:completion]; 237 | } 238 | 239 | #pragma mark - Module Management Methods 240 | 241 | - (void)enableModule:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion { 242 | [self sendCommand:macwmfxServerCommandEnableModule withData:moduleName completion:completion]; 243 | } 244 | 245 | - (void)disableModule:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion { 246 | [self sendCommand:macwmfxServerCommandDisableModule withData:moduleName completion:completion]; 247 | } 248 | 249 | - (void)getModuleInfo:(NSString *)moduleName completion:(nullable macwmfxClientCompletionBlock)completion { 250 | [self sendCommand:macwmfxServerCommandGetModuleInfo withData:moduleName completion:completion]; 251 | } 252 | 253 | - (void)listModulesWithCompletion:(nullable macwmfxClientCompletionBlock)completion { 254 | [self sendCommand:macwmfxServerCommandListModules withData:nil completion:completion]; 255 | } 256 | 257 | @end 258 | --------------------------------------------------------------------------------