NetSurf
corewindow.c
Go to the documentation of this file.
1/*
2 * Copyright 2017 Chris Young <chris@unsatisfactorysoftware.co.uk>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * Amiga core window interface.
22 *
23 * Provides interface for core renderers to the Amiga Intuition drawable area.
24 *
25 * This module is an object that must be encapsulated. Client users
26 * should embed a struct ami_corewindow at the beginning of their
27 * context for this display surface, fill in relevant data and then
28 * call ami_corewindow_init()
29 *
30 * The Amiga core window structure requires the callback for draw, key and
31 * mouse operations.
32 */
33
34#include "amiga/os3support.h"
35
36#include <assert.h>
37#include <stdlib.h>
38#include <string.h>
39#include <math.h>
40
41#include "utils/log.h"
42#include "utils/utils.h"
43#include "utils/messages.h"
44#include "utils/utf8.h"
45#include "netsurf/keypress.h"
46#include "netsurf/mouse.h"
47#include "netsurf/plot_style.h"
48
49#include <proto/exec.h>
50#include <proto/graphics.h>
51#include <proto/intuition.h>
52#include <proto/layout.h>
53#include <proto/utility.h>
54
55#include <classes/window.h>
56#include <gadgets/layout.h>
57#include <gadgets/scroller.h>
58#include <gadgets/space.h>
59#include <intuition/icclass.h>
60#include <reaction/reaction_macros.h>
61
62#include "amiga/corewindow.h"
63#include "amiga/drag.h"
64#include "amiga/memory.h"
65#include "amiga/misc.h"
66#include "amiga/object.h"
67#include "amiga/schedule.h"
68#include "amiga/utf8.h"
69
70static void
72 ULONG *restrict x,
73 ULONG *restrict y)
74{
75 ULONG xs = 0;
76 ULONG ys = 0;
77
78 if(ami_cw->scroll_x_visible == true) {
79 GetAttr(SCROLLER_Top, ami_cw->objects[GID_CW_HSCROLL], &xs);
80 }
81
82 if(ami_cw->scroll_y_visible == true) {
83 GetAttr(SCROLLER_Top, ami_cw->objects[GID_CW_VSCROLL], &ys);
84 }
85
86 *x = xs;
87 *y = ys;
88}
89
90static void
91ami_cw_window_size(struct ami_corewindow *ami_cw, int *width, int *height)
92{
93 struct IBox *bbox;
94
95 if(ami_gui_get_space_box((Object *)ami_cw->objects[GID_CW_DRAW], &bbox) != NSERROR_OK) {
96 amiga_warn_user("NoMemory", "");
97 return;
98 }
99
100 *width = bbox->Width;
101 *height = bbox->Height;
102
104}
105
106
107/**
108 * Convert co-ordinates relative to space.gadget
109 * into document co-ordinates
110 *
111 * @param ami_cw core window
112 * @param x co-ordinate, will be updated to new x co-ordinate
113 * @param y co-ordinate, will be updated to new y co-ordinate
114 */
115static void
116ami_cw_coord_amiga_to_ns(struct ami_corewindow *ami_cw, int *restrict x, int *restrict y)
117{
118 ULONG xs = 0;
119 ULONG ys = 0;
120
121 ami_cw_scroller_top(ami_cw, &xs, &ys);
122
123 *x = *x + xs;
124 *y = *y + ys;
125}
126
127/**
128 * check if mouse has moved since position was stored
129 * @param ami_cw corewindow
130 * @param x current x position
131 * @param y current y position
132 * @param click true to check since last click, false since last drag (press)
133 * @return true if it has, false otherwise
134 */
135static bool
136ami_cw_mouse_moved(struct ami_corewindow *ami_cw, int x, int y, bool click)
137{
138 int mx, my;
139
140 if(click == true) {
141 mx = ami_cw->mouse_x_click;
142 my = ami_cw->mouse_y_click;
143 } else {
144 mx = ami_cw->drag_x_start;
145 my = ami_cw->drag_y_start;
146 }
147
148 if(abs(x - mx) > 5) return true;
149 if(abs(y - my) > 5) return true;
150 return false;
151}
152
153/* get current mouse position in the draw area, adjusted for scroll.
154 * @return true if the mouse was in the draw area and co-ordinates updated
155 */
156static bool
157ami_cw_mouse_pos(struct ami_corewindow *ami_cw, int *restrict x, int *restrict y)
158{
159 int16 xm, ym;
160 ULONG xs, ys;
161 struct IBox *bbox;
162
163 xm = ami_cw->win->MouseX;
164 ym = ami_cw->win->MouseY;
165
166 if(ami_gui_get_space_box((Object *)ami_cw->objects[GID_CW_DRAW], &bbox) != NSERROR_OK) {
167 amiga_warn_user("NoMemory", "");
168 return false;
169 }
170
171 xm -= bbox->Left;
172 ym -= bbox->Top;
173
174 if((xm < 0) || (ym < 0) || (xm > bbox->Width) || (ym > bbox->Height))
175 return false;
176
178 ami_cw_scroller_top(ami_cw, &xs, &ys);
179
180 xm += xs;
181 ym += ys;
182 *x = xm;
183 *y = ym;
184
185 return true;
186}
187
188/* handle keypress */
189static void
190ami_cw_key(struct ami_corewindow *ami_cw, int nskey)
191{
192 ami_cw->key(ami_cw, nskey);
193
194 switch(nskey) {
196 /* if we've copied a selection we need to clear it - style guide rules */
197 ami_cw->key(ami_cw, NS_KEY_CLEAR_SELECTION);
198 break;
199
200 /* we may need to deal with scroll-related keys here */
201 }
202}
203
204
205/**
206 * Redraw functions
207 *
208 * This is slightly over-engineered as it was taken from the main
209 * browser/old tree redraws and supports deferred drawing of
210 * rectangles and tiling
211 */
212
213/**
214 * Redraw an area of a core window
215 *
216 * \param ami_cw An Amiga core window structure
217 * \param r rect (in document co-ordinates)
218 */
219
220static void
221ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
222{
223 struct IBox *bbox;
224 ULONG pos_x, pos_y;
225 struct rect draw_rect;
226 int tile_size_x;
227 int tile_size_y;
228 int tile_x, tile_y, tile_w, tile_h;
229 int x = r->x0;
230 int y = r->y0;
231 int width = r->x1 - r->x0;
232 int height = r->y1 - r->y0;
233
234 struct redraw_context ctx = {
235 .interactive = true,
236 .background_images = true,
237 .plot = &amiplot,
238 .priv = ami_cw->gg
239 };
240
241 if(ami_gui_get_space_box((Object *)ami_cw->objects[GID_CW_DRAW], &bbox) != NSERROR_OK) {
242 amiga_warn_user("NoMemory", "");
243 return;
244 }
245
246 ami_cw_scroller_top(ami_cw, &pos_x, &pos_y);
247
248 if(x - (LONG)pos_x + width > bbox->Width) width = bbox->Width - (x - pos_x);
249 if(y - (LONG)pos_y + height > bbox->Height) height = bbox->Height - (y - pos_y);
250
251 if(x < (LONG)pos_x) {
252 width -= pos_x - x;
253 x = pos_x;
254 }
255
256 if(y < (LONG)pos_y) {
257 height -= pos_y - y;
258 y = pos_y;
259 }
260
261 ami_plot_ra_get_size(ami_cw->gg, &tile_size_x, &tile_size_y);
262
263 for(tile_y = y; tile_y < (y + height); tile_y += tile_size_y) {
264 tile_h = tile_size_y;
265 if(((y + height) - tile_y) < tile_size_y)
266 tile_h = (y + height) - tile_y;
267
268 for(tile_x = x; tile_x < (x + width); tile_x += tile_size_x) {
269 tile_w = tile_size_x;
270 if(((x + width) - tile_x) < tile_size_x)
271 tile_w = (x + width) - tile_x;
272
273 draw_rect.x0 = tile_x; // was -
274 draw_rect.y0 = tile_y; // was -
275 draw_rect.x1 = tile_x + tile_w;
276 draw_rect.y1 = tile_y + tile_h;
277
278 ami_cw->draw(ami_cw, -tile_x, -tile_y, &draw_rect, &ctx);
279
280#ifdef __amigaos4__
281 BltBitMapTags(BLITA_SrcType, BLITT_BITMAP,
282 BLITA_Source, ami_plot_ra_get_bitmap(ami_cw->gg),
283 BLITA_SrcX, 0,
284 BLITA_SrcY, 0,
285 BLITA_DestType, BLITT_RASTPORT,
286 BLITA_Dest, ami_cw->win->RPort,
287 BLITA_DestX, bbox->Left + tile_x - pos_x,
288 BLITA_DestY, bbox->Top + tile_y - pos_y,
289 BLITA_Width, tile_w,
290 BLITA_Height, tile_h,
291 TAG_DONE);
292#else
293 BltBitMapRastPort(ami_plot_ra_get_bitmap(ami_cw->gg), 0, 0,
294 ami_cw->win->RPort, bbox->Left + tile_x - pos_x, bbox->Top + tile_y - pos_y,
295 tile_w, tile_h, 0xC0);
296#endif
297 }
298 }
299
301 ami_clearclipreg(ami_cw->gg);
302}
303
304
305/**
306 * Draw the deferred rectangles
307 *
308 * \param ami_cw An Amiga core window structure to queue redraw
309 * \param draw set to false to just delete the queue
310 */
311static void ami_cw_redraw_queue(struct ami_corewindow *ami_cw, bool draw)
312{
313 struct nsObject *node;
314 struct nsObject *nnode;
315 struct rect *rect;
316
317 if(IsMinListEmpty(ami_cw->deferred_rects)) return;
318
319 if(draw == false) {
320 NSLOG(netsurf, INFO, "Ignoring deferred box redraw queue");
321 } // else should probably show busy pointer
322
323 node = (struct nsObject *)GetHead((struct List *)ami_cw->deferred_rects);
324
325 do {
326 if(draw == true) {
327 rect = (struct rect *)node->objstruct;
328 ami_cw_redraw_rect(ami_cw, rect);
329 }
330 nnode = (struct nsObject *)GetSucc((struct Node *)node);
331 ami_memory_itempool_free(ami_cw->deferred_rects_pool, node->objstruct, sizeof(struct rect));
332 DelObjectNoFree(node);
333 } while((node = nnode));
334}
335
336static void
338{
339 struct ami_corewindow *ami_cw = (struct ami_corewindow *)p;
340
341 ami_cw_redraw_queue(ami_cw, true);
342}
343
344/**
345 * Queue a redraw of a rectangle
346 *
347 * @param ami_cw the core window to redraw
348 * @param r the rectangle (in doc coords) to redraw, or NULL for full window
349 */
350
351static void
352ami_cw_redraw(struct ami_corewindow *ami_cw, const struct rect *restrict r)
353{
354 struct nsObject *nsobj;
355 struct rect *restrict deferred_rect;
356 struct rect new_rect;
357
358 if(r == NULL) {
359 struct IBox *bbox;
360 if(ami_gui_get_space_box((Object *)ami_cw->objects[GID_CW_DRAW], &bbox) != NSERROR_OK) {
361 amiga_warn_user("NoMemory", "");
362 return;
363 }
364
365 new_rect.x0 = 0;
366 new_rect.y0 = 0;
367 ami_cw_coord_amiga_to_ns(ami_cw, &new_rect.x0, &new_rect.y0);
368 new_rect.x1 = new_rect.x0 + bbox->Width;
369 new_rect.y1 = new_rect.y0 + bbox->Height;
370
372
373 r = &new_rect;
374 }
375
377 ami_cw->deferred_rects_pool)) {
378 deferred_rect = ami_memory_itempool_alloc(ami_cw->deferred_rects_pool, sizeof(struct rect));
379 CopyMem(r, deferred_rect, sizeof(struct rect));
380 nsobj = AddObject(ami_cw->deferred_rects, AMINS_RECT);
381 nsobj->objstruct = deferred_rect;
382 } else {
383 NSLOG(netsurf, INFO,
384 "Ignoring duplicate or subset of queued box redraw");
385 }
386 ami_schedule(1, ami_cw_redraw_cb, ami_cw);
387}
388
389static void ami_cw_simplerefresh(struct ami_corewindow *ami_cw)
390{
391 struct rect r;
392 struct RegionRectangle *regrect;
393
394 BeginRefresh(ami_cw->win);
395
396 r.x0 = ami_cw->win->RPort->Layer->DamageList->bounds.MinX;
397 r.x1 = ami_cw->win->RPort->Layer->DamageList->bounds.MaxX;
398 r.y0 = ami_cw->win->RPort->Layer->DamageList->bounds.MinY;
399 r.y1 = ami_cw->win->RPort->Layer->DamageList->bounds.MaxY;
400
401 ami_cw_coord_amiga_to_ns(ami_cw, &r.x0, &r.y0);
402 ami_cw_coord_amiga_to_ns(ami_cw, &r.y0, &r.y1);
403
404 regrect = ami_cw->win->RPort->Layer->DamageList->RegionRectangle;
405
406 ami_cw_redraw(ami_cw, &r); /* queue redraw */
407
408 while(regrect) {
409 r.x0 = regrect->bounds.MinX;
410 r.x1 = regrect->bounds.MaxX;
411 r.y0 = regrect->bounds.MinY;
412 r.y1 = regrect->bounds.MaxY;
413 ami_cw_coord_amiga_to_ns(ami_cw, &r.x0, &r.y0);
414 ami_cw_coord_amiga_to_ns(ami_cw, &r.y0, &r.y1);
415
416 regrect = regrect->Next;
417
418 ami_cw_redraw(ami_cw, &r); /* queue redraw */
419 }
420
421 EndRefresh(ami_cw->win, TRUE);
422}
423
424static void
425ami_cw_toggle_scrollbar(struct ami_corewindow *ami_cw, bool vert, bool visible)
426{
427 Object *scroller;
428 Object *layout;
429 ULONG tag;
430
431 if(vert == true) {
432 if(visible == ami_cw->scroll_y_visible) {
433 return;
434 } else {
435 scroller = ami_cw->objects[GID_CW_VSCROLL];
436 layout = ami_cw->objects[GID_CW_VSCROLLLAYOUT];
437 tag = WINDOW_VertProp;
438 ami_cw->scroll_y_visible = visible;
439 }
440 } else {
441 if(visible == ami_cw->scroll_x_visible) {
442 return;
443 } else {
444 scroller = ami_cw->objects[GID_CW_HSCROLL];
445 layout = ami_cw->objects[GID_CW_HSCROLLLAYOUT];
446 tag = WINDOW_HorizProp;
447 ami_cw->scroll_x_visible = visible;
448 }
449 }
450
451 if(visible == true) {
452 if(ami_cw->in_border_scroll == true) {
453 SetAttrs(ami_cw->objects[GID_CW_WIN],
454 tag, 1,
455 TAG_DONE);
456 } else {
457#ifdef __amigaos4__
458 IDoMethod(layout, LM_ADDCHILD, ami_cw->win, scroller, NULL);
459#else
460 SetAttrs(layout, LAYOUT_AddChild, scroller, TAG_DONE);
461#endif
462 }
463 } else {
464 if(ami_cw->in_border_scroll == true) {
465 SetAttrs(ami_cw->objects[GID_CW_WIN],
466 tag, -1,
467 TAG_DONE);
468 } else {
469#ifdef __amigaos4__
470 IDoMethod(layout, LM_REMOVECHILD, ami_cw->win, scroller);
471#else
472 SetAttrs(layout, LAYOUT_RemoveChild, scroller, TAG_DONE);
473#endif
474 }
475 }
476
477 if(ami_cw->in_border_scroll == false) {
478 FlushLayoutDomainCache((struct Gadget *)ami_cw->objects[GID_CW_WIN]);
479 RethinkLayout((struct Gadget *)ami_cw->objects[GID_CW_WIN],
480 ami_cw->win, NULL, TRUE);
481 }
482
483 /* probably need to redraw here */
484 ami_cw_redraw(ami_cw, NULL);
485}
486
487static void
489{
490 struct ami_corewindow *ami_cw = (struct ami_corewindow *)w;
491
492 ami_cw->close(ami_cw);
493}
494
495HOOKF(void, ami_cw_idcmp_hook, Object *, object, struct IntuiMessage *)
496{
497 struct ami_corewindow *ami_cw = hook->h_Data;
498 struct IntuiWheelData *wheel;
499 ULONG gid = GetTagData( GA_ID, 0, msg->IAddress );
500
501 switch(msg->Class)
502 {
503 case IDCMP_IDCMPUPDATE:
504 switch(gid)
505 {
506 case GID_CW_HSCROLL:
507 case GID_CW_VSCROLL:
508 ami_cw_redraw(ami_cw, NULL);
509 break;
510 }
511 break;
512#ifdef __amigaos4__
514 if(msg->Code == IMSGCODE_INTUIWHEELDATA)
515 {
516 wheel = (struct IntuiWheelData *)msg->IAddress;
517
518 //ami_tree_scroll(twin, (wheel->WheelX * 20), (wheel->WheelY * 20));
519 }
520 break;
521#endif
522
523 case IDCMP_SIZEVERIFY:
524 break;
525
526 case IDCMP_REFRESHWINDOW:
527 ami_cw_simplerefresh(ami_cw);
528 break;
529
530 default:
531 NSLOG(netsurf, INFO,
532 "IDCMP hook unhandled event: %ld", msg->Class);
533 break;
534 }
535}
536
537/**
538 * Drag start
539 */
540static void
541ami_cw_drag_start(struct ami_corewindow *ami_cw, int x, int y)
542{
543 if(ami_cw->dragging == true) return;
544
545 ami_cw->dragging = true;
546 ami_cw->drag_x_start = x;
547 ami_cw->drag_y_start = y;
548
549 switch(ami_cw->drag_status) {
551 break;
552
554 ami_drag_icon_show(ami_cw->win, "project");
555 break;
556
557 default:
558 break;
559 }
560}
561
562/**
563 * Drag progress
564 */
565static void
566ami_cw_drag_progress(struct ami_corewindow *ami_cw, int x, int y)
567{
568 if(ami_cw->dragging == false) return;
569
570 switch(ami_cw->drag_status) {
572 break;
573
576 break;
577
578 default:
579 break;
580 }
581}
582
583/**
584 * Drag end
585 */
586static void
587ami_cw_drag_end(struct ami_corewindow *ami_cw, int x, int y)
588{
589 if(ami_cw->dragging == false) return;
590 struct Screen *scrn = ami_gui_get_screen();
591
592 switch(ami_cw->drag_status) {
594 break;
595
597 ami_drag_icon_close(ami_cw->win);
598 if((ami_cw != ami_window_at_pointer(AMINS_COREWINDOW)) && (ami_cw->drag_end != NULL)) {
599 ami_cw->drag_end(ami_cw, scrn->MouseX, scrn->MouseY);
600 }
601 break;
602
603 default:
604 break;
605 }
606
608 ami_cw->dragging = false;
609}
610
611/**
612 * User has resized window
613 */
614
615static void
617{
618 int win_w, win_h;
619 ami_cw_window_size(ami_cw, &win_w, &win_h);
620
621 if(ami_cw->objects[GID_CW_HSCROLL] != NULL) {
622 RefreshSetGadgetAttrs((struct Gadget *)ami_cw->objects[GID_CW_HSCROLL], ami_cw->win, NULL,
623 SCROLLER_Visible, win_w,
624 TAG_DONE);
625 }
626
627 if(ami_cw->objects[GID_CW_VSCROLL] != NULL) {
628 RefreshSetGadgetAttrs((struct Gadget *)ami_cw->objects[GID_CW_VSCROLL], ami_cw->win, NULL,
629 SCROLLER_Visible, win_h,
630 TAG_DONE);
631 }
632
633 ami_cw_redraw(ami_cw, NULL);
634}
635
636/**
637 * Main event loop for our core window
638 *
639 * \return TRUE if window destroyed
640 */
641static BOOL
643{
644 struct ami_corewindow *ami_cw = (struct ami_corewindow *)w;
645
646 ULONG result;
647 ULONG storage;
648 uint16 code;
649 struct InputEvent *ie;
650 int nskey;
651 int key_state = 0;
652 struct timeval curtime;
653 int x = 0, y = 0;
654
655 while((result = RA_HandleInput(ami_cw->objects[GID_CW_WIN], &code)) != WMHI_LASTMSG) {
656 if(ami_cw->close_window == true) {
657 ami_cw_close(ami_cw);
658 return TRUE;
659 }
660
661 switch(result & WMHI_CLASSMASK) {
662 case WMHI_MOUSEMOVE:
663 if(ami_cw_mouse_pos(ami_cw, &x, &y) == true) {
664 if(ami_cw_mouse_moved(ami_cw, x, y, false)) {
665 if(ami_cw->mouse_state & BROWSER_MOUSE_PRESS_1) {
666 /* Start button 1 drag */
667 ami_cw->mouse(ami_cw, BROWSER_MOUSE_DRAG_1, x, y);
668 /* Replace PRESS with HOLDING and declare drag in progress */
670 } else if(ami_cw->mouse_state & BROWSER_MOUSE_PRESS_2) {
671 /* Start button 2 drag */
672 ami_cw->mouse(ami_cw, BROWSER_MOUSE_DRAG_2, x, y);
673 /* Replace PRESS with HOLDING and declare drag in progress */
675 }
676 key_state = ami_gui_get_quals(ami_cw->objects[GID_CW_WIN]);
677 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state, x, y);
678 if(ami_cw->mouse_state & BROWSER_MOUSE_DRAG_ON) {
679 ami_cw_drag_start(ami_cw, x, y);
680 }
681 } else {
682 key_state = ami_gui_get_quals(ami_cw->objects[GID_CW_WIN]);
683 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state, x, y);
684 }
685 }
686 ami_cw_drag_progress(ami_cw, x, y);
687 break;
688
689 case WMHI_MOUSEBUTTONS:
690 if(ami_cw_mouse_pos(ami_cw, &x, &y) == true) {
691 key_state = ami_gui_get_quals(ami_cw->objects[GID_CW_WIN]);
692 switch(code) {
693 case SELECTDOWN:
695 ami_cw->drag_x_start = x;
696 ami_cw->drag_y_start = y;
697 break;
698
699 case MIDDLEDOWN:
701 ami_cw->drag_x_start = x;
702 ami_cw->drag_y_start = y;
703 break;
704
705 case SELECTUP:
706 if(ami_cw->mouse_state & BROWSER_MOUSE_PRESS_1) {
707 CurrentTime((ULONG *)&curtime.tv_sec, (ULONG *)&curtime.tv_usec);
708
710
711 if(ami_cw->lastclick.tv_sec) {
712 if((ami_cw_mouse_moved(ami_cw, x, y, true) == false) &&
713 (DoubleClick(ami_cw->lastclick.tv_sec,
714 ami_cw->lastclick.tv_usec,
715 curtime.tv_sec, curtime.tv_usec)))
717 }
718
719 ami_cw->mouse_x_click = x;
720 ami_cw->mouse_y_click = y;
721
723 ami_cw->lastclick.tv_sec = 0;
724 ami_cw->lastclick.tv_usec = 0;
725 } else {
726 ami_cw->lastclick.tv_sec = curtime.tv_sec;
727 ami_cw->lastclick.tv_usec = curtime.tv_usec;
728 }
729 }
730
731 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state, x, y);
733 break;
734
735 case MIDDLEUP:
738
739 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state, x, y);
741 break;
742 }
743
744 if(ami_cw->mouse_state == BROWSER_MOUSE_HOVER) {
745 ami_cw_drag_end(ami_cw, x, y);
746 }
747
748 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state, x, y);
749 } else {
750 /* event is happening away from our corewindow area */
751 switch(code) {
752 case SELECTUP:
753 case MIDDLEUP:
755 break;
756
757 default:
758 break;
759 }
760
761 if(ami_cw->mouse_state == BROWSER_MOUSE_HOVER) {
762 ami_cw_drag_end(ami_cw, x, y);
763 ami_cw->mouse(ami_cw, ami_cw->mouse_state | key_state,
764 ami_cw->drag_x_start, ami_cw->drag_y_start); // placate core
765 }
766 }
767 break;
768
769 case WMHI_RAWKEY:
770 storage = result & WMHI_GADGETMASK;
771
772 GetAttr(WINDOW_InputEvent, ami_cw->objects[GID_CW_WIN], (ULONG *)&ie);
773 nskey = ami_key_to_nskey(storage, ie);
774
775 ami_cw_key(ami_cw, nskey);
776 break;
777
778 case WMHI_NEWSIZE:
779 ami_cw_newsize(ami_cw);
780 break;
781
782 case WMHI_CLOSEWINDOW:
783 ami_cw_close(ami_cw);
784 return TRUE;
785 break;
786
787 default:
788 /* pass the event to the window owner */
789 if(ami_cw->event != NULL)
790 if(ami_cw->event(ami_cw, result) == TRUE) {
791 return TRUE;
792 }
793 break;
794 }
795 };
796
797 return FALSE;
798}
799
800static const struct ami_win_event_table ami_cw_table = {
803};
804
805
806/**
807 * callback from core to request an invalidation of a amiga core window area.
808 *
809 * The specified area of the window should now be considered
810 * out of date. If the area is NULL the entire window must be
811 * invalidated.
812 *
813 * \param[in] cw The core window to invalidate.
814 * \param[in] r area to redraw or NULL for the entire window area.
815 * \return NSERROR_OK on success or appropriate error code.
816 */
817static nserror
818ami_cw_invalidate_area(struct core_window *cw, const struct rect *r)
819{
820 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
821
822 ami_cw_redraw(ami_cw, r);
823
824 return NSERROR_OK;
825}
826
827
828static nserror
829ami_cw_get_window_dimensions(const struct core_window *cw,
830 int *width, int *height)
831{
832 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
833
835 return NSERROR_OK;
836}
837
838
839static nserror
840ami_cw_update_size(struct core_window *cw, int width, int height)
841{
842 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
843 int win_w, win_h;
844
845 ami_cw_window_size(ami_cw, &win_w, &win_h);
846
847 if(width == -1) {
848 ami_cw_toggle_scrollbar(ami_cw, false, false);
849 } else {
850 ami_cw_toggle_scrollbar(ami_cw, false, true);
851 RefreshSetGadgetAttrs((struct Gadget *)ami_cw->objects[GID_CW_HSCROLL], ami_cw->win, NULL,
852 SCROLLER_Total, (ULONG)width,
853 SCROLLER_Visible, win_w,
854 TAG_DONE);
855 }
856
857 if(height == -1) {
858 ami_cw_toggle_scrollbar(ami_cw, true, false);
859 } else {
860 ami_cw_toggle_scrollbar(ami_cw, true, true);
861 RefreshSetGadgetAttrs((struct Gadget *)ami_cw->objects[GID_CW_VSCROLL], ami_cw->win, NULL,
862 SCROLLER_Total, height,
863 SCROLLER_Visible, win_h,
864 TAG_DONE);
865 }
866 return NSERROR_OK;
867}
868
869
870static nserror
871ami_cw_get_scroll(const struct core_window *cw, int *x, int *y)
872{
873 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
874 ULONG win_x0, win_y0;
875
876 ami_cw_scroller_top(ami_cw, &win_x0, &win_y0);
877
878 *x = win_x0;
879 *y = win_y0;
880 return NSERROR_OK;
881}
882
883
884static nserror
885ami_cw_set_scroll(struct core_window *cw, int x, int y)
886{
887 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
888
889 if(ami_cw->scroll_y_visible == true) {
890 RefreshSetGadgetAttrs((APTR)ami_cw->objects[GID_CW_VSCROLL], ami_cw->win, NULL,
891 SCROLLER_Top, y,
892 TAG_DONE);
893 }
894
895 if(ami_cw->scroll_x_visible == true) {
896 RefreshSetGadgetAttrs((APTR)ami_cw->objects[GID_CW_HSCROLL], ami_cw->win, NULL,
897 SCROLLER_Top, x,
898 TAG_DONE);
899 }
900
901 /* probably need to redraw here */
902 ami_cw_redraw(ami_cw, NULL);
903 return NSERROR_OK;
904}
905
906
907static nserror
909{
910 struct ami_corewindow *ami_cw = (struct ami_corewindow *)cw;
911 ami_cw->drag_status = ds;
912 return NSERROR_OK;
913}
914
915
918 .update_size = ami_cw_update_size,
919 .set_scroll = ami_cw_set_scroll,
920 .get_scroll = ami_cw_get_scroll,
921 .get_window_dimensions = ami_cw_get_window_dimensions,
922 .drag_status = ami_cw_drag_status
923};
924
925/* exported function documented example/corewindow.h */
927{
928 /* setup the core window callback table */
929 ami_cw->cb_table = &ami_cw_cb_table;
931
932 /* clear some vars */
934 ami_cw->lastclick.tv_sec = 0;
935 ami_cw->lastclick.tv_usec = 0;
936 ami_cw->scroll_x_visible = true;
937 ami_cw->scroll_y_visible = true;
938 ami_cw->in_border_scroll = false;
939 ami_cw->dragging = false;
940
941 /* allocate drawing area etc */
942 ami_cw->gg = ami_plot_ra_alloc(100, 100, false, true); // force tiles to save memory
943
944 ami_cw->deferred_rects = NewObjList();
945 ami_cw->deferred_rects_pool = ami_memory_itempool_create(sizeof(struct rect));
946
947 /* add the core window to our window list so we process events */
949
950 /* set up the IDCMP hook for event processing (extended mouse, scrollbars) */
951 ami_cw->idcmp_hook.h_Entry = (void *)ami_cw_idcmp_hook;
952 ami_cw->idcmp_hook.h_Data = ami_cw;
953
954 /* open the window */
955 ami_cw->win = (struct Window *)RA_OpenWindow(ami_cw->objects[GID_CW_WIN]);
956
957 /* attach the scrollbars for event processing _if they are in the window border_ */
958 if(ami_cw->objects[GID_CW_HSCROLL] == NULL) {
959 GetAttr(WINDOW_HorizObject, ami_cw->objects[GID_CW_WIN],
960 (ULONG *)&ami_cw->objects[GID_CW_HSCROLL]);
961
962 RefreshSetGadgetAttrs((APTR)ami_cw->objects[GID_CW_HSCROLL], ami_cw->win, NULL,
963 GA_ID, GID_CW_HSCROLL,
964 ICA_TARGET, ICTARGET_IDCMP,
965 TAG_DONE);
966
967 ami_cw->in_border_scroll = true;
968 }
969
970 if(ami_cw->objects[GID_CW_VSCROLL] == NULL) {
971 GetAttr(WINDOW_VertObject, ami_cw->objects[GID_CW_WIN],
972 (ULONG *)&ami_cw->objects[GID_CW_VSCROLL]);
973
974 RefreshSetGadgetAttrs((APTR)ami_cw->objects[GID_CW_VSCROLL], ami_cw->win, NULL,
975 GA_ID, GID_CW_VSCROLL,
976 ICA_TARGET, ICTARGET_IDCMP,
977 TAG_DONE);
978
979 ami_cw->in_border_scroll = true;
980 }
981
982 return NSERROR_OK;
983}
984
985/* exported interface documented in example/corewindow.h */
987{
988 /* remove any pending redraws */
989 ami_schedule(-1, ami_cw_redraw_cb, ami_cw);
992
993 /* destroy the window */
994 ami_cw->win = NULL;
995 DisposeObject(ami_cw->objects[GID_CW_WIN]);
996
997#if 0
998 /* ensure our scrollbars are destroyed */
999 /* it appears these are disposed anyway,
1000 * even if the gadgets are no longer attached to the window */
1001 if(ami_cw->in_border_scroll == false) {
1002 if(ami_cw->scroll_x_visible == false) {
1003 DisposeObject(ami_cw->objects[GID_CW_HSCROLL]);
1004 }
1005 if(ami_cw->scroll_y_visible == false) {
1006 DisposeObject(ami_cw->objects[GID_CW_VSCROLL]);
1007 }
1008 }
1009#endif
1010
1011 /* release off-screen bitmap stuff */
1012 ami_plot_ra_free(ami_cw->gg);
1013
1014 /* free the window title */
1015 ami_utf8_free(ami_cw->wintitle);
1016
1017 /* remove the core window from our window list */
1019
1020 return NSERROR_OK;
1021}
1022
static nserror ami_cw_update_size(struct core_window *cw, int width, int height)
Definition: corewindow.c:840
static void ami_cw_drag_start(struct ami_corewindow *ami_cw, int x, int y)
Drag start.
Definition: corewindow.c:541
static void ami_cw_redraw_rect(struct ami_corewindow *ami_cw, struct rect *r)
Redraw functions.
Definition: corewindow.c:221
static void ami_cw_redraw_cb(void *p)
Definition: corewindow.c:337
static void ami_cw_redraw(struct ami_corewindow *ami_cw, const struct rect *restrict r)
Queue a redraw of a rectangle.
Definition: corewindow.c:352
nserror ami_corewindow_fini(struct ami_corewindow *ami_cw)
finalise elements of Amiga core window.
Definition: corewindow.c:986
static void ami_cw_drag_progress(struct ami_corewindow *ami_cw, int x, int y)
Drag progress.
Definition: corewindow.c:566
static nserror ami_cw_get_scroll(const struct core_window *cw, int *x, int *y)
Definition: corewindow.c:871
static void ami_cw_scroller_top(struct ami_corewindow *ami_cw, ULONG *restrict x, ULONG *restrict y)
Definition: corewindow.c:71
static BOOL ami_cw_event(void *w)
Main event loop for our core window.
Definition: corewindow.c:642
nserror ami_corewindow_init(struct ami_corewindow *ami_cw)
initialise elements of Amiga core window.
Definition: corewindow.c:926
static void ami_cw_drag_end(struct ami_corewindow *ami_cw, int x, int y)
Drag end.
Definition: corewindow.c:587
static void ami_cw_key(struct ami_corewindow *ami_cw, int nskey)
Definition: corewindow.c:190
HOOKF(void, ami_cw_idcmp_hook, Object *, object, struct IntuiMessage *)
Definition: corewindow.c:495
static nserror ami_cw_get_window_dimensions(const struct core_window *cw, int *width, int *height)
Definition: corewindow.c:829
struct core_window_callback_table ami_cw_cb_table
Definition: corewindow.c:916
static bool ami_cw_mouse_pos(struct ami_corewindow *ami_cw, int *restrict x, int *restrict y)
Definition: corewindow.c:157
static bool ami_cw_mouse_moved(struct ami_corewindow *ami_cw, int x, int y, bool click)
check if mouse has moved since position was stored
Definition: corewindow.c:136
static void ami_cw_close(void *w)
Definition: corewindow.c:488
static void ami_cw_simplerefresh(struct ami_corewindow *ami_cw)
Definition: corewindow.c:389
static nserror ami_cw_invalidate_area(struct core_window *cw, const struct rect *r)
callback from core to request an invalidation of a amiga core window area.
Definition: corewindow.c:818
static nserror ami_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
Definition: corewindow.c:908
static nserror ami_cw_set_scroll(struct core_window *cw, int x, int y)
Definition: corewindow.c:885
static void ami_cw_newsize(struct ami_corewindow *ami_cw)
User has resized window.
Definition: corewindow.c:616
static void ami_cw_window_size(struct ami_corewindow *ami_cw, int *width, int *height)
Definition: corewindow.c:91
static void ami_cw_coord_amiga_to_ns(struct ami_corewindow *ami_cw, int *restrict x, int *restrict y)
Convert co-ordinates relative to space.gadget into document co-ordinates.
Definition: corewindow.c:116
static void ami_cw_toggle_scrollbar(struct ami_corewindow *ami_cw, bool vert, bool visible)
Definition: corewindow.c:425
static void ami_cw_redraw_queue(struct ami_corewindow *ami_cw, bool draw)
Draw the deferred rectangles.
Definition: corewindow.c:311
static const struct ami_win_event_table ami_cw_table
Definition: corewindow.c:800
@ GID_CW_VSCROLLLAYOUT
Definition: corewindow.h:38
@ GID_CW_WIN
Definition: corewindow.h:32
@ GID_CW_VSCROLL
Definition: corewindow.h:36
@ GID_CW_DRAW
Definition: corewindow.h:34
@ GID_CW_HSCROLL
Definition: corewindow.h:35
@ GID_CW_HSCROLLLAYOUT
Definition: corewindow.h:37
bool ami_gui_window_update_box_deferred_check(struct MinList *deferred_rects, const struct rect *restrict new_rect, APTR mempool)
Check rect is not already queued for redraw.
Definition: gui.c:5681
int ami_key_to_nskey(ULONG keycode, struct InputEvent *ie)
Definition: gui.c:1704
struct Screen * ami_gui_get_screen(void)
Get a pointer to the screen NetSurf is running on.
Definition: gui.c:403
static struct Screen * scrn
Definition: gui.c:326
nserror ami_gui_win_list_add(void *win, int type, const struct ami_win_event_table *table)
Add a window to the NetSurf window list (to enable event processing)
Definition: gui.c:4668
void * ami_window_at_pointer(int type)
undocumented, or internal, or documented elsewhere
Definition: gui.c:682
nserror ami_gui_get_space_box(Object *obj, struct IBox **bbox)
Compatibility function to get space.gadget render area.
Definition: gui.c:1857
void ami_gui_free_space_box(struct IBox *bbox)
Free any data obtained via ami_gui_get_space_box().
Definition: gui.c:1874
void ami_gui_win_list_remove(void *win)
Remove a window from the NetSurf window list.
Definition: gui.c:4682
int ami_gui_get_quals(Object *win_obj)
Get which qualifier keys are being pressed.
Definition: gui.c:1826
nserror amiga_warn_user(const char *warning, const char *detail)
Warn the user of an event.
Definition: misc.c:79
const struct plotter_table amiplot
Definition: plotters.c:1180
void ami_plot_ra_free(struct gui_globals *gg)
Free a plotter render area.
Definition: plotters.c:258
struct BitMap * ami_plot_ra_get_bitmap(struct gui_globals *gg)
Get a drawing BitMap associated with a render area.
Definition: plotters.c:295
void ami_plot_ra_get_size(struct gui_globals *gg, int *width, int *height)
Get size of BitMap associated with a render area.
Definition: plotters.c:300
void ami_clearclipreg(struct gui_globals *gg)
Definition: plotters.c:311
struct gui_globals * ami_plot_ra_alloc(ULONG width, ULONG height, bool force32bit, bool alloc_pen_list)
Alloc a plotter render area.
Definition: plotters.c:113
nserror ami_schedule(int t, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: schedule.c:331
STATIC char result[100]
Definition: arexx.c:77
core_window_drag_status
drag status passed to drag_status callback
Definition: core_window.h:41
@ CORE_WINDOW_DRAG_NONE
Definition: core_window.h:42
@ CORE_WINDOW_DRAG_MOVE
Definition: core_window.h:45
@ CORE_WINDOW_DRAG_SELECTION
Definition: core_window.h:43
void ami_drag_icon_show(struct Window *win, const char *type)
Definition: drag.c:311
bool ami_drag_icon_move(void)
Definition: drag.c:319
void ami_drag_icon_close(struct Window *win)
Definition: drag.c:315
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
struct MinList * NewObjList(void)
Definition: object.c:71
void FreeObjList(struct MinList *objlist)
Definition: object.c:117
struct nsObject * AddObject(struct MinList *objlist, ULONG otype)
Definition: object.c:77
void DelObjectNoFree(struct nsObject *dtzo)
Definition: object.c:112
@ AMINS_RECT
Definition: object.h:39
@ AMINS_COREWINDOW
Definition: object.h:36
void ami_utf8_free(char *ptr)
Definition: utf8.c:104
Core mouse and pointer states.
@ BROWSER_MOUSE_PRESS_1
button 1 pressed
Definition: mouse.h:50
@ BROWSER_MOUSE_CLICK_2
button 2 clicked.
Definition: mouse.h:57
@ BROWSER_MOUSE_PRESS_2
button 2 pressed
Definition: mouse.h:52
@ BROWSER_MOUSE_HOVER
No mouse buttons pressed, May be used to indicate hover or end of drag.
Definition: mouse.h:47
@ BROWSER_MOUSE_CLICK_1
button 1 clicked.
Definition: mouse.h:55
@ BROWSER_MOUSE_DOUBLE_CLICK
button double clicked
Definition: mouse.h:60
@ BROWSER_MOUSE_DRAG_1
start of button 1 drag
Definition: mouse.h:65
@ BROWSER_MOUSE_HOLDING_2
during button 2 drag
Definition: mouse.h:75
@ BROWSER_MOUSE_HOLDING_1
during button 1 drag
Definition: mouse.h:73
@ BROWSER_MOUSE_DRAG_ON
a drag operation was started and a mouse button is still pressed
Definition: mouse.h:70
@ BROWSER_MOUSE_DRAG_2
start of button 2 drag
Definition: mouse.h:67
Interface to key press operations.
@ NS_KEY_COPY_SELECTION
Definition: keypress.h:33
@ NS_KEY_CLEAR_SELECTION
Definition: keypress.h:45
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
#define ami_memory_itempool_create(s)
Definition: memory.h:54
#define ami_memory_itempool_alloc(p, s)
Definition: memory.h:56
#define ami_memory_itempool_free(p, i, s)
Definition: memory.h:57
#define ami_memory_itempool_delete(p)
Definition: memory.h:55
Localised message support (interface).
struct Node * GetHead(struct List *list)
Definition: os3support.c:364
ULONG RefreshSetGadgetAttrs(struct Gadget *g, struct Window *w, struct Requester *r, Tag tag1,...)
Definition: os3support.c:429
struct Node * GetSucc(struct Node *node)
Definition: os3support.c:381
Minimal compatibility header for AmigaOS 3.
#define IDoMethod
Definition: os3support.h:169
#define IDCMP_EXTENDEDMOUSE
Definition: os3support.h:121
int16_t int16
Definition: os3support.h:181
uint16_t uint16
Definition: os3support.h:182
#define IsMinListEmpty(L)
Definition: os3support.h:54
plotter style interfaces, generic styles and style colour helpers.
int width
Definition: gui.c:159
int height
Definition: gui.c:160
Interface to utility string handling.
Amiga core window state.
Definition: corewindow.h:45
bool scroll_y_visible
Definition: corewindow.h:73
void(* close)(struct ami_corewindow *ami_cw)
callback to close an Amiga core window
Definition: corewindow.h:165
Object * objects[GID_CW_LAST]
Definition: corewindow.h:52
struct core_window_callback_table * cb_table
table of callbacks for core window operations
Definition: corewindow.h:86
bool close_window
Definition: corewindow.h:65
nserror(* mouse)(struct ami_corewindow *ami_cw, browser_mouse_state mouse_state, int x, int y)
callback for mouse event on Amiga core window
Definition: corewindow.h:121
nserror(* draw)(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx)
callback to draw on drawable area of Amiga core window
Definition: corewindow.h:98
struct ami_generic_window w
Definition: corewindow.h:50
APTR deferred_rects_pool
Definition: corewindow.h:67
struct timeval lastclick
Definition: corewindow.h:55
nserror(* key)(struct ami_corewindow *ami_cw, uint32_t nskey)
callback for keypress on Amiga core window
Definition: corewindow.h:110
struct MinList * deferred_rects
Definition: corewindow.h:68
bool in_border_scroll
keep track of the scrollbar type we're using
Definition: corewindow.h:71
struct Window * win
Definition: corewindow.h:51
BOOL(* event)(struct ami_corewindow *ami_cw, ULONG result)
callback for unknown events on Amiga core window eg.
Definition: corewindow.h:133
core_window_drag_status drag_status
drag status set by core
Definition: corewindow.h:83
nserror(* drag_end)(struct ami_corewindow *ami_cw, int x, int y)
callback for drag end on Amiga core window ie.
Definition: corewindow.h:144
bool scroll_x_visible
Definition: corewindow.h:72
struct gui_globals * gg
stuff for our off-screen render bitmap
Definition: corewindow.h:79
struct Hook idcmp_hook
Definition: corewindow.h:54
char * wintitle
window title, must be allocated wth ami_utf8 function
Definition: corewindow.h:76
Callbacks to achieve various core window functionality.
Definition: core_window.h:51
nserror(* invalidate)(struct core_window *cw, const struct rect *rect)
Invalidate an area of a window.
Definition: core_window.h:69
void * objstruct
Definition: object.h:46
Rectangle coordinates.
Definition: types.h:40
int x0
Definition: types.h:41
int y0
Top left.
Definition: types.h:41
int x1
Definition: types.h:42
int y1
Bottom right.
Definition: types.h:42
Redraw context.
Definition: plotters.h:51
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
struct rect rect
Rectangle coordinates.
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.