Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>dev.warp.WarpDockTilePlugin</string>
<key>CFBundleExecutable</key>
<string>WarpDockTilePlugin</string>
<key>CFBundleName</key>
<string>WarpDockTilePlugin</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSPrincipalClass</key>
<string>WarpDockTilePlugin</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
</dict>
</plist>
+20
View File
@@ -0,0 +1,20 @@
BUNDLE_NAME = WarpDockTilePlugin.docktileplugin
OBJC_FILES = WarpDockTilePlugin.m
FRAMEWORKS = -framework Cocoa -framework AppKit -framework Foundation
# Compile a universal binary for both arm64 and x86_64.
CFLAGS = -fobjc-arc -bundle -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) -arch arm64 -arch x86_64
LDFLAGS = -ObjC
.PHONY: all clean
all: $(BUNDLE_NAME)
$(BUNDLE_NAME): $(OBJC_FILES)
mkdir -p $(BUNDLE_NAME)/Contents/MacOS
clang $(CFLAGS) $(LDFLAGS) $(FRAMEWORKS) $(OBJC_FILES) -o $(BUNDLE_NAME)/Contents/MacOS/WarpDockTilePlugin
cp Info.plist $(BUNDLE_NAME)/Contents/
mkdir -p $(BUNDLE_NAME)/Contents/Resources
cp Resources/* $(BUNDLE_NAME)/Contents/Resources/
clean:
rm -rf $(BUNDLE_NAME)
+23
View File
@@ -0,0 +1,23 @@
Implements a dock tile plugin for Warp.
The plugin is used to update the dock tile icon when the app icon changes and allows for app icon changes to be persisted across app restarts. Without the plugin, the icon state reverts to the default upon the first time the app quits (although for some reason after the first quit the icon state is preserved).
The plugin is implemented in Objective-C and is built using the `clang` compiler
with the `-bundle` flag. See the Makefile for more details.
The plugin is installed into the app bundle at `Contents/PlugIns/WarpDockTilePlugin.docktileplugin` and is bundled using the script/mac/bundle script. It is built as a universal binary for both arm64 and x86_64.
The plugin is a simple Objective-C program that listens for notifications from the mainapplication when the app icon changes. When it receives a notification, it updates the dock tile icon.
See Mac documentation for more details:
https://developer.apple.com/documentation/appkit/nsdocktileplugin?language=objc
Note, that during development, MacOS is not great about reloading the plugin when changes are made.
The suggested workflow after rebuilding is to
1. Remove the icon from the dock.
2. Run `killall Dock && killall SystemUIServer`
Also, there is a sample plugin at [MacDockTileSample](https://github.com/CartBlanche/MacDockTileSample) that is helpful for installing and iterating on.
Another tip is to add file based debug logs rather than using NSLog, as it's impossible to find where NSLogs are being written to.
Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

+12
View File
@@ -0,0 +1,12 @@
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
@interface WarpDockTilePlugIn : NSObject <NSDockTilePlugIn>
{
id iconChangedObserver;
id defaultsObserver;
}
@property(strong) id iconChangedObserver;
@property(strong) id defaultsObserver;
@end
+228
View File
@@ -0,0 +1,228 @@
#include "WarpDockTilePlugin.h"
@implementation WarpDockTilePlugIn {
NSFileHandle *_logFileHandle;
}
@synthesize iconChangedObserver;
@synthesize defaultsObserver;
- (void)logMessage:(NSString *)message {
if (_logFileHandle) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
NSString *timestamp = [formatter stringFromDate:[NSDate date]];
NSString *logEntry = [NSString stringWithFormat:@"[%@] %@\n", timestamp, message];
[_logFileHandle writeData:[logEntry dataUsingEncoding:NSUTF8StringEncoding]];
[_logFileHandle synchronizeFile];
}
}
- (instancetype)init {
self = [super init];
if (self) {
@try {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"];
NSString *timestamp = [formatter stringFromDate:[NSDate date]];
NSString *logPath = [NSString stringWithFormat:@"/tmp/warp_docktile_%@.log", timestamp];
NSError *error = nil;
[[NSFileManager defaultManager] createFileAtPath:logPath contents:nil attributes:nil];
_logFileHandle = [NSFileHandle fileHandleForWritingAtPath:logPath];
[self logMessage:@"WarpDockTilePlugin initialized"];
} @catch (NSException *exception) {
NSLog(@"Exception during initialization: %@\nStack trace: %@",
exception.reason,
exception.callStackSymbols);
}
}
return self;
}
- (void)updateAppIcon:(NSDockTile *)tile {
@try {
[self logMessage:@"updateAppIcon called"];
// Retrieve the bundle ID for the main app from the Info.plist file in the plugin bundle
NSBundle *pluginBundle = [NSBundle bundleForClass:[self class]];
NSString *path = [[pluginBundle bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString *bundleId = dict[@"MainAppBundleIdentifier"];
BOOL isDev = [bundleId containsString:@"Dev"];
BOOL isPreview = [bundleId containsString:@"Preview"];
BOOL isLocal = [bundleId containsString:@"Local"];
[self logMessage:[NSString stringWithFormat:@"Plugin Bundle ID: %@", bundleId]];
// Initialize the user defaults for the main app
NSUserDefaults *hostDefaults = [[NSUserDefaults alloc] initWithSuiteName:bundleId];
[hostDefaults synchronize];
// Get the icon name from the user defaults
NSString* appIconName = [hostDefaults stringForKey:@"AppIcon"];
// Check if the user has set a non-default icon. If the AppIcon key is nil, empty, or "Default", reset to the
// icon bundled with the app by setting the content to "nil". Using the icon bundled in the app will allow macOS
// to handle the icon, including respecting "Icon & Widget Style" setting and applying a color filter. Non-
// default icons do not respect that setting.
NSString* cleanName = [[appIconName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\""]] lowercaseString];
if (!appIconName || [appIconName length] == 0 || [cleanName isEqualToString:@"default"]) {
[self logMessage:@"User has default icon, resetting dock tile to system default"];
[tile setContentView:nil];
[tile display];
return;
}
NSString* iconFileName = [self convertAppIconNameToFileName:appIconName isDev:isDev isLocal:isLocal isPreview:isPreview];
[self logMessage:[NSString stringWithFormat:@"Icon file name: %@", iconFileName]];
// Load the icon image
NSImage* currentImage = [self LoadDockTileImage:iconFileName];
// Set the image on the dock tile
// 256 x 256 is the preferred size for retina dock icons.
NSImageView* imageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 256, 256)];
[imageView setImage:currentImage];
[imageView setImageScaling:NSImageScaleProportionallyUpOrDown];
[tile setContentView:imageView];
[tile display];
[self logMessage:[NSString stringWithFormat:@"Dock tile updated with icon: %@", iconFileName]];
} @catch (NSException *exception) {
[self logMessage:[NSString stringWithFormat:@"Exception updating dock tile icon: %@\nStack trace: %@\nTile: %@",
exception.reason,
exception.callStackSymbols,
tile ? @"valid" : @"nil"]];
}
}
// See app_icon.rs for the rust version of this conversion.
- (NSString*)convertAppIconNameToFileName:(NSString*)appIconName isDev:(BOOL)isDev isLocal:(BOOL)isLocal isPreview:(BOOL)isPreview {
// First remove quotes and convert to lowercase
NSString* cleanName = [[appIconName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\""]] lowercaseString];
NSDictionary* mapping = @{
@"aurora": @"aurora",
@"classic1": @"classic_1",
@"classic2": @"classic_2",
@"classic3": @"classic_3",
@"comets": @"comets",
@"glasssky": @"glass_sky",
@"glitch": @"glitch",
@"glow": @"glow",
@"holographic": @"holographic",
@"mono": @"mono",
@"neon": @"neon",
@"original": @"original",
@"starburst": @"starburst",
@"sticker": @"sticker",
@"warpone": @"blue",
@"cow": @"cow"
};
NSString* fileName = mapping[cleanName];
// If the mapping doesn't exist, return the default icon
// conditional on whether this is a local, dev, or preview build.
return fileName ?: isLocal ? @"local" : isDev ? @"dev" : isPreview ? @"preview" : @"warp_2";
}
// Helper function to load named image from the plugin's resource bundle
- (NSImage*)LoadDockTileImage:(NSString*)imageName {
NSBundle* pluginBundle = [NSBundle bundleForClass:[self class]];
NSString* imagePath = [pluginBundle pathForResource:imageName ofType:@"png"];
[self logMessage:[NSString stringWithFormat:@"Image path: %@", imagePath]];
if (imagePath == nil) {
[self logMessage:[NSString stringWithFormat:@"Could not find image named %@ in the plugin resources", imageName]];
return nil;
}
return [[NSImage alloc] initWithContentsOfFile:imagePath];
}
// Protocol method that is invoked by the system when the dock for Warp is updated.
// Note that we listen for direct changes to the AppIcon key in the user defaults.
- (void)setDockTile:(NSDockTile *)dockTile {
@try {
[self logMessage:[NSString stringWithFormat:@"setDockTile called with tile: %@", dockTile ? @"valid" : @"nil"]];
if (dockTile) {
// Get the bundle ID for setting up user defaults observation
NSBundle *pluginBundle = [NSBundle bundleForClass:[WarpDockTilePlugIn class]];
NSString *path = [[pluginBundle bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString *bundleId = dict[@"MainAppBundleIdentifier"];
[self logMessage:[NSString stringWithFormat:@"Main app bundleId: %@", bundleId]];
// Set up user defaults observer
NSUserDefaults *hostDefaults = [[NSUserDefaults alloc] initWithSuiteName:bundleId];
[hostDefaults addObserver:self
forKeyPath:@"AppIcon"
options:NSKeyValueObservingOptionNew
context:(__bridge void * _Nullable)(dockTile)];
self.defaultsObserver = hostDefaults;
[self logMessage:[NSString stringWithFormat:@"Host defaults: %@", hostDefaults]];
// Make sure the icon is updated from the get-go as well.
[self updateAppIcon:dockTile];
} else {
[self logMessage:@"No docktile, clearing icon observer"];
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self.iconChangedObserver];
self.iconChangedObserver = nil;
if (self.defaultsObserver) {
[(NSUserDefaults *)self.defaultsObserver removeObserver:self forKeyPath:@"AppIcon"];
self.defaultsObserver = nil;
}
}
} @catch (NSException *exception) {
[self logMessage:[NSString stringWithFormat:@"Exception in setDockTile: %@\nStack trace: %@\nDockTile: %@",
exception.reason,
exception.callStackSymbols,
dockTile ? @"valid" : @"nil"]];
}
}
- (void)dealloc {
@try {
[self logMessage:@"WarpDockTilePlugin deallocating"];
if (self.iconChangedObserver) {
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self.iconChangedObserver];
self.iconChangedObserver = nil;
}
if (self.defaultsObserver) {
[(NSUserDefaults *)self.defaultsObserver removeObserver:self forKeyPath:@"AppIcon"];
self.defaultsObserver = nil;
}
if (_logFileHandle) {
[self logMessage:@"Closing log file"];
[_logFileHandle closeFile];
_logFileHandle = nil;
}
} @catch (NSException *exception) {
NSLog(@"Exception during deallocation: %@\nStack trace: %@",
exception.reason,
exception.callStackSymbols);
}
}
// KVO callback method
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context {
@try {
if ([keyPath isEqualToString:@"AppIcon"]) {
[self logMessage:@"AppIcon value changed in user defaults"];
NSDockTile *dockTile = (__bridge NSDockTile *)context;
[self updateAppIcon:dockTile];
}
} @catch (NSException *exception) {
[self logMessage:[NSString stringWithFormat:@"Exception in KVO handler: %@\nStack trace: %@\nKeyPath: %@\nObject: %@\nChange: %@",
exception.reason,
exception.callStackSymbols,
keyPath,
object,
change]];
}
}
@end