539 lines
19 KiB
C
539 lines
19 KiB
C
/* Native MontaukOS browser shell for the NetSurf core. */
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <montauk.h>
|
|
|
|
#include "utils/errors.h"
|
|
#include "utils/nsurl.h"
|
|
#include "netsurf/browser_window.h"
|
|
#include "netsurf/clipboard.h"
|
|
#include "netsurf/search.h"
|
|
#include "netsurf/keypress.h"
|
|
#include "netsurf/mouse.h"
|
|
#include "desktop/browser_history.h"
|
|
#include "desktop/search.h"
|
|
#include "monkey/browser.h"
|
|
#include "monkey/plot.h"
|
|
#include "monkey/schedule.h"
|
|
#include "monkey/montauk_ui.h"
|
|
#include "content/fetchers/montauk_bridge.h"
|
|
#include "content/urldb.h"
|
|
|
|
#define MENU_ITEMS 10
|
|
#define MAX_TABS 16
|
|
#define MAX_BOOKMARKS 64
|
|
#define HOME_URL "https://html.duckduckgo.com/"
|
|
|
|
static char bookmark_urls[MAX_BOOKMARKS][1024];
|
|
static char bookmark_titles[MAX_BOOKMARKS][128];
|
|
static size_t bookmark_count;
|
|
static char bookmark_path[256];
|
|
|
|
struct mtk_clipboard_info {
|
|
uint32_t text_bytes;
|
|
uint32_t pad;
|
|
uint64_t serial;
|
|
};
|
|
|
|
static void clipboard_get(char **buffer, size_t *length)
|
|
{
|
|
struct mtk_clipboard_info info = {0};
|
|
uint32_t actual = 0;
|
|
*buffer = NULL;
|
|
*length = 0;
|
|
if (_mtk_syscall1(MTK_SYS_CLIPBOARD_GET_INFO, (long)&info) != 0 ||
|
|
info.text_bytes == 0 || info.text_bytes > 4u * 1024u * 1024u)
|
|
return;
|
|
char *copy = malloc((size_t)info.text_bytes + 1);
|
|
if (copy == NULL) return;
|
|
if (_mtk_syscall4(MTK_SYS_CLIPBOARD_GET_TEXT, (long)copy,
|
|
(long)info.text_bytes, (long)&actual, 0) != 0 || actual > info.text_bytes) {
|
|
free(copy);
|
|
return;
|
|
}
|
|
copy[actual] = 0;
|
|
*buffer = copy;
|
|
*length = actual;
|
|
}
|
|
|
|
static void clipboard_set(const char *buffer, size_t length,
|
|
nsclipboard_styles styles[], int n_styles)
|
|
{
|
|
(void)styles;
|
|
(void)n_styles;
|
|
if (buffer != NULL && length <= UINT32_MAX)
|
|
_mtk_syscall2(MTK_SYS_CLIPBOARD_SET_TEXT, (long)buffer, (long)length);
|
|
}
|
|
|
|
struct gui_clipboard_table monkey_native_clipboard_table = {
|
|
.get = clipboard_get,
|
|
.set = clipboard_set,
|
|
};
|
|
|
|
static void search_status(bool found, void *private)
|
|
{
|
|
struct gui_window *g = private;
|
|
if (g == NULL) return;
|
|
strcpy(g->status, found ? "Match found" : "No matches");
|
|
g->dirty = true;
|
|
}
|
|
|
|
static void search_hourglass(bool active, void *private) { (void)active; (void)private; }
|
|
static void search_recent(const char *value, void *private) { (void)value; (void)private; }
|
|
static void search_state(bool active, void *private) { (void)active; (void)private; }
|
|
|
|
struct gui_search_table monkey_native_search_table = {
|
|
.status = search_status,
|
|
.hourglass = search_hourglass,
|
|
.add_recent = search_recent,
|
|
.forward_state = search_state,
|
|
.back_state = search_state,
|
|
};
|
|
|
|
static uint32_t rgb(unsigned r, unsigned g, unsigned b)
|
|
{
|
|
return 0xff000000u | (r << 16) | (g << 8) | b;
|
|
}
|
|
|
|
static void fill(struct gui_window *g, int x, int y, int w, int h, uint32_t c)
|
|
{
|
|
if (x < 0) { w += x; x = 0; }
|
|
if (y < 0) { h += y; y = 0; }
|
|
if (x + w > g->width) w = g->width - x;
|
|
if (y + h > g->height) h = g->height - y;
|
|
if (w <= 0 || h <= 0) return;
|
|
for (int py = y; py < y + h; py++)
|
|
for (int px = x; px < x + w; px++)
|
|
g->pixels[py * g->width + px] = c;
|
|
}
|
|
|
|
|
|
static void new_tab(struct gui_window *g)
|
|
{
|
|
if (monkey_native_tab_count() >= MAX_TABS) {
|
|
strcpy(g->status, "Tab limit reached"); g->dirty = true; return;
|
|
}
|
|
nsurl *url = NULL;
|
|
struct browser_window *created = NULL;
|
|
if (nsurl_create("about:blank", &url) != NSERROR_OK) return;
|
|
browser_window_create(BW_CREATE_HISTORY | BW_CREATE_TAB |
|
|
BW_CREATE_FOREGROUND | BW_CREATE_FOCUS_LOCATION,
|
|
url, NULL, g->bw, &created);
|
|
nsurl_unref(url);
|
|
struct gui_window *active = monkey_native_get_window();
|
|
if (active != NULL) {
|
|
active->address[0] = 0;
|
|
active->address_focus = true;
|
|
mtk_netsurf_address_input_focus((uintptr_t)active,
|
|
active->address, true);
|
|
active->dirty = true;
|
|
}
|
|
}
|
|
|
|
static void cycle_tab(struct gui_window *g, bool backwards)
|
|
{
|
|
size_t count = monkey_native_tab_count();
|
|
if (count < 2) return;
|
|
size_t current = 0;
|
|
for (; current < count; current++)
|
|
if (monkey_native_tab_at(current) == g) break;
|
|
if (current == count) return;
|
|
current = backwards ? (current + count - 1) % count : (current + 1) % count;
|
|
monkey_native_activate_window(monkey_native_tab_at(current));
|
|
}
|
|
|
|
static void bookmarks_save(void)
|
|
{
|
|
if (bookmark_path[0] == 0) return;
|
|
int file = mtk_create(bookmark_path);
|
|
if (file < 0) return;
|
|
unsigned long offset = 0;
|
|
for (size_t i = 0; i < bookmark_count; i++) {
|
|
size_t len = strlen(bookmark_urls[i]);
|
|
mtk_write(file, (const uint8_t *)bookmark_urls[i], offset, len); offset += len;
|
|
mtk_write(file, (const uint8_t *)"\n", offset, 1); offset++;
|
|
}
|
|
mtk_close(file);
|
|
}
|
|
|
|
static void bookmarks_load(void)
|
|
{
|
|
char user[64] = {0};
|
|
if (_mtk_syscall2(MTK_SYS_GETUSER, (long)user, sizeof(user)) < 0 || user[0] == 0)
|
|
strcpy(user, "admin");
|
|
char directory[224];
|
|
snprintf(directory, sizeof(directory), "0:/users/%s/.netsurf", user);
|
|
mtk_mkdir(directory);
|
|
snprintf(bookmark_path, sizeof(bookmark_path), "%s/bookmarks", directory);
|
|
int file = mtk_open(bookmark_path);
|
|
if (file < 0) return;
|
|
unsigned long size = mtk_getsize(file);
|
|
if (size > 128u * 1024u) size = 128u * 1024u;
|
|
char *data = malloc(size + 1);
|
|
if (data == NULL) { mtk_close(file); return; }
|
|
int got = mtk_read(file, (uint8_t *)data, 0, size);
|
|
mtk_close(file);
|
|
if (got < 0) { free(data); return; }
|
|
data[got] = 0;
|
|
char *line = data;
|
|
while (*line != 0 && bookmark_count < MAX_BOOKMARKS) {
|
|
char *end = strchr(line, '\n');
|
|
if (end != NULL) *end = 0;
|
|
if (line[0] != 0) {
|
|
strncpy(bookmark_urls[bookmark_count], line,
|
|
sizeof(bookmark_urls[bookmark_count]) - 1);
|
|
strncpy(bookmark_titles[bookmark_count], line,
|
|
sizeof(bookmark_titles[bookmark_count]) - 1);
|
|
bookmark_count++;
|
|
}
|
|
if (end == NULL) break;
|
|
line = end + 1;
|
|
}
|
|
free(data);
|
|
}
|
|
|
|
static void bookmark_page(struct gui_window *g)
|
|
{
|
|
nsurl *url = browser_window_access_url(g->bw);
|
|
if (url == NULL) { strcpy(g->status, "Could not save bookmark"); g->dirty = true; return; }
|
|
const char *value = nsurl_access(url);
|
|
for (size_t i = 0; i < bookmark_count; i++) {
|
|
if (strcmp(bookmark_urls[i], value) == 0) {
|
|
strcpy(g->status, "Already bookmarked"); g->dirty = true; return;
|
|
}
|
|
}
|
|
if (bookmark_count >= MAX_BOOKMARKS) {
|
|
strcpy(g->status, "Bookmark limit reached"); g->dirty = true; return;
|
|
}
|
|
strncpy(bookmark_urls[bookmark_count], value, sizeof(bookmark_urls[0]) - 1);
|
|
strncpy(bookmark_titles[bookmark_count], g->title[0] ? g->title : value,
|
|
sizeof(bookmark_titles[0]) - 1);
|
|
bookmark_count++;
|
|
urldb_set_url_persistence(url, true);
|
|
bookmarks_save();
|
|
strcpy(g->status, "Bookmark saved");
|
|
g->dirty = true;
|
|
}
|
|
|
|
static void close_all_tabs(void)
|
|
{
|
|
while (monkey_native_tab_count() != 0) {
|
|
struct gui_window *tab = monkey_native_tab_at(0);
|
|
if (tab == NULL) break;
|
|
browser_window_destroy(tab->bw);
|
|
}
|
|
}
|
|
|
|
void monkey_native_draw_chrome(struct gui_window *g)
|
|
{
|
|
if (g == NULL || g->pixels == NULL) return;
|
|
struct mtk_netsurf_chrome_model model = {0};
|
|
model.pixels = g->pixels;
|
|
model.width = g->width;
|
|
model.height = g->height;
|
|
model.scale = g->ui_scale;
|
|
model.mouse_x = g->mouse_x;
|
|
model.mouse_y = g->mouse_y;
|
|
model.can_back = browser_window_history_back_available(g->bw);
|
|
model.can_forward = browser_window_history_forward_available(g->bw);
|
|
model.loading = g->loading;
|
|
model.address_focus = g->address_focus;
|
|
model.address_input_key = (uintptr_t)g;
|
|
model.address = g->address;
|
|
model.menu_mode = g->menu_open;
|
|
model.find_focus = g->find_focus;
|
|
model.find_text = g->find_text;
|
|
model.status = g->status;
|
|
model.extent_height = g->extent_height;
|
|
model.scroll_y = g->scrolly;
|
|
model.scrollbar_hover = g->scrollbar_hover;
|
|
model.scrollbar_dragging = g->scrollbar_dragging;
|
|
model.tab_count = (int)monkey_native_tab_count();
|
|
for (int i = 0; i < model.tab_count && i < MTK_NETSURF_MAX_TABS; i++) {
|
|
struct gui_window *tab = monkey_native_tab_at((size_t)i);
|
|
model.tab_titles[i] = tab != NULL && tab->title[0] ? tab->title : "New Tab";
|
|
if (tab == g) model.active_tab = i;
|
|
}
|
|
model.bookmark_count = bookmark_count < MTK_NETSURF_MAX_BOOKMARK_ROWS ?
|
|
(int)bookmark_count : MTK_NETSURF_MAX_BOOKMARK_ROWS;
|
|
for (int i = 0; i < model.bookmark_count; i++)
|
|
model.bookmark_titles[i] = bookmark_titles[i];
|
|
mtk_netsurf_chrome_draw(&model);
|
|
if (g->caret_visible) {
|
|
int cx = g->caret_x - g->scrollx;
|
|
int cy = g->chrome_height + g->caret_y - g->scrolly;
|
|
if (cx >= 0 && cx < mtk_netsurf_page_view_width(g->width) &&
|
|
cy >= g->chrome_height &&
|
|
cy + g->caret_height < g->height)
|
|
fill(g, cx, cy, 1, g->caret_height, rgb(25, 25, 25));
|
|
}
|
|
}
|
|
|
|
static void navigate(struct gui_window *g, const char *input)
|
|
{
|
|
char expanded[2048];
|
|
if (strstr(input, "://") == NULL && strncmp(input, "about:", 6) != 0) {
|
|
snprintf(expanded, sizeof(expanded), "https://%s", input);
|
|
input = expanded;
|
|
}
|
|
nsurl *url = NULL;
|
|
if (nsurl_create(input, &url) == NSERROR_OK) {
|
|
browser_window_navigate(g->bw, url, NULL, BW_NAVIGATE_HISTORY,
|
|
NULL, NULL, NULL);
|
|
nsurl_unref(url);
|
|
}
|
|
}
|
|
|
|
static void key_event(struct gui_window *g, const mtk_key_event *key)
|
|
{
|
|
if (!key->pressed) return;
|
|
if (key->scancode == 0x01 && g->menu_open) { g->menu_open = 0; g->dirty = true; return; }
|
|
if (key->ctrl && (key->ascii == 't' || key->ascii == 'T' || key->scancode == 0x14)) { new_tab(g); return; }
|
|
if (key->ctrl && (key->ascii == 'w' || key->ascii == 'W' || key->scancode == 0x11)) {
|
|
browser_window_destroy(g->bw);
|
|
return;
|
|
}
|
|
if (key->ctrl && key->scancode == 0x0f) { cycle_tab(g, key->shift); return; }
|
|
if (key->ctrl && (key->ascii == 'f' || key->ascii == 'F')) {
|
|
g->find_focus = true; g->dirty = true; return;
|
|
}
|
|
if (key->ctrl && (key->ascii == 'd' || key->ascii == 'D')) {
|
|
bookmark_page(g); return;
|
|
}
|
|
if (g->find_focus) {
|
|
if (key->scancode == 0x01) {
|
|
g->find_focus = false; browser_window_search_clear(g->bw); g->dirty = true; return;
|
|
}
|
|
if (key->scancode == 0x1c || key->ascii == '\r' || key->ascii == '\n') {
|
|
if (g->find_text[0]) browser_window_search(g->bw, g, SEARCH_FLAG_FORWARDS, g->find_text);
|
|
return;
|
|
}
|
|
if (key->ascii == '\b' || key->scancode == 0x0e) {
|
|
size_t n = strlen(g->find_text); if (n) g->find_text[n-1] = 0;
|
|
} else if (key->ascii >= 32 && key->ascii < 127) {
|
|
size_t n = strlen(g->find_text);
|
|
if (n + 1 < sizeof(g->find_text)) { g->find_text[n] = key->ascii; g->find_text[n+1] = 0; }
|
|
}
|
|
if (g->find_text[0]) browser_window_search(g->bw, g, SEARCH_FLAG_FORWARDS | SEARCH_FLAG_SHOWALL, g->find_text);
|
|
else browser_window_search_clear(g->bw);
|
|
g->dirty = true; return;
|
|
}
|
|
if (key->ctrl && (key->ascii == 'l' || key->ascii == 'L')) {
|
|
g->address_focus = true;
|
|
mtk_netsurf_address_input_focus((uintptr_t)g, g->address, true);
|
|
g->dirty = true; return;
|
|
}
|
|
if (g->address_focus) {
|
|
if (key->scancode == 0x01) { g->address_focus = false; g->dirty = true; return; }
|
|
if (key->scancode == 0x1c || key->ascii == '\r' || key->ascii == '\n') {
|
|
g->address_focus = false;
|
|
navigate(g, g->address); return;
|
|
}
|
|
int result = mtk_netsurf_address_input_key((uintptr_t)g,
|
|
g->address, (int)sizeof(g->address), key->scancode,
|
|
key->ascii, key->pressed, key->shift, key->ctrl, key->alt);
|
|
if (result != 0) g->dirty = true;
|
|
return;
|
|
}
|
|
if (key->ctrl && (key->ascii == 'r' || key->ascii == 'R')) { browser_window_reload(g->bw, false); return; }
|
|
if (key->ctrl && (key->ascii == '+' || key->ascii == '=')) { browser_window_set_scale(g->bw, .1f, false); return; }
|
|
if (key->ctrl && key->ascii == '-') { browser_window_set_scale(g->bw, -.1f, false); return; }
|
|
if (key->ctrl && key->ascii == '0') { browser_window_set_scale(g->bw, 1.0f, true); return; }
|
|
if (key->ctrl && (key->ascii == 'a' || key->ascii == 'A')) { browser_window_key_press(g->bw, NS_KEY_SELECT_ALL); return; }
|
|
if (key->ctrl && (key->ascii == 'c' || key->ascii == 'C')) { browser_window_key_press(g->bw, NS_KEY_COPY_SELECTION); return; }
|
|
if (key->ctrl && (key->ascii == 'x' || key->ascii == 'X')) { browser_window_key_press(g->bw, NS_KEY_CUT_SELECTION); return; }
|
|
if (key->ctrl && (key->ascii == 'v' || key->ascii == 'V')) { browser_window_key_press(g->bw, NS_KEY_PASTE); return; }
|
|
uint32_t nskey = 0;
|
|
switch (key->scancode) {
|
|
case 0x48: nskey = NS_KEY_UP; break; case 0x50: nskey = NS_KEY_DOWN; break;
|
|
case 0x4b: nskey = NS_KEY_LEFT; break; case 0x4d: nskey = NS_KEY_RIGHT; break;
|
|
case 0x49: nskey = NS_KEY_PAGE_UP; break; case 0x51: nskey = NS_KEY_PAGE_DOWN; break;
|
|
case 0x0e: nskey = NS_KEY_DELETE_LEFT; break; case 0x53: nskey = NS_KEY_DELETE_RIGHT; break;
|
|
case 0x0f: nskey = key->shift ? NS_KEY_SHIFT_TAB : NS_KEY_TAB; break;
|
|
case 0x1c: nskey = NS_KEY_CR; break;
|
|
default: if (key->ascii >= 32) nskey = (unsigned char)key->ascii; break;
|
|
}
|
|
if (nskey != 0 && browser_window_key_press(g->bw, nskey)) return;
|
|
if (key->scancode == 0x48) g->scrolly -= 40;
|
|
if (key->scancode == 0x50) g->scrolly += 40;
|
|
if (key->scancode == 0x49) g->scrolly -= g->height - g->chrome_height - g->status_height;
|
|
if (key->scancode == 0x51) g->scrolly += g->height - g->chrome_height - g->status_height;
|
|
g->dirty = true;
|
|
}
|
|
|
|
static void clamp_scroll(struct gui_window *g)
|
|
{
|
|
int view = g->height - g->chrome_height - g->status_height;
|
|
int max = g->extent_height > view ? g->extent_height - view : 0;
|
|
if (g->scrolly < 0) g->scrolly = 0;
|
|
if (g->scrolly > max) g->scrolly = max;
|
|
}
|
|
|
|
static void mouse_event(struct gui_window *g, const mtk_win_event *ev)
|
|
{
|
|
int x = ev->mouse.x, y = ev->mouse.y;
|
|
struct mtk_netsurf_chrome_metrics m;
|
|
mtk_netsurf_chrome_metrics(g->ui_scale, g->width,
|
|
(int)monkey_native_tab_count(), &m);
|
|
int ch = m.chrome_h, sh = m.status_h;
|
|
if (g->mouse_x != x || g->mouse_y != y) {
|
|
g->mouse_x = x;
|
|
g->mouse_y = y;
|
|
g->dirty = true;
|
|
}
|
|
bool left_press = (ev->mouse.buttons & 1) && !(ev->mouse.prev_buttons & 1);
|
|
bool left_release = !(ev->mouse.buttons & 1) && (ev->mouse.prev_buttons & 1);
|
|
bool address_hit = x >= m.address_x && x < m.address_x + m.address_w &&
|
|
y >= m.address_y && y < m.address_y + m.address_h;
|
|
if (address_hit && ((ev->mouse.buttons & 3) != 0))
|
|
g->address_focus = true;
|
|
if (g->address_focus || address_hit) {
|
|
int input_result = mtk_netsurf_address_input_mouse((uintptr_t)g,
|
|
g->address, (int)sizeof(g->address), x, y,
|
|
ev->mouse.buttons, ev->mouse.prev_buttons,
|
|
m.address_x, m.address_y, m.address_w, m.address_h,
|
|
g->width, g->height, g->address_focus);
|
|
if (input_result != 0) {
|
|
g->dirty = true;
|
|
return;
|
|
}
|
|
}
|
|
int scrollbar_result = mtk_netsurf_page_scrollbar_mouse(x, y,
|
|
ev->mouse.buttons, ev->mouse.prev_buttons, g->width, g->height,
|
|
ch, g->extent_height, &g->scrolly, &g->scrollbar_hover,
|
|
&g->scrollbar_dragging, &g->scrollbar_drag_offset);
|
|
if ((scrollbar_result & 2) != 0) g->dirty = true;
|
|
if ((scrollbar_result & 1) != 0) return;
|
|
if (left_press && !address_hit) g->address_focus = false;
|
|
if (ev->mouse.scroll != 0 && y >= ch) {
|
|
g->scrolly -= ev->mouse.scroll * 50; clamp_scroll(g); g->dirty = true; return;
|
|
}
|
|
if (left_press && y >= m.tab_y && y < m.tab_h) {
|
|
size_t count = monkey_native_tab_count();
|
|
for (size_t i = 0; i < count; i++) {
|
|
int tx = m.tab_x + (int)i * m.tab_w;
|
|
if (x >= tx && x < tx + m.tab_content_w) {
|
|
struct gui_window *tab = monkey_native_tab_at(i);
|
|
if (tab != NULL && x >= tx + m.tab_content_w - m.tab_close_w)
|
|
browser_window_destroy(tab->bw);
|
|
else monkey_native_activate_window(tab);
|
|
return;
|
|
}
|
|
}
|
|
if (x >= m.add_x && x < m.add_x + m.add_w) new_tab(g);
|
|
return;
|
|
}
|
|
if (left_press && g->menu_open) {
|
|
if (y >= m.button_y && y < m.button_y + m.button_size &&
|
|
x >= m.menu_x && x < m.menu_x + m.button_size) {
|
|
g->menu_open = false; g->dirty = true; return;
|
|
}
|
|
if (g->menu_open == 2 && x >= m.popup_x && x < m.popup_x + m.popup_w && y >= m.popup_y) {
|
|
int item = (y - m.popup_y - 4) / m.popup_item_h - 1;
|
|
if (item >= 0 && item < (int)bookmark_count && item < 8)
|
|
navigate(g, bookmark_urls[item]);
|
|
g->menu_open = 0; g->dirty = true; return;
|
|
}
|
|
if (g->menu_open == 1 && x >= m.popup_x && x < m.popup_x + m.popup_w &&
|
|
y >= m.popup_y && y < m.popup_y + MENU_ITEMS * m.popup_item_h + 8) {
|
|
int item = (y - m.popup_y - 4) / m.popup_item_h;
|
|
g->menu_open = 0;
|
|
switch (item) {
|
|
case 0: new_tab(g); break;
|
|
case 1: g->find_focus = true; g->dirty = true; break;
|
|
case 2: bookmark_page(g); break;
|
|
case 3: g->menu_open = 2; g->dirty = true; break;
|
|
case 4: clipboard_set(g->address, strlen(g->address), NULL, 0); break;
|
|
case 5: browser_window_set_scale(g->bw, .1f, false); break;
|
|
case 6: browser_window_set_scale(g->bw, -.1f, false); break;
|
|
case 7: browser_window_set_scale(g->bw, 1.0f, true); break;
|
|
case 8: navigate(g, HOME_URL); break;
|
|
case 9: close_all_tabs(); break;
|
|
}
|
|
return;
|
|
}
|
|
g->menu_open = 0; g->dirty = true;
|
|
}
|
|
if (left_press && y >= m.button_y && y < m.button_y + m.button_size) {
|
|
if (x >= m.back_x && x < m.back_x + m.button_size && browser_window_history_back_available(g->bw))
|
|
browser_window_history_back(g->bw, false);
|
|
else if (x >= m.forward_x && x < m.forward_x + m.button_size && browser_window_history_forward_available(g->bw))
|
|
browser_window_history_forward(g->bw, false);
|
|
else if (x >= m.reload_x && x < m.reload_x + m.button_size) {
|
|
if (g->loading) browser_window_stop(g->bw); else browser_window_reload(g->bw, false);
|
|
} else if (x >= m.address_x && x < m.address_x + m.address_w) {
|
|
/* The MTK input handler above owns address-field interaction. */
|
|
} else if (x >= m.home_x && x < m.home_x + m.button_size) {
|
|
navigate(g, HOME_URL);
|
|
} else if (x >= m.menu_x && x < m.menu_x + m.button_size) {
|
|
g->menu_open = g->menu_open ? 0 : 1;
|
|
}
|
|
g->dirty = true; return;
|
|
}
|
|
if (left_press && y >= ch && y < g->height - sh) {
|
|
g->address_focus = false;
|
|
browser_window_mouse_click(g->bw, BROWSER_MOUSE_PRESS_1,
|
|
x + g->scrollx, y - ch + g->scrolly);
|
|
/* A press can dispatch form/content callbacks and invalidate the
|
|
* browser window. Continue tracking on the next mouse event, after the
|
|
* event loop has reacquired the active gui_window. */
|
|
return;
|
|
}
|
|
if (left_release && y >= ch && y < g->height - sh) {
|
|
browser_window_mouse_click(g->bw, BROWSER_MOUSE_CLICK_1,
|
|
x + g->scrollx, y - ch + g->scrolly);
|
|
/* A click may navigate, replace the current content, or destroy the
|
|
* target browser window. Do not dereference g or g->bw afterward. */
|
|
return;
|
|
}
|
|
if (y >= ch && y < g->height - sh)
|
|
browser_window_mouse_track(g->bw,
|
|
(ev->mouse.buttons & 1) ? BROWSER_MOUSE_HOLDING_1 : BROWSER_MOUSE_HOVER,
|
|
x + g->scrollx, y - ch + g->scrolly);
|
|
}
|
|
|
|
void monkey_native_run(const char *initial_url)
|
|
{
|
|
nsurl *url = NULL;
|
|
bookmarks_load();
|
|
if (initial_url == NULL || initial_url[0] == 0) initial_url = HOME_URL;
|
|
if (nsurl_create(initial_url, &url) != NSERROR_OK) return;
|
|
if (browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, NULL) != NSERROR_OK) {
|
|
nsurl_unref(url); return;
|
|
}
|
|
nsurl_unref(url);
|
|
|
|
for (;;) {
|
|
struct gui_window *g = monkey_native_get_window();
|
|
if (g == NULL) break;
|
|
monkey_schedule_run();
|
|
mtk_win_event ev;
|
|
int events = 0;
|
|
while (events++ < 32 && mtk_win_poll(g->native_id, &ev) > 0) {
|
|
if (ev.type == MTK_EVENT_CLOSE) { close_all_tabs(); g = NULL; break; }
|
|
if (ev.type == MTK_EVENT_RESIZE || ev.type == MTK_EVENT_SCALE) {
|
|
if (ev.type == MTK_EVENT_RESIZE) {
|
|
uint32_t *pixels = (uint32_t *)(uintptr_t)mtk_win_resize(g->native_id,
|
|
ev.resize.w, ev.resize.h);
|
|
monkey_native_resize_tabs(g, ev.resize.w, ev.resize.h, pixels);
|
|
}
|
|
if (ev.type == MTK_EVENT_SCALE)
|
|
monkey_native_set_scale(g, mtk_win_getscale());
|
|
g->dirty = true;
|
|
} else if (ev.type == MTK_EVENT_KEY) key_event(g, &ev.key);
|
|
else if (ev.type == MTK_EVENT_MOUSE) mouse_event(g, &ev);
|
|
g = monkey_native_get_window();
|
|
if (g == NULL) break;
|
|
}
|
|
if (g == NULL) break;
|
|
clamp_scroll(g);
|
|
if (g->dirty) monkey_native_redraw(g);
|
|
mtk_sleep_ms(5);
|
|
}
|
|
mtk_netsurf_icons_cleanup();
|
|
}
|