mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-05 00:12:45 +08:00
763 lines
22 KiB
Go
763 lines
22 KiB
Go
//go:build linux && !purego
|
|
|
|
package application
|
|
|
|
/*
|
|
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdk.h>
|
|
#include <webkit2/webkit2.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
|
|
|
|
// exported below
|
|
extern gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
|
|
extern void processRequest(void *request, gpointer user_data);
|
|
extern void onDragNDrop(
|
|
void *target,
|
|
GdkDragContext* context,
|
|
gint x,
|
|
gint y,
|
|
gpointer seldata,
|
|
guint info,
|
|
guint time,
|
|
gpointer data);
|
|
// exported below (end)
|
|
|
|
static void signal_connect(GtkWidget *widget, char *event, void *cb, void* data) {
|
|
// g_signal_connect is a macro and can't be called directly
|
|
g_signal_connect(widget, event, cb, data);
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/wailsapp/wails/v2/pkg/assetserver/webview"
|
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
)
|
|
|
|
var showDevTools = func(window unsafe.Pointer) {}
|
|
|
|
func gtkBool(input bool) C.gboolean {
|
|
if input {
|
|
return C.gboolean(1)
|
|
}
|
|
return C.gboolean(0)
|
|
}
|
|
|
|
type dragInfo struct {
|
|
XRoot int
|
|
YRoot int
|
|
DragTime int
|
|
MouseButton uint
|
|
}
|
|
|
|
type linuxWebviewWindow struct {
|
|
id uint
|
|
application unsafe.Pointer
|
|
window unsafe.Pointer
|
|
webview unsafe.Pointer
|
|
parent *WebviewWindow
|
|
menubar *C.GtkWidget
|
|
vbox *C.GtkWidget
|
|
menu *menu.Menu
|
|
accels *C.GtkAccelGroup
|
|
lastWidth int
|
|
lastHeight int
|
|
drag dragInfo
|
|
}
|
|
|
|
var (
|
|
registered bool = false // avoid 'already registered message' about 'wails://'
|
|
)
|
|
|
|
//export buttonEvent
|
|
func buttonEvent(_ *C.GtkWidget, event *C.GdkEventButton, data unsafe.Pointer) C.gboolean {
|
|
// Constants (defined here to be easier to use with )
|
|
GdkButtonPress := C.GDK_BUTTON_PRESS // 4
|
|
Gdk2ButtonPress := C.GDK_2BUTTON_PRESS // 5 for double-click
|
|
GdkButtonRelease := C.GDK_BUTTON_RELEASE // 7
|
|
|
|
windowId := uint(*((*C.uint)(data)))
|
|
window := globalApplication.getWindowForID(windowId)
|
|
if window == nil {
|
|
return C.gboolean(0)
|
|
}
|
|
lw, ok := (window.impl).(*linuxWebviewWindow)
|
|
if !ok {
|
|
return C.gboolean(0)
|
|
}
|
|
|
|
if event == nil {
|
|
return C.gboolean(0)
|
|
}
|
|
if event.button == 3 {
|
|
return C.gboolean(0)
|
|
}
|
|
|
|
switch int(event._type) {
|
|
case GdkButtonPress:
|
|
lw.startDrag(uint(event.button), int(event.x_root), int(event.y_root))
|
|
case Gdk2ButtonPress:
|
|
fmt.Printf("%d - button %d - double-clicked\n", windowId, int(event.button))
|
|
case GdkButtonRelease:
|
|
lw.endDrag(uint(event.button), int(event.x_root), int(event.y_root))
|
|
}
|
|
|
|
return C.gboolean(0)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) startDrag(button uint, x, y int) {
|
|
fmt.Println("startDrag ", button, x, y)
|
|
w.drag.XRoot = x
|
|
w.drag.YRoot = y
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) endDrag(button uint, x, y int) {
|
|
fmt.Println("endDrag", button, x, y)
|
|
}
|
|
|
|
//export onDragNDrop
|
|
func onDragNDrop(target unsafe.Pointer, context *C.GdkDragContext, x C.gint, y C.gint, seldata unsafe.Pointer, info C.guint, time C.guint, data unsafe.Pointer) {
|
|
fmt.Println("target", target, info)
|
|
var length C.gint
|
|
selection := unsafe.Pointer(C.gtk_selection_data_get_data_with_length((*C.GtkSelectionData)(seldata), &length))
|
|
extracted := C.g_uri_list_extract_uris((*C.char)(selection))
|
|
defer C.g_strfreev(extracted)
|
|
|
|
uris := unsafe.Slice(
|
|
(**C.char)(unsafe.Pointer(extracted)),
|
|
int(length))
|
|
|
|
var filenames []string
|
|
for _, uri := range uris {
|
|
if uri == nil {
|
|
break
|
|
}
|
|
filenames = append(filenames, strings.TrimPrefix(C.GoString(uri), "file://"))
|
|
}
|
|
windowDragAndDropBuffer <- &dragAndDropMessage{
|
|
windowId: uint(*((*C.uint)(data))),
|
|
filenames: filenames,
|
|
}
|
|
C.gtk_drag_finish(context, C.true, C.false, time)
|
|
}
|
|
|
|
//export processRequest
|
|
func processRequest(request unsafe.Pointer, data unsafe.Pointer) {
|
|
windowId := uint(*((*C.uint)(data)))
|
|
webviewRequests <- &webViewAssetRequest{
|
|
Request: webview.NewRequest(request),
|
|
windowId: windowId,
|
|
windowName: globalApplication.getWindowForID(windowId).Name(),
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) enableDND() {
|
|
dnd := C.CString("text/uri-list")
|
|
defer C.free(unsafe.Pointer(dnd))
|
|
targetentry := C.gtk_target_entry_new(dnd, 0, C.guint(w.parent.id))
|
|
defer C.gtk_target_entry_free(targetentry)
|
|
C.gtk_drag_dest_set((*C.GtkWidget)(w.webview), C.GTK_DEST_DEFAULT_DROP, targetentry, 1, C.GDK_ACTION_COPY)
|
|
event := C.CString("drag-data-received")
|
|
defer C.free(unsafe.Pointer(event))
|
|
id := C.uint(w.parent.id)
|
|
C.signal_connect((*C.GtkWidget)(unsafe.Pointer(w.webview)), event, C.onDragNDrop, unsafe.Pointer(C.gpointer(&id)))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) newWebview(gpuPolicy int) unsafe.Pointer {
|
|
manager := C.webkit_user_content_manager_new()
|
|
external := C.CString("external")
|
|
C.webkit_user_content_manager_register_script_message_handler(manager, external)
|
|
|
|
C.free(unsafe.Pointer(external))
|
|
webview := C.webkit_web_view_new_with_user_content_manager(manager)
|
|
id := C.uint(w.parent.id)
|
|
if !registered {
|
|
wails := C.CString("wails")
|
|
C.webkit_web_context_register_uri_scheme(
|
|
C.webkit_web_context_get_default(),
|
|
wails,
|
|
C.WebKitURISchemeRequestCallback(C.processRequest),
|
|
C.gpointer(&id),
|
|
nil)
|
|
registered = true
|
|
C.free(unsafe.Pointer(wails))
|
|
}
|
|
settings := C.webkit_web_view_get_settings((*C.WebKitWebView)(unsafe.Pointer(webview)))
|
|
wails_io := C.CString("wails.io")
|
|
empty := C.CString("")
|
|
defer C.free(unsafe.Pointer(wails_io))
|
|
defer C.free(unsafe.Pointer(empty))
|
|
C.webkit_settings_set_user_agent_with_application_details(settings, wails_io, empty)
|
|
|
|
switch gpuPolicy {
|
|
case 0:
|
|
C.webkit_settings_set_hardware_acceleration_policy(settings, C.WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS)
|
|
break
|
|
case 1:
|
|
C.webkit_settings_set_hardware_acceleration_policy(settings, C.WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND)
|
|
break
|
|
case 2:
|
|
C.webkit_settings_set_hardware_acceleration_policy(settings, C.WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER)
|
|
break
|
|
default:
|
|
C.webkit_settings_set_hardware_acceleration_policy(settings, C.WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND)
|
|
}
|
|
return unsafe.Pointer(webview)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) connectSignals() {
|
|
event := C.CString("delete-event")
|
|
defer C.free(unsafe.Pointer(event))
|
|
|
|
// Window close handler
|
|
|
|
if w.parent.options.HideOnClose {
|
|
C.signal_connect((*C.GtkWidget)(w.window), event, C.gtk_widget_hide_on_delete, C.NULL)
|
|
} else {
|
|
|
|
// C.signal_connect((*C.GtkWidget)(window), event, C.close_button_pressed, w.parent.id)
|
|
}
|
|
/*
|
|
event = C.CString("load-changed")
|
|
defer C.free(unsafe.Pointer(event))
|
|
C.signal_connect(webview, event, C.webviewLoadChanged, unsafe.Pointer(&w.parent.id))
|
|
*/
|
|
id := C.uint(w.parent.id)
|
|
event = C.CString("button-press-event")
|
|
C.signal_connect((*C.GtkWidget)(unsafe.Pointer(w.webview)), event, C.buttonEvent, unsafe.Pointer(&id))
|
|
C.free(unsafe.Pointer(event))
|
|
event = C.CString("button-release-event")
|
|
defer C.free(unsafe.Pointer(event))
|
|
C.signal_connect((*C.GtkWidget)(unsafe.Pointer(w.webview)), event, C.buttonEvent, unsafe.Pointer(&id))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData) {
|
|
// Create the menu
|
|
thisMenu := newMenuImpl(menu)
|
|
thisMenu.update()
|
|
fmt.Println("linux.openContextMenu()")
|
|
/* void
|
|
gtk_menu_popup_at_rect (
|
|
GtkMenu* menu,
|
|
GdkWindow* rect_window,
|
|
const GdkRectangle* rect,
|
|
GdkGravity rect_anchor,
|
|
GdkGravity menu_anchor,
|
|
const GdkEvent* trigger_event
|
|
)
|
|
*/
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) getZoom() float64 {
|
|
return float64(C.webkit_web_view_get_zoom_level((*C.WebKitWebView)(w.webview)))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setZoom(zoom float64) {
|
|
C.webkit_web_view_set_zoom_level((*C.WebKitWebView)(w.webview), C.double(zoom))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setFrameless(frameless bool) {
|
|
if frameless {
|
|
C.gtk_window_set_decorated((*C.GtkWindow)(w.window), C.gboolean(0))
|
|
} else {
|
|
C.gtk_window_set_decorated((*C.GtkWindow)(w.window), C.gboolean(1))
|
|
// TODO: Deal with transparency for the titlebar if possible
|
|
// Perhaps we just make it undecorated and add a menu bar inside?
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) getScreen() (*Screen, error) {
|
|
mx, my, width, height, scale := w.getCurrentMonitorGeometry()
|
|
return &Screen{
|
|
ID: fmt.Sprintf("%d", w.id), // A unique identifier for the display
|
|
Name: w.parent.Name(), // The name of the display
|
|
Scale: float32(scale), // The scale factor of the display
|
|
X: mx, // The x-coordinate of the top-left corner of the rectangle
|
|
Y: my, // The y-coordinate of the top-left corner of the rectangle
|
|
Size: Size{Width: width, Height: height}, // The size of the display
|
|
Bounds: Rect{}, // The bounds of the display
|
|
WorkArea: Rect{}, // The work area of the display
|
|
IsPrimary: false, // Whether this is the primary display
|
|
Rotation: 0.0, // The rotation of the display
|
|
}, nil
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) show() {
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
C.gtk_widget_show_all((*C.GtkWidget)(w.window))
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) hide() {
|
|
C.gtk_widget_hide((*C.GtkWidget)(w.window))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) isNormal() bool {
|
|
return !w.isMinimised() && !w.isMaximised() && !w.isFullscreen()
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) isVisible() bool {
|
|
if C.gtk_widget_is_visible((*C.GtkWidget)(w.window)) == 1 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setFullscreenButtonEnabled(enabled bool) {
|
|
// C.setFullscreenButtonEnabled(w.nsWindow, C.bool(enabled))
|
|
fmt.Println("setFullscreenButtonEnabled - not implemented")
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) disableSizeConstraints() {
|
|
x, y, width, height, scale := w.getCurrentMonitorGeometry()
|
|
w.setMinMaxSize(x, y, width*scale, height*scale)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) unfullscreen() {
|
|
C.gtk_window_unfullscreen((*C.GtkWindow)(w.window))
|
|
w.unmaximise()
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) fullscreen() {
|
|
w.maximise()
|
|
w.lastWidth, w.lastHeight = w.size()
|
|
x, y, width, height, scale := w.getCurrentMonitorGeometry()
|
|
if x == -1 && y == -1 && width == -1 && height == -1 {
|
|
return
|
|
}
|
|
w.setMinMaxSize(0, 0, width*scale, height*scale)
|
|
w.setSize(width*scale, height*scale)
|
|
C.gtk_window_fullscreen((*C.GtkWindow)(w.window))
|
|
w.setPosition(0, 0)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) unminimise() {
|
|
C.gtk_window_present((*C.GtkWindow)(w.window))
|
|
// gtk_window_unminimize ((*C.GtkWindow)(w.window)) /// gtk4
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) unmaximise() {
|
|
C.gtk_window_unmaximize((*C.GtkWindow)(w.window))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) maximise() {
|
|
C.gtk_window_maximize((*C.GtkWindow)(w.window))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) minimise() {
|
|
C.gtk_window_iconify((*C.GtkWindow)(w.window))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) on(eventID uint) {
|
|
// Don't think this is correct!
|
|
// GTK Events are strings
|
|
fmt.Println("on()", eventID)
|
|
//C.registerListener(C.uint(eventID))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) zoom() {
|
|
w.zoomIn()
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) windowZoom() {
|
|
w.zoom() // FIXME> This should be removed
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) close() {
|
|
C.gtk_window_close((*C.GtkWindow)(w.window))
|
|
if !w.parent.options.HideOnClose {
|
|
globalApplication.deleteWindowByID(w.parent.id)
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) zoomIn() {
|
|
lvl := C.webkit_web_view_get_zoom_level((*C.WebKitWebView)(w.webview))
|
|
C.webkit_web_view_set_zoom_level((*C.WebKitWebView)(w.webview), lvl+0.5)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) zoomOut() {
|
|
lvl := C.webkit_web_view_get_zoom_level((*C.WebKitWebView)(w.webview))
|
|
C.webkit_web_view_set_zoom_level((*C.WebKitWebView)(w.webview), lvl-0.5)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) zoomReset() {
|
|
C.webkit_web_view_set_zoom_level((*C.WebKitWebView)(w.webview), 0.0)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) reload() {
|
|
// TODO: This should be a constant somewhere I feel
|
|
uri := C.CString("wails://")
|
|
C.webkit_web_view_load_uri((*C.WebKitWebView)(w.window), uri)
|
|
C.free(unsafe.Pointer(uri))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) forceReload() {
|
|
w.reload()
|
|
}
|
|
|
|
func (w linuxWebviewWindow) getCurrentMonitor() *C.GdkMonitor {
|
|
// Get the monitor that the window is currently on
|
|
display := C.gtk_widget_get_display((*C.GtkWidget)(w.window))
|
|
gdk_window := C.gtk_widget_get_window((*C.GtkWidget)(w.window))
|
|
if gdk_window == nil {
|
|
return nil
|
|
}
|
|
return C.gdk_display_get_monitor_at_window(display, gdk_window)
|
|
}
|
|
|
|
func (w linuxWebviewWindow) getCurrentMonitorGeometry() (x int, y int, width int, height int, scale int) {
|
|
monitor := w.getCurrentMonitor()
|
|
if monitor == nil {
|
|
return -1, -1, -1, -1, 1
|
|
}
|
|
var result C.GdkRectangle
|
|
C.gdk_monitor_get_geometry(monitor, &result)
|
|
scale = int(C.gdk_monitor_get_scale_factor(monitor))
|
|
return int(result.x), int(result.y), int(result.width), int(result.height), scale
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) center() {
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
x, y, width, height, _ := w.getCurrentMonitorGeometry()
|
|
if x == -1 && y == -1 && width == -1 && height == -1 {
|
|
return
|
|
}
|
|
|
|
var windowWidth C.int
|
|
var windowHeight C.int
|
|
C.gtk_window_get_size((*C.GtkWindow)(w.window), &windowWidth, &windowHeight)
|
|
|
|
newX := C.int(((width - int(windowWidth)) / 2) + x)
|
|
newY := C.int(((height - int(windowHeight)) / 2) + y)
|
|
|
|
// Place the window at the center of the monitor
|
|
C.gtk_window_move((*C.GtkWindow)(w.window), newX, newY)
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) isMinimised() bool {
|
|
gdkwindow := C.gtk_widget_get_window((*C.GtkWidget)(w.window))
|
|
state := C.gdk_window_get_state(gdkwindow)
|
|
return state&C.GDK_WINDOW_STATE_ICONIFIED > 0
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) isMaximised() bool {
|
|
return w.syncMainThreadReturningBool(func() bool {
|
|
gdkwindow := C.gtk_widget_get_window((*C.GtkWidget)(w.window))
|
|
state := C.gdk_window_get_state(gdkwindow)
|
|
return state&C.GDK_WINDOW_STATE_MAXIMIZED > 0 && state&C.GDK_WINDOW_STATE_FULLSCREEN == 0
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) isFullscreen() bool {
|
|
return w.syncMainThreadReturningBool(func() bool {
|
|
gdkwindow := C.gtk_widget_get_window((*C.GtkWidget)(w.window))
|
|
state := C.gdk_window_get_state(gdkwindow)
|
|
return state&C.GDK_WINDOW_STATE_FULLSCREEN > 0
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) syncMainThreadReturningBool(fn func() bool) bool {
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
var result bool
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
result = fn()
|
|
wg.Done()
|
|
})
|
|
wg.Wait()
|
|
return result
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) restore() {
|
|
// restore window to normal size
|
|
// FIXME: never called! - remove from webviewImpl interface
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) execJS(js string) {
|
|
value := C.CString(js)
|
|
C.webkit_web_view_evaluate_javascript((*C.WebKitWebView)(w.webview),
|
|
value,
|
|
C.long(len(js)),
|
|
nil,
|
|
C.CString(""),
|
|
nil,
|
|
nil,
|
|
nil)
|
|
C.free(unsafe.Pointer(value))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setURL(uri string) {
|
|
if uri != "" {
|
|
url, err := url.Parse(uri)
|
|
if err == nil && url.Scheme == "" && url.Host == "" {
|
|
// TODO handle this in a central location, the scheme and host might be platform dependant.
|
|
url.Scheme = "wails"
|
|
url.Host = "wails"
|
|
uri = url.String()
|
|
}
|
|
}
|
|
target := C.CString(uri)
|
|
C.webkit_web_view_load_uri((*C.WebKitWebView)(w.webview), target)
|
|
C.free(unsafe.Pointer(target))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) {
|
|
C.gtk_window_set_keep_above((*C.GtkWindow)(w.window), gtkBool(alwaysOnTop))
|
|
}
|
|
|
|
func newWindowImpl(parent *WebviewWindow) *linuxWebviewWindow {
|
|
// (*C.struct__GtkWidget)(m.native)
|
|
//var menubar *C.struct__GtkWidget
|
|
return &linuxWebviewWindow{
|
|
application: getNativeApplication(),
|
|
parent: parent,
|
|
// menubar: menubar,
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setTitle(title string) {
|
|
if !w.parent.options.Frameless {
|
|
cTitle := C.CString(title)
|
|
C.gtk_window_set_title((*C.GtkWindow)(w.window), cTitle)
|
|
C.free(unsafe.Pointer(cTitle))
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setSize(width, height int) {
|
|
C.gtk_window_resize((*C.GtkWindow)(w.window), C.gint(width), C.gint(height))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setMinMaxSize(minWidth, minHeight, maxWidth, maxHeight int) {
|
|
fmt.Println("setMinMaxSize", minWidth, minHeight, maxWidth, maxHeight)
|
|
if minWidth == 0 {
|
|
minWidth = -1
|
|
}
|
|
if minHeight == 0 {
|
|
minHeight = -1
|
|
}
|
|
if maxWidth == 0 {
|
|
maxWidth = -1
|
|
}
|
|
if maxHeight == 0 {
|
|
maxHeight = -1
|
|
}
|
|
size := C.GdkGeometry{
|
|
min_width: C.int(minWidth),
|
|
min_height: C.int(minHeight),
|
|
max_width: C.int(maxWidth),
|
|
max_height: C.int(maxHeight),
|
|
}
|
|
C.gtk_window_set_geometry_hints((*C.GtkWindow)(w.window), nil, &size, C.GDK_HINT_MAX_SIZE|C.GDK_HINT_MIN_SIZE)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setMinSize(width, height int) {
|
|
w.setMinMaxSize(width, height, w.parent.options.MaxWidth, w.parent.options.MaxHeight)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setMaxSize(width, height int) {
|
|
w.setMinMaxSize(w.parent.options.MinWidth, w.parent.options.MinHeight, width, height)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setResizable(resizable bool) {
|
|
if resizable {
|
|
C.gtk_window_set_resizable((*C.GtkWindow)(w.window), 1)
|
|
} else {
|
|
C.gtk_window_set_resizable((*C.GtkWindow)(w.window), 0)
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) toggleDevTools() {
|
|
settings := C.webkit_web_view_get_settings((*C.WebKitWebView)(w.webview))
|
|
enabled := C.webkit_settings_get_enable_developer_extras(settings)
|
|
if enabled == C.int(0) {
|
|
enabled = C.int(1)
|
|
} else {
|
|
enabled = C.int(0)
|
|
}
|
|
C.webkit_settings_set_enable_developer_extras(settings, enabled)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) size() (int, int) {
|
|
var width, height C.int
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
C.gtk_window_get_size((*C.GtkWindow)(w.window), &width, &height)
|
|
wg.Done()
|
|
})
|
|
wg.Wait()
|
|
return int(width), int(height)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setPosition(x, y int) {
|
|
mx, my, _, _, _ := w.getCurrentMonitorGeometry()
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
C.gtk_window_move((*C.GtkWindow)(w.window), C.int(x+mx), C.int(y+my))
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) width() int {
|
|
width, _ := w.size()
|
|
return width
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) height() int {
|
|
_, height := w.size()
|
|
return height
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) run() {
|
|
for eventId := range w.parent.eventListeners {
|
|
w.on(eventId)
|
|
}
|
|
|
|
app := getNativeApplication()
|
|
menu := app.applicationMenu
|
|
|
|
globalApplication.dispatchOnMainThread(func() {
|
|
w.window = unsafe.Pointer(C.gtk_application_window_new((*C.GtkApplication)(w.application)))
|
|
app.registerWindow((*C.GtkWindow)(w.window), w.parent.id) // record our mapping
|
|
C.g_object_ref_sink(C.gpointer(w.window))
|
|
w.webview = w.newWebview(1)
|
|
w.connectSignals()
|
|
if w.parent.options.EnableDragAndDrop {
|
|
w.enableDND()
|
|
}
|
|
w.vbox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0)
|
|
C.gtk_container_add((*C.GtkContainer)(w.window), w.vbox)
|
|
if menu != nil {
|
|
C.gtk_box_pack_start((*C.GtkBox)(unsafe.Pointer(w.vbox)), (*C.GtkWidget)(menu), 0, 0, 0)
|
|
}
|
|
C.gtk_box_pack_start((*C.GtkBox)(unsafe.Pointer(w.vbox)), (*C.GtkWidget)(w.webview), 1, 1, 0)
|
|
|
|
w.setTitle(w.parent.options.Title)
|
|
w.setAlwaysOnTop(w.parent.options.AlwaysOnTop)
|
|
w.setResizable(!w.parent.options.DisableResize)
|
|
// only set min/max size if actually set
|
|
if w.parent.options.MinWidth != 0 &&
|
|
w.parent.options.MinHeight != 0 &&
|
|
w.parent.options.MaxWidth != 0 &&
|
|
w.parent.options.MaxHeight != 0 {
|
|
w.setMinMaxSize(
|
|
w.parent.options.MinWidth,
|
|
w.parent.options.MinHeight,
|
|
w.parent.options.MaxWidth,
|
|
w.parent.options.MaxHeight,
|
|
)
|
|
}
|
|
w.setSize(w.parent.options.Width, w.parent.options.Height)
|
|
w.setZoom(w.parent.options.Zoom)
|
|
w.setBackgroundColour(w.parent.options.BackgroundColour)
|
|
w.setFrameless(w.parent.options.Frameless)
|
|
|
|
if w.parent.options.X != 0 || w.parent.options.Y != 0 {
|
|
w.setPosition(w.parent.options.X, w.parent.options.Y)
|
|
} else {
|
|
fmt.Println("attempting to set in the center")
|
|
w.center()
|
|
}
|
|
switch w.parent.options.StartState {
|
|
case WindowStateMaximised:
|
|
w.maximise()
|
|
case WindowStateMinimised:
|
|
w.minimise()
|
|
case WindowStateFullscreen:
|
|
w.fullscreen()
|
|
}
|
|
|
|
if w.parent.options.URL != "" {
|
|
w.setURL(w.parent.options.URL)
|
|
}
|
|
// We need to wait for the HTML to load before we can execute the javascript
|
|
// FIXME: What event is this? DomReady?
|
|
w.parent.On(events.Mac.WebViewDidFinishNavigation, func(_ *WindowEventContext) {
|
|
if w.parent.options.JS != "" {
|
|
w.execJS(w.parent.options.JS)
|
|
}
|
|
if w.parent.options.CSS != "" {
|
|
js := fmt.Sprintf("(function() { var style = document.createElement('style'); style.appendChild(document.createTextNode('%s')); document.head.appendChild(style); })();", w.parent.options.CSS)
|
|
fmt.Println(js)
|
|
w.execJS(js)
|
|
}
|
|
})
|
|
if w.parent.options.HTML != "" {
|
|
w.setHTML(w.parent.options.HTML)
|
|
}
|
|
if !w.parent.options.Hidden {
|
|
w.show()
|
|
if w.parent.options.X != 0 || w.parent.options.Y != 0 {
|
|
w.setPosition(w.parent.options.X, w.parent.options.Y)
|
|
} else {
|
|
fmt.Println("attempting to set in the center")
|
|
w.center()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setTransparent() {
|
|
screen := C.gtk_widget_get_screen((*C.GtkWidget)(w.window))
|
|
visual := C.gdk_screen_get_rgba_visual(screen)
|
|
|
|
if visual != nil && C.gdk_screen_is_composited(screen) == C.int(1) {
|
|
C.gtk_widget_set_app_paintable((*C.GtkWidget)(w.window), C.gboolean(1))
|
|
C.gtk_widget_set_visual((*C.GtkWidget)(w.window), visual)
|
|
}
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setBackgroundColour(colour RGBA) {
|
|
if colour.Alpha != 0 {
|
|
w.setTransparent()
|
|
}
|
|
rgba := C.GdkRGBA{C.double(colour.Red) / 255.0, C.double(colour.Green) / 255.0, C.double(colour.Blue) / 255.0, C.double(colour.Alpha) / 255.0}
|
|
fmt.Println(unsafe.Pointer(&rgba))
|
|
C.webkit_web_view_set_background_color((*C.WebKitWebView)(w.webview), &rgba)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) position() (int, int) {
|
|
var x, y C.int
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
go globalApplication.dispatchOnMainThread(func() {
|
|
C.gtk_window_get_position((*C.GtkWindow)(w.window), &x, &y)
|
|
wg.Done()
|
|
})
|
|
wg.Wait()
|
|
return int(x), int(y)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) destroy() {
|
|
C.gtk_window_close((*C.GtkWindow)(w.window))
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) setHTML(html string) {
|
|
cHTML := C.CString(html)
|
|
uri := C.CString("wails://")
|
|
empty := C.CString("")
|
|
defer C.free(unsafe.Pointer(cHTML))
|
|
defer C.free(unsafe.Pointer(uri))
|
|
defer C.free(unsafe.Pointer(empty))
|
|
C.webkit_web_view_load_alternate_html(
|
|
(*C.WebKitWebView)(w.webview),
|
|
cHTML,
|
|
uri,
|
|
empty)
|
|
}
|
|
|
|
func (w *linuxWebviewWindow) nativeWindowHandle() uintptr {
|
|
return uintptr(w.window)
|
|
}
|