1 /*
2  * Copyright 2005 Richard Wilson <info@tinct.net>
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  * RISC OS option setting (implementation).
22  */
23 
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <oslib/os.h>
30 #include <oslib/osbyte.h>
31 #include <oslib/territory.h>
32 #include <oslib/wimp.h>
33 
34 #include "utils/log.h"
35 #include "utils/messages.h"
36 
37 #include "riscos/gui.h"
38 #include "riscos/dialog.h"
39 #include "riscos/configure.h"
40 #include "riscos/wimp.h"
41 #include "riscos/wimp_event.h"
42 #include "riscos/configure/configure.h"
43 
44 #define CONFIGURE_ICON_PADDING_H 32
45 #define CONFIGURE_ICON_PADDING_V 32
46 #define CONFIGURE_DEFAULT_ICON_WIDTH (68 + CONFIGURE_ICON_PADDING_H)
47 #define CONFIGURE_DEFAULT_ICON_HEIGHT (128 + CONFIGURE_ICON_PADDING_V)
48 
49 struct configure_tool {
50 	const char *name;
51 #define CONFIGURE_TOOL_TRANSLATED_SIZE 64
52 	char translated[CONFIGURE_TOOL_TRANSLATED_SIZE];
53 	char *validation;
54 	bool (*initialise)(wimp_w w);
55 	void (*finalise)(wimp_w w);
56 	wimp_w w;
57 	wimp_i i;
58 	bool open;
59 	struct configure_tool *next;
60 };
61 
62 static wimp_w configure_window;
63 static int configure_current_encoding;
64 static int configure_icons = 0;
65 static struct configure_tool *configure_tools = NULL;
66 static int configure_icon_width = CONFIGURE_DEFAULT_ICON_WIDTH;
67 static int configure_icon_height = CONFIGURE_DEFAULT_ICON_HEIGHT;
68 static int configure_icons_per_line = 0;
69 static int configure_width;
70 static int configure_height;
71 
72 static bool ro_gui_configure_click(wimp_pointer *pointer);
73 static void ro_gui_configure_open_window(wimp_open *open);
74 static void ro_gui_configure_close(wimp_w w);
75 static bool ro_gui_configure_translate(void);
76 static void ro_gui_configure_register(const char *window,
77 		bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w));
78 
ro_gui_configure_initialise(void)79 void ro_gui_configure_initialise(void)
80 {
81 	/* create our window */
82 	configure_window = ro_gui_dialog_create("configure");
83 	ro_gui_wimp_event_register_open_window(configure_window,
84 			ro_gui_configure_open_window);
85 	ro_gui_wimp_event_register_mouse_click(configure_window,
86 			ro_gui_configure_click);
87 	ro_gui_wimp_event_set_help_prefix(configure_window, "HelpConfigure");
88 
89 	/* add in our option windows */
90 	ro_gui_configure_register("con_cache",
91 			ro_gui_options_cache_initialise,
92 			ro_gui_wimp_event_finalise);
93 	ro_gui_configure_register("con_connect",
94 			ro_gui_options_connection_initialise,
95 			ro_gui_wimp_event_finalise);
96 	ro_gui_configure_register("con_content",
97 			ro_gui_options_content_initialise,
98 			ro_gui_wimp_event_finalise);
99 	ro_gui_configure_register("con_fonts",
100 			ro_gui_options_fonts_initialise,
101 			ro_gui_wimp_event_finalise);
102 	ro_gui_configure_register("con_home",
103 			ro_gui_options_home_initialise,
104 			ro_gui_wimp_event_finalise);
105 	ro_gui_configure_register("con_image",
106 			ro_gui_options_image_initialise,
107 			ro_gui_options_image_finalise);
108 	ro_gui_configure_register("con_inter",
109 			ro_gui_options_interface_initialise,
110 			ro_gui_wimp_event_finalise);
111 	ro_gui_configure_register("con_lang",
112 			ro_gui_options_language_initialise,
113 			ro_gui_wimp_event_finalise);
114 	ro_gui_configure_register("con_theme",
115 			ro_gui_options_theme_initialise,
116 			ro_gui_options_theme_finalise);
117 	ro_gui_configure_register("con_secure",
118 			ro_gui_options_security_initialise,
119 			ro_gui_wimp_event_finalise);
120 
121 	/* translate the icons */
122 	if (!ro_gui_configure_translate())
123 		die("ro_gui_configure_translate failed");
124 }
125 
ro_gui_configure_show(void)126 void ro_gui_configure_show(void)
127 {
128 	int width, height;
129 
130 	width = configure_icon_width << 2;
131 	height = ((configure_icons + 3) >> 2) * configure_icon_height;
132 	ro_gui_dialog_open_top(configure_window, NULL, width, height);
133 }
134 
ro_gui_configure_click(wimp_pointer * pointer)135 bool ro_gui_configure_click(wimp_pointer *pointer)
136 {
137 	struct configure_tool *tool;
138 
139 	if (pointer->buttons == wimp_CLICK_MENU)
140 		return true;
141 
142 	for (tool = configure_tools; tool; tool = tool->next) {
143 		if (tool->i == pointer->i) {
144 			if (!tool->open) {
145 				tool->open = true;
146 				if (!tool->initialise(tool->w))
147 					return false;
148 				ro_gui_dialog_open_persistent(
149 						configure_window,
150 						tool->w, true);
151 				ro_gui_wimp_event_register_close_window(
152 						tool->w,
153 						ro_gui_configure_close);
154 			} else {
155 				ro_gui_dialog_open_top(tool->w, NULL, 0, 0);
156 			}
157 			break;
158 		}
159 	}
160 	return true;
161 }
162 
ro_gui_configure_close(wimp_w w)163 void ro_gui_configure_close(wimp_w w)
164 {
165 	struct configure_tool *tool;
166 
167 	for (tool = configure_tools; tool; tool = tool->next) {
168 		if (tool->w == w) {
169 			tool->open = false;
170 			if (tool->finalise)
171 				tool->finalise(w);
172 			break;
173 		}
174 	}
175 }
176 
ro_gui_configure_open_window(wimp_open * open)177 void ro_gui_configure_open_window(wimp_open *open)
178 {
179 	os_error *error;
180 	int screen_width, screen_height;
181 	int height, width;
182 	int icons_per_line, icon_lines;
183 	int max_height;
184 	os_box extent = { 0, 0, 0, 0 };
185 	struct configure_tool *tool;
186 
187 	if (!ro_gui_configure_translate()) {
188 		ro_warn_user("ro_gui_configure_translate failed", 0);
189 		return;
190 	}
191 
192 	width = open->visible.x1 - open->visible.x0;
193 	height = open->visible.y1 - open->visible.y0;
194 	icons_per_line = width / configure_icon_width;
195 	if (icons_per_line < 1)
196 		icons_per_line = 1;
197 
198 	/* move our icons */
199 	if (icons_per_line != configure_icons_per_line) {
200 		int x, y, l;
201 		configure_icons_per_line = icons_per_line;
202 		x = CONFIGURE_ICON_PADDING_H / 2;
203 		y = -configure_icon_height + (CONFIGURE_ICON_PADDING_V / 2);
204 		l = 0;
205 		for (tool = configure_tools; tool; tool = tool->next) {
206 			error = xwimp_resize_icon(configure_window,
207 				tool->i,
208 				x,
209 				y,
210 				x + configure_icon_width -
211 						CONFIGURE_ICON_PADDING_H,
212 				y + configure_icon_height -
213 						CONFIGURE_ICON_PADDING_V);
214 			if (error) {
215 				NSLOG(netsurf, INFO,
216 				      "xwimp_resize_icon: 0x%x: %s",
217 				      error->errnum,
218 				      error->errmess);
219 			}
220 			x += configure_icon_width;
221 			l++;
222 			if (l >= icons_per_line) {
223 				x = CONFIGURE_ICON_PADDING_H / 2;
224 				l = 0;
225 				y -= configure_icon_height;
226                         }
227 		}
228 		error = xwimp_force_redraw(configure_window,
229 				0, -16384, 16384, 0);
230 		if (error) {
231 			NSLOG(netsurf, INFO, "xwimp_force_redraw: 0x%x: %s",
232 			      error->errnum, error->errmess);
233 			ro_warn_user("WimpError", error->errmess);
234 		}
235 	}
236 
237 	/* restrict our height */
238 	icon_lines = (configure_icons + icons_per_line - 1) /
239 			icons_per_line;
240 	max_height = (icon_lines * configure_icon_height);
241 	if (height > max_height)
242 		open->visible.y0 = open->visible.y1 - max_height;
243 
244 	/* set the extent */
245 	if ((configure_height != height) || (configure_width != width)) {
246 		int max_icons_per_line;
247 		ro_gui_screen_size(&screen_width, &screen_height);
248 		max_icons_per_line = screen_width / configure_icon_width;
249 		if (max_icons_per_line > configure_icons)
250 			max_icons_per_line = configure_icons;
251 		extent.x1 = configure_icon_width * max_icons_per_line;
252 		extent.y0 = -max_height;
253 		error = xwimp_set_extent(open->w, &extent);
254 		if (error) {
255 			NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
256 			      error->errnum, error->errmess);
257 			ro_warn_user("WimpError", error->errmess);
258 			return;
259 		}
260 		configure_height = height;
261 		configure_width = width;
262 	}
263 
264 	/* open the window */
265 	error = xwimp_open_window(open);
266 	if (error) {
267 		NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
268 		      error->errnum, error->errmess);
269 		ro_warn_user("WimpError", error->errmess);
270 		return;
271 	}
272 }
273 
ro_gui_configure_register(const char * window,bool (* initialise)(wimp_w w),void (* finalise)(wimp_w w))274 void ro_gui_configure_register(const char *window,
275 		bool (*initialise)(wimp_w w), void (*finalise)(wimp_w w))
276 {
277 	wimp_icon_create new_icon;
278 	struct configure_tool *tool;
279 	struct configure_tool *link;
280 	os_error *error;
281 
282 	/* create our tool */
283 	tool = calloc(sizeof(struct configure_tool), 1);
284 	if (!tool) {
285 		NSLOG(netsurf, INFO, "Insufficient memory for calloc()");
286 		die("Insufficient memory");
287 		return; /* For the benefit of scan-build */
288 	}
289 	tool->name = window;
290 	tool->translated[0] = '\0';
291 	tool->validation = malloc(strlen(window) + 2);
292 	if (!tool->validation) {
293 		NSLOG(netsurf, INFO, "Insufficient memory for malloc()");
294 		die("Insufficient memory");
295 	}
296 	sprintf(tool->validation, "S%s", window);
297 	tool->initialise = initialise;
298 	tool->finalise = finalise;
299 	tool->w = ro_gui_dialog_create(tool->name);
300 
301 	/* create the icon */
302 	new_icon.w = configure_window;
303 	new_icon.icon.extent.x0 = 0;
304 	new_icon.icon.extent.x1 = configure_icon_width;
305 	new_icon.icon.extent.y1 = 0;
306 	new_icon.icon.extent.y0 = -configure_icon_height;
307 	new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE |
308 			wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED |
309 			(wimp_COLOUR_VERY_LIGHT_GREY << wimp_ICON_BG_COLOUR_SHIFT) |
310 			(wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) |
311 			(wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT);
312 	new_icon.icon.data.indirected_text_and_sprite.text =
313 			tool->translated;
314 	new_icon.icon.data.indirected_text_and_sprite.validation =
315 			tool->validation;
316 	new_icon.icon.data.indirected_text_and_sprite.size =
317 			CONFIGURE_TOOL_TRANSLATED_SIZE;
318 	error = xwimp_create_icon(&new_icon, &tool->i);
319 	if (error) {
320 		NSLOG(netsurf, INFO, "xwimp_create_icon: 0x%x: %s",
321 		      error->errnum, error->errmess);
322 		die(error->errmess);
323 	}
324 
325 	/* Set the icon's text in current local encoding */
326 	ro_gui_set_icon_string(configure_window, tool->i,
327 			messages_get(tool->name), true);
328 
329 	/* link into our list alphabetically */
330 	if ((!configure_tools) ||
331 			(strcmp(configure_tools->translated,
332 					tool->translated) > 0)) {
333 		tool->next = configure_tools;
334 		configure_tools = tool;
335 	} else {
336 		for (link = configure_tools; link; link = link->next) {
337 			if (link->next) {
338 				if (strcmp(link->next->translated,
339 						tool->translated) > 0) {
340 					tool->next = link->next;
341 					link->next = tool;
342 					break;
343 				}
344 			} else {
345 				link->next = tool;
346 				break;
347 			}
348 		}
349 	}
350 	configure_icons++;
351 }
352 
353 /**
354  * Translate tool icons into the system local encoding.
355  * This will also recalculate the minimum required icon width.
356  *
357  * \return true on success, false on memory exhaustion
358  */
ro_gui_configure_translate(void)359 bool ro_gui_configure_translate(void)
360 {
361 	int alphabet;
362 	struct configure_tool *tool;
363 	int icon_width;
364 	os_error *error;
365 
366 	/* read current alphabet */
367 	error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0,
368 			&alphabet);
369 	if (error) {
370 		NSLOG(netsurf, INFO, "failed reading alphabet: 0x%x: %s",
371 		      error->errnum, error->errmess);
372 		/* assume Latin1 */
373 		alphabet = territory_ALPHABET_LATIN1;
374 	}
375 
376 	if (alphabet == configure_current_encoding)
377 		/* text is already in the correct encoding */
378 		return true;
379 
380 	/* reset icon width */
381 	configure_icon_width = CONFIGURE_DEFAULT_ICON_WIDTH;
382 
383 	for (tool = configure_tools; tool; tool = tool->next) {
384 		/* re-translate the text */
385 		ro_gui_set_icon_string(configure_window, tool->i,
386 				messages_get(tool->name), true);
387 
388 		/* update the width */
389 		error = xwimptextop_string_width(tool->translated,
390 				strlen(tool->translated), &icon_width);
391 		if (error) {
392 			NSLOG(netsurf, INFO,
393 			      "xwimptextop_string_width: 0x%x: %s",
394 			      error->errnum,
395 			      error->errmess);
396 			return false;
397 		}
398 		icon_width += CONFIGURE_ICON_PADDING_H;
399 		if (icon_width > configure_icon_width)
400 			configure_icon_width = icon_width;
401 
402 		error = xwimp_resize_icon(configure_window,
403 				tool->i,
404 				0,
405 				-configure_icon_height,
406 				configure_icon_width,
407 				0);
408 		if (error) {
409 			NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
410 			      error->errnum, error->errmess);
411 		}
412 	}
413 
414 	/* invalidate our global icons_per_line setting
415 	 * so the icons get reflowed */
416 	configure_icons_per_line = 0;
417 
418 	/* finally, set the current encoding */
419 	configure_current_encoding = alphabet;
420 
421 	return true;
422 }
423