AmendHub

Download:

jcs

/

detritus

/

amendments

/

48

browser: Keep track of link rects, show URI and finger when hovering

Each time we scroll, find the links in the viewport and remember
their rects. In idle handler, check pointer coords and if it's in
any link rects, set cursor and show the link URI in the statusbar.
 
A nicer way to do this might have been to use the mouseRgn field of
WaitNextEvent that was the screen region with link rects cut out of
it, that way we only get a mouse move event when the cursor is in
those cutouts. But since our ticks value to WaitNextEvent is so
small, none of the mouse move events were coming through, so just
rely on nullEvent.where being the mouse cursor coordinates.

jcs made amendment 48 about 1 year ago
--- browser.c Fri Nov 15 12:32:50 2024 +++ browser.c Thu Nov 21 12:09:37 2024 @@ -51,6 +51,7 @@ void browser_update_buttons(struct browser *browser); void browser_update(struct focusable *focusable, EventRecord *event); void browser_key_down(struct focusable *focusable, EventRecord *event); void browser_mouse_down(struct focusable *focusable, EventRecord *event); +void browser_mouse_move(struct focusable *focusable, EventRecord *event); bool browser_handle_menu(struct focusable *focusable, short menu, short item); void browser_atexit(struct focusable *focusable); @@ -63,6 +64,9 @@ void browser_finished_loading(struct browser *browser) void browser_follow_redir(struct browser *browser); void browser_stop_loading_page(struct browser *browser); void browser_free_links(struct browser *browser); +void browser_find_links(struct browser *browser); +Boolean browser_find_links_callback(struct TVRec *tv, + struct TVFindInRectMatch *match, void *cookie); void browser_idle(struct focusable *focusable, EventRecord *event) @@ -74,6 +78,9 @@ browser_idle(struct focusable *focusable, EventRecord TEIdle(browser->uri_te); + GlobalToLocal(&event->where); + browser_mouse_move(focusable, event); + if (browser->loading_page) { HLock(browser->loading_page); page = *(browser->loading_page); @@ -91,7 +98,7 @@ browser_idle(struct focusable *focusable, EventRecord handler = page->handler; } - if (page->download_frefnum == 0) + if (!page->download_frefnum) ret &= handler->process(browser->loading_page); if (!ret) @@ -124,6 +131,7 @@ browser_init(void) PADDING - (GetMBarHeight() * 2); height = MIN(height, 290); center_in_screen(width, height, true, &bounds); +bounds.top = (screenBits.bounds.bottom / 2); snprintf(title, sizeof(title), "%s", PROGRAM_NAME); CtoPstr(title); @@ -231,6 +239,7 @@ browser_init(void) focusable->idle = browser_idle; focusable->update = browser_update; focusable->mouse_down = browser_mouse_down; + focusable->mouse_move = browser_mouse_move; focusable->key_down = browser_key_down; focusable->menu = browser_handle_menu; focusable->close = browser_close; @@ -238,7 +247,7 @@ browser_init(void) focusable_add(focusable); browser_update(focusable, NULL); - browser_statusf(browser, "Hello, cyberpals!"); + browser_statusf(browser, "Hello, cyberpal"); return browser; } @@ -331,6 +340,8 @@ browser_finished_loading(struct browser *browser) if (committed) browser_statusf(browser, "Done (%ld bytes)", (*(browser->current_page))->content_len); + + browser_find_links(browser); } void @@ -402,6 +413,12 @@ browser_free_links(struct browser *browser) browser->first_link = NULL; browser->last_link = NULL; + + if (browser->hover_link) { + SetCursor(&arrow); + browser->hover_link = NULL; + browser_statusf(browser, ""); + } } void @@ -576,6 +593,7 @@ browser_mouse_down(struct focusable *focusable, EventR break; TVSetTrackScrollControl(browser->output_tv); TrackControl(control, p, TVTrackScrollControl); + browser_find_links(browser); break; case inThumb: val = GetCtlValue(control); @@ -587,12 +605,51 @@ browser_mouse_down(struct focusable *focusable, EventR if (control == browser->output_tv_scroller) TVScroll(browser->output_tv, 0, adj); SetCtlValue(control, val); + browser_find_links(browser); } break; } } void +browser_mouse_move(struct focusable *focusable, EventRecord *event) +{ + struct browser *browser = (struct browser *)(focusable->cookie); + struct browser_link *link; + long h, v; + + if (event->where.v < (*(browser->output_tv))->view.top) + goto no_link; + + h = event->where.h - (*(browser->output_tv))->view.left - + (*(browser->output_tv))->scrolled.left; + v = event->where.v - (*(browser->output_tv))->view.top - + (*(browser->output_tv))->scrolled.top; + + for (link = browser->first_link; link; link = link->next_link) { + if (h >= link->rect.left && h <= link->rect.right && + v >= link->rect.top && v <= link->rect.bottom) { + if (link == browser->hover_link) + return; + browser->hover_link = link; + SetCursor(&finger_cursor); + if (browser->hover_link->uri[0]) + browser_statusf(browser, browser->hover_link->uri); + else + browser_statusf(browser, ""); + return; + } + } + +no_link: + SetCursor(&arrow); + if (browser->hover_link) { + browser->hover_link = NULL; + browser_statusf(browser, ""); + } +} + +void browser_key_down(struct focusable *focusable, EventRecord *event) { struct browser *browser = (struct browser *)(focusable->cookie); @@ -811,11 +868,12 @@ browser_build_tvstyle(struct browser *browser) if (browser->style & STYLE_BOLD) style.style |= bold | condense; - if (browser->style & (STYLE_H1 | STYLE_H2 | STYLE_H3)) + if (browser->style & (STYLE_H1 | STYLE_H2 | STYLE_H3 | STYLE_H4 | + STYLE_H5 | STYLE_H6)) style.style |= bold; if (browser->style & STYLE_ITALIC) style.style |= italic; - if (browser->style & STYLE_LINK) + if (browser->style & (STYLE_LINK | STYLE_UNDERLINE)) style.style |= underline; if (browser->style & STYLE_PRE) { style.font = BROWSER_PRE_FONT; @@ -828,6 +886,10 @@ browser_build_tvstyle(struct browser *browser) style.size += 4; else if (browser->style & STYLE_H3) style.size += 2; + else if (browser->style & STYLE_H5) + style.size -= 2; + else if (browser->style & STYLE_H6) + style.size -= 4; return &style; } @@ -882,9 +944,10 @@ size_t browser_print_link(struct browser *browser, const char *uri, size_t uri_len, const char *title, size_t title_len, bool newline) { - struct TVStyle style; + struct TVStyle *style; struct browser_link *link; - size_t n, len; + size_t len; + unsigned long nlines; len = sizeof(struct browser_link) + uri_len + 1 + title_len + 1; link = xmalloczero(len); @@ -916,7 +979,15 @@ browser_print_link(struct browser *browser, const char browser->last_link = link; browser->style |= STYLE_LINK; - browser_print(browser, link->title, link->len, newline); + style = browser_build_tvstyle(browser); + style->tag = (unsigned long)(char *)link; + + nlines = (*(browser->output_tv))->nlines; + (newline ? TVAppendLine : TVAppend)(browser->output_tv, style, + link->title, link->len); + if ((*(browser->output_tv))->nlines != nlines) + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); + browser->style &= ~(STYLE_LINK); return link->len; @@ -944,7 +1015,7 @@ browser_commit_to_loading_page(struct browser *browser TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); TVAutoCalc(browser->output_tv, true); browser->style = STYLE_NONE; - + if (browser->current_page) { fpage = (*(browser->current_page))->fwd_page; bpage = (*(browser->current_page))->back_page; @@ -1058,6 +1129,41 @@ browser_grow_page_content(struct page *page, size_t le /* keep locked */ return *pageh; +} + +void +browser_find_links(struct browser *browser) +{ + bool ret; + BigRect visible; + + visible.top = -((*(browser->output_tv))->scrolled.top); + visible.left = -((*(browser->output_tv))->scrolled.left); + visible.bottom = visible.top + (*(browser->output_tv))->frame.bottom; + visible.right = visible.left + (*(browser->output_tv))->frame.right; + + ret = TVFindInRect(browser->output_tv, &visible, 0, + browser_find_links_callback, browser); +} + +Boolean +browser_find_links_callback(struct TVRec *tv, + struct TVFindInRectMatch *match, void *cookie) +{ + struct browser *browser = (struct browser *)cookie; + struct browser_link *link; + + if (match->style->tag == 0) + return true; + + /* probably just a newline */ + if (match->rect.left == match->rect.right) + return true; + + link = (struct browser_link *)(match->style->tag); + link->rect = match->rect; + + return true; } bool --- browser.h Fri Nov 15 17:31:13 2024 +++ browser.h Thu Nov 21 10:10:04 2024 @@ -32,16 +32,21 @@ #define STYLE_H1 (1UL << 2) #define STYLE_H2 (1UL << 3) #define STYLE_H3 (1UL << 4) -#define STYLE_LINK (1UL << 5) -#define STYLE_PRE (1UL << 6) -#define STYLE_LIST (1UL << 7) -#define STYLE_QUOTE (1UL << 8) +#define STYLE_H4 (1UL << 5) +#define STYLE_H5 (1UL << 6) +#define STYLE_H6 (1UL << 7) +#define STYLE_LINK (1UL << 8) +#define STYLE_PRE (1UL << 9) +#define STYLE_LIST (1UL << 10) +#define STYLE_QUOTE (1UL << 11) +#define STYLE_UNDERLINE (1UL << 12) struct browser_link { char *uri; char *title; unsigned short pos; unsigned short len; + BigRect rect; struct browser_link *next_link; }; @@ -77,6 +82,9 @@ struct page { char content[]; }; +#define PAGE_CAN_READ_MORE(page) ((page)->request && \ + !(page)->request->tcp_done_reading) + struct browser { WindowPtr win; RgnHandle header; @@ -98,6 +106,7 @@ struct browser { unsigned long style; struct browser_link *first_link; struct browser_link *last_link; + struct browser_link *hover_link; }; struct page_handler {