1 /*
2  * Copyright 2020 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 implementation of page info using core windows.
22  */
23 
24 #include <stdint.h>
25 #include <stdlib.h>
26 
27 #include <proto/intuition.h>
28 
29 #include <classes/window.h>
30 #include <gadgets/layout.h>
31 #include <gadgets/scroller.h>
32 #include <gadgets/space.h>
33 #include <images/label.h>
34 
35 #include <intuition/icclass.h>
36 #include <reaction/reaction_macros.h>
37 
38 #include "utils/log.h"
39 #include "netsurf/keypress.h"
40 #include "netsurf/plotters.h"
41 #include "desktop/page-info.h"
42 #include "utils/messages.h"
43 #include "utils/nsoption.h"
44 
45 #include "amiga/corewindow.h"
46 #include "amiga/libs.h"
47 #include "amiga/pageinfo.h"
48 #include "amiga/schedule.h"
49 #include "amiga/utf8.h"
50 
51 
52 /**
53  * Amiga page info window context
54  */
55 struct ami_pageinfo_window {
56 	/** Amiga core window context */
57 	struct ami_corewindow core;
58 	/** core pageinfo */
59 	struct page_info *pi;
60 };
61 
62 /**
63  * destroy a previously created pageinfo window
64  */
65 static void
ami_pageinfo_destroy(struct ami_corewindow * ami_cw)66 ami_pageinfo_destroy(struct ami_corewindow *ami_cw)
67 {
68 	nserror res;
69 	struct ami_pageinfo_window *pageinfo_win = (struct ami_pageinfo_window *)ami_cw;
70 	res = page_info_destroy(pageinfo_win->pi);
71 	if (res == NSERROR_OK) {
72 		ami_corewindow_fini(&pageinfo_win->core); /* closes the window for us */
73 	}
74 }
75 
76 /**
77  * close pageinfo window (callback)
78  */
79 static void
ami_pageinfo_close_cb(void * p)80 ami_pageinfo_close_cb(void *p)
81 {
82 	ami_pageinfo_destroy((struct ami_corewindow *)p);
83 }
84 
85 /**
86  * callback for unknown events on Amiga core window
87  * (result & WMHI_CLASSMASK) gives the class of event (eg. WMHI_GADGETUP)
88  * (result & WMHI_GADGETMASK) gives the gadget ID (eg. GID_SSLCERT_ACCEPT)
89  *
90  * \param ami_cw The Amiga core window structure.
91  * \param result event as returned by RA_HandleInput()
92  * \return TRUE if window closed during event processing
93  */
94 static BOOL
ami_pageinfo_event(struct ami_corewindow * ami_cw,ULONG result)95 ami_pageinfo_event(struct ami_corewindow *ami_cw, ULONG result)
96 {
97 	if((result & WMHI_CLASSMASK) == WMHI_INACTIVE) {
98 		/* Window went inactive, so close it */
99 		ami_pageinfo_destroy(ami_cw);
100 		return TRUE;
101 	}
102 	return FALSE;
103 }
104 
105 /**
106  * callback for mouse action for pageinfo on core window
107  *
108  * \param ami_cw The Amiga core window structure.
109  * \param mouse_state netsurf mouse state on event
110  * \param x location of event
111  * \param y location of event
112  * \return NSERROR_OK on success otherwise apropriate error code
113  */
114 static nserror
ami_pageinfo_mouse(struct ami_corewindow * ami_cw,browser_mouse_state mouse_state,int x,int y)115 ami_pageinfo_mouse(struct ami_corewindow *ami_cw,
116 					browser_mouse_state mouse_state,
117 					int x, int y)
118 {
119 	bool did_something = false;
120 	struct ami_pageinfo_window *pageinfo_win = (struct ami_pageinfo_window *)ami_cw;
121 
122 	if(page_info_mouse_action(pageinfo_win->pi, mouse_state, x, y, &did_something) == NSERROR_OK)
123 		if (did_something == true) {
124 			/* Something happened so we need to close ourselves */
125 			ami_schedule(0, ami_pageinfo_close_cb, pageinfo_win);
126 		}
127 
128 	return NSERROR_OK;
129 }
130 
131 /**
132  * callback for keypress for pageinfo on core window
133  *
134  * \param ami_cw The Amiga core window structure.
135  * \param nskey The netsurf key code
136  * \return NSERROR_OK on success otherwise apropriate error code
137  */
138 static nserror
ami_pageinfo_key(struct ami_corewindow * ami_cw,uint32_t nskey)139 ami_pageinfo_key(struct ami_corewindow *ami_cw, uint32_t nskey)
140 {
141 	struct ami_pageinfo_window *pageinfo_win = (struct ami_pageinfo_window *)ami_cw;
142 
143 	if (page_info_keypress(pageinfo_win->pi, nskey)) {
144 			return NSERROR_OK;
145 	}
146 	return NSERROR_NOT_IMPLEMENTED;
147 }
148 
149 /**
150  * callback on draw event for pageinfo on core window
151  *
152  * \param ami_cw The Amiga core window structure.
153  * \param x the x coordinate to draw
154  * \param y the y coordinate to draw
155  * \param r The rectangle of the window that needs updating.
156  * \param ctx The drawing context
157  * \return NSERROR_OK on success otherwise apropriate error code
158  */
159 static nserror
ami_pageinfo_draw(struct ami_corewindow * ami_cw,int x,int y,struct rect * r,struct redraw_context * ctx)160 ami_pageinfo_draw(struct ami_corewindow *ami_cw, int x, int y, struct rect *r, struct redraw_context *ctx)
161 {
162 	struct ami_pageinfo_window *pageinfo_win = (struct ami_pageinfo_window *)ami_cw;
163 
164 	page_info_redraw(pageinfo_win->pi, x, y, r, ctx);
165 
166 	return NSERROR_OK;
167 }
168 
169 static nserror
ami_pageinfo_create_window(struct ami_pageinfo_window * pageinfo_win,ULONG left,ULONG top)170 ami_pageinfo_create_window(struct ami_pageinfo_window *pageinfo_win, ULONG left, ULONG top)
171 {
172 	struct ami_corewindow *ami_cw = (struct ami_corewindow *)&pageinfo_win->core;
173 	ULONG refresh_mode = WA_SmartRefresh;
174 	struct Screen *scrn = ami_gui_get_screen();
175 
176 	if(nsoption_bool(window_simple_refresh) == true) {
177 		refresh_mode = WA_SimpleRefresh;
178 	}
179 
180 	ami_cw->objects[GID_CW_WIN] = WindowObj,
181   	    WA_ScreenTitle, ami_gui_get_screen_title(),
182        	WA_Activate, TRUE,
183        	WA_DepthGadget, FALSE,
184        	WA_DragBar, FALSE,
185        	WA_CloseGadget, FALSE,
186        	WA_SizeGadget, FALSE,
187        	WA_Borderless, TRUE,
188 		WA_Left, left,
189 		WA_Top, top,
190 		WA_PubScreen, scrn,
191 		WA_ReportMouse, TRUE,
192 		refresh_mode, TRUE,
193 		WA_IDCMP, IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
194 				IDCMP_RAWKEY | IDCMP_IDCMPUPDATE | IDCMP_INACTIVEWINDOW |
195 				IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW,
196 		WINDOW_IDCMPHook, &ami_cw->idcmp_hook,
197 		WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE |
198 				IDCMP_SIZEVERIFY | IDCMP_REFRESHWINDOW,
199 		WINDOW_SharedPort, ami_gui_get_shared_msgport(),
200 		WINDOW_UserData, pageinfo_win,
201 		WINDOW_IconifyGadget, FALSE,
202 		WINDOW_ParentGroup, ami_cw->objects[GID_CW_MAIN] = LayoutVObj,
203 			LAYOUT_AddChild, ami_cw->objects[GID_CW_DRAW] = SpaceObj,
204 				GA_ID, GID_CW_DRAW,
205 				SPACE_Transparent, TRUE,
206 				SPACE_BevelStyle, BVS_BOX,
207 				GA_RelVerify, TRUE,
208    			SpaceEnd,
209 		EndGroup,
210 	EndWindow;
211 
212 	if(ami_cw->objects[GID_CW_WIN] == NULL) {
213 		return NSERROR_NOMEM;
214 	}
215 
216 	return NSERROR_OK;
217 }
218 
219 /* exported interface documented in amiga/pageinfo.h */
ami_pageinfo_open(struct browser_window * bw,ULONG left,ULONG top)220 nserror ami_pageinfo_open(struct browser_window *bw, ULONG left, ULONG top)
221 {
222 	struct ami_pageinfo_window *ncwin;
223 	nserror res;
224 	int width, height;
225 
226 	ncwin = calloc(1, sizeof(struct ami_pageinfo_window));
227 	if (ncwin == NULL) {
228 		return NSERROR_NOMEM;
229 	}
230 
231 	ncwin->core.wintitle = ami_utf8_easy((char *)messages_get("PageInfo"));
232 
233 	res = ami_pageinfo_create_window(ncwin, left, top);
234 	if (res != NSERROR_OK) {
235 		NSLOG(netsurf, INFO, "Page info init failed");
236 		ami_utf8_free(ncwin->core.wintitle);
237 		free(ncwin);
238 		return res;
239 	}
240 
241 	/* initialise Amiga core window */
242 	ncwin->core.draw = ami_pageinfo_draw;
243 	ncwin->core.key = ami_pageinfo_key;
244 	ncwin->core.mouse = ami_pageinfo_mouse;
245 	ncwin->core.close = ami_pageinfo_destroy;
246 	ncwin->core.event = ami_pageinfo_event;
247 
248 	res = ami_corewindow_init(&ncwin->core);
249 	if (res != NSERROR_OK) {
250 		ami_utf8_free(ncwin->core.wintitle);
251 		DisposeObject(ncwin->core.objects[GID_CW_WIN]);
252 		free(ncwin);
253 		return res;
254 	}
255 
256 	res = page_info_create(ncwin->core.cb_table,
257 					  (struct core_window *)ncwin,
258 					  bw,
259 					  &ncwin->pi);
260 
261 	if (res != NSERROR_OK) {
262 		ami_utf8_free(ncwin->core.wintitle);
263 		DisposeObject(ncwin->core.objects[GID_CW_WIN]);
264 		free(ncwin);
265 		return res;
266 	}
267 
268 	if(page_info_get_size(ncwin->pi, &width, &height) == NSERROR_OK) {
269 		/* Set window to the correct size.
270 		 * TODO: this should really set the size of ncwin->core.objects[GID_CW_DRAW]
271 		 * and let the window adjust, here we've hardcoded to add 6x4px as that's
272 		 * what window.class does before v45.
273 		 */
274 		SetAttrs(ncwin->core.objects[GID_CW_WIN], WA_InnerWidth, width + 6, WA_InnerHeight, height + 4, TAG_DONE);
275 	}
276 
277 	return NSERROR_OK;
278 }
279 
280