mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
gtk drop refactored using events.
This commit is contained in:
parent
253247f6ce
commit
a96b770052
53
internal/desktop/drop.go
Normal file
53
internal/desktop/drop.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package desktop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"demodesk/neko/internal/desktop/drop"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DROP_DELAY = 100 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
|
func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
drop.Emmiter.Clear()
|
||||||
|
|
||||||
|
drop.Emmiter.Once("create", func(payload ...interface{}) {
|
||||||
|
manager.Move(0, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
drop.Emmiter.Once("cursor-enter", func(payload ...interface{}) {
|
||||||
|
manager.ButtonDown(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
drop.Emmiter.Once("button-press", func(payload ...interface{}) {
|
||||||
|
manager.Move(x, y)
|
||||||
|
})
|
||||||
|
|
||||||
|
drop.Emmiter.Once("begin", func(payload ...interface{}) {
|
||||||
|
manager.Move(x, y)
|
||||||
|
time.Sleep(DROP_DELAY)
|
||||||
|
manager.Move(x, y)
|
||||||
|
time.Sleep(DROP_DELAY)
|
||||||
|
manager.ButtonUp(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
finished := make(chan bool)
|
||||||
|
drop.Emmiter.Once("finish", func(payload ...interface{}) {
|
||||||
|
finished <- payload[0].(bool)
|
||||||
|
})
|
||||||
|
|
||||||
|
go drop.OpenWindow(files)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case succeeded := <- finished:
|
||||||
|
return succeeded
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
drop.CloseWindow();
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
93
internal/desktop/drop/drop.c
Normal file
93
internal/desktop/drop/drop.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "drop.h"
|
||||||
|
|
||||||
|
GtkWidget *drag_widget = NULL;
|
||||||
|
|
||||||
|
static void dragDataGet(
|
||||||
|
GtkWidget *widget,
|
||||||
|
GdkDragContext *context,
|
||||||
|
GtkSelectionData *data,
|
||||||
|
guint target_type,
|
||||||
|
guint time,
|
||||||
|
gpointer user_data
|
||||||
|
) {
|
||||||
|
gchar **uris = (gchar **) user_data;
|
||||||
|
|
||||||
|
if (target_type == DRAG_TARGET_TYPE_URI) {
|
||||||
|
gtk_selection_data_set_uris(data, uris);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_type == DRAG_TARGET_TYPE_TEXT) {
|
||||||
|
gtk_selection_data_set_text(data, uris[0], -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dragEnd(
|
||||||
|
GtkWidget *widget,
|
||||||
|
GdkDragContext *context,
|
||||||
|
gpointer user_data
|
||||||
|
) {
|
||||||
|
gboolean succeeded = gdk_drag_drop_succeeded(context);
|
||||||
|
gtk_widget_destroy(widget);
|
||||||
|
goDragFinish(succeeded);
|
||||||
|
drag_widget = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dragWindowOpen(char **uris) {
|
||||||
|
if (drag_widget != NULL) dragWindowClose();
|
||||||
|
|
||||||
|
gtk_init(NULL, NULL);
|
||||||
|
|
||||||
|
GtkWidget *widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);;
|
||||||
|
GtkWindow *window = GTK_WINDOW(widget);
|
||||||
|
|
||||||
|
gtk_window_move(window, 0, 0);
|
||||||
|
gtk_window_set_title(window, "Neko Drag & Drop Window");
|
||||||
|
gtk_window_set_decorated(window, FALSE);
|
||||||
|
gtk_window_set_keep_above(window, TRUE);
|
||||||
|
gtk_window_set_default_size(window, 100, 100);
|
||||||
|
|
||||||
|
GtkTargetList* target_list = gtk_target_list_new(NULL, 0);
|
||||||
|
gtk_target_list_add_uri_targets(target_list, DRAG_TARGET_TYPE_URI);
|
||||||
|
gtk_target_list_add_text_targets(target_list, DRAG_TARGET_TYPE_TEXT);
|
||||||
|
|
||||||
|
gtk_drag_source_set(widget, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK);
|
||||||
|
gtk_drag_source_set_target_list(widget, target_list);
|
||||||
|
|
||||||
|
g_signal_connect(widget, "map-event", G_CALLBACK(goDragCreate), NULL);
|
||||||
|
g_signal_connect(widget, "enter-notify-event", G_CALLBACK(goDragCursorEnter), NULL);
|
||||||
|
g_signal_connect(widget, "button-press-event", G_CALLBACK(goDragButtonPress), NULL);
|
||||||
|
g_signal_connect(widget, "drag-begin", G_CALLBACK(goDragBegin), NULL);
|
||||||
|
|
||||||
|
g_signal_connect(widget, "drag-data-get", G_CALLBACK(dragDataGet), uris);
|
||||||
|
g_signal_connect(widget, "drag-end", G_CALLBACK(dragEnd), NULL);
|
||||||
|
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||||
|
|
||||||
|
gtk_widget_show_all(widget);
|
||||||
|
drag_widget = widget;
|
||||||
|
|
||||||
|
gtk_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dragWindowClose() {
|
||||||
|
gtk_widget_destroy(drag_widget);
|
||||||
|
drag_widget = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **dragUrisMake(int size) {
|
||||||
|
return calloc(size + 1, sizeof(char *));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dragUrisSetFile(char **uris, char *file, int n) {
|
||||||
|
GFile *gfile = g_file_new_for_path(file);
|
||||||
|
uris[n] = g_file_get_uri(gfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dragUrisFree(char **uris, int size) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
free(uris[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(uris);
|
||||||
|
}
|
65
internal/desktop/drop/drop.go
Normal file
65
internal/desktop/drop/drop.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package drop
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo pkg-config: gtk+-3.0
|
||||||
|
|
||||||
|
#include "drop.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/kataras/go-events"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Emmiter events.EventEmmiter
|
||||||
|
var mu = sync.Mutex{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Emmiter = events.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func OpenWindow(files []string) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
size := C.int(len(files))
|
||||||
|
urisUnsafe := C.dragUrisMake(size);
|
||||||
|
defer C.dragUrisFree(urisUnsafe, size)
|
||||||
|
|
||||||
|
for i, file := range files {
|
||||||
|
C.dragUrisSetFile(urisUnsafe, C.CString(file), C.int(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.dragWindowOpen(urisUnsafe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseWindow() {
|
||||||
|
C.dragWindowClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goDragCreate
|
||||||
|
func goDragCreate(widget *C.GtkWidget, event *C.GdkEvent, user_data C.gpointer) {
|
||||||
|
go Emmiter.Emit("create")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goDragCursorEnter
|
||||||
|
func goDragCursorEnter(widget *C.GtkWidget, event *C.GdkEvent, user_data C.gpointer) {
|
||||||
|
go Emmiter.Emit("cursor-enter")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goDragButtonPress
|
||||||
|
func goDragButtonPress(widget *C.GtkWidget, event *C.GdkEvent, user_data C.gpointer) {
|
||||||
|
go Emmiter.Emit("button-press")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goDragBegin
|
||||||
|
func goDragBegin(widget *C.GtkWidget, context *C.GdkDragContext, user_data C.gpointer) {
|
||||||
|
go Emmiter.Emit("begin")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goDragFinish
|
||||||
|
func goDragFinish(succeeded C.gboolean) {
|
||||||
|
go Emmiter.Emit("finish", bool(succeeded == C.int(1)))
|
||||||
|
}
|
36
internal/desktop/drop/drop.h
Normal file
36
internal/desktop/drop/drop.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DRAG_TARGET_TYPE_TEXT,
|
||||||
|
DRAG_TARGET_TYPE_URI
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void goDragCreate(GtkWidget *widget, GdkEvent *event, gpointer user_data);
|
||||||
|
extern void goDragCursorEnter(GtkWidget *widget, GdkEvent *event, gpointer user_data);
|
||||||
|
extern void goDragButtonPress(GtkWidget *widget, GdkEvent *event, gpointer user_data);
|
||||||
|
extern void goDragBegin(GtkWidget *widget, GdkDragContext *context, gpointer user_data);
|
||||||
|
extern void goDragFinish(gboolean succeeded);
|
||||||
|
|
||||||
|
static void dragDataGet(
|
||||||
|
GtkWidget *widget,
|
||||||
|
GdkDragContext *context,
|
||||||
|
GtkSelectionData *data,
|
||||||
|
guint target_type,
|
||||||
|
guint time,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
static void dragEnd(
|
||||||
|
GtkWidget *widget,
|
||||||
|
GdkDragContext *context,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
void dragWindowOpen(char **uris);
|
||||||
|
void dragWindowClose();
|
||||||
|
|
||||||
|
char **dragUrisMake(int size);
|
||||||
|
void dragUrisSetFile(char **uris, char *file, int n);
|
||||||
|
void dragUrisFree(char **uris, int size);
|
@ -1,38 +0,0 @@
|
|||||||
package desktop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"demodesk/neko/internal/desktop/gtk"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DELAY = 100 * time.Millisecond
|
|
||||||
)
|
|
||||||
|
|
||||||
func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
go gtk.DragWindow(files)
|
|
||||||
|
|
||||||
// TODO: Find a bettter way.
|
|
||||||
for step := 1; step <= 6; step++ {
|
|
||||||
time.Sleep(DELAY)
|
|
||||||
|
|
||||||
switch step {
|
|
||||||
case 1:
|
|
||||||
manager.Move(0, 0)
|
|
||||||
case 2:
|
|
||||||
manager.ButtonDown(1)
|
|
||||||
case 3:
|
|
||||||
fallthrough
|
|
||||||
case 4:
|
|
||||||
fallthrough
|
|
||||||
case 5:
|
|
||||||
manager.Move(x, y)
|
|
||||||
case 6:
|
|
||||||
manager.ButtonUp(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
#include "gtk.h"
|
|
||||||
|
|
||||||
static void drag_data_get(
|
|
||||||
GtkWidget *widget,
|
|
||||||
GdkDragContext *context,
|
|
||||||
GtkSelectionData *data,
|
|
||||||
guint target_type,
|
|
||||||
guint time,
|
|
||||||
gpointer user_data
|
|
||||||
) {
|
|
||||||
gchar **uris = (gchar **) user_data;
|
|
||||||
|
|
||||||
if (target_type == TARGET_TYPE_URI) {
|
|
||||||
gtk_selection_data_set_uris(data, uris);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_type == TARGET_TYPE_TEXT) {
|
|
||||||
gtk_selection_data_set_text(data, uris[0], -1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drag_end(
|
|
||||||
GtkWidget *widget,
|
|
||||||
GdkDragContext *context,
|
|
||||||
gpointer user_data
|
|
||||||
) {
|
|
||||||
gboolean succeeded = gdk_drag_drop_succeeded(context);
|
|
||||||
GdkDragAction action = gdk_drag_context_get_selected_action(context);
|
|
||||||
|
|
||||||
char* action_str;
|
|
||||||
switch (action) {
|
|
||||||
case GDK_ACTION_COPY:
|
|
||||||
action_str = "COPY"; break;
|
|
||||||
case GDK_ACTION_MOVE:
|
|
||||||
action_str = "MOVE"; break;
|
|
||||||
case GDK_ACTION_LINK:
|
|
||||||
action_str = "LINK"; break;
|
|
||||||
case GDK_ACTION_ASK:
|
|
||||||
action_str = "ASK"; break;
|
|
||||||
default:
|
|
||||||
action_str = malloc(sizeof(char) * 20);
|
|
||||||
snprintf(action_str, 20, "invalid (%d)", action);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Selected drop action: %s; Succeeded: %d\n", action_str, succeeded);
|
|
||||||
if (action_str[0] == 'i') {
|
|
||||||
free(action_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_destroy(widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drag_window(char **uris) {
|
|
||||||
if (gtk_init_check(NULL, NULL) == FALSE) {
|
|
||||||
fprintf(stderr, "Unable to initialize GTK for drag and drop widget!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkWidget *widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
||||||
GtkWindow *window = GTK_WINDOW(widget);
|
|
||||||
|
|
||||||
gtk_window_move(window, 0, 0);
|
|
||||||
gtk_window_set_title(window, "Neko Drag & Drop Window");
|
|
||||||
gtk_window_set_decorated(window, FALSE);
|
|
||||||
gtk_window_set_keep_above(window, TRUE);
|
|
||||||
gtk_window_set_default_size(window, 0, 0);
|
|
||||||
|
|
||||||
GtkTargetList* target_list = gtk_target_list_new(NULL, 0);
|
|
||||||
gtk_target_list_add_uri_targets(target_list, TARGET_TYPE_URI);
|
|
||||||
gtk_target_list_add_text_targets(target_list, TARGET_TYPE_TEXT);
|
|
||||||
|
|
||||||
gtk_drag_source_set(widget, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK);
|
|
||||||
gtk_drag_source_set_target_list(widget, target_list);
|
|
||||||
|
|
||||||
g_signal_connect(widget, "drag-data-get", G_CALLBACK(drag_data_get), uris);
|
|
||||||
g_signal_connect(widget, "drag-end", G_CALLBACK(drag_end), NULL);
|
|
||||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
|
||||||
|
|
||||||
fprintf(stderr, "Preparing to show drag and drop widget.\n");
|
|
||||||
gtk_widget_show_all(widget);
|
|
||||||
gtk_main();
|
|
||||||
}
|
|
||||||
|
|
||||||
char **uris_make(int size) {
|
|
||||||
return calloc(size + 1, sizeof(char *));
|
|
||||||
}
|
|
||||||
|
|
||||||
void uris_set_file(char **uris, char *file, int n) {
|
|
||||||
GFile *gfile = g_file_new_for_path(file);
|
|
||||||
uris[n] = g_file_get_uri(gfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uris_free(char **uris, int size) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
free(uris[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(uris);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package gtk
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo pkg-config: gtk+-3.0
|
|
||||||
|
|
||||||
#include "gtk.h"
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var mu = sync.Mutex{}
|
|
||||||
|
|
||||||
func DragWindow(files []string) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
size := C.int(len(files))
|
|
||||||
urisUnsafe := C.uris_make(size);
|
|
||||||
defer C.uris_free(urisUnsafe, size)
|
|
||||||
|
|
||||||
for i, file := range files {
|
|
||||||
C.uris_set_file(urisUnsafe, C.CString(file), C.int(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
C.drag_window(urisUnsafe)
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
TARGET_TYPE_TEXT,
|
|
||||||
TARGET_TYPE_URI
|
|
||||||
};
|
|
||||||
|
|
||||||
static void drag_data_get(
|
|
||||||
GtkWidget *widget,
|
|
||||||
GdkDragContext *context,
|
|
||||||
GtkSelectionData *data,
|
|
||||||
guint target_type,
|
|
||||||
guint time,
|
|
||||||
gpointer user_data
|
|
||||||
);
|
|
||||||
|
|
||||||
static void drag_end(
|
|
||||||
GtkWidget *widget,
|
|
||||||
GdkDragContext *context,
|
|
||||||
gpointer user_data
|
|
||||||
);
|
|
||||||
|
|
||||||
void drag_window(char **uris);
|
|
||||||
|
|
||||||
char **uris_make(int size);
|
|
||||||
void uris_set_file(char **uris, char *file, int n);
|
|
||||||
void uris_free(char **uris, int size);
|
|
@ -59,5 +59,5 @@ type DesktopManager interface {
|
|||||||
WriteClipboard(data string)
|
WriteClipboard(data string)
|
||||||
|
|
||||||
// drop
|
// drop
|
||||||
DropFiles(x int, y int, files []string)
|
DropFiles(x int, y int, files []string) bool
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user