app: fix status item icons
@ -22,24 +22,33 @@
|
|||||||
// user about what this is doing, and ideally use Touch ID.
|
// user about what this is doing, and ideally use Touch ID.
|
||||||
// or add an alias in the current shell environment,
|
// or add an alias in the current shell environment,
|
||||||
// which wouldn't require any special privileges
|
// which wouldn't require any special privileges
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
createSymlinkWithAuthorization();
|
// createSymlinkWithAuthorization();
|
||||||
});
|
// });
|
||||||
|
|
||||||
// show status menu
|
// show status menu
|
||||||
NSMenu *menu = [[NSMenu alloc] init];
|
NSMenu *menu = [[NSMenu alloc] init];
|
||||||
|
|
||||||
NSMenuItem *openSettingsItem = [[NSMenuItem alloc] initWithTitle:@"Settings..." action:@selector(openSettingsWindow) keyEquivalent:@""];
|
|
||||||
[menu addItem:openSettingsItem];
|
|
||||||
[menu addItem:[NSMenuItem separatorItem]];
|
|
||||||
[menu addItemWithTitle:@"Quit Ollama" action:@selector(quit) keyEquivalent:@"q"];
|
[menu addItemWithTitle:@"Quit Ollama" action:@selector(quit) keyEquivalent:@"q"];
|
||||||
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
|
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
|
||||||
|
[self.statusItem addObserver:self forKeyPath:@"button.effectiveAppearance" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial context:nil];
|
||||||
|
|
||||||
self.statusItem.menu = menu;
|
self.statusItem.menu = menu;
|
||||||
NSImage *statusImage = [NSImage imageNamed:@"icon"];
|
[self showIcon];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) showIcon {
|
||||||
|
NSAppearance* appearance = self.statusItem.button.effectiveAppearance;
|
||||||
|
NSString* appearanceName = (NSString*)(appearance.name);
|
||||||
|
NSString* iconName = [[appearanceName lowercaseString] containsString:@"dark"] ? @"iconDark" : @"icon";
|
||||||
|
NSImage* statusImage = [NSImage imageNamed:iconName];
|
||||||
[statusImage setTemplate:YES];
|
[statusImage setTemplate:YES];
|
||||||
self.statusItem.button.image = statusImage;
|
self.statusItem.button.image = statusImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||||
|
[self showIcon];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)openSettingsWindow {
|
- (void)openSettingsWindow {
|
||||||
if (!self.settingsWindow) {
|
if (!self.settingsWindow) {
|
||||||
// Create the settings window centered on the screen
|
// Create the settings window centered on the screen
|
||||||
@ -66,57 +75,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSToolbarDelegate
|
|
||||||
|
|
||||||
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
|
|
||||||
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
|
|
||||||
|
|
||||||
if ([itemIdentifier isEqualToString:@"General"]) {
|
|
||||||
toolbarItem.label = @"General";
|
|
||||||
toolbarItem.paletteLabel = @"General";
|
|
||||||
toolbarItem.toolTip = @"General Settings";
|
|
||||||
toolbarItem.image = [NSImage imageWithSystemSymbolName:@"gear" accessibilityDescription:nil]; // Monochrome symbol
|
|
||||||
toolbarItem.target = self;
|
|
||||||
toolbarItem.action = @selector(switchTabs:);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([itemIdentifier isEqualToString:@"Networking"]) {
|
|
||||||
toolbarItem.label = @"Networking";
|
|
||||||
toolbarItem.paletteLabel = @"Networking";
|
|
||||||
toolbarItem.toolTip = @"Networking Settings";
|
|
||||||
toolbarItem.image = [NSImage imageWithSystemSymbolName:@"network" accessibilityDescription:nil]; // Monochrome symbol
|
|
||||||
toolbarItem.target = self;
|
|
||||||
toolbarItem.action = @selector(switchTabs:);
|
|
||||||
}
|
|
||||||
// Create other items with their respective images and selectors here...
|
|
||||||
|
|
||||||
return toolbarItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray<NSToolbarItemIdentifier> *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
|
|
||||||
return @[
|
|
||||||
NSToolbarFlexibleSpaceItemIdentifier,
|
|
||||||
@"General",
|
|
||||||
@"Networking",
|
|
||||||
NSToolbarFlexibleSpaceItemIdentifier
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray<NSToolbarItemIdentifier> *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
|
|
||||||
return @[
|
|
||||||
NSToolbarFlexibleSpaceItemIdentifier,
|
|
||||||
@"General",
|
|
||||||
@"Networking",
|
|
||||||
NSToolbarFlexibleSpaceItemIdentifier
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)switchTabs:(NSToolbarItem *)sender {
|
|
||||||
// Your code to switch tabs based on the sender's identifier
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)quit {
|
- (void)quit {
|
||||||
Quit();
|
[NSApp stop:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -132,12 +92,13 @@ int askToMoveToApplications() {
|
|||||||
[alert setInformativeText:@"Ollama works best when run from the Applications directory."];
|
[alert setInformativeText:@"Ollama works best when run from the Applications directory."];
|
||||||
[alert addButtonWithTitle:@"Move to Applications"];
|
[alert addButtonWithTitle:@"Move to Applications"];
|
||||||
[alert addButtonWithTitle:@"Don't move"];
|
[alert addButtonWithTitle:@"Don't move"];
|
||||||
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
|
||||||
if ([alert runModal] != NSAlertFirstButtonReturn) {
|
if ([alert runModal] != NSAlertFirstButtonReturn) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move to applications
|
// move to applications
|
||||||
NSString *applicationsPath = @"/Applications";
|
NSString *applicationsPath = @"/Applications";
|
||||||
NSString *newPath = [applicationsPath stringByAppendingPathComponent:@"Ollama.app"];
|
NSString *newPath = [applicationsPath stringByAppendingPathComponent:@"Ollama.app"];
|
||||||
|
@ -33,21 +33,22 @@ func run() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resources := filepath.Join(filepath.Dir(exe), "..", "Resources")
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
var done chan int
|
var done chan int
|
||||||
|
|
||||||
done, err = SpawnServer(ctx, filepath.Join(resources, "ollama"))
|
done, err = SpawnServer(ctx, filepath.Join(filepath.Dir(exe), "..", "Resources", "ollama"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error(fmt.Sprintf("Failed to spawn ollama server %s", err))
|
slog.Error(fmt.Sprintf("Failed to spawn ollama server %s", err))
|
||||||
done = make(chan int, 1)
|
done = make(chan int, 1)
|
||||||
done <- 1
|
done <- 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the native app
|
// Run the native macOS app
|
||||||
|
// Note: this will block until the app is closed
|
||||||
C.run()
|
C.run()
|
||||||
|
|
||||||
|
slog.Info("ollama macOS app closed")
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
slog.Info("Waiting for ollama server to shutdown...")
|
slog.Info("Waiting for ollama server to shutdown...")
|
||||||
if done != nil {
|
if done != nil {
|
||||||
|
@ -38,4 +38,4 @@ void killOtherInstances() {
|
|||||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/jmorganca/ollama/app/lifecycle"
|
"github.com/ollama/ollama/app/lifecycle"
|
||||||
"github.com/jmorganca/ollama/app/store"
|
"github.com/ollama/ollama/app/store"
|
||||||
"github.com/jmorganca/ollama/app/tray"
|
"github.com/ollama/ollama/app/tray"
|
||||||
"github.com/jmorganca/ollama/app/updater"
|
"github.com/ollama/ollama/app/updater"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 668 B After Width: | Height: | Size: 691 B |
Before Width: | Height: | Size: 381 B After Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 721 B |
@ -1,92 +0,0 @@
|
|||||||
package lifecycle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/ollama/ollama/app/store"
|
|
||||||
"github.com/ollama/ollama/app/tray"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Run() {
|
|
||||||
InitLogging()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
var done chan int
|
|
||||||
|
|
||||||
t, err := tray.NewTray()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to start: %s", err)
|
|
||||||
}
|
|
||||||
callbacks := t.GetCallbacks()
|
|
||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
slog.Debug("starting callback loop")
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-callbacks.Quit:
|
|
||||||
slog.Debug("quit called")
|
|
||||||
t.Quit()
|
|
||||||
case <-signals:
|
|
||||||
slog.Debug("shutting down due to signal")
|
|
||||||
t.Quit()
|
|
||||||
case <-callbacks.Update:
|
|
||||||
err := DoUpgrade(cancel, done)
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn(fmt.Sprintf("upgrade attempt failed: %s", err))
|
|
||||||
}
|
|
||||||
case <-callbacks.ShowLogs:
|
|
||||||
ShowLogs()
|
|
||||||
case <-callbacks.DoFirstUse:
|
|
||||||
err := GetStarted()
|
|
||||||
if err != nil {
|
|
||||||
slog.Warn(fmt.Sprintf("Failed to launch getting started shell: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Are we first use?
|
|
||||||
if !store.GetFirstTimeRun() {
|
|
||||||
slog.Debug("First time run")
|
|
||||||
err = t.DisplayFirstUseNotification()
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug(fmt.Sprintf("XXX failed to display first use notification %v", err))
|
|
||||||
}
|
|
||||||
store.SetFirstTimeRun(true)
|
|
||||||
} else {
|
|
||||||
slog.Debug("Not first time, skipping first run notification")
|
|
||||||
}
|
|
||||||
|
|
||||||
if IsServerRunning(ctx) {
|
|
||||||
slog.Info("Detected another instance of ollama running, exiting")
|
|
||||||
os.Exit(1)
|
|
||||||
} else {
|
|
||||||
done, err = SpawnServer(ctx, CLIName)
|
|
||||||
if err != nil {
|
|
||||||
// TODO - should we retry in a backoff loop?
|
|
||||||
// TODO - should we pop up a warning and maybe add a menu item to view application logs?
|
|
||||||
slog.Error(fmt.Sprintf("Failed to spawn ollama server %s", err))
|
|
||||||
done = make(chan int, 1)
|
|
||||||
done <- 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StartBackgroundUpdaterChecker(ctx, t.UpdateAvailable)
|
|
||||||
|
|
||||||
t.Run()
|
|
||||||
cancel()
|
|
||||||
slog.Info("Waiting for ollama server to shutdown...")
|
|
||||||
if done != nil {
|
|
||||||
<-done
|
|
||||||
}
|
|
||||||
slog.Info("Ollama app exiting")
|
|
||||||
}
|
|
@ -1,5 +1,3 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
@ -1,25 +0,0 @@
|
|||||||
# Set your variables here.
|
|
||||||
REPO="jmorganca/ollama"
|
|
||||||
|
|
||||||
# Check if VERSION is set
|
|
||||||
if [[ -z "${VERSION}" ]]; then
|
|
||||||
echo "VERSION is not set. Please set the VERSION environment variable."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
OS=$(go env GOOS)
|
|
||||||
|
|
||||||
./script/build_${OS}.sh
|
|
||||||
|
|
||||||
# Create a new tag if it doesn't exist.
|
|
||||||
if ! git rev-parse v$VERSION >/dev/null 2>&1; then
|
|
||||||
git tag v$VERSION
|
|
||||||
fi
|
|
||||||
|
|
||||||
git push origin v$VERSION
|
|
||||||
|
|
||||||
# Create a new release.
|
|
||||||
gh release create -p v$VERSION -t v$VERSION
|
|
||||||
|
|
||||||
# Upload the zip file.
|
|
||||||
gh release upload v$VERSION ./dist/* --clobber
|
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
rm -rf $TMPDIR/Ollama.app
|
||||||
cp -R app/darwin/Ollama.app $TMPDIR/Ollama.app
|
cp -R app/darwin/Ollama.app $TMPDIR/Ollama.app
|
||||||
mkdir -p $TMPDIR/Ollama.app/Contents/Resources $TMPDIR/Ollama.app/Contents/MacOS
|
mkdir -p $TMPDIR/Ollama.app/Contents/Resources $TMPDIR/Ollama.app/Contents/MacOS
|
||||||
go build -o $TMPDIR/Ollama.app/Contents/Resources/ollama .
|
go build -o $TMPDIR/Ollama.app/Contents/Resources/ollama .
|
||||||
|