Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/GioActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import android.app.Activity;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import android.view.ViewGroup;
import android.view.View;
Expand All @@ -29,6 +30,7 @@ public final class GioActivity extends Activity {

layer.addView(view);
setContentView(layer);
onNewIntent(this.getIntent());
}

@Override public void onDestroy() {
Expand Down Expand Up @@ -60,4 +62,9 @@ public final class GioActivity extends Activity {
if (!view.backPressed())
super.onBackPressed();
}

@Override protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
view.onIntentEvent(intent);
}
}
11 changes: 11 additions & 0 deletions app/GioView.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
Expand Down Expand Up @@ -311,6 +312,15 @@ private void setHighRefreshRate() {
window.setAttributes(layoutParams);
}

protected void onIntentEvent(Intent intent) {
if (intent == null) {
return;
}
if (intent.getData() != null) {
this.onOpenURI(nhandle, intent.getData().toString());
}
}

@Override protected boolean dispatchHoverEvent(MotionEvent event) {
if (!accessManager.isTouchExplorationEnabled()) {
return super.dispatchHoverEvent(event);
Expand Down Expand Up @@ -549,6 +559,7 @@ void updateCaret(float m00, float m01, float m02, float m10, float m11, float m1
static private native void onExitTouchExploration(long handle);
static private native void onA11yFocus(long handle, int viewId);
static private native void onClearA11yFocus(long handle, int viewId);
static private native void onOpenURI(long handle, String uri);
static private native void imeSetSnippet(long handle, int start, int end);
static private native String imeSnippet(long handle);
static private native int imeSnippetStart(long handle);
Expand Down
1 change: 1 addition & 0 deletions app/framework_ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#include <UIKit/UIKit.h>

@interface GioViewController : UIViewController
- (BOOL)onOpenURI:(NSString *)url;
@end
138 changes: 137 additions & 1 deletion app/internal/windows/windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package windows

import (
"fmt"
"golang.org/x/sys/windows/registry"
"os"
"runtime"
"time"
"unicode/utf16"
Expand Down Expand Up @@ -99,6 +101,8 @@ const (

CW_USEDEFAULT = -2147483648

ERROR_ALREADY_EXISTS = 183

GWL_STYLE = ^(uintptr(16) - 1) // -16

GCS_COMPSTR = 0x0008
Expand All @@ -111,7 +115,8 @@ const (
CFS_POINT = 0x0002
CFS_CANDIDATEPOS = 0x0040

HWND_TOPMOST = ^(uint32(1) - 1) // -1
HWND_TOPMOST = ^(uint32(1) - 1) // -1
HWND_BROADCAST = 0xFFFF

HTCAPTION = 2
HTCLIENT = 1
Expand Down Expand Up @@ -303,15 +308,30 @@ const (
LR_MONOCHROME = 0x00000001
LR_SHARED = 0x00008000
LR_VGACOLOR = 0x00000080

FILE_MAP_WRITE = 0x0002
FILE_MAP_READ = 0x0004

PAGE_READWRITE = 0x00000004
)

var (
GIO_OPEN_URL uint32 // Custom message for deep linking, lazy init
)

var (
kernel32 = syscall.NewLazySystemDLL("kernel32.dll")
_CreateMutex = kernel32.NewProc("CreateMutexW")
_GetMutexInfo = kernel32.NewProc("GetMutexInfo")
_GetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
_GlobalAlloc = kernel32.NewProc("GlobalAlloc")
_GlobalFree = kernel32.NewProc("GlobalFree")
_GlobalLock = kernel32.NewProc("GlobalLock")
_GlobalUnlock = kernel32.NewProc("GlobalUnlock")
_MapViewOfFile = kernel32.NewProc("MapViewOfFile")
_OpenFileMapping = kernel32.NewProc("OpenFileMappingW")
_ReleaseMutex = kernel32.NewProc("ReleaseMutex")
_UnmapViewOfFile = kernel32.NewProc("UnmapViewOfFile")

user32 = syscall.NewLazySystemDLL("user32.dll")
_AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx")
Expand Down Expand Up @@ -347,9 +367,11 @@ var (
_PostQuitMessage = user32.NewProc("PostQuitMessage")
_ReleaseCapture = user32.NewProc("ReleaseCapture")
_RegisterClassExW = user32.NewProc("RegisterClassExW")
_RegisterWindowMessage = user32.NewProc("RegisterWindowMessageW")
_ReleaseDC = user32.NewProc("ReleaseDC")
_ScreenToClient = user32.NewProc("ScreenToClient")
_ShowWindow = user32.NewProc("ShowWindow")
_SendMessage = user32.NewProc("SendMessageW")
_SetCapture = user32.NewProc("SetCapture")
_SetCursor = user32.NewProc("SetCursor")
_SetClipboardData = user32.NewProc("SetClipboardData")
Expand Down Expand Up @@ -651,6 +673,65 @@ func GlobalUnlock(h syscall.Handle) {
_GlobalUnlock.Call(uintptr(h))
}

func CreateMutex(name string) (ptr syscall.Handle, err error) {
r, _, err := _CreateMutex.Call(0, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))))
switch err.(syscall.Errno) {
case ERROR_ALREADY_EXISTS:
return 0, err
}
return syscall.Handle(r), nil
}

func GetMutexInfo(h syscall.Handle) (pid, count uint32, err error) {
r, _, err := _GetMutexInfo.Call(uintptr(h), uintptr(unsafe.Pointer(&pid)), uintptr(unsafe.Pointer(&count)))
if r == 0 {
return 0, 0, fmt.Errorf("GetMutexInfo: %v", err)
}
return pid, count, nil
}

func CreateFileMapping(mode uint32, name string, size int) (ptr syscall.Handle, err error) {
return syscall.CreateFileMapping(syscall.InvalidHandle, nil, mode, 0, uint32(size), syscall.StringToUTF16Ptr("Local"+name))
}

func OpenFileMapping(mode int32, name string) (syscall.Handle, error) {
r, _, err := _OpenFileMapping.Call(uintptr(mode), 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Local"+name))))
if r == 0 {
return 0, fmt.Errorf("OpenFileMapping: %v", err)
}
return syscall.Handle(r), nil
}

func CloseFileMapping(h syscall.Handle) error {
return syscall.Close(h)
}

func MapViewOfFile(h syscall.Handle, mode int32, size int) ([]byte, error) {
r, _, err := _MapViewOfFile.Call(uintptr(h), uintptr(mode), 0, 0, uintptr(size))
if r == 0 {
return nil, fmt.Errorf("MapViewOfFile: %v", err)
}

slice := [3]uintptr{r, uintptr(size), uintptr(size)}
return *(*[]byte)(unsafe.Pointer(&slice)), nil
}

func UnmapViewOfFile(b []byte) error {
r, _, err := _UnmapViewOfFile.Call(uintptr(unsafe.Pointer(&b[0])))
if r == 0 {
return fmt.Errorf("UnmapViewOfFile: %v", err)
}
return nil
}

func ReleaseMutex(h uintptr) error {
r, _, err := _ReleaseMutex.Call(h)
if r == 0 {
return fmt.Errorf("ReleaseMutex: %v", err)
}
return nil
}

func KillTimer(hwnd syscall.Handle, nIDEvent uintptr) error {
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0)
if r == 0 {
Expand Down Expand Up @@ -735,10 +816,26 @@ func RegisterClassEx(cls *WndClassEx) (uint16, error) {
return uint16(a), nil
}

func RegisterWindowMessage(name string) (uint32, error) {
r, _, err := _RegisterWindowMessage.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))))
if r == 0 {
return 0, fmt.Errorf("RegisterWindowMessage: %v", err)
}
return uint32(r), nil
}

func ReleaseDC(hdc syscall.Handle) {
_ReleaseDC.Call(uintptr(hdc))
}

func SendMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error {
r, _, err := _SendMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam)
if r == 0 {
return fmt.Errorf("SendMessage failed: %v", err)
}
return nil
}

func SetForegroundWindow(hwnd syscall.Handle) {
_SetForegroundWindow.Call(uintptr(hwnd))
}
Expand Down Expand Up @@ -814,3 +911,42 @@ func (p *WindowPlacement) Set(Left, Top, Right, Bottom int) {
p.rcNormalPosition.Right = int32(Right)
p.rcNormalPosition.Bottom = int32(Bottom)
}

func RegisterScheme(scheme string) error {
path, err := os.Executable()
if err != nil {
return err
}

key, _, err := registry.CreateKey(registry.CURRENT_USER, `Software\\Classes\\`+scheme, registry.ALL_ACCESS)
if err != nil {
return err
}
defer key.Close()

if err = key.SetStringValue("", "URL:"+scheme+" Protocol"); err != nil {
return err
}

if err = key.SetStringValue("URL Protocol", ""); err != nil {
return err
}

icon, _, err := registry.CreateKey(key, `DefaultIcon`, registry.ALL_ACCESS)
if err != nil {
return err
}
defer icon.Close()

if err = icon.SetStringValue("", `"`+path+`",1`); err != nil {
return err
}

cmd, _, err := registry.CreateKey(key, `shell\\open\\command`, registry.ALL_ACCESS)
if err != nil {
return err
}
defer cmd.Close()

return cmd.SetStringValue("", `"`+path+`" "%1"`)
}
12 changes: 12 additions & 0 deletions app/os_android.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,11 @@ import "C"
import (
"errors"
"fmt"
"gioui.org/io/transfer"
"image"
"image/color"
"math"
"net/url"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -659,6 +661,16 @@ func Java_org_gioui_GioView_onClearA11yFocus(env *C.JNIEnv, class C.jclass, view
}
}

//export Java_org_gioui_GioView_onOpenURI
func Java_org_gioui_GioView_onOpenURI(env *C.JNIEnv, class C.jclass, view C.jlong, uri C.jstring) {
w := cgo.Handle(view).Value().(*window)
u, err := url.Parse(goString(env, uri))
if err != nil {
return
}
w.callbacks.Event(transfer.URLEvent{URL: u})
}

func (w *window) initAccessibilityNodeInfo(env *C.JNIEnv, sem router.SemanticNode, off image.Point, info C.jobject) error {
for _, ch := range sem.Children {
err := callVoidMethod(env, info, android.accessibilityNodeInfo.addChild, jvalue(w.view), jvalue(w.virtualIDFor(ch.ID)))
Expand Down
22 changes: 22 additions & 0 deletions app/os_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ static struct drawParams viewDrawParams(CFTypeRef viewRef) {
import "C"

import (
"gioui.org/io/transfer"
"image"
"net/url"
"runtime"
"runtime/debug"
"time"
Expand Down Expand Up @@ -131,6 +133,9 @@ func onCreate(view, controller C.CFTypeRef) {
w.Configure(wopts.options)
w.w.Event(system.StageEvent{Stage: system.StagePaused})
w.w.Event(ViewEvent{ViewController: uintptr(controller)})
if startupURI != nil {
w.w.Event(transfer.URLEvent{URL: startupURI})
}
}

//export gio_onDraw
Expand Down Expand Up @@ -351,6 +356,23 @@ func newWindow(win *callbacks, options []Option) error {
func osMain() {
}

var startupURI *url.URL

//export gio_onOpenURI
func gio_onOpenURI(uri C.CFTypeRef) {
u, err := url.Parse(nsstringToString(uri))
if err != nil {
return
}
if len(views) == 0 {
startupURI = u
return
}
for _, w := range views {
w.w.Event(transfer.URLEvent{URL: u})
}
}

//export gio_runMain
func gio_runMain() {
runMain()
Expand Down
5 changes: 5 additions & 0 deletions app/os_ios.m
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ - (void)keyboardWillHide:(NSNotification *)note {
_keyboardHeight = 0.0;
[self.view setNeedsLayout];
}

- (BOOL)onOpenURI:(NSString *)url {
gio_onOpenURI((__bridge CFTypeRef)url);
return YES;
}
@end

static void handleTouches(int last, UIView *view, NSSet<UITouch *> *touches, UIEvent *event) {
Expand Down
22 changes: 22 additions & 0 deletions app/os_macos.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package app

import (
"errors"
"gioui.org/io/transfer"
"image"
"net/url"
"runtime"
"time"
"unicode"
Expand Down Expand Up @@ -842,6 +844,23 @@ func gio_onFinishLaunching() {
close(launched)
}

var startupURI *url.URL

//export gio_onOpenURI
func gio_onOpenURI(uri C.CFTypeRef) {
u, err := url.Parse(nsstringToString(uri))
if err != nil {
return
}
if len(viewMap) == 0 {
startupURI = u
return
}
for _, w := range viewMap {
w.w.Event(transfer.URLEvent{URL: u})
}
}

func newWindow(win *callbacks, options []Option) error {
<-launched
errch := make(chan error)
Expand All @@ -867,6 +886,9 @@ func newWindow(win *callbacks, options []Option) error {
C.makeKeyAndOrderFront(window)
layer := C.layerForView(w.view)
w.w.Event(ViewEvent{View: uintptr(w.view), Layer: uintptr(layer)})
if startupURI != nil {
w.w.Event(transfer.URLEvent{URL: startupURI})
}
})
return <-errch
}
Expand Down
Loading