From 5fa58247084fcfc152725a2a2fc4beae7d8c5fe1 Mon Sep 17 00:00:00 2001 From: Ox Cart Date: Wed, 18 Sep 2019 06:58:35 -0500 Subject: [PATCH] Added support for App Window --- example/main.go | 6 +-- go.mod | 8 ++++ go.sum | 22 +++++++++++ systray.h | 2 + systray_browser_darwin.m | 79 ++++++++++++++++++++++++++++++++++++++++ systray_browser_linux.c | 46 +++++++++++++++++++++++ systray_darwin.m | 5 +++ systray_linux.c | 3 ++ systray_nonwindows.go | 16 +++++++- 9 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 systray_browser_darwin.m create mode 100644 systray_browser_linux.c diff --git a/example/main.go b/example/main.go index 5542b89..88bf7a5 100644 --- a/example/main.go +++ b/example/main.go @@ -7,7 +7,6 @@ import ( "github.com/getlantern/systray" "github.com/getlantern/systray/example/icon" - "github.com/skratchdot/open-golang/open" ) func main() { @@ -22,6 +21,7 @@ func main() { } func onReady() { + systray.EnableAppWindow("Lantern", 1024, 768) systray.SetIcon(icon.Data) systray.SetTitle("Awesome App") systray.SetTooltip("Lantern") @@ -42,7 +42,7 @@ func onReady() { mChecked := systray.AddMenuItem("Unchecked", "Check Me") mEnabled := systray.AddMenuItem("Enabled", "Enabled") systray.AddMenuItem("Ignored", "Ignored") - mUrl := systray.AddMenuItem("Open Lantern.org", "my home") + mUrl := systray.AddMenuItem("Open UI", "my home") mQuit := systray.AddMenuItem("退出", "Quit the whole app") // Sets the icon of a menu item. Only available on Mac. @@ -67,7 +67,7 @@ func onReady() { mEnabled.SetTitle("Disabled") mEnabled.Disable() case <-mUrl.ClickedCh: - open.Run("https://www.getlantern.org") + systray.ShowAppWindow("https://www.getlantern.org") case <-mToggle.ClickedCh: if shown { mQuitOrig.Hide() diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..91cdf7b --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/getlantern/systray + +go 1.12 + +require ( + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 + github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e1d551d --- /dev/null +++ b/go.sum @@ -0,0 +1,22 @@ +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= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= +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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e h1:VAzdS5Nw68fbf5RZ8RDVlUvPXNU6Z3jtPCK/qvm4FoQ= +github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/systray.h b/systray.h index 36bcf98..cecdc40 100644 --- a/systray.h +++ b/systray.h @@ -7,6 +7,8 @@ void setIcon(const char* iconBytes, int length); void setMenuItemIcon(const char* iconBytes, int length, int menuId); void setTitle(char* title); void setTooltip(char* tooltip); +void configureAppWindow(char* title, int width, int height); +void showAppWindow(char* url); void add_or_update_menu_item(int menuId, char* title, char* tooltip, short disabled, short checked); void add_separator(int menuId); void hide_menu_item(int menuId); diff --git a/systray_browser_darwin.m b/systray_browser_darwin.m new file mode 100644 index 0000000..c20c7f6 --- /dev/null +++ b/systray_browser_darwin.m @@ -0,0 +1,79 @@ +#import +#import +#include "systray.h" + +NSWindowController *windowController = nil; +WKWebView *webView = nil; + +void doConfigureAppWindow(char* title, int width, int height) +{ + if (windowController != nil) { + // already configured, ignore + return; + } + + NSRect frame = NSMakeRect(0, 0, width, height); + int mask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable; + id window = + [[NSWindow alloc] initWithContentRect:frame + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; + [window setTitle:[[NSString alloc] initWithUTF8String:title]]; + [window makeKeyAndOrderFront:nil]; + [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); +} + +void configureAppWindow(char* title, int width, int height) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + doConfigureAppWindow(title, width, height); + }); +} + +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.window orderFrontRegardless]; + free(url); +} + +void showAppWindow(char* url) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + doShowAppWindow(url); + }); +} diff --git a/systray_browser_linux.c b/systray_browser_linux.c new file mode 100644 index 0000000..af32294 --- /dev/null +++ b/systray_browser_linux.c @@ -0,0 +1,46 @@ +#include +#include + +static GtkWidget *web_window = NULL; +static WebKitWebView *webView = NULL; + +static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window); + +void prepareBrowser() +{ + // Create an 800x600 window that will contain the browser instance + web_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(web_window), 800, 600); + + // Create a browser instance + webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); + + // Put the browser area into the web window + gtk_container_add(GTK_CONTAINER(web_window), GTK_WIDGET(webView)); + + g_signal_connect(webView, "close", G_CALLBACK(closeWebViewCb), web_window); + + // Make sure that when the browser area becomes visible, it will get mouse + // and keyboard events + gtk_widget_grab_focus(GTK_WIDGET(webView)); +} + +gboolean do_open_in_browser(gpointer data) +{ + gtk_widget_show_all(web_window); + return TRUE; +} + +void openInBrowser(char* url) +{ + // Load a web page into the browser instance + webkit_web_view_load_uri(webView, url); + + gdk_threads_add_idle(do_open_in_browser, url); +} + +static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window) +{ + gtk_widget_destroy(window); + return TRUE; +} \ No newline at end of file diff --git a/systray_darwin.m b/systray_darwin.m index b0f2172..7189ef5 100644 --- a/systray_darwin.m +++ b/systray_darwin.m @@ -70,6 +70,11 @@ systray_ready(); } +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender +{ + return FALSE; +} + - (void)applicationWillTerminate:(NSNotification *)aNotification { systray_on_exit(); diff --git a/systray_linux.c b/systray_linux.c index 72cd614..20eedaf 100644 --- a/systray_linux.c +++ b/systray_linux.c @@ -23,6 +23,8 @@ typedef struct { short checked; } MenuItemInfo; +void prepareBrowser(); + int nativeLoop(void) { gtk_init(0, NULL); global_app_indicator = app_indicator_new("systray", "", @@ -31,6 +33,7 @@ int nativeLoop(void) { global_tray_menu = gtk_menu_new(); app_indicator_set_menu(global_app_indicator, GTK_MENU(global_tray_menu)); systray_ready(); + prepareBrowser(); gtk_main(); systray_on_exit(); return 0; diff --git a/systray_nonwindows.go b/systray_nonwindows.go index 4868b55..03af1bb 100644 --- a/systray_nonwindows.go +++ b/systray_nonwindows.go @@ -3,9 +3,10 @@ package systray /* -#cgo linux pkg-config: gtk+-3.0 appindicator3-0.1 +#cgo linux CFLAGS: -DWEBVIEW_GTK=1 +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 appindicator3-0.1 #cgo darwin CFLAGS: -DDARWIN -x objective-c -fobjc-arc -#cgo darwin LDFLAGS: -framework Cocoa +#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit #include "systray.h" */ @@ -42,6 +43,17 @@ func SetTooltip(tooltip string) { C.setTooltip(C.CString(tooltip)) } +// EnableAppWindow enables a single application window for this app. +func EnableAppWindow(title string, width int, height int) { + C.configureAppWindow(C.CString(title), C.int(width), C.int(height)) +} + +// ShowAppWindow shows the given URL in the application window. Only works if +// configureAppWindow has been called first. +func ShowAppWindow(url string) { + C.showAppWindow(C.CString(url)) +} + func addOrUpdateMenuItem(item *MenuItem) { var disabled C.short if item.disabled {