--- a/ui/gtk/dnd.c Tue Nov 26 11:38:10 2024 +0100 +++ b/ui/gtk/dnd.c Wed Nov 27 13:27:30 2024 +0100 @@ -32,6 +32,7 @@ #include "dnd.h" #include <cx/buffer.h> +#include <cx/array_list.h> #ifdef UI_GTK2LEGACY static gboolean selection_data_set_uris(GtkSelectionData *selection_data, char **uris) { @@ -102,18 +103,193 @@ } */ +#if GTK_MAJOR_VERSION >= 4 + void ui_selection_settext(UiDnD *sel, char *str, int len) { + if(!sel->providers) { + return; + } + if(len == -1) { + len = strlen(str); + } + GBytes *bytes = g_bytes_new(str, len); + GdkContentProvider *provider = gdk_content_provider_new_for_bytes("text/plain;charset=utf-8", bytes); + g_bytes_unref(bytes); + + cxListAdd(sel->providers, &provider); } void ui_selection_seturis(UiDnD *sel, char **uris, int nelm) { + if(!sel->providers) { + return; + } + GFile **files = calloc(nelm, sizeof(GFile*)); + for(int i=0;i<nelm;i++) { + GFile *file = uris[i][0] == '/' ? g_file_new_for_path(uris[i]) : g_file_new_for_uri(uris[i]); + files[i] = file; + } + GdkFileList *list = gdk_file_list_new_from_array(files, nelm); + + GdkContentProvider *provider = gdk_content_provider_new_typed(GDK_TYPE_FILE_LIST, list); + cxListAdd(sel->providers, &provider); + + g_slist_free_full ((GSList*)list, g_object_unref); + free(files); } char* ui_selection_gettext(UiDnD *sel) { + if(!sel->value) { + return NULL; + } + + if(G_VALUE_HOLDS(sel->value, G_TYPE_STRING)) { + const char *str = g_value_get_string(sel->value); + return str ? strdup(str) : NULL; + } + return NULL; } UiFileList ui_selection_geturis(UiDnD *sel) { + if(!sel->value) { + return (UiFileList){NULL,0}; + } + + if(G_VALUE_HOLDS(sel->value, GDK_TYPE_FILE_LIST)) { + GSList *list = g_value_get_boxed(sel->value); + if(!list) { + return (UiFileList){NULL,0}; + } + guint size = g_slist_length(list); + + UiFileList flist; + flist.nfiles = size; + flist.files = calloc(size, sizeof(char*)); + int i=0; + while(list) { + GFile *file = list->data; + char *uri = g_file_get_uri(file); + flist.files[i++] = strdup(uri); + g_free(uri); + list = list->next; + } + return flist; + } return (UiFileList){NULL,0}; } + + +UiDnD* ui_create_dnd(void) { + UiDnD *dnd = malloc(sizeof(UiDnD)); + memset(dnd, 0, sizeof(UiDnD)); + dnd->providers = cxArrayListCreateSimple(sizeof(void*), 16); + dnd->selected_action = 0; + dnd->delete = FALSE; + return dnd; +} + +void ui_dnd_free(UiDnD *dnd) { + cxListDestroy(dnd->providers); + free(dnd); +} + +UiDnDAction ui_dnd_result(UiDnD *dnd) { + switch(dnd->selected_action) { + case 0: return UI_DND_ACTION_NONE; + case GDK_ACTION_COPY: return UI_DND_ACTION_COPY; + case GDK_ACTION_MOVE: return UI_DND_ACTION_MOVE; + case GDK_ACTION_LINK: return UI_DND_ACTION_LINK; + default: break; + } + return UI_DND_ACTION_CUSTOM; +} + +#else + +void ui_selection_settext(UiDnD *sel, char *str, int len) { + gtk_selection_data_set_text(sel->data, str, len); +} + +void ui_selection_seturis(UiDnD *sel, char **uris, int nelm) { + char **uriarray = calloc(nelm+1, sizeof(char*)); + for(int i=0;i<nelm;i++) { + uriarray[i] = uris[i]; + } + uriarray[nelm] = NULL; + gtk_selection_data_set_uris(sel->data, uriarray); + free(uriarray); +} + +char* ui_selection_gettext(UiDnD *sel) { + if(!sel->data) { + return NULL; + } + + guchar *text = gtk_selection_data_get_text(sel->data); + if(text) { + char *textcp = strdup((char*)text); + g_free(text); + return textcp; + } + return NULL; +} + +UiFileList ui_selection_geturis(UiDnD *sel) { + if(!sel->data) { + return (UiFileList){NULL,0}; + } + + gchar **uris = gtk_selection_data_get_uris(sel->data); + if(uris) { + size_t al = 32; + char **array = malloc(al * sizeof(char*)); + size_t i = 0; + while(uris[i] != NULL) { + if(i >= al) { + al *= 2; + array = realloc(array, al * sizeof(char*)); + } + array[i] = strdup((char*)uris[i]); + i++; + } + g_strfreev(uris); + return (UiFileList){array,i}; + } + + return (UiFileList){NULL,0}; +} + +UiDnDAction ui_dnd_result(UiDnD *dnd) { + switch(dnd->selected_action) { + case 0: return UI_DND_ACTION_NONE; + case GDK_ACTION_COPY: return UI_DND_ACTION_COPY; + case GDK_ACTION_MOVE: return UI_DND_ACTION_MOVE; + case GDK_ACTION_LINK: return UI_DND_ACTION_LINK; + default: break; + } + return UI_DND_ACTION_CUSTOM; +} + + +UiDnD* ui_create_dnd(void) { + UiDnD *dnd = malloc(sizeof(UiDnD)); + memset(dnd, 0, sizeof(UiDnD)); + return dnd; +} + +void ui_dnd_free(UiDnD *dnd) { + free(dnd); +} + +#endif + +UiBool ui_dnd_need_delete(UiDnD *dnd) { + return dnd->delete; +} + +void ui_dnd_accept(UiDnD *dnd, UiBool accept) { + dnd->accept = accept; +} +