├── UTCMenuClock
├── en.lproj
│ ├── InfoPlist.strings
│ └── Credits.rtf
├── Images.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ ├── clock-icon-1024.png
│ │ ├── clock-icon-128.png
│ │ ├── clock-icon-17.png
│ │ ├── clock-icon-256.png
│ │ ├── clock-icon-257.png
│ │ ├── clock-icon-32.png
│ │ ├── clock-icon-33.png
│ │ ├── clock-icon-512.png
│ │ ├── clock-icon-513.png
│ │ ├── clock-icon-64.png
│ │ └── Contents.json
├── LaunchAtLoginController
│ ├── LaunchAtLoginController.h
│ ├── LaunchAtLoginController.m
│ └── README.md
├── main.m
├── UTCMenuClock-Prefix.pch
├── UTCMenuClock-Info.plist
├── UTCMenuClockAppDelegate.h
├── UTCMenuClockAppDelegate.m
└── Base.lproj
│ └── MainMenu.xib
├── UTCMenuClockTests
├── en.lproj
│ └── InfoPlist.strings
├── UTCMenuClockTests-Info.plist
├── UTCMenuClockTests.h
└── UTCMenuClockTests.m
├── downloads
├── UTCMenuClock_v1.3_universal.zip
└── UTCMenuClock_v1.4_universal.zip
├── UTCMenuClock.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── jna.xcuserdatad
│ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── jna.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── UTCMenuClock - Release.xcscheme
│ │ └── UTCMenuClock.xcscheme
└── project.pbxproj
├── PackageMakerProject.pmdoc
├── 01utcmenuclock-contents.xml
├── index.xml
└── 01utcmenuclock.xml
├── CHANGELOG.md
├── README.md
└── LICENSE
/UTCMenuClock/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/UTCMenuClockTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/downloads/UTCMenuClock_v1.3_universal.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/downloads/UTCMenuClock_v1.3_universal.zip
--------------------------------------------------------------------------------
/downloads/UTCMenuClock_v1.4_universal.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/downloads/UTCMenuClock_v1.4_universal.zip
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-1024.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-128.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-17.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-256.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-257.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-257.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-32.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-33.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-512.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-513.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-513.png
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock/Images.xcassets/AppIcon.appiconset/clock-icon-64.png
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.xcworkspace/xcuserdata/jna.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netik/UTCMenuClock/HEAD/UTCMenuClock.xcodeproj/project.xcworkspace/xcuserdata/jna.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UTCMenuClock/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3 | {\colortbl;\red255\green255\blue255;}
4 | \vieww9600\viewh8400\viewkind0
5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
6 |
7 | \f0\b\fs24 \cf0 Engineering:
8 | \b0 \
9 | John Adams \
10 | }
--------------------------------------------------------------------------------
/UTCMenuClock/LaunchAtLoginController/LaunchAtLoginController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LaunchAtLoginController.h
3 | //
4 |
5 | #import
6 |
7 | @interface LaunchAtLoginController : NSObject {
8 |
9 | }
10 |
11 | @property BOOL launchAtLogin;
12 |
13 | - (void)setLaunchAtLogin:(BOOL)enabled;
14 | - (void)setLaunchAtLogin:(NSURL *)itemURL enabled:(BOOL)enabled;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.xcworkspace/xcuserdata/jna.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | ShowSharedSchemesAutomaticallyEnabled
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/UTCMenuClockTests/UTCMenuClockTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PackageMakerProject.pmdoc/01utcmenuclock-contents.xml:
--------------------------------------------------------------------------------
1 | owner
--------------------------------------------------------------------------------
/PackageMakerProject.pmdoc/index.xml:
--------------------------------------------------------------------------------
1 | UTCMenuClock/Users/jna/Desktop/UTCMenuClock_1.2_installer.pkgnet.retinaUTC menu clock version 1.2, puts a simple clock on your desktop that displays the current time in UTC.
2 | - 01utcmenuclock.xml
properties.titledescription
--------------------------------------------------------------------------------
/UTCMenuClock/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // UTCMenuClock
4 | //
5 | // Created by John Adams on 11/14/11.
6 | //
7 | // Copyright 2011 John Adams
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 | #import
21 |
22 | int main(int argc, char *argv[])
23 | {
24 | return NSApplicationMain(argc, (const char **)argv);
25 | }
26 |
--------------------------------------------------------------------------------
/UTCMenuClockTests/UTCMenuClockTests.h:
--------------------------------------------------------------------------------
1 | //
2 | // UTCMenuClockTests.h
3 | // UTCMenuClockTests
4 | //
5 | // Created by John Adams on 11/14/11.
6 | //
7 | // Copyright 2011 John Adams
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | #import
22 |
23 | @interface UTCMenuClockTests : SenTestCase
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/UTCMenuClock/UTCMenuClock-Prefix.pch:
--------------------------------------------------------------------------------
1 |
2 | // Created by John Adams on 11/14/11.
3 | //
4 | // Copyright 2011 John Adams
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | //
17 |
18 | //
19 | // Prefix header for all source files of the 'UTCMenuClock' target in the 'UTCMenuClock' project
20 | //
21 |
22 | #ifdef __OBJC__
23 | #import
24 | #endif
25 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/xcuserdata/jna.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | UTCMenuClock - Release.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 1
11 |
12 | UTCMenuClock.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 0
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | A8B118851471AE3A008A993B
21 |
22 | primary
23 |
24 |
25 | A8B118A61471AE3A008A993B
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/PackageMakerProject.pmdoc/01utcmenuclock.xml:
--------------------------------------------------------------------------------
1 | net.retina.utcmenuclock.UTCMenuClock.pkg1.0/Users/jna/Library/Developer/Xcode/DerivedData/UTCMenuClock-hhdrixwssblomieblzccyedtwekb/Build/Products/Release/UTCMenuClock.app/Applicationsparent01utcmenuclock-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$
--------------------------------------------------------------------------------
/UTCMenuClockTests/UTCMenuClockTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // UTCMenuClockTests.m
3 | // UTCMenuClockTests
4 | //
5 | // Created by John Adams on 11/14/11.
6 | //
7 | // Copyright 2011 John Adams
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 | #import "UTCMenuClockTests.h"
21 |
22 | @implementation UTCMenuClockTests
23 |
24 | - (void)setUp
25 | {
26 | [super setUp];
27 |
28 | // Set-up code here.
29 | }
30 |
31 | - (void)tearDown
32 | {
33 | // Tear-down code here.
34 |
35 | [super tearDown];
36 | }
37 |
38 | - (void)testExample
39 | {
40 | STFail(@"Unit tests are not implemented yet in UTCMenuClockTests");
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/UTCMenuClock/UTCMenuClock-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.4
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 14
23 | LSApplicationCategoryType
24 | public.app-category.utilities
25 | LSMinimumSystemVersion
26 | 15.0
27 | LSUIElement
28 |
29 | NSHumanReadableCopyright
30 | Copyright © 2011-2022 John Adams, Apache Software License.
31 | NSMainNibFile
32 | MainMenu
33 | NSPrincipalClass
34 | NSApplication
35 |
36 |
37 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to UTCMenuClock are documented here. Dates use the
4 | commit date from the repository history.
5 |
6 | ## 1.4 - 2025-12-11
7 | - Modernized for macOS 15 / Xcode 16 and enabled ARC.
8 | - Reduced CPU usage and tightened timer scheduling tolerance.
9 | - Switched the menubar clock to monospaced digits and cleaned compiler warnings.
10 |
11 | ## 1.3 — 2022-10-07
12 | - Added ISO-8601 display override and a separate “Copy as ISO-8601” action.
13 | - Added clipboard copy for the current UTC string that respects user format.
14 | - Fixed menu starting state, preference handling, and refreshed release packaging.
15 |
16 | ## 1.2.3 — 2016-12-25
17 | - Added AM/PM support alongside the existing 24-hour display.
18 | - Shipped new app icons and proper release configuration; published the 1.2.3 zip.
19 | - Miscellaneous cleanups and README updates.
20 |
21 | ## 1.1 — 2012-08-31
22 | - Added Julian date option, timezone suffix toggle, and improved default preferences.
23 | - Introduced the “Show Seconds” toggle and refactored preference getters.
24 | - Added the PackageMaker project and installer adjustments.
25 |
26 | ## 1.0 — 2011-11-14
27 | - Initial public release: UTC menubar clock with show-date toggle, GitHub link, and open-at-login support.
28 | - Added credits entry and Apache 2.0 licensing.
29 |
--------------------------------------------------------------------------------
/UTCMenuClock/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "clock-icon-17.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "clock-icon-33.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "clock-icon-32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "clock-icon-64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "clock-icon-128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "clock-icon-257.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "clock-icon-256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "clock-icon-513.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "clock-icon-512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "clock-icon-1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/UTCMenuClock/UTCMenuClockAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // UTCMenuClockAppDelegate.h
3 | // UTCMenuClock
4 | //
5 | // Created by John Adams on 11/14/11.
6 | //
7 | // Copyright 2011 John Adams
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | #import
22 |
23 | @interface UTCMenuClockAppDelegate : NSObject
24 |
25 | // Window outlet (weak - owned by nib)
26 | @property (weak) IBOutlet NSWindow *window;
27 |
28 | // Menu is created programmatically, so we need a strong reference
29 | @property (strong, nonatomic) NSMenu *mainMenu;
30 |
31 | // Status bar item (strong - we own it)
32 | @property (strong, nonatomic) NSStatusItem *statusItem;
33 |
34 | // Timer for clock updates
35 | @property (strong, nonatomic) NSTimer *timer;
36 |
37 | // Menu items that need state management
38 | @property (strong, nonatomic) NSMenuItem *dateMenuItem;
39 | @property (strong, nonatomic) NSMenuItem *show24Item;
40 | @property (strong, nonatomic) NSMenuItem *showDateItem;
41 | @property (strong, nonatomic) NSMenuItem *showSecondsItem;
42 | @property (strong, nonatomic) NSMenuItem *showJulianItem;
43 | @property (strong, nonatomic) NSMenuItem *showTimeZoneItem;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/UTCMenuClock/LaunchAtLoginController/LaunchAtLoginController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LaunchAtLoginController.m
3 | //
4 | // Updated to use SMAppService for macOS 13+ (modern API)
5 | //
6 |
7 | #import "LaunchAtLoginController.h"
8 | #import
9 |
10 | @implementation LaunchAtLoginController
11 |
12 | - (NSURL *)appURL {
13 | return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
14 | }
15 |
16 | /**
17 | Returns whether the application is set to launch at login.
18 | Uses the modern SMAppService API (macOS 13+).
19 |
20 | @return YES if the app will launch at login, NO otherwise.
21 | */
22 | - (BOOL)launchAtLogin {
23 | SMAppService *service = [SMAppService mainAppService];
24 | return (service.status == SMAppServiceStatusEnabled);
25 | }
26 |
27 | /**
28 | Sets the application to launch at login or not.
29 | Uses the modern SMAppService API (macOS 13+).
30 |
31 | @param itemURL The URL of the application bundle (unused in modern API).
32 | @param enabled A boolean indicating whether the application should launch at login.
33 | */
34 | - (void)setLaunchAtLogin:(NSURL *)itemURL enabled:(BOOL)enabled {
35 | SMAppService *service = [SMAppService mainAppService];
36 | NSError *error = nil;
37 |
38 | if (enabled) {
39 | if (![service registerAndReturnError:&error]) {
40 | NSLog(@"Failed to enable launch at login: %@", error.localizedDescription);
41 | }
42 | } else {
43 | if (![service unregisterAndReturnError:&error]) {
44 | NSLog(@"Failed to disable launch at login: %@", error.localizedDescription);
45 | }
46 | }
47 | }
48 |
49 | /**
50 | Sets the application to launch at login or not.
51 |
52 | @param enabled A boolean indicating whether the application should launch at login.
53 | */
54 | - (void)setLaunchAtLogin:(BOOL)enabled {
55 | [self willChangeValueForKey:@"startAtLogin"];
56 | [self setLaunchAtLogin:[self appURL] enabled:enabled];
57 | [self didChangeValueForKey:@"startAtLogin"];
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UTCMenuClock
2 |
3 | UTCMenuClock is a lightweight macOS menubar app that keeps Coordinated
4 | Universal Time (UTC) visible at all times. It is handy for operations
5 | teams, distributed work, aviation, astronomy, or anyone who needs a
6 | reliable UTC reference next to the system clock.
7 |
8 | ## Features
9 | - UTC clock in the menu bar using monospaced digits for stable alignment.
10 | - Toggle 24-hour/12-hour display, seconds, date, Julian day, and timezone suffix.
11 | - ISO-8601 override for the menubar text plus “Copy as ISO-8601.”
12 | - Copy the current UTC timestamp (using your selected format) to the clipboard.
13 | - “Open at Login” toggle built into the menu.
14 |
15 | ## Download prebuilt binary
16 | - Grab the unsigned universal binary: [`downloads/UTCMenuClock_v1.4_universal.zip`](https://github.com/netik/UTCMenuClock/blob/master/downloads/UTCMenuClock_v1.4_universal.zip).
17 | - Because the app is unsigned, macOS will warn on first launch. Use
18 | `Right Click > Open` to allow it, or permit it under System Settings → Privacy & Security.
19 |
20 | ## Build from source
21 | - Requirements: macOS 15+, Xcode 16 (project is updated for ARC).
22 | - Open `UTCMenuClock.xcodeproj`, select the `UTCMenuClock` scheme, then build & run.
23 | - The built app will appear in Xcode’s derived data under
24 | `build/Release/UTCMenuClock.app` when using a Release build.
25 |
26 | ## Using the app
27 | - Launching the app adds the UTC clock to the menu bar; click it to open the menu.
28 | - Menu items:
29 | - `Copy` copies the current UTC string using your chosen format.
30 | - `Copy as ISO-8601` copies an ISO-8601 UTC timestamp.
31 | - Toggles: `24 HR Time`, `Show Date`, `Show Seconds`, `Show Julian Date`,
32 | `Show Time Zone`, `Show ISO8601 Instead`.
33 | - `Open at Login` toggles a login item; `Quit` exits the app.
34 | - When `Show ISO8601 Instead` is enabled, the other format toggles are disabled and
35 | the menubar displays a full ISO-8601 string.
36 |
37 | ## Troubleshooting
38 | - Unsigned app: allow it via `Right Click > Open` or Security settings after the first block.
39 | - If the clock stops updating after sleep, toggle a preference or restart the app
40 | to rebuild the timer (the app also listens for wake events).
41 |
42 | ## Credits
43 | - Built and maintained by John Adams (`jna@retina.net`).
44 | - LaunchAtLoginController by Ben Clark-Robinson (`ben.clarkrobinson@gmail.com`).
45 | - Licensed under the Apache License 2.0. See `LICENSE` for details.
46 |
--------------------------------------------------------------------------------
/UTCMenuClock/LaunchAtLoginController/README.md:
--------------------------------------------------------------------------------
1 | # LaunchAtLoginController
2 |
3 | A simple controller for Cocoa Mac Apps to register/deregister for Launch at Login using the modern SMAppService API (macOS 13+).
4 |
5 | ## IMPLEMENTATION (Code):
6 |
7 | ### Will app launch at login?
8 |
9 | ```objc
10 | LaunchAtLoginController *launchController = [[LaunchAtLoginController alloc] init];
11 | BOOL launch = [launchController launchAtLogin];
12 | ```
13 |
14 | ### Set launch at login state.
15 |
16 | ```objc
17 | LaunchAtLoginController *launchController = [[LaunchAtLoginController alloc] init];
18 | [launchController setLaunchAtLogin:YES];
19 | ```
20 |
21 | ## IMPLEMENTATION (Interface builder):
22 |
23 | * Open Interface Builder
24 | * Place a NSObject (the blue box) into the nib window
25 | * From the Inspector - Identity Tab (Cmd+6) set the Class to LaunchAtLoginController
26 | * Place a Checkbox on your Window/View
27 | * From the Inspector - Bindings Tab (Cmd+4) unroll the > Value item
28 | * Bind to Launch at Login Controller
29 | * Model Key Path: launchAtLogin
30 |
31 | ## IS IT WORKING:
32 |
33 | After implementing either through code or through IB, setLaunchAtLogin:YES and then check System Settings > General > Login Items. You should see your app in the list of apps that will start when the user logs in.
34 |
35 | ## REQUIREMENTS:
36 |
37 | Requires macOS 13.0 (Ventura) or later. Uses SMAppService API.
38 |
39 | ## ORIGINAL CODE IDEAS:
40 |
41 | * Growl.
42 | * User: invariant Link: (http://stackoverflow.com/questions/815063/how-do-you-make-your-app-open-at-login/2318004#2318004)
43 | * Updated for SMAppService by UTCMenuClock project
44 |
45 | ## LICENSE:
46 |
47 | (The MIT License)
48 |
49 | Copyright (c) 2010 Ben Clark-Robinson, ben.clarkrobinson@gmail.com
50 |
51 | Permission is hereby granted, free of charge, to any person obtaining
52 | a copy of this software and associated documentation files (the
53 | 'Software'), to deal in the Software without restriction, including
54 | without limitation the rights to use, copy, modify, merge, publish,
55 | distribute, sublicense, and/or sell copies of the Software, and to
56 | permit persons to whom the Software is furnished to do so, subject to
57 | the following conditions:
58 |
59 | The above copyright notice and this permission notice shall be
60 | included in all copies or substantial portions of the Software.
61 |
62 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
63 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
65 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
66 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
67 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
68 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/xcshareddata/xcschemes/UTCMenuClock - Release.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/xcshareddata/xcschemes/UTCMenuClock.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/UTCMenuClock/UTCMenuClockAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // UTCMenuClockAppDelegate.m
3 | // UTCMenuClock
4 | //
5 | // Created by John Adams on 11/14/11.
6 | //
7 | // Copyright 2011-2025 John Adams
8 | //
9 | // Licensed under the Apache License, Version 2.0 (the "License");
10 | // you may not use this file except in compliance with the License.
11 | // You may obtain a copy of the License at
12 | //
13 | // http://www.apache.org/licenses/LICENSE-2.0
14 | //
15 | // Unless required by applicable law or agreed to in writing, software
16 | // distributed under the License is distributed on an "AS IS" BASIS,
17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | // See the License for the specific language governing permissions and
19 | // limitations under the License.
20 | //
21 |
22 | #import "UTCMenuClockAppDelegate.h"
23 | #import "LaunchAtLoginController.h"
24 |
25 | static NSString *const showDatePreferenceKey = @"ShowDate";
26 | static NSString *const showSecondsPreferenceKey = @"ShowSeconds";
27 | static NSString *const showJulianDatePreferenceKey = @"ShowJulianDate";
28 | static NSString *const showTimeZonePreferenceKey = @"ShowTimeZone";
29 | static NSString *const show24HourPreferenceKey = @"24HRTime";
30 | static NSString *const showISO8601PreferenceKey = @"ISO8601";
31 |
32 | /* Some app constants go here */
33 | static NSString *const GITHUB_URL = @"http://github.com/netik/UTCMenuClock";
34 |
35 | @implementation UTCMenuClockAppDelegate
36 |
37 | /*!
38 | @brief Exits the app
39 | */
40 | - (void) quitProgram:(id)sender {
41 | // Cleanup here if necessary...
42 | [[NSApplication sharedApplication] terminate:nil];
43 | }
44 |
45 | /*!
46 | @brief Flips the user preference that starts the application at launch.
47 | */
48 | - (void) toggleLaunch:(id)sender {
49 | NSInteger state = [sender state];
50 | LaunchAtLoginController *launchController = [[LaunchAtLoginController alloc] init];
51 |
52 | if (state == NSControlStateValueOff) {
53 | [sender setState:NSControlStateValueOn];
54 | [launchController setLaunchAtLogin:YES];
55 | } else {
56 | [sender setState:NSControlStateValueOff];
57 | [launchController setLaunchAtLogin:NO];
58 | }
59 |
60 | }
61 |
62 | /*!
63 | @brief Returns a preference's setting based on the key
64 | @param preference The preference to retrieve as an NSString
65 | @return boolean from the preference list
66 | */
67 | - (BOOL) fetchBooleanPreference:(NSString *)preference {
68 | NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
69 | BOOL value = [standardUserDefaults boolForKey:preference];
70 | return value;
71 | }
72 |
73 | /*!
74 | @brief Flips the user preference that starts the application at launch.
75 | @param sender The menu component to change
76 | */
77 | - (void) togglePreference:(id)sender {
78 | NSInteger state = [sender state];
79 | NSString *preference = [sender representedObject];
80 | NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
81 |
82 | if (state == NSControlStateValueOff) {
83 | [sender setState:NSControlStateValueOn];
84 | [standardUserDefaults setBool:YES forKey:preference];
85 | } else {
86 | [sender setState:NSControlStateValueOff];
87 | [standardUserDefaults setBool:NO forKey:preference];
88 | }
89 | [self scheduleTimer];
90 | }
91 |
92 | /*!
93 | @brief Flips the user preference that starts the application at launch.
94 | @param sender The menu component to change
95 | */
96 | - (void) toggleISOPreference:(id)sender {
97 | NSInteger state = [sender state];
98 |
99 | [self togglePreference:sender];
100 |
101 | if (state == NSControlStateValueOff) {
102 | // disable all of the menu items which are not related to ISO state
103 | [_show24Item setEnabled:NO];
104 | [_showDateItem setEnabled:NO];
105 | [_showSecondsItem setEnabled:NO];
106 | [_showJulianItem setEnabled:NO];
107 | [_showTimeZoneItem setEnabled:NO];
108 |
109 | } else {
110 | // enable all of the menu items which are not related to ISO state
111 | [_show24Item setEnabled:YES];
112 | [_showDateItem setEnabled:YES];
113 | [_showSecondsItem setEnabled:YES];
114 | [_showJulianItem setEnabled:YES];
115 | [_showTimeZoneItem setEnabled:YES];
116 | }
117 |
118 | }
119 |
120 |
121 | /*!
122 | @brief Copies the current date and time to the pasteboard based on user preferences
123 | */
124 | - (void) copyToPasteboard {
125 | NSString *dateString = [self makeDateString];
126 |
127 | // Set string
128 | [[NSPasteboard generalPasteboard] clearContents];
129 | [[NSPasteboard generalPasteboard] setString:dateString forType:NSPasteboardTypeString];
130 | }
131 |
132 | /*!
133 | @brief Copies the current date and time to the pasteboard as an ISO8601 date
134 | */
135 | - (void) copyIS08601ToPasteboard {
136 | NSString *dateString = [self makeISO8601DateString];
137 |
138 | // Set string
139 | [[NSPasteboard generalPasteboard] clearContents];
140 | [[NSPasteboard generalPasteboard] setString:dateString forType:NSPasteboardTypeString];
141 | }
142 |
143 | /*!
144 | @brief Opens the github URL in the default Browser where the source code lives
145 | */
146 | - (void) openGithubURL:(id)sender {
147 | [[NSWorkspace sharedWorkspace]
148 | openURL:[NSURL URLWithString:GITHUB_URL]];
149 | }
150 |
151 | /*!
152 | @brief Formats the current date as an ISO8601 date string
153 | @return NSString the date as a string
154 | */
155 | - (NSString *) makeISO8601DateString {
156 | NSDate* date = [NSDate date];
157 | NSISO8601DateFormatter* UTCiso = [[NSISO8601DateFormatter alloc] init];
158 | NSTimeZone* UTCtz = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
159 | [UTCiso setTimeZone: UTCtz];
160 | return [UTCiso stringFromDate: date];
161 |
162 | }
163 | /*!
164 | @brief Formats the current date based on the user's preferences
165 | @return NSString the date as a string
166 | */
167 | - (NSString *) makeDateString {
168 | NSDate* date = [NSDate date];
169 | NSDateFormatter* UTCdf = [[NSDateFormatter alloc] init];
170 | NSDateFormatter* UTCdateDF = [[NSDateFormatter alloc] init];
171 | NSDateFormatter* UTCdateShortDF = [[NSDateFormatter alloc] init];
172 | NSDateFormatter* UTCdaynum = [[NSDateFormatter alloc] init];
173 |
174 | NSTimeZone* UTCtz = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
175 |
176 | [UTCdf setTimeZone: UTCtz];
177 | [UTCdateDF setTimeZone: UTCtz];
178 | [UTCdateShortDF setTimeZone: UTCtz];
179 | [UTCdaynum setTimeZone: UTCtz];
180 |
181 | BOOL showDate = [self fetchBooleanPreference:showDatePreferenceKey];
182 | BOOL showSeconds = [self fetchBooleanPreference:showSecondsPreferenceKey];
183 | BOOL showJulian = [self fetchBooleanPreference:showJulianDatePreferenceKey];
184 | BOOL showTimeZone = [self fetchBooleanPreference:showTimeZonePreferenceKey];
185 | BOOL show24HrTime = [self fetchBooleanPreference:show24HourPreferenceKey];
186 | BOOL showISO8601 = [self fetchBooleanPreference:showISO8601PreferenceKey];
187 |
188 | // a side effect of this function is that we also update the menu with the proper UTC date.
189 | [UTCdateDF setDateStyle:NSDateFormatterFullStyle];
190 | [UTCdateShortDF setDateStyle:NSDateFormatterShortStyle];
191 | [UTCdaynum setDateFormat:@"D/"];
192 | NSString* UTCdatepart = [UTCdateDF stringFromDate: date];
193 |
194 | [_dateMenuItem setTitle:UTCdatepart];
195 |
196 | // showISO8601 overrides everything...
197 | if (showISO8601) {
198 | NSString *dateString = [self makeISO8601DateString];
199 | return dateString;
200 | }
201 |
202 | if (showSeconds) {
203 | if (show24HrTime){
204 | [UTCdf setDateFormat: @"HH:mm:ss"];
205 | } else {
206 | [UTCdf setDateFormat: @"hh:mm:ss a"];
207 | }
208 | } else {
209 | if (show24HrTime){
210 | [UTCdf setDateFormat: @"HH:mm"];
211 | } else {
212 | [UTCdf setDateFormat: @"hh:mm a"];
213 | }
214 | }
215 |
216 | NSString* UTCtimepart = [UTCdf stringFromDate: date];
217 | NSString* UTCdateShort = [UTCdateShortDF stringFromDate: date];
218 | NSString* UTCJulianDay;
219 | NSString* UTCTzString;
220 |
221 | if (showJulian) {
222 | UTCJulianDay = [UTCdaynum stringFromDate: date];
223 | } else {
224 | UTCJulianDay = @"";
225 | }
226 |
227 | if (showTimeZone) {
228 | UTCTzString = @" UTC";
229 | } else {
230 | UTCTzString = @"";
231 | }
232 |
233 | if (showDate) {
234 | return [NSString stringWithFormat:@"%@ %@%@%@", UTCdateShort, UTCJulianDay, UTCtimepart, UTCTzString];
235 | } else {
236 | return [NSString stringWithFormat:@"%@%@%@", UTCJulianDay, UTCtimepart, UTCTzString];
237 | }
238 |
239 | }
240 |
241 | /*!
242 | @brief updates the date in the menu bar
243 | */
244 | - (void) doDateUpdate {
245 | NSString *dateString = [self makeDateString];
246 | _statusItem.button.title = dateString;
247 | }
248 |
249 | // Unused for now... need to finish.
250 | - (IBAction)showFontMenu:(id)sender {
251 | NSFontManager *fontManager = [NSFontManager sharedFontManager];
252 |
253 | NSFontPanel *fontPanel = [fontManager fontPanel:YES];
254 | [fontPanel makeKeyAndOrderFront:sender];
255 | }
256 |
257 | /*!
258 | @brief Fires to update the clock
259 | */
260 | - (void) fireTimer:(NSTimer*)theTimer {
261 | [self doDateUpdate];
262 | }
263 |
264 | - (id)init {
265 | if (self = [super init]) {
266 | // set our default preferences at each launch.
267 |
268 | NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
269 | NSDictionary *appDefaults = @{showTimeZonePreferenceKey: @YES,
270 | show24HourPreferenceKey: @YES,
271 | showJulianDatePreferenceKey: @NO,
272 | showDatePreferenceKey: @NO,
273 | showSecondsPreferenceKey: @NO};
274 | [standardUserDefaults registerDefaults:appDefaults];
275 | NSString *dateKey = @"dateKey";
276 | //Remove old, outdated date key
277 | [standardUserDefaults removeObjectForKey:dateKey];
278 | }
279 | return self;
280 |
281 | }
282 |
283 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
284 | [self doDateUpdate];
285 | }
286 |
287 | /*!
288 | @brief Runs right after the nib loads
289 | */
290 | - (void)awakeFromNib
291 | {
292 | _mainMenu = [[NSMenu alloc] init];
293 |
294 | // Disable auto enable
295 | [_mainMenu setAutoenablesItems:NO];
296 |
297 | //Create Image for menu item
298 | NSStatusBar *bar = [NSStatusBar systemStatusBar];
299 | NSStatusItem *theItem;
300 | theItem = [bar statusItemWithLength:NSVariableStatusItemLength];
301 | // while some day we may want more customizable font selection, for now
302 | // set the system font to use fixed-width digits
303 | theItem.button.font = [NSFont monospacedDigitSystemFontOfSize:NSFont.systemFontSize weight:NSFontWeightRegular];
304 | // retain a reference to the item so we don't have to find it again
305 | _statusItem = theItem;
306 |
307 | // build the menu
308 | NSMenuItem *mainItem = [[NSMenuItem alloc] init];
309 | _dateMenuItem = mainItem;
310 | [mainItem setEnabled:NO];
311 |
312 | NSMenuItem *cp1Item = [[NSMenuItem alloc] init];
313 | NSMenuItem *cp2Item = [[NSMenuItem alloc] init];
314 | NSMenuItem *cp3Item = [[NSMenuItem alloc] init];
315 | NSMenuItem *quitItem = [[NSMenuItem alloc] init];
316 | NSMenuItem *copyItem = [[NSMenuItem alloc] init];
317 | NSMenuItem *copy2Item = [[NSMenuItem alloc] init];
318 | NSMenuItem *launchItem = [[NSMenuItem alloc] init];
319 | NSMenuItem *showISO8601Item = [[NSMenuItem alloc] init];
320 |
321 | // date specific items
322 | _showDateItem = [[NSMenuItem alloc] init];
323 | _show24Item = [[NSMenuItem alloc] init];
324 | _showSecondsItem = [[NSMenuItem alloc] init];
325 | _showJulianItem = [[NSMenuItem alloc] init];
326 | _showTimeZoneItem = [[NSMenuItem alloc] init];
327 |
328 |
329 | // NSMenuItem *changeFontItem = [[NSMenuItem alloc] init];
330 |
331 | // Every menu separator must be it's own element.
332 | NSMenuItem *sep1Item = [NSMenuItem separatorItem];
333 | NSMenuItem *sep2Item = [NSMenuItem separatorItem];
334 | NSMenuItem *sep3Item = [NSMenuItem separatorItem];
335 | NSMenuItem *sep4Item = [NSMenuItem separatorItem];
336 | NSMenuItem *sep5Item = [NSMenuItem separatorItem];
337 |
338 | // Build all of the individual elements in the menu
339 | [mainItem setTitle:@""];
340 |
341 | [copyItem setTitle:@"Copy"];
342 | [copyItem setEnabled:YES];
343 | [copyItem setAction:@selector(copyToPasteboard)];
344 |
345 | [copy2Item setTitle:@"Copy as ISO-8601"];
346 | [copy2Item setEnabled:YES];
347 | [copy2Item setAction:@selector(copyIS08601ToPasteboard)];
348 |
349 | [cp3Item setEnabled:YES];
350 | [cp3Item setAction:@selector(openGithubURL:)];
351 |
352 | [launchItem setTitle:@"Open at Login"];
353 | [launchItem setEnabled:YES];
354 | [launchItem setAction:@selector(toggleLaunch:)];
355 |
356 | [_show24Item setTitle:@"24 HR Time"];
357 | [_show24Item setEnabled:YES];
358 | [_show24Item setAction:@selector(togglePreference:)];
359 | [_show24Item setRepresentedObject:show24HourPreferenceKey];
360 |
361 | [_showDateItem setTitle:@"Show Date"];
362 | [_showDateItem setEnabled:YES];
363 | [_showDateItem setAction:@selector(togglePreference:)];
364 | [_showDateItem setRepresentedObject:showDatePreferenceKey];
365 |
366 | [_showSecondsItem setTitle:@"Show Seconds"];
367 | [_showSecondsItem setEnabled:YES];
368 | [_showSecondsItem setAction:@selector(togglePreference:)];
369 | [_showSecondsItem setRepresentedObject:showSecondsPreferenceKey];
370 |
371 | [_showJulianItem setTitle:@"Show Julian Date"];
372 | [_showJulianItem setEnabled:YES];
373 | [_showJulianItem setAction:@selector(togglePreference:)];
374 | [_showJulianItem setRepresentedObject:showJulianDatePreferenceKey];
375 |
376 | [_showTimeZoneItem setTitle:@"Show Time Zone"];
377 | [_showTimeZoneItem setEnabled:YES];
378 | [_showTimeZoneItem setAction:@selector(togglePreference:)];
379 | [_showTimeZoneItem setRepresentedObject:showTimeZonePreferenceKey];
380 |
381 | [showISO8601Item setTitle:@"Show ISO8601 Instead"];
382 | [showISO8601Item setEnabled:YES];
383 | [showISO8601Item setAction:@selector(toggleISOPreference:)];
384 | [showISO8601Item setRepresentedObject:showISO8601PreferenceKey];
385 |
386 | // [changeFontItem setTitle:@"Change Font..."];
387 | // [changeFontItem setAction:@selector(showFontMenu:)];
388 |
389 | [quitItem setTitle:@"Quit"];
390 | [quitItem setEnabled:YES];
391 | [quitItem setAction:@selector(quitProgram:)];
392 |
393 | // promo junk (menu bottom)
394 | [cp1Item setTitle:@"UTC Menu Clock v1.4"];
395 | [cp1Item setEnabled:NO];
396 | [cp2Item setTitle:@"jna@retina.net"];
397 | [cp2Item setEnabled:NO];
398 | [cp3Item setTitle:@"http://github.com/netik/UTCMenuClock"];
399 | [cp3Item setEnabled:NO];
400 |
401 | // the full menu gets built here.
402 | [_mainMenu addItem:mainItem];
403 | // "---"
404 | [_mainMenu addItem:sep1Item];
405 | // Copy section
406 | [_mainMenu addItem:copyItem];
407 | [_mainMenu addItem:copy2Item];
408 | // "---"
409 | [_mainMenu addItem:sep2Item];
410 |
411 | // Preferences area
412 | BOOL showDate = [self fetchBooleanPreference:showDatePreferenceKey];
413 | BOOL showSeconds = [self fetchBooleanPreference:showSecondsPreferenceKey];
414 | BOOL showJulian = [self fetchBooleanPreference:showJulianDatePreferenceKey];
415 | BOOL showTimeZone = [self fetchBooleanPreference:showTimeZonePreferenceKey];
416 | BOOL show24HrTime = [self fetchBooleanPreference:show24HourPreferenceKey];
417 | BOOL showISOInstead = [self fetchBooleanPreference:showISO8601PreferenceKey];
418 |
419 | // set the menu states based on the preferences
420 | [_show24Item setState:show24HrTime ? NSControlStateValueOn : NSControlStateValueOff];
421 | [_showDateItem setState:showDate ? NSControlStateValueOn : NSControlStateValueOff];
422 | [_showSecondsItem setState:showSeconds ? NSControlStateValueOn : NSControlStateValueOff];
423 | [_showJulianItem setState:showJulian ? NSControlStateValueOn : NSControlStateValueOff];
424 | [_showTimeZoneItem setState:showTimeZone ? NSControlStateValueOn : NSControlStateValueOff];
425 |
426 | if (showISOInstead) {
427 | [showISO8601Item setState:NSControlStateValueOn];
428 |
429 | // disable all of the menu items which are not related to ISO state
430 | [_show24Item setEnabled:NO];
431 | [_showDateItem setEnabled:NO];
432 | [_showSecondsItem setEnabled:NO];
433 | [_showJulianItem setEnabled:NO];
434 | [_showTimeZoneItem setEnabled:NO];
435 |
436 | } else {
437 | [showISO8601Item setState:NSControlStateValueOff];
438 |
439 | // enable all of the menu items which are not related to ISO state
440 | [_show24Item setEnabled:YES];
441 | [_showDateItem setEnabled:YES];
442 | [_showSecondsItem setEnabled:YES];
443 | [_showJulianItem setEnabled:YES];
444 | [_showTimeZoneItem setEnabled:YES];
445 | }
446 |
447 | // Lastly, deal with Launch at Login
448 | LaunchAtLoginController *launchController = [[LaunchAtLoginController alloc] init];
449 | BOOL launch = [launchController launchAtLogin];
450 |
451 | [launchItem setState:launch ? NSControlStateValueOn : NSControlStateValueOff];
452 |
453 | [_mainMenu addItem:launchItem];
454 | [_mainMenu addItem:_show24Item];
455 | [_mainMenu addItem:_showDateItem];
456 | [_mainMenu addItem:_showSecondsItem];
457 | [_mainMenu addItem:_showJulianItem];
458 | [_mainMenu addItem:_showTimeZoneItem];
459 | [_mainMenu addItem:showISO8601Item];
460 | // [_mainMenu addItem:changeFontItem];
461 | // "---"
462 | [_mainMenu addItem:sep3Item];
463 | [_mainMenu addItem:quitItem];
464 |
465 | // promo stuff
466 | [_mainMenu addItem:sep4Item];
467 | // "---"
468 | [_mainMenu addItem:cp1Item];
469 | [_mainMenu addItem:cp2Item];
470 | [_mainMenu addItem:sep5Item];
471 | [_mainMenu addItem:cp3Item];
472 |
473 | [theItem setMenu:_mainMenu];
474 |
475 | [self scheduleTimer];
476 | }
477 |
478 | - (void)scheduleTimer {
479 | // Invalidate and dealloc old timer
480 | [_timer invalidate];
481 | _timer = nil;
482 |
483 | // Update the date immediately
484 | [self doDateUpdate];
485 |
486 | // Get the current date components (without ms)
487 | NSDateComponents *startUnits = [[NSCalendar currentCalendar] components:
488 | (NSCalendarUnitYear |
489 | NSCalendarUnitMonth |
490 | NSCalendarUnitDay |
491 | NSCalendarUnitHour |
492 | NSCalendarUnitMinute |
493 | NSCalendarUnitSecond)
494 | fromDate: [NSDate date]];
495 |
496 | NSTimeInterval interval;
497 | NSTimeInterval tolerance;
498 |
499 | // Schedule the timer
500 | if ([self fetchBooleanPreference:showSecondsPreferenceKey]) {
501 | // Update every 1 second with 50ms of tolerance to allow for CPU sleep
502 | // (Chosen arbitrarily: 100ms of tolerance makes the updates visibly irregular, 50ms looks fine)
503 |
504 | // Start at the next whole second
505 | [startUnits setSecond:[startUnits second] + 1.0];
506 |
507 | interval = 1.0;
508 | tolerance = 0.05;
509 | } else {
510 | // If we're not showing seconds, set the timer to fire at the next whole minute then every 60 seconds
511 | [startUnits setSecond:0];
512 | [startUnits setMinute:[startUnits minute] + 1.0];
513 |
514 | // Update every 60 seconds with 500ms of tolerance
515 | interval = 60.0;
516 | tolerance = 0.5;
517 | }
518 |
519 | // Set up wake notifications to reset the timer after sleep
520 | [self fileNotifications];
521 |
522 | NSDate *startDateTime = [[NSCalendar currentCalendar] dateFromComponents:startUnits];
523 | _timer = [[NSTimer alloc] initWithFireDate:startDateTime interval:interval target:self selector:@selector(fireTimer:) userInfo:nil repeats:YES];
524 | _timer.tolerance = tolerance;
525 |
526 | // Schedule the timer
527 | [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
528 | }
529 |
530 | - (void)receiveWakeNote: (NSNotification*) note
531 | {
532 | // When the machine wakes from sleep, reset our timer to make sure we're still running on the second/minute
533 | [self scheduleTimer];
534 | }
535 |
536 | - (void)fileNotifications
537 | {
538 | // https://developer.apple.com/library/archive/qa/qa1340/_index.html
539 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
540 | selector: @selector(receiveWakeNote:)
541 | name: NSWorkspaceDidWakeNotification object: nil];
542 | }
543 |
544 | - (void)dealloc
545 | {
546 | // Remove notification observer
547 | [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
548 |
549 | // Invalidate timer (ARC handles the release)
550 | [_timer invalidate];
551 | }
552 |
553 | @end
554 |
--------------------------------------------------------------------------------
/UTCMenuClock.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A88E0A712CC2E2B600BC0123 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A88E0A702CC2E2B600BC0123 /* ServiceManagement.framework */; };
11 | A88E0A722CC2E2B600BC0123 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A88E0A702CC2E2B600BC0123 /* ServiceManagement.framework */; };
12 | A8B1188B1471AE3A008A993B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8B1188A1471AE3A008A993B /* Cocoa.framework */; };
13 | A8B118951471AE3A008A993B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A8B118931471AE3A008A993B /* InfoPlist.strings */; };
14 | A8B118971471AE3A008A993B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B118961471AE3A008A993B /* main.m */; };
15 | A8B1189B1471AE3A008A993B /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = A8B118991471AE3A008A993B /* Credits.rtf */; };
16 | A8B1189E1471AE3A008A993B /* UTCMenuClockAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B1189D1471AE3A008A993B /* UTCMenuClockAppDelegate.m */; };
17 | A8B118A11471AE3A008A993B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A8B1189F1471AE3A008A993B /* MainMenu.xib */; };
18 | A8B118A91471AE3A008A993B /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8B118A81471AE3A008A993B /* SenTestingKit.framework */; };
19 | A8B118AA1471AE3A008A993B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8B1188A1471AE3A008A993B /* Cocoa.framework */; };
20 | A8B118B21471AE3A008A993B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A8B118B01471AE3A008A993B /* InfoPlist.strings */; };
21 | A8B118B41471AE3A008A993B /* UTCMenuClockTests.h in Resources */ = {isa = PBXBuildFile; fileRef = A8B118B31471AE3A008A993B /* UTCMenuClockTests.h */; };
22 | A8B118B61471AE3A008A993B /* UTCMenuClockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B118B51471AE3A008A993B /* UTCMenuClockTests.m */; };
23 | A8B119261471EB13008A993B /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B119011471EB13008A993B /* LaunchAtLoginController.m */; };
24 | A8B119271471EB13008A993B /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = A8B119021471EB13008A993B /* README.md */; };
25 | DA1B0A0B1822FCFF00C57253 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1B0A0A1822FCFF00C57253 /* Images.xcassets */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | A8B118AB1471AE3A008A993B /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = A8B1187D1471AE3A008A993B /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = A8B118851471AE3A008A993B;
34 | remoteInfo = UTCMenuClock;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXFileReference section */
39 | A88E0A702CC2E2B600BC0123 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/ServiceManagement.framework; sourceTree = DEVELOPER_DIR; };
40 | A8B118861471AE3A008A993B /* UTCMenuClock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UTCMenuClock.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | A8B1188A1471AE3A008A993B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
42 | A8B1188D1471AE3A008A993B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
43 | A8B1188E1471AE3A008A993B /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
44 | A8B1188F1471AE3A008A993B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
45 | A8B118921471AE3A008A993B /* UTCMenuClock-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UTCMenuClock-Info.plist"; sourceTree = ""; };
46 | A8B118941471AE3A008A993B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
47 | A8B118961471AE3A008A993B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
48 | A8B118981471AE3A008A993B /* UTCMenuClock-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UTCMenuClock-Prefix.pch"; sourceTree = ""; };
49 | A8B1189A1471AE3A008A993B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; };
50 | A8B1189C1471AE3A008A993B /* UTCMenuClockAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTCMenuClockAppDelegate.h; sourceTree = ""; };
51 | A8B1189D1471AE3A008A993B /* UTCMenuClockAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTCMenuClockAppDelegate.m; sourceTree = ""; };
52 | A8B118A71471AE3A008A993B /* UTCMenuClockTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UTCMenuClockTests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
53 | A8B118A81471AE3A008A993B /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
54 | A8B118AF1471AE3A008A993B /* UTCMenuClockTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UTCMenuClockTests-Info.plist"; sourceTree = ""; };
55 | A8B118B11471AE3A008A993B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
56 | A8B118B31471AE3A008A993B /* UTCMenuClockTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTCMenuClockTests.h; sourceTree = ""; };
57 | A8B118B51471AE3A008A993B /* UTCMenuClockTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTCMenuClockTests.m; sourceTree = ""; };
58 | A8B119001471EB13008A993B /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = ""; };
59 | A8B119011471EB13008A993B /* LaunchAtLoginController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = ""; };
60 | A8B119021471EB13008A993B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; };
61 | A8DCEE662EEB9390009EE388 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
62 | A8DFE58328F0B2A40048B113 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
63 | DA1B0A0A1822FCFF00C57253 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
64 | /* End PBXFileReference section */
65 |
66 | /* Begin PBXFrameworksBuildPhase section */
67 | A8B118831471AE3A008A993B /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 2147483647;
70 | files = (
71 | A8B1188B1471AE3A008A993B /* Cocoa.framework in Frameworks */,
72 | A88E0A712CC2E2B600BC0123 /* ServiceManagement.framework in Frameworks */,
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | A8B118A31471AE3A008A993B /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | A88E0A722CC2E2B600BC0123 /* ServiceManagement.framework in Frameworks */,
81 | A8B118A91471AE3A008A993B /* SenTestingKit.framework in Frameworks */,
82 | A8B118AA1471AE3A008A993B /* Cocoa.framework in Frameworks */,
83 | );
84 | runOnlyForDeploymentPostprocessing = 0;
85 | };
86 | /* End PBXFrameworksBuildPhase section */
87 |
88 | /* Begin PBXGroup section */
89 | A8B1187B1471AE3A008A993B = {
90 | isa = PBXGroup;
91 | children = (
92 | A8DCEE662EEB9390009EE388 /* README.md */,
93 | A8B118901471AE3A008A993B /* UTCMenuClock */,
94 | A8B118AD1471AE3A008A993B /* UTCMenuClockTests */,
95 | A8B118891471AE3A008A993B /* Frameworks */,
96 | A8B118871471AE3A008A993B /* Products */,
97 | );
98 | sourceTree = "";
99 | };
100 | A8B118871471AE3A008A993B /* Products */ = {
101 | isa = PBXGroup;
102 | children = (
103 | A8B118861471AE3A008A993B /* UTCMenuClock.app */,
104 | A8B118A71471AE3A008A993B /* UTCMenuClockTests.octest */,
105 | );
106 | name = Products;
107 | sourceTree = "";
108 | };
109 | A8B118891471AE3A008A993B /* Frameworks */ = {
110 | isa = PBXGroup;
111 | children = (
112 | A8B1188A1471AE3A008A993B /* Cocoa.framework */,
113 | A8B118A81471AE3A008A993B /* SenTestingKit.framework */,
114 | A88E0A702CC2E2B600BC0123 /* ServiceManagement.framework */,
115 | A8B1188C1471AE3A008A993B /* Other Frameworks */,
116 | );
117 | name = Frameworks;
118 | sourceTree = "";
119 | };
120 | A8B1188C1471AE3A008A993B /* Other Frameworks */ = {
121 | isa = PBXGroup;
122 | children = (
123 | A8B1188D1471AE3A008A993B /* AppKit.framework */,
124 | A8B1188E1471AE3A008A993B /* CoreData.framework */,
125 | A8B1188F1471AE3A008A993B /* Foundation.framework */,
126 | );
127 | name = "Other Frameworks";
128 | sourceTree = "";
129 | };
130 | A8B118901471AE3A008A993B /* UTCMenuClock */ = {
131 | isa = PBXGroup;
132 | children = (
133 | A8B1189C1471AE3A008A993B /* UTCMenuClockAppDelegate.h */,
134 | A8B1189D1471AE3A008A993B /* UTCMenuClockAppDelegate.m */,
135 | A8B118BF1471EB12008A993B /* LaunchAtLoginController */,
136 | A8B1189F1471AE3A008A993B /* MainMenu.xib */,
137 | DA1B0A0A1822FCFF00C57253 /* Images.xcassets */,
138 | A8B118911471AE3A008A993B /* Supporting Files */,
139 | );
140 | path = UTCMenuClock;
141 | sourceTree = "";
142 | };
143 | A8B118911471AE3A008A993B /* Supporting Files */ = {
144 | isa = PBXGroup;
145 | children = (
146 | A8B118921471AE3A008A993B /* UTCMenuClock-Info.plist */,
147 | A8B118931471AE3A008A993B /* InfoPlist.strings */,
148 | A8B118961471AE3A008A993B /* main.m */,
149 | A8B118981471AE3A008A993B /* UTCMenuClock-Prefix.pch */,
150 | A8B118991471AE3A008A993B /* Credits.rtf */,
151 | );
152 | name = "Supporting Files";
153 | sourceTree = "";
154 | };
155 | A8B118AD1471AE3A008A993B /* UTCMenuClockTests */ = {
156 | isa = PBXGroup;
157 | children = (
158 | A8B118B31471AE3A008A993B /* UTCMenuClockTests.h */,
159 | A8B118B51471AE3A008A993B /* UTCMenuClockTests.m */,
160 | A8B118AE1471AE3A008A993B /* Supporting Files */,
161 | );
162 | path = UTCMenuClockTests;
163 | sourceTree = "";
164 | };
165 | A8B118AE1471AE3A008A993B /* Supporting Files */ = {
166 | isa = PBXGroup;
167 | children = (
168 | A8B118AF1471AE3A008A993B /* UTCMenuClockTests-Info.plist */,
169 | A8B118B01471AE3A008A993B /* InfoPlist.strings */,
170 | );
171 | name = "Supporting Files";
172 | sourceTree = "";
173 | };
174 | A8B118BF1471EB12008A993B /* LaunchAtLoginController */ = {
175 | isa = PBXGroup;
176 | children = (
177 | A8B119001471EB13008A993B /* LaunchAtLoginController.h */,
178 | A8B119011471EB13008A993B /* LaunchAtLoginController.m */,
179 | A8B119021471EB13008A993B /* README.md */,
180 | );
181 | path = LaunchAtLoginController;
182 | sourceTree = "";
183 | };
184 | /* End PBXGroup section */
185 |
186 | /* Begin PBXNativeTarget section */
187 | A8B118851471AE3A008A993B /* UTCMenuClock */ = {
188 | isa = PBXNativeTarget;
189 | buildConfigurationList = A8B118B91471AE3A008A993B /* Build configuration list for PBXNativeTarget "UTCMenuClock" */;
190 | buildPhases = (
191 | A8B118821471AE3A008A993B /* Sources */,
192 | A8B118831471AE3A008A993B /* Frameworks */,
193 | A8B118841471AE3A008A993B /* Resources */,
194 | );
195 | buildRules = (
196 | );
197 | dependencies = (
198 | );
199 | name = UTCMenuClock;
200 | productName = UTCMenuClock;
201 | productReference = A8B118861471AE3A008A993B /* UTCMenuClock.app */;
202 | productType = "com.apple.product-type.application";
203 | };
204 | A8B118A61471AE3A008A993B /* UTCMenuClockTests */ = {
205 | isa = PBXNativeTarget;
206 | buildConfigurationList = A8B118BC1471AE3A008A993B /* Build configuration list for PBXNativeTarget "UTCMenuClockTests" */;
207 | buildPhases = (
208 | A8B118A21471AE3A008A993B /* Sources */,
209 | A8B118A31471AE3A008A993B /* Frameworks */,
210 | A8B118A41471AE3A008A993B /* Resources */,
211 | A8B118A51471AE3A008A993B /* ShellScript */,
212 | );
213 | buildRules = (
214 | );
215 | dependencies = (
216 | A8B118AC1471AE3A008A993B /* PBXTargetDependency */,
217 | );
218 | name = UTCMenuClockTests;
219 | productName = UTCMenuClockTests;
220 | productReference = A8B118A71471AE3A008A993B /* UTCMenuClockTests.octest */;
221 | productType = "com.apple.product-type.bundle.ocunit-test";
222 | };
223 | /* End PBXNativeTarget section */
224 |
225 | /* Begin PBXProject section */
226 | A8B1187D1471AE3A008A993B /* Project object */ = {
227 | isa = PBXProject;
228 | attributes = {
229 | BuildIndependentTargetsInParallel = YES;
230 | LastTestingUpgradeCheck = 0730;
231 | LastUpgradeCheck = 1600;
232 | ORGANIZATIONNAME = "";
233 | TargetAttributes = {
234 | A8B118851471AE3A008A993B = {
235 | ProvisioningStyle = Automatic;
236 | };
237 | };
238 | };
239 | buildConfigurationList = A8B118801471AE3A008A993B /* Build configuration list for PBXProject "UTCMenuClock" */;
240 | compatibilityVersion = "Xcode 3.2";
241 | developmentRegion = en;
242 | hasScannedForEncodings = 0;
243 | knownRegions = (
244 | en,
245 | Base,
246 | );
247 | mainGroup = A8B1187B1471AE3A008A993B;
248 | productRefGroup = A8B118871471AE3A008A993B /* Products */;
249 | projectDirPath = "";
250 | projectRoot = "";
251 | targets = (
252 | A8B118851471AE3A008A993B /* UTCMenuClock */,
253 | A8B118A61471AE3A008A993B /* UTCMenuClockTests */,
254 | );
255 | };
256 | /* End PBXProject section */
257 |
258 | /* Begin PBXResourcesBuildPhase section */
259 | A8B118841471AE3A008A993B /* Resources */ = {
260 | isa = PBXResourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | A8B118951471AE3A008A993B /* InfoPlist.strings in Resources */,
264 | A8B1189B1471AE3A008A993B /* Credits.rtf in Resources */,
265 | A8B118A11471AE3A008A993B /* MainMenu.xib in Resources */,
266 | DA1B0A0B1822FCFF00C57253 /* Images.xcassets in Resources */,
267 | A8B119271471EB13008A993B /* README.md in Resources */,
268 | );
269 | runOnlyForDeploymentPostprocessing = 0;
270 | };
271 | A8B118A41471AE3A008A993B /* Resources */ = {
272 | isa = PBXResourcesBuildPhase;
273 | buildActionMask = 2147483647;
274 | files = (
275 | A8B118B21471AE3A008A993B /* InfoPlist.strings in Resources */,
276 | A8B118B41471AE3A008A993B /* UTCMenuClockTests.h in Resources */,
277 | );
278 | runOnlyForDeploymentPostprocessing = 0;
279 | };
280 | /* End PBXResourcesBuildPhase section */
281 |
282 | /* Begin PBXShellScriptBuildPhase section */
283 | A8B118A51471AE3A008A993B /* ShellScript */ = {
284 | isa = PBXShellScriptBuildPhase;
285 | buildActionMask = 2147483647;
286 | files = (
287 | );
288 | inputPaths = (
289 | );
290 | outputPaths = (
291 | );
292 | runOnlyForDeploymentPostprocessing = 0;
293 | shellPath = /bin/sh;
294 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n";
295 | };
296 | /* End PBXShellScriptBuildPhase section */
297 |
298 | /* Begin PBXSourcesBuildPhase section */
299 | A8B118821471AE3A008A993B /* Sources */ = {
300 | isa = PBXSourcesBuildPhase;
301 | buildActionMask = 2147483647;
302 | files = (
303 | A8B118971471AE3A008A993B /* main.m in Sources */,
304 | A8B1189E1471AE3A008A993B /* UTCMenuClockAppDelegate.m in Sources */,
305 | A8B119261471EB13008A993B /* LaunchAtLoginController.m in Sources */,
306 | );
307 | runOnlyForDeploymentPostprocessing = 0;
308 | };
309 | A8B118A21471AE3A008A993B /* Sources */ = {
310 | isa = PBXSourcesBuildPhase;
311 | buildActionMask = 2147483647;
312 | files = (
313 | A8B118B61471AE3A008A993B /* UTCMenuClockTests.m in Sources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | /* End PBXSourcesBuildPhase section */
318 |
319 | /* Begin PBXTargetDependency section */
320 | A8B118AC1471AE3A008A993B /* PBXTargetDependency */ = {
321 | isa = PBXTargetDependency;
322 | target = A8B118851471AE3A008A993B /* UTCMenuClock */;
323 | targetProxy = A8B118AB1471AE3A008A993B /* PBXContainerItemProxy */;
324 | };
325 | /* End PBXTargetDependency section */
326 |
327 | /* Begin PBXVariantGroup section */
328 | A8B118931471AE3A008A993B /* InfoPlist.strings */ = {
329 | isa = PBXVariantGroup;
330 | children = (
331 | A8B118941471AE3A008A993B /* en */,
332 | );
333 | name = InfoPlist.strings;
334 | sourceTree = "";
335 | };
336 | A8B118991471AE3A008A993B /* Credits.rtf */ = {
337 | isa = PBXVariantGroup;
338 | children = (
339 | A8B1189A1471AE3A008A993B /* en */,
340 | );
341 | name = Credits.rtf;
342 | sourceTree = "";
343 | };
344 | A8B1189F1471AE3A008A993B /* MainMenu.xib */ = {
345 | isa = PBXVariantGroup;
346 | children = (
347 | A8DFE58328F0B2A40048B113 /* Base */,
348 | );
349 | name = MainMenu.xib;
350 | sourceTree = "";
351 | };
352 | A8B118B01471AE3A008A993B /* InfoPlist.strings */ = {
353 | isa = PBXVariantGroup;
354 | children = (
355 | A8B118B11471AE3A008A993B /* en */,
356 | );
357 | name = InfoPlist.strings;
358 | sourceTree = "";
359 | };
360 | /* End PBXVariantGroup section */
361 |
362 | /* Begin XCBuildConfiguration section */
363 | A8B118B71471AE3A008A993B /* Debug */ = {
364 | isa = XCBuildConfiguration;
365 | buildSettings = {
366 | ALWAYS_SEARCH_USER_PATHS = NO;
367 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
368 | CLANG_ENABLE_OBJC_ARC = YES;
369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
370 | CLANG_WARN_BOOL_CONVERSION = YES;
371 | CLANG_WARN_COMMA = YES;
372 | CLANG_WARN_CONSTANT_CONVERSION = YES;
373 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
374 | CLANG_WARN_EMPTY_BODY = YES;
375 | CLANG_WARN_ENUM_CONVERSION = YES;
376 | CLANG_WARN_INFINITE_RECURSION = YES;
377 | CLANG_WARN_INT_CONVERSION = YES;
378 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
379 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
380 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
381 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
382 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
383 | CLANG_WARN_STRICT_PROTOTYPES = YES;
384 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
385 | CLANG_WARN_UNREACHABLE_CODE = YES;
386 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
387 | COPY_PHASE_STRIP = NO;
388 | DEAD_CODE_STRIPPING = YES;
389 | ENABLE_STRICT_OBJC_MSGSEND = YES;
390 | ENABLE_TESTABILITY = YES;
391 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
392 | GCC_C_LANGUAGE_STANDARD = gnu99;
393 | GCC_DYNAMIC_NO_PIC = NO;
394 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
395 | GCC_NO_COMMON_BLOCKS = YES;
396 | GCC_OPTIMIZATION_LEVEL = 0;
397 | GCC_PREPROCESSOR_DEFINITIONS = (
398 | "DEBUG=1",
399 | "$(inherited)",
400 | );
401 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
402 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
403 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
404 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
405 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
406 | GCC_WARN_UNDECLARED_SELECTOR = YES;
407 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
408 | GCC_WARN_UNUSED_FUNCTION = YES;
409 | GCC_WARN_UNUSED_VARIABLE = YES;
410 | MACOSX_DEPLOYMENT_TARGET = 15.0;
411 | ONLY_ACTIVE_ARCH = YES;
412 | SDKROOT = macosx;
413 | };
414 | name = Debug;
415 | };
416 | A8B118B81471AE3A008A993B /* Release */ = {
417 | isa = XCBuildConfiguration;
418 | buildSettings = {
419 | ALWAYS_SEARCH_USER_PATHS = NO;
420 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
421 | CLANG_ENABLE_OBJC_ARC = YES;
422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
423 | CLANG_WARN_BOOL_CONVERSION = YES;
424 | CLANG_WARN_COMMA = YES;
425 | CLANG_WARN_CONSTANT_CONVERSION = YES;
426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
427 | CLANG_WARN_EMPTY_BODY = YES;
428 | CLANG_WARN_ENUM_CONVERSION = YES;
429 | CLANG_WARN_INFINITE_RECURSION = YES;
430 | CLANG_WARN_INT_CONVERSION = YES;
431 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
432 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
433 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
434 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
436 | CLANG_WARN_STRICT_PROTOTYPES = YES;
437 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
438 | CLANG_WARN_UNREACHABLE_CODE = YES;
439 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
440 | COPY_PHASE_STRIP = YES;
441 | DEAD_CODE_STRIPPING = YES;
442 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
443 | ENABLE_STRICT_OBJC_MSGSEND = YES;
444 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
445 | GCC_C_LANGUAGE_STANDARD = gnu99;
446 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
447 | GCC_NO_COMMON_BLOCKS = YES;
448 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
449 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
450 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
451 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
452 | GCC_WARN_UNDECLARED_SELECTOR = YES;
453 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
454 | GCC_WARN_UNUSED_FUNCTION = YES;
455 | GCC_WARN_UNUSED_VARIABLE = YES;
456 | MACOSX_DEPLOYMENT_TARGET = 15.0;
457 | SDKROOT = macosx;
458 | };
459 | name = Release;
460 | };
461 | A8B118BA1471AE3A008A993B /* Debug */ = {
462 | isa = XCBuildConfiguration;
463 | buildSettings = {
464 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
465 | CLANG_ENABLE_OBJC_WEAK = YES;
466 | CODE_SIGN_IDENTITY = "Mac Developer";
467 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
468 | COMBINE_HIDPI_IMAGES = YES;
469 | DEAD_CODE_STRIPPING = YES;
470 | DEVELOPMENT_TEAM = "";
471 | ENABLE_HARDENED_RUNTIME = YES;
472 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
473 | GCC_PREFIX_HEADER = "UTCMenuClock/UTCMenuClock-Prefix.pch";
474 | INFOPLIST_FILE = "UTCMenuClock/UTCMenuClock-Info.plist";
475 | MACOSX_DEPLOYMENT_TARGET = 15.0;
476 | PRODUCT_BUNDLE_IDENTIFIER = net.retina.UTCMenuClock;
477 | PRODUCT_NAME = "$(TARGET_NAME)";
478 | WRAPPER_EXTENSION = app;
479 | };
480 | name = Debug;
481 | };
482 | A8B118BB1471AE3A008A993B /* Release */ = {
483 | isa = XCBuildConfiguration;
484 | buildSettings = {
485 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
486 | CLANG_ENABLE_OBJC_WEAK = YES;
487 | CODE_SIGN_IDENTITY = "Mac Developer";
488 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
489 | COMBINE_HIDPI_IMAGES = YES;
490 | DEAD_CODE_STRIPPING = YES;
491 | DEVELOPMENT_TEAM = "";
492 | ENABLE_HARDENED_RUNTIME = YES;
493 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
494 | GCC_PREFIX_HEADER = "UTCMenuClock/UTCMenuClock-Prefix.pch";
495 | INFOPLIST_FILE = "UTCMenuClock/UTCMenuClock-Info.plist";
496 | MACOSX_DEPLOYMENT_TARGET = 15.0;
497 | PRODUCT_BUNDLE_IDENTIFIER = net.retina.UTCMenuClock;
498 | PRODUCT_NAME = "$(TARGET_NAME)";
499 | WRAPPER_EXTENSION = app;
500 | };
501 | name = Release;
502 | };
503 | A8B118BD1471AE3A008A993B /* Debug */ = {
504 | isa = XCBuildConfiguration;
505 | buildSettings = {
506 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/UTCMenuClock.app/Contents/MacOS/UTCMenuClock";
507 | CLANG_ENABLE_OBJC_WEAK = YES;
508 | COMBINE_HIDPI_IMAGES = YES;
509 | DEAD_CODE_STRIPPING = YES;
510 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
511 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
512 | GCC_PREFIX_HEADER = "UTCMenuClock/UTCMenuClock-Prefix.pch";
513 | INFOPLIST_FILE = "UTCMenuClockTests/UTCMenuClockTests-Info.plist";
514 | MACOSX_DEPLOYMENT_TARGET = 15.0;
515 | PRODUCT_BUNDLE_IDENTIFIER = "net.retina.${PRODUCT_NAME:rfc1034identifier}";
516 | PRODUCT_NAME = "$(TARGET_NAME)";
517 | TEST_HOST = "$(BUNDLE_LOADER)";
518 | WRAPPER_EXTENSION = octest;
519 | };
520 | name = Debug;
521 | };
522 | A8B118BE1471AE3A008A993B /* Release */ = {
523 | isa = XCBuildConfiguration;
524 | buildSettings = {
525 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/UTCMenuClock.app/Contents/MacOS/UTCMenuClock";
526 | CLANG_ENABLE_OBJC_WEAK = YES;
527 | COMBINE_HIDPI_IMAGES = YES;
528 | DEAD_CODE_STRIPPING = YES;
529 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
530 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
531 | GCC_PREFIX_HEADER = "UTCMenuClock/UTCMenuClock-Prefix.pch";
532 | INFOPLIST_FILE = "UTCMenuClockTests/UTCMenuClockTests-Info.plist";
533 | MACOSX_DEPLOYMENT_TARGET = 15.0;
534 | PRODUCT_BUNDLE_IDENTIFIER = "net.retina.${PRODUCT_NAME:rfc1034identifier}";
535 | PRODUCT_NAME = "$(TARGET_NAME)";
536 | TEST_HOST = "$(BUNDLE_LOADER)";
537 | WRAPPER_EXTENSION = octest;
538 | };
539 | name = Release;
540 | };
541 | /* End XCBuildConfiguration section */
542 |
543 | /* Begin XCConfigurationList section */
544 | A8B118801471AE3A008A993B /* Build configuration list for PBXProject "UTCMenuClock" */ = {
545 | isa = XCConfigurationList;
546 | buildConfigurations = (
547 | A8B118B71471AE3A008A993B /* Debug */,
548 | A8B118B81471AE3A008A993B /* Release */,
549 | );
550 | defaultConfigurationIsVisible = 0;
551 | defaultConfigurationName = Release;
552 | };
553 | A8B118B91471AE3A008A993B /* Build configuration list for PBXNativeTarget "UTCMenuClock" */ = {
554 | isa = XCConfigurationList;
555 | buildConfigurations = (
556 | A8B118BA1471AE3A008A993B /* Debug */,
557 | A8B118BB1471AE3A008A993B /* Release */,
558 | );
559 | defaultConfigurationIsVisible = 0;
560 | defaultConfigurationName = Release;
561 | };
562 | A8B118BC1471AE3A008A993B /* Build configuration list for PBXNativeTarget "UTCMenuClockTests" */ = {
563 | isa = XCConfigurationList;
564 | buildConfigurations = (
565 | A8B118BD1471AE3A008A993B /* Debug */,
566 | A8B118BE1471AE3A008A993B /* Release */,
567 | );
568 | defaultConfigurationIsVisible = 0;
569 | defaultConfigurationName = Release;
570 | };
571 | /* End XCConfigurationList section */
572 | };
573 | rootObject = A8B1187D1471AE3A008A993B /* Project object */;
574 | }
575 |
--------------------------------------------------------------------------------
/UTCMenuClock/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
651 |
652 |
653 |
654 |
655 |
--------------------------------------------------------------------------------