NetSurf
query.c
Go to the documentation of this file.
1/*
2 * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.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#include <stdlib.h>
20#include <string.h>
21#include <stdbool.h>
22
23#include "utils/log.h"
24#include "utils/messages.h"
25#include "utils/utf8.h"
26#include "utils/utils.h"
27
28#include "riscos/gui.h"
29#include "riscos/query.h"
30#include "riscos/wimp.h"
31#include "riscos/wimp_event.h"
32#include "riscos/ucstables.h"
33#include "riscos/dialog.h"
34
35#define ICON_QUERY_MESSAGE 0
36#define ICON_QUERY_YES 1
37#define ICON_QUERY_NO 2
38#define ICON_QUERY_HELP 3
39
40/** Data for a query window */
42{
43 struct gui_query_window *prev; /** Previous query in list */
44 struct gui_query_window *next; /** Next query in list */
45
46 query_id id; /** unique ID number for this query */
47 wimp_w window; /** RISC OS window handle */
48
49 const query_callback *cb; /** Table of callback functions */
50 void *pw; /** Handle passed to callback functions */
51
52 bool default_confirm; /** Default action is to confirm */
53};
54
55
56/** Next unallocated query id */
58
59/** List of all query windows. */
61
62/** Template for a query window. */
63static struct wimp_window *query_template;
64
65/** Widths of Yes and No buttons */
66static int query_yes_width = 0;
67static int query_no_width = 0;
68
70
71static bool ro_gui_query_click(wimp_pointer *pointer);
72static void ro_gui_query_close(wimp_w w);
73static bool ro_gui_query_apply(wimp_w w);
74
75
77{
79}
80
81
82/**
83 * Lookup a query window using its ID number
84 *
85 * \param id id to search for
86 * \return pointer to query window or NULL
87 */
88
90{
92 while (qw && qw->id != id)
93 qw = qw->next;
94 return qw;
95}
96
97
98/**
99 * Display a query to the user, requesting a response, near the current
100 * pointer position to keep the required mouse travel small, but also
101 * protecting against spurious mouse clicks.
102 *
103 * \param query message token of query
104 * \param detail parameter used in expanding tokenised message
105 * \param cb table of callback functions to be called when user responds
106 * \param pw handle to be passed to callback functions
107 * \param yes text to use for 'Yes' button' (or NULL for default)
108 * \param no text to use for 'No' button (or NULL for default)
109 * \return id number of the query (or QUERY_INVALID if it failed)
110 */
111
112query_id query_user(const char *query, const char *detail,
113 const query_callback *cb, void *pw,
114 const char *yes, const char *no)
115{
116 wimp_pointer pointer;
117 if (xwimp_get_pointer_info(&pointer))
118 pointer.pos.y = pointer.pos.x = -1;
119
120 return query_user_xy(query, detail, cb, pw, yes, no,
121 pointer.pos.x, pointer.pos.y);
122}
123
124
125/**
126 * Display a query to the user, requesting a response, at a specified
127 * screen position (x,y). The window is positioned relative to the given
128 * location such that the required mouse travel is small, but non-zero
129 * for protection spurious double-clicks.
130 *
131 * \param query message token of query
132 * \param detail parameter used in expanding tokenised message
133 * \param cb table of callback functions to be called when user responds
134 * \param pw handle to be passed to callback functions
135 * \param yes text to use for 'Yes' button' (or NULL for default)
136 * \param no text to use for 'No' button (or NULL for default)
137 * \param x x position in screen coordinates (-1 = centred on screen)
138 * \param y y position in screen coordinates (-1 = centred on screen)
139 * \return id number of the query (or QUERY_INVALID if it failed)
140 */
141
142query_id query_user_xy(const char *query, const char *detail,
143 const query_callback *cb, void *pw,
144 const char *yes, const char *no,
145 int x, int y)
146{
147 struct gui_query_window *qw;
148 char query_buffer[300];
149 os_error *error;
150 wimp_icon *icn;
151 int width;
152 int len;
153 int tx;
154 char *local_text = NULL;
155 nserror err;
156
157 qw = malloc(sizeof(struct gui_query_window));
158 if (!qw) {
159 ro_warn_user("NoMemory", NULL);
160 return QUERY_INVALID;
161 }
162
163 qw->cb = cb;
164 qw->pw = pw;
165 qw->id = next_id++;
166 qw->default_confirm = false;
167
168 if (next_id == QUERY_INVALID)
169 next_id++;
170
171 if (!yes) yes = messages_get("Yes");
172 if (!no) no = messages_get("No");
173
174 /* set the text of the 'Yes' button and size accordingly */
175 err = utf8_to_local_encoding(yes, 0, &local_text);
176 if (err != NSERROR_OK) {
177 assert(err != NSERROR_BAD_ENCODING);
178 NSLOG(netsurf, INFO, "utf8_to_local_encoding_failed");
179 local_text = NULL;
180 }
181
182 icn = &query_template->icons[ICON_QUERY_YES];
183 len = strlen(local_text ? local_text : yes);
184 len = max(len, icn->data.indirected_text.size - 1);
185 memcpy(icn->data.indirected_text.text,
186 local_text ? local_text: yes, len);
187 icn->data.indirected_text.text[len] = '\0';
188
189 free(local_text);
190 local_text = NULL;
191
192 error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
193 if (error) {
194 NSLOG(netsurf, INFO, "xwimptextop_string_width: 0x%x:%s",
195 error->errnum, error->errmess);
196 width = len * 16;
197 }
198 if (!query_yes_width) query_yes_width = icn->extent.x1 - icn->extent.x0;
199 width += 44;
202 icn->extent.x0 = tx = icn->extent.x1 - width;
203
204 /* set the text of the 'No' button and size accordingly */
205 err = utf8_to_local_encoding(no, 0, &local_text);
206 if (err != NSERROR_OK) {
207 assert(err != NSERROR_BAD_ENCODING);
208 NSLOG(netsurf, INFO, "utf8_to_local_encoding_failed");
209 local_text = NULL;
210 }
211
212 icn = &query_template->icons[ICON_QUERY_NO];
213 len = strlen(local_text ? local_text : no);
214 len = max(len, icn->data.indirected_text.size - 1);
215 memcpy(icn->data.indirected_text.text,
216 local_text ? local_text : no, len);
217 icn->data.indirected_text.text[len] = '\0';
218
219 free(local_text);
220 local_text = NULL;
221
222 if (!query_no_width) query_no_width = icn->extent.x1 - icn->extent.x0;
223 icn->extent.x1 = tx - 16;
224 error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width);
225 if (error) {
226 NSLOG(netsurf, INFO, "xwimptextop_string_width: 0x%x:%s",
227 error->errnum, error->errmess);
228 width = len * 16;
229 }
230 width += 28;
231 if (width < query_no_width)
233 icn->extent.x0 = icn->extent.x1 - width;
234
235 error = xwimp_create_window(query_template, &qw->window);
236 if (error) {
237 ro_warn_user("WimpError", error->errmess);
238 free(qw);
239 return QUERY_INVALID;
240 }
241
242 snprintf(query_buffer, sizeof query_buffer, "%s %s",
243 messages_get(query), detail ? detail : "");
244 query_buffer[sizeof query_buffer - 1] = 0;
245
247 query_buffer, true);
248
249 xwimp_set_icon_state(qw->window, ICON_QUERY_HELP,
250 wimp_ICON_DELETED, wimp_ICON_DELETED);
251
252 if (x >= 0 && y >= 0) {
253 x -= tx - 8;
254 y += (query_template->visible.y1 - query_template->visible.y0) / 2;
255 ro_gui_dialog_open_xy(qw->window, x, y);
256 }
257 else
259
265
266 error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
267 if (error) {
268 NSLOG(netsurf, INFO, "xwimp_get_caret_position: 0x%x : %s",
269 error->errnum, error->errmess);
270 ro_warn_user("WimpError", error->errmess);
271 }
272
273 /* put this query window at the head of our list */
276
277 qw->prev = NULL;
280
281 return qw->id;
282}
283
284
285/**
286 * Close a query window without waiting for a response from the user.
287 * (should normally only be called if the user has responded in some other
288 * way of which the query window in unaware.)
289 *
290 * \param id id of query window to close
291 */
292
294{
296 if (!qw)
297 return;
299
300}
301
302
304{
306 if (qw) {
307 os_error *error;
308
310
311 error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1);
312 if (error) {
313 NSLOG(netsurf, INFO,
314 "xwimp_get_caret_position: 0x%x : %s",
315 error->errnum,
316 error->errmess);
317 ro_warn_user("WimpError", error->errmess);
318 }
319 }
320}
321
322
323/**
324 * Handle closing of query dialog
325 */
326void ro_gui_query_close(wimp_w w)
327{
328 struct gui_query_window *qw;
329 os_error *error;
330
332
334 error = xwimp_delete_window(qw->window);
335 if (error) {
336 NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
337 error->errnum, error->errmess);
338 ro_warn_user("WimpError", error->errmess);
339 }
341
342 /* remove from linked-list of query windows and release memory */
343 if (qw->prev)
344 qw->prev->next = qw->next;
345 else
347
348 if (qw->next)
349 qw->next->prev = qw->prev;
350 free(qw);
351}
352
353
354/**
355 * Handle acceptance of query dialog
356 */
357bool ro_gui_query_apply(wimp_w w)
358{
359 struct gui_query_window *qw;
360 const query_callback *cb;
361
363 cb = qw->cb;
364 cb->confirm(qw->id, QUERY_YES, qw->pw);
365 return true;
366}
367
368
369/**
370 * Handle clicks in query dialog
371 */
372bool ro_gui_query_click(wimp_pointer *pointer)
373{
374 struct gui_query_window *qw;
375 const query_callback *cb;
376
377 qw = (struct gui_query_window *)ro_gui_wimp_event_get_user_data(pointer->w);
378 cb = qw->cb;
379
380 switch (pointer->i) {
381 case ICON_QUERY_NO:
382 cb->cancel(qw->id, QUERY_NO, qw->pw);
383 break;
384 default:
385 return false;
386 }
387 return false;
388}
wimp_window * ro_gui_dialog_load_template(const char *template_name)
Load a template without creating a window.
Definition: dialog.c:242
void ro_gui_dialog_open(wimp_w w)
Open a dialog box, centred on the screen.
Definition: dialog.c:297
void ro_gui_dialog_close(wimp_w close)
Close a dialog box.
Definition: dialog.c:335
void ro_gui_dialog_open_xy(wimp_w w, int x, int y)
Open window at a specified location.
Definition: dialog.c:487
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_BAD_ENCODING
The character set is unknown.
Definition: errors.h:45
@ NSERROR_OK
No error.
Definition: errors.h:30
nserror utf8_to_local_encoding(const char *string, size_t len, char **result)
Definition: utf8.c:89
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
#define ICON_QUERY_NO
Definition: query.c:37
#define ICON_QUERY_HELP
Definition: query.c:38
static int query_yes_width
Widths of Yes and No buttons.
Definition: query.c:66
void ro_gui_query_init(void)
Definition: query.c:76
static struct gui_query_window * gui_query_window_list
List of all query windows.
Definition: query.c:60
static bool ro_gui_query_click(wimp_pointer *pointer)
Handle clicks in query dialog.
Definition: query.c:372
void ro_gui_query_window_bring_to_front(query_id id)
Definition: query.c:303
#define ICON_QUERY_MESSAGE
Definition: query.c:35
void query_close(query_id id)
Close a query window without waiting for a response from the user.
Definition: query.c:293
static bool ro_gui_query_apply(wimp_w w)
Handle acceptance of query dialog.
Definition: query.c:357
static struct gui_query_window * ro_gui_query_window_lookup_id(query_id id)
Lookup a query window using its ID number.
Definition: query.c:89
#define ICON_QUERY_YES
Definition: query.c:36
query_id query_user_xy(const char *query, const char *detail, const query_callback *cb, void *pw, const char *yes, const char *no, int x, int y)
Display a query to the user, requesting a response, at a specified screen position (x,...
Definition: query.c:142
static query_id next_id
Next unallocated query id.
Definition: query.c:57
static void ro_gui_query_close(wimp_w w)
Handle closing of query dialog.
Definition: query.c:326
static int query_no_width
Definition: query.c:67
static struct wimp_window * query_template
Template for a query window.
Definition: query.c:63
query_id query_user(const char *query, const char *detail, const query_callback *cb, void *pw, const char *yes, const char *no)
Display a query to the user, requesting a response, near the current pointer position to keep the req...
Definition: query.c:112
@ QUERY_YES
Definition: query.h:27
@ QUERY_NO
Definition: query.h:28
#define QUERY_INVALID
Definition: query.h:34
int query_id
Definition: query.h:32
int width
Definition: gui.c:159
nserror ro_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.c:2076
Interface to utility string handling.
Data for a query window.
Definition: query.c:42
wimp_w window
unique ID number for this query
Definition: query.c:47
void * pw
Table of callback functions.
Definition: query.c:50
query_id id
Next query in list.
Definition: query.c:46
struct gui_query_window * next
Previous query in list.
Definition: query.c:44
const query_callback * cb
RISC OS window handle.
Definition: query.c:49
bool default_confirm
Handle passed to callback functions.
Definition: query.c:52
struct gui_query_window * prev
Definition: query.c:43
void(* cancel)(query_id, enum query_response res, void *pw)
Definition: query.h:39
void(* confirm)(query_id id, enum query_response res, void *pw)
Definition: query.h:38
UCS conversion tables (interface) This is only used if nothing claims Service_International,...
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.
#define max(x, y)
Definition: utils.h:50
void ro_gui_set_icon_string(wimp_w w, wimp_i i, const char *text, bool is_utf8)
Set the contents of a text or sprite icon to a string.
Definition: wimp.c:269
General RISC OS WIMP/OS library functions (interface).
void ro_gui_wimp_event_finalise(wimp_w w)
Free any resources associated with a window.
Definition: wimp_event.c:296
void * ro_gui_wimp_event_get_user_data(wimp_w w)
Gets the user data associated with a window.
Definition: wimp_event.c:486
bool ro_gui_wimp_event_register_cancel(wimp_w w, wimp_i i)
Register a function to be called for the Cancel action on a window.
Definition: wimp_event.c:1403
bool ro_gui_wimp_event_register_mouse_click(wimp_w w, bool(*callback)(wimp_pointer *pointer))
Register a function to be called for all mouse-clicks to icons in a window that don't have registered...
Definition: wimp_event.c:1439
bool ro_gui_wimp_event_set_user_data(wimp_w w, void *user)
Sets the user data associated with a window.
Definition: wimp_event.c:467
bool ro_gui_wimp_event_register_ok(wimp_w w, wimp_i i, bool(*callback)(wimp_w w))
Register a function to be called for the OK action on a window.
Definition: wimp_event.c:1417
bool ro_gui_wimp_event_register_close_window(wimp_w w, void(*callback)(wimp_w w))
Register a function to be called after the window has been closed.
Definition: wimp_event.c:1492
Automated RISC OS WIMP event handling (interface).