1 /*
2  * Copyright 2006 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 /** \file
20  * UTF8 status bar (implementation).
21  */
22 
23 #include <assert.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include "swis.h"
27 #include "oslib/colourtrans.h"
28 #include "oslib/os.h"
29 #include "oslib/wimp.h"
30 #include "oslib/wimpspriteop.h"
31 
32 #include "utils/log.h"
33 #include "utils/utils.h"
34 #include "netsurf/plotters.h"
35 
36 #include "riscos/gui.h"
37 #include "riscos/wimp.h"
38 #include "riscos/wimp_event.h"
39 #include "riscos/wimputils.h"
40 #include "riscos/font.h"
41 #include "riscos/gui/progress_bar.h"
42 #include "riscos/gui/status_bar.h"
43 
44 #define ICON_WIDGET 0
45 #define WIDGET_WIDTH 12
46 #define PROGRESS_WIDTH 160
47 
48 struct status_bar {
49 	wimp_w w;			/**< status bar window handle */
50 	wimp_w parent;			/**< parent window handle */
51 	const char *text;		/**< status bar text */
52 	struct progress_bar *pb;	/**< progress bar */
53 	unsigned int scale;		/**< current status bar scale */
54 	int width;			/**< current status bar width */
55 	bool visible;			/**< status bar is visible? */
56 };
57 
58 static char status_widget_text[] = "";
59 static char status_widget_validation[] = "R5;Pptr_lr,8,6";
60 
61 wimp_WINDOW(1) status_bar_definition = {
62 	{0, 0, 1, 1},
63 	0,
64 	0,
65 	wimp_TOP,
66 	wimp_WINDOW_NEW_FORMAT | wimp_WINDOW_MOVEABLE |
67 			wimp_WINDOW_FURNITURE_WINDOW |
68 			wimp_WINDOW_IGNORE_XEXTENT,
69 	wimp_COLOUR_BLACK,
70 	wimp_COLOUR_LIGHT_GREY,
71 	wimp_COLOUR_LIGHT_GREY,
72 	wimp_COLOUR_VERY_LIGHT_GREY,
73 	wimp_COLOUR_DARK_GREY,
74 	wimp_COLOUR_MID_LIGHT_GREY,
75 	wimp_COLOUR_CREAM,
76 	wimp_WINDOW_NEVER3D | 0x16u /* RISC OS 5.03+ */,
77 	{0, 0, 65535, 65535},
78 	0,
79 	0,
80 	wimpspriteop_AREA,
81 	1,
82 	1,
83 	{""},
84 	1,
85 	{
86 	  	{
87 			{0, 0, 1, 1},
88 			wimp_ICON_TEXT | wimp_ICON_INDIRECTED |
89 					wimp_ICON_BORDER | wimp_ICON_FILLED |
90 					(wimp_COLOUR_LIGHT_GREY <<
91 						wimp_ICON_BG_COLOUR_SHIFT) |
92 					(wimp_BUTTON_CLICK_DRAG <<
93 						wimp_ICON_BUTTON_TYPE_SHIFT),
94 			{
95 				.indirected_text = {
96 						status_widget_text,
97 				  		status_widget_validation,
98 			  			1
99 			  	}
100 			}
101 		}
102 	}
103 };
104 
105 static void ro_gui_status_bar_open(wimp_open *open);
106 static bool ro_gui_status_bar_click(wimp_pointer *pointer);
107 static void ro_gui_status_bar_redraw(wimp_draw *redraw);
108 static void ro_gui_status_bar_redraw_callback(void *handle);
109 static void ro_gui_status_position_progress_bar(struct status_bar *sb);
110 
111 
112 /**
113  * Create a new status bar
114  *
115  * \param  parent  the window to contain the status bar
116  * \param  width  the proportional width to use (0...10,000)
117  */
ro_gui_status_bar_create(wimp_w parent,unsigned int width)118 struct status_bar *ro_gui_status_bar_create(wimp_w parent, unsigned int width)
119 {
120 	struct status_bar *sb;
121 	os_error *error;
122 
123 	sb = calloc(1, sizeof(*sb));
124 	if (!sb)
125 		return NULL;
126 
127 	sb->pb = ro_gui_progress_bar_create();
128 	if (!sb->pb)
129 		return NULL;
130 
131 	error = xwimp_create_window((wimp_window *)&status_bar_definition,
132 				&sb->w);
133 	if (error) {
134 		NSLOG(netsurf, INFO, "xwimp_create_window: 0x%x: %s",
135 		      error->errnum, error->errmess);
136 		free(sb);
137 		return NULL;
138 	}
139 	sb->parent = parent;
140 	sb->scale = width;
141 	sb->visible = true;
142 
143 	ro_gui_wimp_event_set_user_data(sb->w, sb);
144 	ro_gui_wimp_event_register_open_window(sb->w,
145 			ro_gui_status_bar_open);
146 	ro_gui_wimp_event_register_mouse_click(sb->w,
147 			ro_gui_status_bar_click);
148 	ro_gui_wimp_event_register_redraw_window(sb->w,
149 			ro_gui_status_bar_redraw);
150 	ro_gui_wimp_event_set_help_prefix(sb->w, "HelpStatus");
151 	ro_gui_status_bar_resize(sb);
152 	return sb;
153 }
154 
155 
156 /**
157  * Destroy a status bar and free all associated resources
158  *
159  * \param  sb  the status bar to destroy
160  */
ro_gui_status_bar_destroy(struct status_bar * sb)161 void ro_gui_status_bar_destroy(struct status_bar *sb)
162 {
163 	os_error *error;
164 	assert(sb);
165 
166 	ro_gui_wimp_event_finalise(sb->w);
167 	error = xwimp_delete_window(sb->w);
168 	if (error) {
169 		NSLOG(netsurf, INFO, "xwimp_delete_window: 0x%x:%s",
170 		      error->errnum, error->errmess);
171 	}
172 
173 	ro_gui_progress_bar_destroy(sb->pb);
174 
175 	/* Remove any scheduled redraw callbacks */
176 	riscos_schedule(-1, ro_gui_status_bar_redraw_callback, (void *) sb);
177 
178 	free(sb);
179 }
180 
181 
182 /**
183  * Get the handle of the window that represents a status bar
184  *
185  * \param  sb  the status bar to get the window handle of
186  * \return the status bar's window handle
187  */
ro_gui_status_bar_get_window(struct status_bar * sb)188 wimp_w ro_gui_status_bar_get_window(struct status_bar *sb)
189 {
190 	assert(sb);
191 
192 	return sb->w;
193 }
194 
195 
196 /**
197  * Get the proportional width the status bar is currently using
198  *
199  * \param  sb  the status bar to get the width of
200  * \return the status bar's width (0...10,000)
201  */
ro_gui_status_bar_get_width(struct status_bar * sb)202 unsigned int ro_gui_status_bar_get_width(struct status_bar *sb)
203 {
204 	assert(sb);
205 
206 	return sb->scale;
207 }
208 
209 
210 /**
211  * Set the visibility status of the status bar
212  *
213  * \param  sb  the status bar to check the visiblity of
214  * \param visible  if the status bar should be shown or not.
215  * \return whether the status bar is visible
216  */
ro_gui_status_bar_set_visible(struct status_bar * sb,bool visible)217 void ro_gui_status_bar_set_visible(struct status_bar *sb, bool visible)
218 {
219 	assert(sb);
220 
221 	sb->visible = visible;
222 	if (visible) {
223 		ro_gui_status_bar_resize(sb);
224 	} else {
225 		os_error *error = xwimp_close_window(sb->w);
226 		if (error) {
227 			NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x:%s",
228 			      error->errnum, error->errmess);
229 		}
230 	}
231 }
232 
233 
234 /**
235  * Get the visibility status of the status bar
236  *
237  * \param  sb  the status bar to check the visiblity of
238  * \return whether the status bar is visible
239  */
ro_gui_status_bar_get_visible(struct status_bar * sb)240 bool ro_gui_status_bar_get_visible(struct status_bar *sb)
241 {
242 	assert(sb);
243 
244 	return sb->visible;
245 }
246 
247 
248 /**
249  * Set the value of the progress bar
250  *
251  * \param  sb  the status bar to set the progress of
252  * \param  value  the value to use
253  */
ro_gui_status_bar_set_progress_value(struct status_bar * sb,unsigned int value)254 void ro_gui_status_bar_set_progress_value(struct status_bar *sb,
255 		unsigned int value)
256 {
257 	assert(sb);
258 
259 	ro_gui_status_bar_set_progress_range(sb,
260 			max(value, ro_gui_progress_bar_get_range(sb->pb)));
261 	ro_gui_progress_bar_set_value(sb->pb, value);
262 }
263 
264 
265 /**
266  * Set the range of the progress bar
267  *
268  * \param  sb  the status bar to set the range of
269  * \param  range  the range of the progress bar
270  */
ro_gui_status_bar_set_progress_range(struct status_bar * sb,unsigned int range)271 void ro_gui_status_bar_set_progress_range(struct status_bar *sb,
272 		unsigned int range)
273 {
274 	unsigned int old_range;
275 
276 	assert(sb);
277 
278 	old_range = ro_gui_progress_bar_get_range(sb->pb);
279 	ro_gui_progress_bar_set_range(sb->pb, range);
280 
281 	NSLOG(netsurf, INFO, "Ranges are %i vs %i", old_range, range);
282 	if ((old_range == 0) && (range != 0)) {
283 		ro_gui_status_position_progress_bar(sb);
284 	} else if ((old_range != 0) && (range == 0)) {
285 		os_error *error = xwimp_close_window(
286 				ro_gui_progress_bar_get_window(sb->pb));
287 		if (error) {
288 			NSLOG(netsurf, INFO, "xwimp_close_window: 0x%x:%s",
289 			      error->errnum, error->errmess);
290 		}
291 	}
292 }
293 
294 
295 /**
296  * Set the icon for the progress bar
297  *
298  * \param  sb  the status bar to set the icon for
299  * \param  icon  the icon to use, or NULL for no icon
300  */
ro_gui_status_bar_set_progress_icon(struct status_bar * sb,const char * icon)301 void ro_gui_status_bar_set_progress_icon(struct status_bar *sb,
302 		const char *icon)
303 {
304 	assert(sb);
305 
306 	ro_gui_progress_bar_set_icon(sb->pb, icon);
307 }
308 
309 
310 /**
311  * Set the text to display in the status bar
312  *
313  * \param  sb  the status bar to set the text for
314  * \param  text  the UTF8 text to display, or NULL for none
315  */
ro_gui_status_bar_set_text(struct status_bar * sb,const char * text)316 void ro_gui_status_bar_set_text(struct status_bar *sb, const char *text)
317 {
318 	assert(sb);
319 
320 	sb->text = text;
321 
322 	/* Schedule a window redraw for 1cs' time.
323 	 *
324 	 * We do this to ensure that redraws as a result of text changes
325 	 * do not prevent other applications obtaining CPU time.
326 	 *
327 	 * The scheduled callback will be run when we receive the first
328 	 * null poll after 1cs has elapsed. It may then issue a redraw
329 	 * request to the Wimp.
330 	 *
331 	 * The scheduler ensures that only one instance of the
332 	 * { callback, handle } pair is registered at once.
333 	 */
334 	if (sb->visible && text != NULL) {
335 		riscos_schedule(10, ro_gui_status_bar_redraw_callback, sb);
336 	}
337 }
338 
339 
340 /**
341  * Resize a status bar following a change in the dimensions of the
342  * parent window.
343  *
344  * \param  sb  the status bar to resize
345  */
ro_gui_status_bar_resize(struct status_bar * sb)346 void ro_gui_status_bar_resize(struct status_bar *sb)
347 {
348 	int window_width;
349 	int status_width, status_height;
350 	wimp_window_state state;
351 	os_error *error;
352 	os_box extent;
353 
354 	if ((!sb) || (!sb->visible))
355 		return;
356 
357 	/* get the window work area dimensions */
358 	state.w = sb->parent;
359 	error = xwimp_get_window_state(&state);
360 	if (error) {
361 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
362 		      error->errnum, error->errmess);
363 		return;
364 	}
365 	window_width = state.visible.x1 - state.visible.x0;
366 
367 
368 	/* recalculate the scaled width */
369 	status_width = (window_width * sb->scale) / 10000;
370 	if (status_width < WIDGET_WIDTH)
371 		status_width = WIDGET_WIDTH;
372 	status_height = ro_get_hscroll_height(sb->parent);
373 
374 	/* resize the status/resize icons */
375 	if (status_width != sb->width) {
376 		/* update the window extent */
377 		int redraw_left, redraw_right;
378 
379 		extent.x0 = 0;
380 		extent.y0 = 0;
381 		extent.x1 = status_width;
382 		extent.y1 = status_height - 4;
383 		error = xwimp_set_extent(sb->w, &extent);
384 		if (error) {
385 			NSLOG(netsurf, INFO, "xwimp_set_extent: 0x%x: %s",
386 			      error->errnum, error->errmess);
387 			return;
388 		}
389 
390 		/* re-open the nested window */
391 		state.w = sb->w;
392 		state.xscroll = 0;
393 		state.yscroll = 0;
394 		state.next = wimp_TOP;
395 		state.visible.x0 = state.visible.x0;
396 		state.visible.y1 = state.visible.y0 - 2;
397 		state.visible.x1 = state.visible.x0 + status_width;
398 		state.visible.y0 = state.visible.y1 - status_height + 4;
399 		error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
400 				sb->parent,
401 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
402 						<< wimp_CHILD_XORIGIN_SHIFT |
403 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
404 						<< wimp_CHILD_YORIGIN_SHIFT |
405 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
406 						<< wimp_CHILD_LS_EDGE_SHIFT |
407 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
408 						<< wimp_CHILD_BS_EDGE_SHIFT |
409 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
410 						<< wimp_CHILD_RS_EDGE_SHIFT |
411 				wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
412 						<< wimp_CHILD_TS_EDGE_SHIFT);
413 		if (error) {
414 			NSLOG(netsurf, INFO,
415 			      "xwimp_open_window_nested: 0x%x: %s",
416 			      error->errnum,
417 			      error->errmess);
418 			return;
419 		}
420 		ro_gui_status_position_progress_bar(sb);
421 		error = xwimp_resize_icon(sb->w, ICON_WIDGET,
422 				status_width - WIDGET_WIDTH, 0,
423 				status_width, status_height - 4);
424 		if (error) {
425 			NSLOG(netsurf, INFO, "xwimp_resize_icon: 0x%x: %s",
426 			      error->errnum, error->errmess);
427 			return;
428 		}
429 
430 		redraw_left = min(status_width, sb->width) - WIDGET_WIDTH - 2;
431 		redraw_right = max(status_width, sb->width);
432 		xwimp_force_redraw(sb->w, redraw_left, 0,
433 				redraw_right, status_height);
434 		sb->width = status_width;
435 	}
436 }
437 
438 
439 /**
440  * Process a WIMP redraw request
441  *
442  * \param  redraw  the redraw request to process
443  */
ro_gui_status_bar_redraw(wimp_draw * redraw)444 void ro_gui_status_bar_redraw(wimp_draw *redraw)
445 {
446 	struct status_bar *sb;
447 	os_error *error;
448 	osbool more;
449 	rufl_code code;
450 	struct redraw_context ctx = {
451 		.interactive = true,
452 		.background_images = true,
453 		.plot = &ro_plotters
454 	};
455 	struct rect rect;
456 
457 	sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(redraw->w);
458 	assert(sb);
459 
460 	/* initialise the plotters */
461 	ro_plot_origin_x = 0;
462 	ro_plot_origin_y = 0;
463 
464 	/* redraw the window */
465 	error = xwimp_redraw_window(redraw, &more);
466 	if (error) {
467 		NSLOG(netsurf, INFO, "xwimp_redraw_window: 0x%x: %s",
468 		      error->errnum, error->errmess);
469 		return;
470 	}
471 	while (more) {
472 		/* redraw the status text */
473 		if (sb->text) {
474 			error = xcolourtrans_set_font_colours(font_CURRENT,
475 					0xeeeeee00, 0x00000000, 14, 0, 0, 0);
476 			if (error) {
477 				NSLOG(netsurf, INFO,
478 				      "xcolourtrans_set_font_colours: 0x%x: %s",
479 				      error->errnum,
480 				      error->errmess);
481 				return;
482 			}
483 			code = rufl_paint(ro_gui_desktop_font_family,
484 					ro_gui_desktop_font_style,
485 					ro_gui_desktop_font_size,
486 					sb->text, strlen(sb->text),
487 					redraw->box.x0 + 6, redraw->box.y0 + 8,
488 					rufl_BLEND_FONT);
489 			if (code != rufl_OK) {
490 				if (code == rufl_FONT_MANAGER_ERROR)
491 					NSLOG(netsurf, INFO,
492 					      "rufl_FONT_MANAGER_ERROR: 0x%x: %s",
493 					      rufl_fm_error->errnum,
494 					      rufl_fm_error->errmess);
495 				else
496 					NSLOG(netsurf, INFO,
497 					      "rufl_paint: 0x%x", code);
498 			}
499 		}
500 
501 		rect.x0 = (redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1;
502 		rect.y0 = -redraw->box.y0 >> 1;
503 		rect.x1 = (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1;
504 		rect.y1 = -redraw->box.y1 >> 1;
505 
506 		/* separate the widget from the text with a line */
507 		ctx.plot->rectangle(&ctx,
508 				    plot_style_fill_black,
509 				    &rect);
510 
511 		error = xwimp_get_rectangle(redraw, &more);
512 		if (error) {
513 			NSLOG(netsurf, INFO, "xwimp_get_rectangle: 0x%x: %s",
514 			      error->errnum, error->errmess);
515 			return;
516 		}
517 	}
518 }
519 
520 /**
521  * Callback for scheduled redraw
522  *
523  * \param handle  Callback handle
524  */
ro_gui_status_bar_redraw_callback(void * handle)525 void ro_gui_status_bar_redraw_callback(void *handle)
526 {
527 	struct status_bar *sb = handle;
528 
529 	wimp_force_redraw(sb->w, 0, 0, sb->width - WIDGET_WIDTH, 65536);
530 }
531 
532 
533 /**
534  * Process an mouse_click event for a status window.
535  *
536  * \param  pointer  details of the mouse click
537  */
ro_gui_status_bar_click(wimp_pointer * pointer)538 bool ro_gui_status_bar_click(wimp_pointer *pointer)
539 {
540 	wimp_drag drag;
541 	os_error *error;
542 
543 	switch (pointer->i) {
544 		case ICON_WIDGET:
545 			drag.w = pointer->w;
546 			drag.type = wimp_DRAG_SYSTEM_SIZE;
547 			drag.initial.x0 = pointer->pos.x;
548 			drag.initial.x1 = pointer->pos.x;
549 			drag.initial.y0 = pointer->pos.y;
550 			drag.initial.y1 = pointer->pos.y;
551 			error = xwimp_drag_box(&drag);
552 			if (error) {
553 				NSLOG(netsurf, INFO,
554 				      "xwimp_drag_box: 0x%x: %s",
555 				      error->errnum,
556 				      error->errmess);
557 			}
558 			break;
559 	}
560 	return true;
561 }
562 
563 
564 /**
565  * Process an open_window request for a status window.
566  *
567  * \param  open  the request to process
568  */
ro_gui_status_bar_open(wimp_open * open)569 void ro_gui_status_bar_open(wimp_open *open)
570 {
571 	struct status_bar *sb;
572 	int window_width, status_width;
573 	wimp_window_state state;
574 	os_error *error;
575 
576 	/* get the parent width for scaling */
577 	sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(open->w);
578 	state.w = sb->parent;
579 	error = xwimp_get_window_state(&state);
580 	if (error) {
581 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
582 		      error->errnum, error->errmess);
583 		return;
584 	}
585 	window_width = state.visible.x1 - state.visible.x0;
586 	if (window_width == 0)
587 		window_width = 1;
588 	status_width = open->visible.x1 - open->visible.x0;
589 	if (status_width <= 12)
590 		status_width = 0;
591 
592 	/* store the new size */
593 	sb->scale = (10000 * status_width) / window_width;
594 	if (sb->scale > 10000)
595 		sb->scale = 10000;
596 	ro_gui_status_bar_resize(sb);
597 }
598 
599 
600 /**
601  * Reposition the progress component following a change in the
602  * dimension of the status window.
603  *
604  * \param  sb  the status bar to update
605  */
ro_gui_status_position_progress_bar(struct status_bar * sb)606 void ro_gui_status_position_progress_bar(struct status_bar *sb)
607 {
608 	wimp_window_state state;
609 	os_error *error;
610 	int left, right;
611 
612 	if (!sb)
613 		return;
614 	if (ro_gui_progress_bar_get_range(sb->pb) == 0)
615 		return;
616 
617 	/* get the window work area dimensions */
618 	state.w = sb->w;
619 	error = xwimp_get_window_state(&state);
620 	if (error) {
621 		NSLOG(netsurf, INFO, "xwimp_get_window_state: 0x%x: %s",
622 		      error->errnum, error->errmess);
623 		return;
624 	}
625 
626 	/* calculate the dimensions */
627 	right = state.visible.x1 - WIDGET_WIDTH - 2;
628 	left = max(state.visible.x0, right - PROGRESS_WIDTH);
629 
630 	/* re-open the nested window */
631 	state.w = ro_gui_progress_bar_get_window(sb->pb);
632 	state.xscroll = 0;
633 	state.yscroll = 0;
634 	state.next = wimp_TOP;
635 	state.visible.x0 = left;
636 	state.visible.x1 = right;
637 	error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state),
638 			sb->w,
639 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
640 					<< wimp_CHILD_XORIGIN_SHIFT |
641 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
642 					<< wimp_CHILD_YORIGIN_SHIFT |
643 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
644 					<< wimp_CHILD_LS_EDGE_SHIFT |
645 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
646 					<< wimp_CHILD_BS_EDGE_SHIFT |
647 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
648 					<< wimp_CHILD_RS_EDGE_SHIFT |
649 			wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT
650 					<< wimp_CHILD_TS_EDGE_SHIFT);
651 	if (error) {
652 		NSLOG(netsurf, INFO, "xwimp_open_window: 0x%x: %s",
653 		      error->errnum, error->errmess);
654 	}
655 
656 	/* update the progress bar display on non-standard width */
657 	if ((right - left) != PROGRESS_WIDTH)
658 		ro_gui_progress_bar_update(sb->pb, right - left,
659 				state.visible.y1 - state.visible.y0);
660 }
661