ui/gtk/dnd.c

Wed, 27 Nov 2024 13:28:21 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 27 Nov 2024 13:28:21 +0100
branch
newapi
changeset 394
bedd499b640d
parent 283
bb0b8927f5c0
permissions
-rw-r--r--

implement table dnd (GTK)

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2017 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#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) {
    CxBuffer *buf = cxBufferCreate(NULL, 1024, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
    char *uri;
    int i = 0;
    while((uri = uris[i]) != NULL) {
        cxBufferPutString(buf, uri);
        cxBufferPutString(buf, "\r\n");
    }
    GdkAtom type = gdk_atom_intern("text/uri-list", FALSE);
    gtk_selection_data_set(selection_data, type, 8, (guchar*)buf->space, buf->pos);
    cxBufferFree(buf);
    return TRUE;
}
static char** selection_data_get_uris(GtkSelectionData *selection_data) {
    // TODO: implement
    return NULL;
}
#define gtk_selection_data_set_uris selection_data_set_uris
#define gtk_selection_data_get_uris selection_data_get_uris
#endif

/*
void ui_selection_settext(UiSelection *sel, char *str, int len) {
    // TODO: handle error?
    gtk_selection_data_set_text(sel->data, str, len);
}

void ui_selection_seturis(UiSelection *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);
}

char* ui_selection_gettext(UiSelection *sel) {
    guchar *text = gtk_selection_data_get_text(sel->data);
    if(text) {
        char *textcp = strdup((char*)text);
        g_free(text);
        return textcp;
    }
    return NULL;
}

char** ui_selection_geturis(UiSelection *sel, size_t *nelm) {
    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++;
        }
        *nelm = i;
        g_strfreev(uris);
        return array;
    }
    return NULL;
}
*/

#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;
}

mercurial