github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/app/internal/window/os_ios.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  // +build darwin,ios
     4  
     5  package window
     6  
     7  /*
     8  #cgo CFLAGS: -DGLES_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c
     9  
    10  #include <CoreGraphics/CoreGraphics.h>
    11  #include <UIKit/UIKit.h>
    12  #include <stdint.h>
    13  #include "os_ios.h"
    14  
    15  */
    16  import "C"
    17  
    18  import (
    19  	"image"
    20  	"runtime"
    21  	"runtime/debug"
    22  	"sync/atomic"
    23  	"time"
    24  
    25  	"github.com/gop9/olt/gio/f32"
    26  	"github.com/gop9/olt/gio/io/key"
    27  	"github.com/gop9/olt/gio/io/pointer"
    28  	"github.com/gop9/olt/gio/io/system"
    29  	"github.com/gop9/olt/gio/unit"
    30  )
    31  
    32  type window struct {
    33  	view C.CFTypeRef
    34  	w    Callbacks
    35  
    36  	layer   C.CFTypeRef
    37  	visible atomic.Value
    38  
    39  	pointerMap []C.CFTypeRef
    40  }
    41  
    42  var mainWindow = newWindowRendezvous()
    43  
    44  var layerFactory func() uintptr
    45  
    46  var views = make(map[C.CFTypeRef]*window)
    47  
    48  func init() {
    49  	// Darwin requires UI operations happen on the main thread only.
    50  	runtime.LockOSThread()
    51  }
    52  
    53  //export onCreate
    54  func onCreate(view C.CFTypeRef) {
    55  	w := &window{
    56  		view: view,
    57  	}
    58  	wopts := <-mainWindow.out
    59  	w.w = wopts.window
    60  	w.w.SetDriver(w)
    61  	w.visible.Store(false)
    62  	w.layer = C.CFTypeRef(layerFactory())
    63  	C.gio_addLayerToView(view, w.layer)
    64  	views[view] = w
    65  	w.w.Event(system.StageEvent{Stage: system.StagePaused})
    66  }
    67  
    68  //export onDraw
    69  func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, top, right, bottom, left C.CGFloat) {
    70  	if width == 0 || height == 0 {
    71  		return
    72  	}
    73  	w := views[view]
    74  	wasVisible := w.isVisible()
    75  	w.visible.Store(true)
    76  	C.gio_updateView(view, w.layer)
    77  	if !wasVisible {
    78  		w.w.Event(system.StageEvent{Stage: system.StageRunning})
    79  	}
    80  	isSync := false
    81  	if sync != 0 {
    82  		isSync = true
    83  	}
    84  	const inchPrDp = 1.0 / 163
    85  	w.w.Event(FrameEvent{
    86  		FrameEvent: system.FrameEvent{
    87  			Size: image.Point{
    88  				X: int(width + .5),
    89  				Y: int(height + .5),
    90  			},
    91  			Insets: system.Insets{
    92  				Top:    unit.Px(float32(top)),
    93  				Right:  unit.Px(float32(right)),
    94  				Bottom: unit.Px(float32(bottom)),
    95  				Left:   unit.Px(float32(left)),
    96  			},
    97  			Config: &config{
    98  				pxPerDp: float32(dpi) * inchPrDp,
    99  				pxPerSp: float32(sdpi) * inchPrDp,
   100  				now:     time.Now(),
   101  			},
   102  		},
   103  		Sync: isSync,
   104  	})
   105  }
   106  
   107  //export onStop
   108  func onStop(view C.CFTypeRef) {
   109  	w := views[view]
   110  	w.visible.Store(false)
   111  	w.w.Event(system.StageEvent{Stage: system.StagePaused})
   112  }
   113  
   114  //export onDestroy
   115  func onDestroy(view C.CFTypeRef) {
   116  	w := views[view]
   117  	delete(views, view)
   118  	w.w.Event(system.DestroyEvent{})
   119  	C.gio_removeLayer(w.layer)
   120  	C.CFRelease(w.layer)
   121  	w.layer = 0
   122  	w.view = 0
   123  }
   124  
   125  //export onFocus
   126  func onFocus(view C.CFTypeRef, focus int) {
   127  	w := views[view]
   128  	w.w.Event(key.FocusEvent{Focus: focus != 0})
   129  }
   130  
   131  //export onLowMemory
   132  func onLowMemory() {
   133  	runtime.GC()
   134  	debug.FreeOSMemory()
   135  }
   136  
   137  //export onUpArrow
   138  func onUpArrow(view C.CFTypeRef) {
   139  	views[view].onKeyCommand(key.NameUpArrow)
   140  }
   141  
   142  //export onDownArrow
   143  func onDownArrow(view C.CFTypeRef) {
   144  	views[view].onKeyCommand(key.NameDownArrow)
   145  }
   146  
   147  //export onLeftArrow
   148  func onLeftArrow(view C.CFTypeRef) {
   149  	views[view].onKeyCommand(key.NameLeftArrow)
   150  }
   151  
   152  //export onRightArrow
   153  func onRightArrow(view C.CFTypeRef) {
   154  	views[view].onKeyCommand(key.NameRightArrow)
   155  }
   156  
   157  //export onDeleteBackward
   158  func onDeleteBackward(view C.CFTypeRef) {
   159  	views[view].onKeyCommand(key.NameDeleteBackward)
   160  }
   161  
   162  //export onText
   163  func onText(view C.CFTypeRef, str *C.char) {
   164  	w := views[view]
   165  	w.w.Event(key.EditEvent{
   166  		Text: C.GoString(str),
   167  	})
   168  }
   169  
   170  //export onTouch
   171  func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.CGFloat, ti C.double) {
   172  	var typ pointer.Type
   173  	switch phase {
   174  	case C.UITouchPhaseBegan:
   175  		typ = pointer.Press
   176  	case C.UITouchPhaseMoved:
   177  		typ = pointer.Move
   178  	case C.UITouchPhaseEnded:
   179  		typ = pointer.Release
   180  	case C.UITouchPhaseCancelled:
   181  		typ = pointer.Cancel
   182  	default:
   183  		return
   184  	}
   185  	w := views[view]
   186  	t := time.Duration(float64(ti) * float64(time.Second))
   187  	p := f32.Point{X: float32(x), Y: float32(y)}
   188  	w.w.Event(pointer.Event{
   189  		Type:      typ,
   190  		Source:    pointer.Touch,
   191  		PointerID: w.lookupTouch(last != 0, touchRef),
   192  		Position:  p,
   193  		Time:      t,
   194  	})
   195  }
   196  
   197  func (w *window) SetAnimating(anim bool) {
   198  	if w.view == 0 {
   199  		return
   200  	}
   201  	var animi C.int
   202  	if anim {
   203  		animi = 1
   204  	}
   205  	C.gio_setAnimating(w.view, animi)
   206  }
   207  
   208  func (w *window) onKeyCommand(name string) {
   209  	w.w.Event(key.Event{
   210  		Name: name,
   211  	})
   212  }
   213  
   214  // lookupTouch maps an UITouch pointer value to an index. If
   215  // last is set, the map is cleared.
   216  func (w *window) lookupTouch(last bool, touch C.CFTypeRef) pointer.ID {
   217  	id := -1
   218  	for i, ref := range w.pointerMap {
   219  		if ref == touch {
   220  			id = i
   221  			break
   222  		}
   223  	}
   224  	if id == -1 {
   225  		id = len(w.pointerMap)
   226  		w.pointerMap = append(w.pointerMap, touch)
   227  	}
   228  	if last {
   229  		w.pointerMap = w.pointerMap[:0]
   230  	}
   231  	return pointer.ID(id)
   232  }
   233  
   234  func (w *window) contextLayer() uintptr {
   235  	return uintptr(w.layer)
   236  }
   237  
   238  func (w *window) isVisible() bool {
   239  	return w.visible.Load().(bool)
   240  }
   241  
   242  func (w *window) ShowTextInput(show bool) {
   243  	if w.view == 0 {
   244  		return
   245  	}
   246  	if show {
   247  		C.gio_showTextInput(w.view)
   248  	} else {
   249  		C.gio_hideTextInput(w.view)
   250  	}
   251  }
   252  
   253  func NewWindow(win Callbacks, opts *Options) error {
   254  	mainWindow.in <- windowAndOptions{win, opts}
   255  	return <-mainWindow.errs
   256  }
   257  
   258  func Main() {
   259  }