mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-08 12:19:18 +08:00
[v3 linux/purego] initial file/directory dialogs impl
This commit is contained in:
parent
d52c26e82f
commit
e92858f64d
@ -54,52 +54,7 @@ func newOpenFileDialogImpl(d *OpenFileDialog) *linuxOpenFileDialog {
|
||||
}
|
||||
|
||||
func (m *linuxOpenFileDialog) show() ([]string, error) {
|
||||
openFileResponses[m.dialog.id] = make(chan string)
|
||||
// nsWindow := unsafe.Pointer(nil)
|
||||
if m.dialog.window != nil {
|
||||
// get NSWindow from window
|
||||
//nsWindow = m.dialog.window.impl.(*macosWebviewWindow).nsWindow
|
||||
}
|
||||
|
||||
// Massage filter patterns into macOS format
|
||||
// We iterate all filter patterns, tidy them up and then join them with a semicolon
|
||||
// This should produce a single string of extensions like "png;jpg;gif"
|
||||
// var filterPatterns string
|
||||
// if len(m.dialog.filters) > 0 {
|
||||
// var allPatterns []string
|
||||
// for _, filter := range m.dialog.filters {
|
||||
// patternComponents := strings.Split(filter.Pattern, ";")
|
||||
// for i, component := range patternComponents {
|
||||
// filterPattern := strings.TrimSpace(component)
|
||||
// filterPattern = strings.TrimPrefix(filterPattern, "*.")
|
||||
// patternComponents[i] = filterPattern
|
||||
// }
|
||||
// allPatterns = append(allPatterns, strings.Join(patternComponents, ";"))
|
||||
// }
|
||||
// filterPatterns = strings.Join(allPatterns, ";")
|
||||
// }
|
||||
|
||||
// C.showOpenFileDialog(C.uint(m.dialog.id),
|
||||
// C.bool(m.dialog.canChooseFiles),
|
||||
// C.bool(m.dialog.canChooseDirectories),
|
||||
// C.bool(m.dialog.canCreateDirectories),
|
||||
// C.bool(m.dialog.showHiddenFiles),
|
||||
// C.bool(m.dialog.allowsMultipleSelection),
|
||||
// C.bool(m.dialog.resolvesAliases),
|
||||
// C.bool(m.dialog.hideExtension),
|
||||
// C.bool(m.dialog.treatsFilePackagesAsDirectories),
|
||||
// C.bool(m.dialog.allowsOtherFileTypes),
|
||||
// toCString(filterPatterns),
|
||||
// C.uint(len(filterPatterns)),
|
||||
// toCString(m.dialog.message),
|
||||
// toCString(m.dialog.directory),
|
||||
// toCString(m.dialog.buttonText),
|
||||
// nsWindow)
|
||||
var result []string
|
||||
for filename := range openFileResponses[m.dialog.id] {
|
||||
result = append(result, filename)
|
||||
}
|
||||
return result, nil
|
||||
return runOpenFileDialog(m.dialog)
|
||||
}
|
||||
|
||||
type linuxSaveFileDialog struct {
|
||||
@ -113,24 +68,5 @@ func newSaveFileDialogImpl(d *SaveFileDialog) *linuxSaveFileDialog {
|
||||
}
|
||||
|
||||
func (m *linuxSaveFileDialog) show() (string, error) {
|
||||
saveFileResponses[m.dialog.id] = make(chan string)
|
||||
// nsWindow := unsafe.Pointer(nil)
|
||||
if m.dialog.window != nil {
|
||||
// get NSWindow from window
|
||||
// nsWindow = m.dialog.window.impl.(*linuxWebviewWindow).nsWindow
|
||||
}
|
||||
|
||||
// C.showSaveFileDialog(C.uint(m.dialog.id),
|
||||
// C.bool(m.dialog.canCreateDirectories),
|
||||
// C.bool(m.dialog.showHiddenFiles),
|
||||
// C.bool(m.dialog.canSelectHiddenExtension),
|
||||
// C.bool(m.dialog.hideExtension),
|
||||
// C.bool(m.dialog.treatsFilePackagesAsDirectories),
|
||||
// C.bool(m.dialog.allowOtherFileTypes),
|
||||
// toCString(m.dialog.message),
|
||||
// toCString(m.dialog.directory),
|
||||
// toCString(m.dialog.buttonText),
|
||||
// toCString(m.dialog.filename),
|
||||
// nsWindow)
|
||||
return <-saveFileResponses[m.dialog.id], nil
|
||||
return runSaveFileDialog(m.dialog)
|
||||
}
|
||||
|
@ -16,7 +16,13 @@ import (
|
||||
type windowPointer uintptr
|
||||
type identifier uint
|
||||
type pointer uintptr
|
||||
type GSList uintptr
|
||||
|
||||
// type GSList uintptr
|
||||
type GSList struct {
|
||||
data pointer
|
||||
next *GSList
|
||||
}
|
||||
|
||||
type GSListPointer *GSList
|
||||
|
||||
const (
|
||||
@ -93,6 +99,7 @@ var (
|
||||
gApplicationRun func(pointer, int, []string) int
|
||||
gBytesNewStatic func(uintptr, int) uintptr
|
||||
gBytesUnref func(uintptr)
|
||||
gFree func(pointer)
|
||||
gIdleAdd func(uintptr)
|
||||
gObjectRefSink func(pointer)
|
||||
gObjectUnref func(pointer)
|
||||
@ -116,63 +123,70 @@ var (
|
||||
gdkWindowGetDisplay func(pointer) pointer
|
||||
|
||||
// gtk functions
|
||||
gtkApplicationNew func(string, uint) pointer
|
||||
gtkApplicationGetActiveWindow func(pointer) pointer
|
||||
gtkApplicationGetWindows func(pointer) *GList
|
||||
gtkApplicationWindowNew func(pointer) pointer
|
||||
gtkBoxNew func(int, int) pointer
|
||||
gtkBoxPackStart func(pointer, pointer, int, int, int)
|
||||
gtkCheckMenuItemGetActive func(pointer) int
|
||||
gtkCheckMenuItemNewWithLabel func(string) pointer
|
||||
gtkCheckMenuItemSetActive func(pointer, int)
|
||||
gtkContainerAdd func(pointer, pointer)
|
||||
gtkDialogAddButton func(pointer, string, int)
|
||||
gtkDialogGetContentArea func(pointer) pointer
|
||||
gtkDialogRun func(pointer) int
|
||||
gtkDialogSetDefaultResponse func(pointer, int)
|
||||
gtkDragDestSet func(pointer, uint, pointer, uint, uint)
|
||||
gtkImageNewFromPixbuf func(pointer) pointer
|
||||
gtkMenuBarNew func() pointer
|
||||
gtkMenuItemNewWithLabel func(string) pointer
|
||||
gtkMenuItemSetLabel func(pointer, string)
|
||||
gtkMenuItemSetSubmenu func(pointer, pointer)
|
||||
gtkMenuNew func() pointer
|
||||
gtkMenuShellAppend func(pointer, pointer)
|
||||
gtkMessageDialogNew func(pointer, int, int, int, string) pointer
|
||||
gtkRadioMenuItemGetGroup func(pointer) GSListPointer
|
||||
gtkRadioMenuItemNewWithLabel func(GSListPointer, string) pointer
|
||||
gtkSeparatorMenuItemNew func() pointer
|
||||
gtkTargetEntryFree func(pointer)
|
||||
gtkTargetEntryNew func(string, int, uint) pointer
|
||||
gtkWidgetDestroy func(pointer)
|
||||
gtkWidgetGetDisplay func(pointer) pointer
|
||||
gtkWidgetGetWindow func(pointer) pointer
|
||||
gtkWidgetGetScreen func(pointer) pointer
|
||||
gtkWidgetHide func(pointer)
|
||||
gtkWidgetIsVisible func(pointer) bool
|
||||
gtkWidgetShow func(pointer)
|
||||
gtkWidgetShowAll func(pointer)
|
||||
gtkWidgetSetAppPaintable func(pointer, int)
|
||||
gtkWidgetSetSensitive func(pointer, int)
|
||||
gtkWidgetSetToolTipText func(pointer, string)
|
||||
gtkWidgetSetVisual func(pointer, pointer)
|
||||
gtkWindowClose func(pointer)
|
||||
gtkWindowFullScreen func(pointer)
|
||||
gtkWindowGetPosition func(pointer, *int, *int) bool
|
||||
gtkWindowGetSize func(pointer, *int, *int)
|
||||
gtkWindowKeepAbove func(pointer, bool)
|
||||
gtkWindowMaximize func(pointer)
|
||||
gtkWindowMinimize func(pointer)
|
||||
gtkWindowMove func(pointer, int, int)
|
||||
gtkWindowPresent func(pointer)
|
||||
gtkWindowResize func(pointer, int, int)
|
||||
gtkWindowSetDecorated func(pointer, int)
|
||||
gtkWindowSetGeometryHints func(pointer, pointer, pointer, int)
|
||||
gtkWindowSetKeepAbove func(pointer, bool)
|
||||
gtkWindowSetResizable func(pointer, bool)
|
||||
gtkWindowSetTitle func(pointer, string)
|
||||
gtkWindowUnfullscreen func(pointer)
|
||||
gtkWindowUnmaximize func(pointer)
|
||||
gtkApplicationNew func(string, uint) pointer
|
||||
gtkApplicationGetActiveWindow func(pointer) pointer
|
||||
gtkApplicationGetWindows func(pointer) *GList
|
||||
gtkApplicationWindowNew func(pointer) pointer
|
||||
gtkBoxNew func(int, int) pointer
|
||||
gtkBoxPackStart func(pointer, pointer, int, int, int)
|
||||
gtkCheckMenuItemGetActive func(pointer) int
|
||||
gtkCheckMenuItemNewWithLabel func(string) pointer
|
||||
gtkCheckMenuItemSetActive func(pointer, int)
|
||||
gtkContainerAdd func(pointer, pointer)
|
||||
gtkDialogAddButton func(pointer, string, int)
|
||||
gtkDialogGetContentArea func(pointer) pointer
|
||||
gtkDialogRun func(pointer) int
|
||||
gtkDialogSetDefaultResponse func(pointer, int)
|
||||
gtkDragDestSet func(pointer, uint, pointer, uint, uint)
|
||||
gtkFileChooserDialogNew func(string, pointer, int, string, int, string, int, pointer) pointer
|
||||
gtkFileChooserGetFilenames func(pointer) *GSList
|
||||
gtkFileChooserSetCreateFolders func(pointer, int)
|
||||
gtkFileChooserSetCurrentFolder func(pointer, string)
|
||||
gtkFileChooserSetSelectMultiple func(pointer, int)
|
||||
gtkFileChooserSetShowHidden func(pointer, int)
|
||||
|
||||
gtkImageNewFromPixbuf func(pointer) pointer
|
||||
gtkMenuBarNew func() pointer
|
||||
gtkMenuItemNewWithLabel func(string) pointer
|
||||
gtkMenuItemSetLabel func(pointer, string)
|
||||
gtkMenuItemSetSubmenu func(pointer, pointer)
|
||||
gtkMenuNew func() pointer
|
||||
gtkMenuShellAppend func(pointer, pointer)
|
||||
gtkMessageDialogNew func(pointer, int, int, int, string) pointer
|
||||
gtkRadioMenuItemGetGroup func(pointer) GSListPointer
|
||||
gtkRadioMenuItemNewWithLabel func(GSListPointer, string) pointer
|
||||
gtkSeparatorMenuItemNew func() pointer
|
||||
gtkTargetEntryFree func(pointer)
|
||||
gtkTargetEntryNew func(string, int, uint) pointer
|
||||
gtkWidgetDestroy func(pointer)
|
||||
gtkWidgetGetDisplay func(pointer) pointer
|
||||
gtkWidgetGetWindow func(pointer) pointer
|
||||
gtkWidgetGetScreen func(pointer) pointer
|
||||
gtkWidgetHide func(pointer)
|
||||
gtkWidgetIsVisible func(pointer) bool
|
||||
gtkWidgetShow func(pointer)
|
||||
gtkWidgetShowAll func(pointer)
|
||||
gtkWidgetSetAppPaintable func(pointer, int)
|
||||
gtkWidgetSetSensitive func(pointer, int)
|
||||
gtkWidgetSetToolTipText func(pointer, string)
|
||||
gtkWidgetSetVisual func(pointer, pointer)
|
||||
gtkWindowClose func(pointer)
|
||||
gtkWindowFullScreen func(pointer)
|
||||
gtkWindowGetPosition func(pointer, *int, *int) bool
|
||||
gtkWindowGetSize func(pointer, *int, *int)
|
||||
gtkWindowKeepAbove func(pointer, bool)
|
||||
gtkWindowMaximize func(pointer)
|
||||
gtkWindowMinimize func(pointer)
|
||||
gtkWindowMove func(pointer, int, int)
|
||||
gtkWindowPresent func(pointer)
|
||||
gtkWindowResize func(pointer, int, int)
|
||||
gtkWindowSetDecorated func(pointer, int)
|
||||
gtkWindowSetGeometryHints func(pointer, pointer, pointer, int)
|
||||
gtkWindowSetKeepAbove func(pointer, bool)
|
||||
gtkWindowSetResizable func(pointer, bool)
|
||||
gtkWindowSetTitle func(pointer, string)
|
||||
gtkWindowUnfullscreen func(pointer)
|
||||
gtkWindowUnmaximize func(pointer)
|
||||
|
||||
// webkit
|
||||
webkitNewWithUserContentManager func(pointer) pointer
|
||||
@ -227,6 +241,7 @@ func init() {
|
||||
purego.RegisterLibFunc(&gApplicationRun, gtk, "g_application_run")
|
||||
purego.RegisterLibFunc(&gBytesNewStatic, gtk, "g_bytes_new_static")
|
||||
purego.RegisterLibFunc(&gBytesUnref, gtk, "g_bytes_unref")
|
||||
purego.RegisterLibFunc(&gFree, gtk, "g_free")
|
||||
purego.RegisterLibFunc(&gIdleAdd, gtk, "g_idle_add")
|
||||
purego.RegisterLibFunc(&gObjectRefSink, gtk, "g_object_ref_sink")
|
||||
purego.RegisterLibFunc(&gObjectUnref, gtk, "g_object_unref")
|
||||
@ -265,6 +280,12 @@ func init() {
|
||||
purego.RegisterLibFunc(>kDialogRun, gtk, "gtk_dialog_run")
|
||||
purego.RegisterLibFunc(>kDialogSetDefaultResponse, gtk, "gtk_dialog_set_default_response")
|
||||
purego.RegisterLibFunc(>kDragDestSet, gtk, "gtk_drag_dest_set")
|
||||
purego.RegisterLibFunc(>kFileChooserDialogNew, gtk, "gtk_file_chooser_dialog_new")
|
||||
purego.RegisterLibFunc(>kFileChooserGetFilenames, gtk, "gtk_file_chooser_get_filenames")
|
||||
purego.RegisterLibFunc(>kFileChooserSetCreateFolders, gtk, "gtk_file_chooser_set_create_folders")
|
||||
purego.RegisterLibFunc(>kFileChooserSetCurrentFolder, gtk, "gtk_file_chooser_set_current_folder")
|
||||
purego.RegisterLibFunc(>kFileChooserSetSelectMultiple, gtk, "gtk_file_chooser_set_select_multiple")
|
||||
purego.RegisterLibFunc(>kFileChooserSetShowHidden, gtk, "gtk_file_chooser_set_show_hidden")
|
||||
purego.RegisterLibFunc(>kImageNewFromPixbuf, gtk, "gtk_image_new_from_pixbuf")
|
||||
purego.RegisterLibFunc(>kMenuItemSetLabel, gtk, "gtk_menu_item_set_label")
|
||||
purego.RegisterLibFunc(>kMenuBarNew, gtk, "gtk_menu_bar_new")
|
||||
@ -919,79 +940,103 @@ func windowMove(window pointer, x, y int) {
|
||||
gtkWindowMove(window, x, y)
|
||||
}
|
||||
|
||||
/*
|
||||
func onButtonEvent(_ pointer, 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
|
||||
func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden bool, currentFolder, title string, action int, acceptLabel string, filters []FileFilter) ([]string, error) {
|
||||
GtkResponseCancel := 0
|
||||
GtkResponseAccept := 1
|
||||
|
||||
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)
|
||||
fc := gtkFileChooserDialogNew(
|
||||
title,
|
||||
window,
|
||||
action,
|
||||
"_Cancel",
|
||||
GtkResponseCancel,
|
||||
acceptLabel,
|
||||
GtkResponseAccept,
|
||||
0)
|
||||
|
||||
for _, filter := range filters {
|
||||
// TODO: Process and add filters
|
||||
// gtk_file_chooser_add_filter(fc, thisFilter)
|
||||
fmt.Println("filter", filter)
|
||||
}
|
||||
|
||||
if event == nil {
|
||||
return C.gboolean(0)
|
||||
}
|
||||
if event.button == 3 {
|
||||
return C.gboolean(0)
|
||||
if allowMultiple {
|
||||
gtkFileChooserSetSelectMultiple(fc, 1)
|
||||
}
|
||||
|
||||
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))
|
||||
if createFolders {
|
||||
gtkFileChooserSetCreateFolders(fc, 1)
|
||||
}
|
||||
|
||||
return C.gboolean(0)
|
||||
}
|
||||
if showHidden {
|
||||
gtkFileChooserSetShowHidden(fc, 1)
|
||||
}
|
||||
|
||||
if currentFolder != "" {
|
||||
gtkFileChooserSetCurrentFolder(fc, currentFolder)
|
||||
}
|
||||
|
||||
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
|
||||
buildStringAndFree := func(s pointer) string {
|
||||
bytes := []byte{}
|
||||
p := unsafe.Pointer(s)
|
||||
for {
|
||||
val := *(*byte)(p)
|
||||
if val == 0 { // this is the null terminator
|
||||
break
|
||||
}
|
||||
bytes = append(bytes, val)
|
||||
p = unsafe.Add(p, 1)
|
||||
}
|
||||
filenames = append(filenames, strings.TrimPrefix(C.GoString(uri), "file://"))
|
||||
gFree(s) // so we don't have to iterate a second time
|
||||
return string(bytes)
|
||||
}
|
||||
windowDragAndDropBuffer <- &dragAndDropMessage{
|
||||
windowId: uint(*((*C.uint)(data))),
|
||||
filenames: filenames,
|
||||
|
||||
response := gtkDialogRun(fc)
|
||||
selections := []string{}
|
||||
if response == GtkResponseAccept {
|
||||
filenames := gtkFileChooserGetFilenames(fc)
|
||||
iter := filenames
|
||||
count := 0
|
||||
for {
|
||||
selection := buildStringAndFree(iter.data)
|
||||
selections = append(selections, selection)
|
||||
iter = iter.next
|
||||
if iter == nil || count == 1024 {
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
C.gtk_drag_finish(context, C.true, C.false, time)
|
||||
defer gtkWidgetDestroy(fc)
|
||||
return selections, nil
|
||||
}
|
||||
|
||||
func onProcessRequest(request unsafe.Pointer, data unsafe.Pointer) {
|
||||
windowId := uint(*((*C.uint)(data)))
|
||||
webviewRequests <- &webViewAssetRequest{
|
||||
Request: webview.NewRequest(request),
|
||||
windowId: windowId,
|
||||
windowName: globalApplication.getWindowForID(windowId).Name(),
|
||||
}
|
||||
}
|
||||
*/
|
||||
// dialog related
|
||||
func runOpenFileDialog(dialog *OpenFileDialog) ([]string, error) {
|
||||
GtkFileChooserActionOpen := 0
|
||||
// GtkFileChooserActionSave := 1
|
||||
// GtkFileChooserActionSelectFolder := 2
|
||||
// GtkFileChooserActionCreateFolder := 3
|
||||
|
||||
// (dialog.window.impl).(*linuxWebviewWindow).window // FIXME: dialog.window == nil!
|
||||
window := pointer(0)
|
||||
buttonText := dialog.buttonText
|
||||
if buttonText == "" {
|
||||
buttonText = "_Open"
|
||||
}
|
||||
|
||||
return runChooserDialog(
|
||||
window,
|
||||
dialog.allowsMultipleSelection,
|
||||
dialog.canCreateDirectories,
|
||||
dialog.showHiddenFiles,
|
||||
dialog.directory,
|
||||
dialog.title,
|
||||
GtkFileChooserActionOpen,
|
||||
buttonText,
|
||||
dialog.filters)
|
||||
}
|
||||
|
||||
// dialog reloated
|
||||
func runQuestionDialog(parent pointer, options *MessageDialog) int {
|
||||
dType, ok := map[DialogType]int{
|
||||
InfoDialog: GtkMessageInfo,
|
||||
@ -1052,3 +1097,30 @@ func runQuestionDialog(parent pointer, options *MessageDialog) int {
|
||||
defer gtkWidgetDestroy(dialog)
|
||||
return gtkDialogRun(dialog)
|
||||
}
|
||||
|
||||
func runSaveFileDialog(dialog *SaveFileDialog) (string, error) {
|
||||
GtkFileChooserActionSave := 1
|
||||
// GtkFileChooserActionSelectFolder := 2
|
||||
// GtkFileChooserActionCreateFolder := 3
|
||||
window := pointer(0)
|
||||
buttonText := dialog.buttonText
|
||||
if buttonText == "" {
|
||||
buttonText = "_Save"
|
||||
}
|
||||
results, err := runChooserDialog(
|
||||
window,
|
||||
false, // multiple selection
|
||||
dialog.canCreateDirectories,
|
||||
dialog.showHiddenFiles,
|
||||
dialog.directory,
|
||||
dialog.title,
|
||||
GtkFileChooserActionSave,
|
||||
buttonText,
|
||||
dialog.filters)
|
||||
|
||||
if err != nil || len(results) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return results[0], nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user