ui/cocoa/webview.m

Mon, 10 Nov 2025 21:52:51 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 10 Nov 2025 21:52:51 +0100
changeset 113
dde28a806552
permissions
-rw-r--r--

update ucx

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2025 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.
 */

#import "webview.h"
#import "Container.h"

UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
    UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
    
    WKWebView *webview = [[WKWebView alloc]init];
    
    UiLayout layout = UI_ARGS2LAYOUT(args);
    ui_container_add(obj, webview, &layout);
    
    if(var) {
        UiGeneric *value = var->value;
        value->get = ui_webview_get;
        value->get_type = ui_webview_get_type;
        value->set = ui_webview_set;
        value->destroy = ui_webview_destroy;
        value->obj = (__bridge void*)webview;
        if(value->value) {
            ui_webview_set(value, value->value, UI_WEBVIEW_OBJECT_TYPE);
        } else {
            UiWebViewData *data = malloc(sizeof(UiWebViewData));
            memset(data, 0, sizeof(UiWebViewData));
            data->webview = (__bridge void*)webview;
            data->javascript = TRUE;
            data->zoom = 1;
            value->value = value;
        }
    }
    
    return (__bridge void*)webview;
}

UiWebViewData* ui_webview_data_clone(UiWebViewData *data) {
    UiWebViewData *newdata = malloc(sizeof(UiWebViewData));
    memset(newdata, 0, sizeof(UiWebViewData));
    newdata->zoom = 1;
    newdata->javascript = TRUE;
    
    if(data) {
        newdata->uri = data->uri ? strdup(data->uri) : NULL;
        newdata->mimetype = data->mimetype ? strdup(data->mimetype) : NULL;
        newdata->encoding = data->encoding ? strdup(data->encoding) : NULL;
        newdata->type = data->type;
        newdata->javascript = data->javascript;
        newdata->zoom = data->zoom;
        if(data->content && data->contentlength > 0) {
            newdata->content = malloc(data->contentlength + 1);
            memcpy(newdata->content, data->content, data->contentlength);
            newdata->content[data->contentlength] = 0;
            newdata->contentlength = data->contentlength;
        }
    }
    
    return newdata;
}

void ui_webview_data_free(UiWebViewData *data) {
    if(!data) {
        return;
    }
    free(data->uri);
    free(data->mimetype);
    free(data->encoding);
    free(data->content);
    free(data);
}

void* ui_webview_get(UiGeneric *g) {
    UiWebViewData *data = g->value;
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    
    if(data->type == WEBVIEW_CONTENT_URL) {
        (void)ui_webview_get_uri(g); // this updates data->uri
    }
    data->zoom = webview.pageZoom;
    
    return ui_webview_data_clone(g->value);
}

const char* ui_webview_get_type(UiGeneric *g) {
    return UI_WEBVIEW_OBJECT_TYPE;
}

int ui_webview_set(UiGeneric *g, void *data, const char *type) {
    if(!data || !type) {
        return 1;
    }
    if(strcmp(type, UI_WEBVIEW_OBJECT_TYPE)) {
        return 1;
    }
    ui_webview_data_free(g->value);
    g->value = ui_webview_data_clone(data);
    
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    UiWebViewData *webd = data;
    if(webd->type == WEBVIEW_CONTENT_URL) {
        const char *uri = webd->uri ? webd->uri : "about:blank";
        NSURL *url = [NSURL URLWithString:[[NSString alloc] initWithUTF8String:uri]];
        if(url) {
            NSURLRequest *req = [NSURLRequest requestWithURL:url];
            if(req) {
                [webview loadRequest:req];
            }
        }
    } else {
        NSString *mimetype = [[NSString alloc]initWithUTF8String: webd->mimetype ? webd->mimetype : "text/plain"];
        NSString *encoding = [[NSString alloc]initWithUTF8String: webd->encoding ? webd->encoding : "UTF-8"];
        NSString *urlStr = [[NSString alloc]initWithUTF8String: webd->uri ? webd->uri : "file:///"];
        NSURL *url = [NSURL URLWithString:urlStr];
        NSData *content = [NSData dataWithBytes:webd->content length:webd->contentlength];
        if(!url) {
            url = [NSURL URLWithString:@"about:blank"];
        }
        [webview loadData:content MIMEType:mimetype characterEncodingName:encoding baseURL:url];
    }
    
    webview.pageZoom = webd->zoom;
    
    return 1;
}

void ui_webview_destroy(UiGeneric *g) {
    ui_webview_data_free(g->value);
    g->value = NULL;
}


void ui_webview_load_url(UiGeneric *g, const char *url) {
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    UiWebViewData *data = g->value;
    data->type = WEBVIEW_CONTENT_URL;
    
    if(!url) {
        url = "about:blank";
    }
    
    NSURL *nsurl = [NSURL URLWithString:[[NSString alloc] initWithUTF8String:url]];
    if(nsurl) {
        NSURLRequest *req = [NSURLRequest requestWithURL:nsurl];
        if(req) {
            [webview loadRequest:req];
        }
    }
}

void ui_webview_load_content(
        UiGeneric *g,
        const char *uri,
        const char *content,
        size_t contentlength,
        const char *mimetype,
        const char *encoding)
{
    UiWebViewData *data = g->value;
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    
    data->type = WEBVIEW_CONTENT_CONTENT;
    
    free(data->uri);
    data->uri = NULL;
    free(data->mimetype);
    free(data->encoding);
    free(data->content);
    data->type = WEBVIEW_CONTENT_URL;
    
    data->content = malloc(contentlength+1);
    memcpy(data->content, content, contentlength);
    data->content[contentlength] = 0;
    
    if(!mimetype) {
        mimetype = "text/plain";
    }
    if(!encoding) {
        encoding = "UTF-8";
    }
    
    data->mimetype = strdup(mimetype);
    data->encoding = strdup(encoding);
    
    NSString *mtype = [[NSString alloc]initWithUTF8String:mimetype];
    NSString *enc = [[NSString alloc]initWithUTF8String:encoding];
    NSData *ct = [NSData dataWithBytes:content length:contentlength];
    NSURL *url;
    if(uri) {
        NSString *uriStr = [[NSString alloc]initWithUTF8String:uri];
        url = [NSURL URLWithString:uriStr];
    } else {
        url = [NSURL URLWithString:@"file:///"];
    }
    [webview loadData:ct MIMEType:mtype characterEncodingName:enc baseURL:url];
}


void ui_webview_reload(UiGeneric *g) {
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    [webview reload];
}

UiBool ui_webview_can_go_back(UiGeneric *g) {
    return FALSE;
}

UiBool ui_webview_can_go_forward(UiGeneric *g) {
    return FALSE;
}

void ui_webview_go_back(UiGeneric *g) {
    
}

void ui_webview_go_forward(UiGeneric *g) {
    
}

const char * ui_webview_get_uri(UiGeneric *g) {
    UiWebViewData *data = g->value;
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    
    free(data->uri);
    data->uri = NULL;
    
    NSURL *url = webview.URL;
    if(url) {
        NSString *s = [url absoluteString];
        if(s) {
            data->uri = strdup(s.UTF8String);
        }
    }
    return data->uri;
}

void ui_webview_enable_javascript(UiGeneric *g, UiBool enable) {
    // unsupported
}

void ui_webview_set_zoom(UiGeneric *g, double zoom) {
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    webview.pageZoom = zoom;
}

double ui_webview_get_zoom(UiGeneric *g) {
    WKWebView *webview = (__bridge WKWebView*)g->obj;
    return webview.pageZoom;
}

mercurial