1#import <AppKit/AppKit.h>
2#import <Foundation/Foundation.h>
3
4static NSTextField *MakeLabel(NSRect frame, NSString *text, NSFont *font, NSColor *color) {
5 NSTextField *label = [[NSTextField alloc] initWithFrame:frame];
6 [label setStringValue:text ?: @""];
7 [label setBezeled:NO];
8 [label setBordered:NO];
9 [label setDrawsBackground:NO];
10 [label setEditable:NO];
11 [label setSelectable:NO];
12 [label setAlignment:NSTextAlignmentCenter];
13 [label setTextColor:color];
14 [label setFont:font];
15 [label setLineBreakMode:NSLineBreakByTruncatingTail];
16 [label setUsesSingleLineMode:YES];
17 return label;
18}
19
20int main(int argc, const char *argv[]) {
21 @autoreleasepool {
22 NSString *message = argc > 1 ? [NSString stringWithUTF8String:argv[1]] : @"Toast";
23 NSString *detail = argc > 2 ? [NSString stringWithUTF8String:argv[2]] : @"";
24 double durationSeconds = argc > 3 ? strtod(argv[3], NULL) : 1.0;
25 if (durationSeconds < 0.25) {
26 durationSeconds = 0.25;
27 }
28 if (durationSeconds > 4.0) {
29 durationSeconds = 4.0;
30 }
31
32 [NSApplication sharedApplication];
33 [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
34
35 CGFloat width = MIN(420.0, MAX(220.0, (CGFloat)message.length * 9.0 + 72.0));
36 CGFloat height = detail.length > 0 ? 72.0 : 52.0;
37 NSRect screenFrame = NSScreen.mainScreen ? NSScreen.mainScreen.visibleFrame : NSMakeRect(0, 0, 1440, 900);
38 CGFloat x = NSMidX(screenFrame) - (width / 2.0);
39 CGFloat y = NSMinY(screenFrame) + 72.0;
40
41 NSPanel *window = [[NSPanel alloc]
42 initWithContentRect:NSMakeRect(x, y, width, height)
43 styleMask:NSWindowStyleMaskBorderless | NSWindowStyleMaskNonactivatingPanel
44 backing:NSBackingStoreBuffered
45 defer:NO];
46 [window setOpaque:NO];
47 [window setBackgroundColor:NSColor.clearColor];
48 [window setHasShadow:YES];
49 [window setIgnoresMouseEvents:YES];
50 [window setFloatingPanel:YES];
51 [window setHidesOnDeactivate:NO];
52 [window setLevel:NSStatusWindowLevel];
53 [window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces |
54 NSWindowCollectionBehaviorFullScreenAuxiliary];
55
56 NSView *contentView = window.contentView;
57 contentView.wantsLayer = YES;
58 contentView.layer.backgroundColor = [[NSColor colorWithCalibratedWhite:0.08 alpha:0.92] CGColor];
59 contentView.layer.cornerRadius = 14.0;
60 contentView.layer.masksToBounds = YES;
61 contentView.layer.borderWidth = 1.0;
62 contentView.layer.borderColor = [[NSColor colorWithCalibratedWhite:1.0 alpha:0.12] CGColor];
63
64 CGFloat titleY = detail.length > 0 ? 34.0 : 15.0;
65 [contentView addSubview:MakeLabel(
66 NSMakeRect(18, titleY, width - 36, 20),
67 message,
68 [NSFont boldSystemFontOfSize:13.0],
69 NSColor.whiteColor)];
70
71 if (detail.length > 0) {
72 [contentView addSubview:MakeLabel(
73 NSMakeRect(18, 14, width - 36, 16),
74 detail,
75 [NSFont systemFontOfSize:11.0],
76 [NSColor colorWithCalibratedWhite:1.0 alpha:0.72])];
77 }
78
79 [window setAlphaValue:0.0];
80 [window orderFrontRegardless];
81
82 for (NSInteger step = 1; step <= 5; step += 1) {
83 [window setAlphaValue:(CGFloat)step / 5.0];
84 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.02]];
85 }
86
87 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:durationSeconds]];
88
89 for (NSInteger step = 4; step >= 0; step -= 1) {
90 [window setAlphaValue:(CGFloat)step / 5.0];
91 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.02]];
92 }
93
94 [window orderOut:nil];
95 }
96
97 return 0;
98}