diff --git a/.gitignore b/.gitignore index ae7e06b..2e85ef6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ example/example +webview_example/webview_example *~ *.swp -*.exe +**/*.exe Release Debug *.sdf diff --git a/example/main.go b/example/main.go index a7308bf..8a02fed 100644 --- a/example/main.go +++ b/example/main.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "io/ioutil" "time" @@ -11,23 +10,13 @@ import ( "github.com/skratchdot/open-golang/open" ) -var ( - webview = flag.Bool("webview", false, "show a webview window along with the systray") -) - func main() { - flag.Parse() onExit := func() { now := time.Now() ioutil.WriteFile(fmt.Sprintf(`on_exit_%d.txt`, now.UnixNano()), []byte(now.String()), 0644) } - if *webview { - systray.Register(onReady, onExit) - showWebviewOnWindows() - } else { - systray.Run(onReady, onExit) - } + systray.Run(onReady, onExit) } func onReady() { diff --git a/example/webview_nonwindows.go b/example/webview_nonwindows.go deleted file mode 100644 index 9496193..0000000 --- a/example/webview_nonwindows.go +++ /dev/null @@ -1,7 +0,0 @@ -//+build !windows - -package main - -func showWebviewOnWindows() { - panic("not implemented") -} diff --git a/go.mod b/go.mod index 6e1e84f..d0a8fc3 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,11 @@ module github.com/getlantern/systray go 1.13 -require github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 +require ( + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 + github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 + github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 + golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c + gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect +) diff --git a/go.sum b/go.sum index 64c1e70..8be5240 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= @@ -13,8 +14,21 @@ github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSl github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 h1:/QwQcwWVOQXcoNuV9tHx30gQ3q7jCE/rKcGjwzsa5tg= +github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 h1:5BmtGkQbch91lglMHQ9JIDGiYCL3kBRBA0ItZTvOcEI= +github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c h1:kISX68E8gSkNYAFRFiDU8rl5RIn1sJYKYb/r2vMLDrU= +golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= diff --git a/webview_example/main.go b/webview_example/main.go new file mode 100644 index 0000000..160a8a5 --- /dev/null +++ b/webview_example/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "github.com/getlantern/systray" + "github.com/getlantern/systray/example/icon" +) + +func main() { + systray.Register(onReady, nil) + configureWebview("Webview example", 1024, 768) +} + +func onReady() { + systray.SetTemplateIcon(icon.Data, icon.Data) + systray.SetTitle("Webview example") + mShowLantern := systray.AddMenuItem("Show Lantern", "") + mShowWikipedia := systray.AddMenuItem("Show Wikipedia", "") + mQuit := systray.AddMenuItem("Quit", "Quit the whole app") + go func() { + for { + select { + case <-mShowLantern.ClickedCh: + showWebview("https://www.getlantern.org") + case <-mShowWikipedia.ClickedCh: + showWebview("https://www.wikipedia.org") + case <-mQuit.ClickedCh: + systray.Quit() + } + } + }() + +} diff --git a/webview_example/webview.h b/webview_example/webview.h new file mode 100644 index 0000000..2e39c6a --- /dev/null +++ b/webview_example/webview.h @@ -0,0 +1,3 @@ +void configureAppWindow(char* title, int width, int height); +void showAppWindow(char* url); + diff --git a/webview_example/webview_darwin.m b/webview_example/webview_darwin.m new file mode 100644 index 0000000..962f653 --- /dev/null +++ b/webview_example/webview_darwin.m @@ -0,0 +1,78 @@ +#import +#import +#include "webview.h" + +NSWindowController *windowController = nil; +NSWindow *window = nil; +WKWebView *webView = nil; + +void configureAppWindow(char* title, int width, int height) +{ + if (windowController != nil) { + // already configured, ignore + return; + } + + NSApplication *app = [NSApplication sharedApplication]; + [app setActivationPolicy:NSApplicationActivationPolicyRegular]; + [app activateIgnoringOtherApps:YES]; + + NSRect frame = NSMakeRect(0, 0, width, height); + int mask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable; + window = [[NSWindow alloc] initWithContentRect:frame + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; + [window setTitle:[[NSString alloc] initWithUTF8String:title]]; + [window center]; + + NSView *contentView = [window contentView]; + webView = [[WKWebView alloc] initWithFrame:[contentView bounds]]; + [webView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [contentView addSubview:webView]; + [contentView addConstraint: + [NSLayoutConstraint constraintWithItem:webView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:contentView + attribute:NSLayoutAttributeWidth + multiplier:1 + constant:0]]; + [contentView addConstraint: + [NSLayoutConstraint constraintWithItem:webView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:contentView + attribute:NSLayoutAttributeHeight + multiplier:1 + constant:0]]; + + // Window controller: + windowController = [[NSWindowController alloc] initWithWindow:window]; + + free(title); + [NSApp run]; +} + +void doShowAppWindow(char* url) +{ + if (windowController == nil) { + // no app window to open + return; + } + + id nsURL = [NSURL URLWithString:[[NSString alloc] initWithUTF8String:url]]; + id req = [[NSURLRequest alloc] initWithURL: nsURL + cachePolicy: NSURLRequestUseProtocolCachePolicy + timeoutInterval: 5]; + [webView loadRequest:req]; + [windowController showWindow:window]; + free(url); +} + +void showAppWindow(char* url) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + doShowAppWindow(url); + }); +} diff --git a/webview_example/webview_linux.c b/webview_example/webview_linux.c new file mode 100644 index 0000000..61a4c61 --- /dev/null +++ b/webview_example/webview_linux.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include "webview.h" + +static GtkWindow *web_window = NULL; +static WebKitWebView *web_view = NULL; + +static gint x, y; +static bool needsMove = false; + +gboolean on_window_deleted(GtkWidget *window, GdkEvent *event, gpointer data) +{ + gtk_window_get_position(GTK_WINDOW(window), &x, &y); + needsMove = true; + gtk_widget_hide(window); + return TRUE; +} + +void configureAppWindow(char* title, int width, int height) +{ + // Create an 800x600 window that will contain the browser instance + web_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_window_set_title(web_window, title); + gtk_window_set_default_size(web_window, width, height); + gtk_window_set_skip_taskbar_hint (web_window, TRUE); + g_signal_connect(G_OBJECT(web_window), "delete-event", G_CALLBACK(on_window_deleted), NULL); + + // Create a browser instance + web_view = WEBKIT_WEB_VIEW(webkit_web_view_new()); + + // Put the browser area into the web window + gtk_container_add(GTK_CONTAINER(web_window), GTK_WIDGET(web_view)); + + // Make sure that when the browser area becomes visible, it will get mouse + // and keyboard events + gtk_widget_grab_focus(GTK_WIDGET(web_view)); + free(title); + gtk_main(); +} + +gboolean do_show_app_window(gpointer data) +{ + gtk_widget_show_all(GTK_WIDGET(web_window)); + if (needsMove) { + gtk_window_move(web_window, x, y); + needsMove = false; + } + gtk_window_present(web_window); + return FALSE; +} + +void showWebview(char* url) +{ + // Load a web page into the browser instance + webkit_web_view_load_uri(web_view, url); + + g_idle_add(do_show_app_window, NULL); + free(url); +} diff --git a/webview_example/webview_nonwindows.go b/webview_example/webview_nonwindows.go new file mode 100644 index 0000000..5c83569 --- /dev/null +++ b/webview_example/webview_nonwindows.go @@ -0,0 +1,20 @@ +//+build !windows + +package main + +/* +#cgo linux pkg-config: gtk+-3.0 appindicator3-0.1 +#cgo darwin CFLAGS: -DDARWIN -x objective-c -fobjc-arc +#cgo darwin LDFLAGS: -framework Cocoa -framework Webkit + +#include "webview.h" +*/ +import "C" + +func configureWebview(title string, width, height int) { + C.configureAppWindow(C.CString(title), C.int(width), C.int(height)) +} + +func showWebview(url string) { + C.showAppWindow(C.CString(url)) +} diff --git a/example/webview_windows.go b/webview_example/webview_windows.go similarity index 63% rename from example/webview_windows.go rename to webview_example/webview_windows.go index 22d4572..4fa28c4 100644 --- a/example/webview_windows.go +++ b/webview_example/webview_windows.go @@ -5,23 +5,27 @@ import ( "github.com/lxn/walk" ) -func showWebviewOnWindows() { +var webView *walk.WebView + +func configureWebview(title string, width, height int) { mainWindow, err := walk.NewMainWindow() if err != nil { panic(fmt.Sprintf("Failed to create main window: %v\n", err)) } - mainWindow.SetTitle("Webview") - mainWindow.SetWidth(800) - mainWindow.SetHeight(600) + mainWindow.SetTitle(title) + mainWindow.SetWidth(width) + mainWindow.SetHeight(height) layout := walk.NewVBoxLayout() if err := mainWindow.SetLayout(layout); err != nil { panic(fmt.Sprintf("Failed to set layout: %v\n", err)) } - webView, err := walk.NewWebView(mainWindow) + webView, err = walk.NewWebView(mainWindow) if err != nil { panic(fmt.Sprintf("Failed to create webview window: %v\n", err)) } - webView.SetURL("https://www.getlantern.org") - mainWindow.SetVisible(true) mainWindow.Run() + mainWindow.SetVisible(true) +} +func showWebview(url string) { + webView.SetURL(url) }