1 /*
2  * Copyright 2008,2010 Vincent Sanders <vince@simtec.co.uk>
3  *
4  * Framebuffer windowing toolkit core.
5  *
6  * This file is part of NetSurf, http://www.netsurf-browser.org/
7  *
8  * NetSurf is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * NetSurf is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <assert.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <stdarg.h>
28 
29 #include <libnsfb.h>
30 #include <libnsfb_plot.h>
31 #include <libnsfb_plot_util.h>
32 #include <libnsfb_event.h>
33 #include <libnsfb_cursor.h>
34 
35 #include "utils/utils.h"
36 #include "utils/log.h"
37 #include "netsurf/browser_window.h"
38 #include "netsurf/plotters.h"
39 
40 #include "framebuffer/gui.h"
41 #include "framebuffer/fbtk.h"
42 #include "framebuffer/image_data.h"
43 
44 #include "widget.h"
45 
46 #ifdef FBTK_LOGGING
47 
48 /* tree dump debug, also example of depth first tree walk */
49 static void
dump_tk_tree(fbtk_widget_t * widget)50 dump_tk_tree(fbtk_widget_t *widget)
51 {
52 	widget = fbtk_get_root_widget(widget);
53 	int indent = 0;
54 
55 	while (widget != NULL) {
56 		NSLOG(fbtk, DEBUG, "%*s%p", indent, "", widget);
57 		if (widget->first_child != NULL) {
58 			widget = widget->first_child;
59 			indent += 6;
60 		} else if (widget->next != NULL) {
61 			widget = widget->next;
62 		} else {
63 			while ((widget->parent != NULL) &&
64 			       (widget->parent->next == NULL)) {
65 				widget = widget->parent;
66 				indent -= 6;
67 			}
68 			if (widget->parent != NULL) {
69 				indent -= 6;
70 				widget = widget->parent->next;
71 			} else {
72 				widget = NULL;
73 			}
74 		}
75 	}
76 }
77 
78 #endif
79 
80 /* exported function documented in fbtk.h */
81 void
fbtk_request_redraw(fbtk_widget_t * widget)82 fbtk_request_redraw(fbtk_widget_t *widget)
83 {
84 	fbtk_widget_t *cwidget;
85 	fbtk_widget_t *pwidget;
86 
87 	assert(widget != NULL);
88 
89 	/* if widget not mapped do not try to redraw it */
90 	pwidget = widget;
91 	while (pwidget != NULL) {
92 		if (pwidget->mapped == false)
93 			return;
94 		pwidget = pwidget->parent;
95 	}
96 
97 	widget->redraw.needed = true;
98 	widget->redraw.x = 0;
99 	widget->redraw.y = 0;
100 	widget->redraw.width = widget->width;
101 	widget->redraw.height = widget->height;
102 
103 	NSLOG(fbtk, DEBUG,
104 	      "redrawing %p %d,%d %d,%d",
105 	      widget,
106 	      widget->redraw.x,
107 	      widget->redraw.y,
108 	      widget->redraw.width,
109 	      widget->redraw.height);
110 
111 	cwidget = widget->last_child;
112 	while (cwidget != NULL) {
113 		fbtk_request_redraw(cwidget);
114 		cwidget = cwidget->prev;
115 	}
116 
117 	while (widget->parent != NULL) {
118 		widget = widget->parent;
119 		widget->redraw.child = true;
120 	}
121 }
122 
123 
124 
125 /* exported function documented in fbtk.h */
126 int
fbtk_set_mapping(fbtk_widget_t * widget,bool map)127 fbtk_set_mapping(fbtk_widget_t *widget, bool map)
128 {
129 	NSLOG(netsurf, INFO, "setting mapping on %p to %d", widget, map);
130 	widget->mapped = map;
131 	if (map) {
132 		fbtk_request_redraw(widget);
133 	} else {
134 		fbtk_request_redraw(widget->parent);
135 	}
136 	return 0;
137 }
138 
139 
140 /**
141  * Swap a sibling widget with the next deepest in the hierachy
142  *
143  * \param lw The widget to swap
144  */
145 static void
swap_siblings(fbtk_widget_t * lw)146 swap_siblings(fbtk_widget_t *lw)
147 {
148 	fbtk_widget_t *rw = lw->next; /* the widget to swap lw with */
149 	fbtk_widget_t *before;
150 	fbtk_widget_t *after;
151 
152 	assert(rw != NULL);
153 
154 	NSLOG(netsurf, INFO, "Swapping %p with %p", lw, rw);
155 	before = lw->prev;
156 	after = rw->next;
157 
158 	if (before == NULL) {
159 		/* left widget is currently the first child */
160 		lw->parent->first_child = rw;
161 	} else {
162 		before->next = rw;
163 	}
164 	rw->prev = before;
165 	rw->next = lw;
166 
167 	if (after == NULL) {
168 		/* right widget is currently the last child */
169 		rw->parent->last_child = lw;
170 	} else {
171 		after->prev = lw;
172 	}
173 	lw->next = after;
174 	lw->prev = rw;
175 }
176 
177 
178 
179 /* exported function documented in fbtk.h */
180 int
fbtk_set_zorder(fbtk_widget_t * widget,int z)181 fbtk_set_zorder(fbtk_widget_t *widget, int z)
182 {
183 	while (z != 0) {
184 		if (z < 0) {
185 			if (widget->prev == NULL)
186 				break; /* cannot go any shallower */
187 
188 			/* swap with previous entry */
189 			swap_siblings(widget->prev);
190 
191 			z++;
192 		} else {
193 			if (widget->next == NULL)
194 				break; /* cannot go any deeper */
195 
196 			/* swap with subsequent entry */
197 			swap_siblings(widget);
198 
199 			z--;
200 		}
201 	}
202 
203 	return z;
204 }
205 
206 
207 /* exported function documented in fbtk.h */
208 bool
fbtk_set_pos_and_size(fbtk_widget_t * widget,int x,int y,int width,int height)209 fbtk_set_pos_and_size(fbtk_widget_t *widget,
210 		      int x, int y,
211 		      int width, int height)
212 {
213 	if (widget->parent != NULL) {
214 		fbtk_widget_t *parent = widget->parent;
215 
216 		/* make new window fit inside parent */
217 		if (width == 0) {
218 			width = parent->width - x;
219 		} else if (width < 0) {
220 			width = parent->width + width - x;
221 		}
222 		if ((width + x) > parent->width) {
223 			width = parent->width - x;
224 		}
225 
226 		if (height == 0) {
227 			height = parent->height - y;
228 		} else if (height < 0) {
229 			height = parent->height + height - y;
230 		}
231 		if ((height + y) > parent->height) {
232 			height = parent->height - y;
233 		}
234 	}
235 
236 	if ((widget->x != x) ||
237 	    (widget->y != y) ||
238 	    (widget->width != width) ||
239 	    (widget->height != height)) {
240 		widget->x = x;
241 		widget->y = y;
242 		widget->width = width;
243 		widget->height = height;
244 		return true;
245 	}
246 	return false;
247 }
248 
249 
250 /* exported function docuemnted in fbtk.h */
251 void
fbtk_set_caret(fbtk_widget_t * widget,bool set,int x,int y,int height,void (* remove_caret)(fbtk_widget_t * widget))252 fbtk_set_caret(fbtk_widget_t *widget, bool set,
253 		int x, int y, int height,
254 		void (*remove_caret)(fbtk_widget_t *widget))
255 {
256 	fbtk_widget_t *root;
257 
258 	assert(widget != NULL);
259 	root = fbtk_get_root_widget(widget);
260 
261 	if (root->u.root.caret.owner != NULL &&
262 			root->u.root.caret.remove_cb != NULL)
263 		root->u.root.caret.remove_cb(widget);
264 
265 	if (set) {
266 		assert(remove_caret != NULL);
267 
268 		root->u.root.caret.owner = widget;
269 		root->u.root.caret.x = x;
270 		root->u.root.caret.y = y;
271 		root->u.root.caret.height = height;
272 		root->u.root.caret.remove_cb = remove_caret;
273 
274 	} else {
275 		root->u.root.caret.owner = NULL;
276 		root->u.root.caret.remove_cb = NULL;
277 	}
278 }
279 
280 /* exported function documented in fbtk.h */
281 int
fbtk_destroy_widget(fbtk_widget_t * widget)282 fbtk_destroy_widget(fbtk_widget_t *widget)
283 {
284 	fbtk_widget_t *parent;
285 	int ret = 0;
286 
287 	ret = fbtk_post_callback(widget, FBTK_CBT_DESTROY);
288 
289 	while (widget->first_child != NULL) {
290 		fbtk_destroy_widget(widget->first_child);
291 	}
292 
293 	parent = widget->parent;
294 	if (parent != NULL) {
295 
296 		/* unlink from siblings */
297 		if (widget->prev != NULL) {
298 			widget->prev->next = widget->next;
299 		} else {
300 			/* must be the first widget, unlink from parent */
301 			parent->first_child = widget->next;
302 		}
303 		if (widget->next != NULL) {
304 			widget->next->prev = widget->prev;
305 		} else {
306 			/* must be the last widget, unlink from parent */
307 			parent->last_child = widget->prev;
308 		}
309 
310 		free(widget);
311 	}
312 
313 	return ret;
314 }
315 
316 /* region coverage flags. */
317 enum {
318 	POINT_LEFTOF_REGION = 1,
319 	POINT_RIGHTOF_REGION = 2,
320 	POINT_ABOVE_REGION = 4,
321 	POINT_BELOW_REGION = 8,
322 };
323 
324 /* Computes where a point lies in respect to an area. */
325 #define REGION(x,y,cx1,cx2,cy1,cy2)			\
326 	(( (y) > (cy2) ? POINT_BELOW_REGION : 0) |	\
327 	 ( (y) < (cy1) ? POINT_ABOVE_REGION : 0) |	\
328 	 ( (x) > (cx2) ? POINT_RIGHTOF_REGION : 0) |	\
329 	 ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
330 
331 /* swap two integers */
332 #define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t;  } while(0)
333 
334 /* exported function documented in fbtk.h */
335 bool
fbtk_clip_rect(const bbox_t * restrict clip,bbox_t * restrict box)336 fbtk_clip_rect(const bbox_t * restrict clip, bbox_t * restrict box)
337 {
338 	uint8_t region1;
339 	uint8_t region2;
340 
341 	/* ensure co-ordinates are in ascending order */
342 	if (box->x1 < box->x0)
343 		SWAP(box->x0, box->x1);
344 	if (box->y1 < box->y0)
345 		SWAP(box->y0, box->y1);
346 
347 	region1 = REGION(box->x0, box->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
348 	region2 = REGION(box->x1, box->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
349 
350 	/* area lies entirely outside the clipping rectangle */
351 	if ((region1 | region2) && (region1 & region2))
352 		return false;
353 
354 	if (box->x0 < clip->x0)
355 		box->x0 = clip->x0;
356 	if (box->x0 > clip->x1)
357 		box->x0 = clip->x1;
358 
359 	if (box->x1 < clip->x0)
360 		box->x1 = clip->x0;
361 	if (box->x1 > clip->x1)
362 		box->x1 = clip->x1;
363 
364 	if (box->y0 < clip->y0)
365 		box->y0 = clip->y0;
366 	if (box->y0 > clip->y1)
367 		box->y0 = clip->y1;
368 
369 	if (box->y1 < clip->y0)
370 		box->y1 = clip->y0;
371 	if (box->y1 > clip->y1)
372 		box->y1 = clip->y1;
373 
374 	return true;
375 }
376 
377 /* exported function documented in fbtk.h */
378 bool
fbtk_clip_to_widget(fbtk_widget_t * widget,bbox_t * restrict box)379 fbtk_clip_to_widget(fbtk_widget_t *widget, bbox_t * restrict box)
380 {
381 	bbox_t wbox;
382 	wbox.x0 = 0;
383 	wbox.y0 = 0;
384 	wbox.x1 = widget->width;
385 	wbox.y1 = widget->height;
386 	return fbtk_clip_rect(&wbox, box);
387 }
388 
389 
390 
391 /* internally exported function documented in widget.h */
392 int
fbtk_set_ptr(fbtk_widget_t * widget,fbtk_callback_info * cbi)393 fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi)
394 {
395 	fbtk_widget_t *root = fbtk_get_root_widget(widget);
396 	struct fbtk_bitmap *bm = cbi->context;
397 
398 	nsfb_cursor_set(root->u.root.fb,
399 			(nsfb_colour_t *)bm->pixdata,
400 			bm->width,
401 			bm->height,
402 			bm->width,
403 			bm->hot_x,
404 			bm->hot_y);
405 
406 	return 0;
407 }
408 
409 
410 /* internally exported function documented in widget.h */
411 fbtk_widget_t *
fbtk_get_root_widget(fbtk_widget_t * widget)412 fbtk_get_root_widget(fbtk_widget_t *widget)
413 {
414 	while (widget->parent != NULL)
415 		widget = widget->parent;
416 
417 	/* check root widget was found */
418 	if (widget->type != FB_WIDGET_TYPE_ROOT) {
419 		NSLOG(netsurf, INFO,
420 		      "Widget with null parent that is not the root widget!");
421 		return NULL;
422 	}
423 
424 	return widget;
425 }
426 
427 
428 /* exported function documented in fbtk.h */
429 int
fbtk_get_absx(fbtk_widget_t * widget)430 fbtk_get_absx(fbtk_widget_t *widget)
431 {
432 	int x = widget->x;
433 
434 	while (widget->parent != NULL) {
435 		widget = widget->parent;
436 		x += widget->x;
437 	}
438 
439 	return x;
440 }
441 
442 
443 /* exported function documented in fbtk.h */
444 int
fbtk_get_absy(fbtk_widget_t * widget)445 fbtk_get_absy(fbtk_widget_t *widget)
446 {
447 	int y = widget->y;
448 
449 	while (widget->parent != NULL) {
450 		widget = widget->parent;
451 		y += widget->y;
452 	}
453 
454 	return y;
455 }
456 
457 
458 /* exported function documented in fbtk.h */
459 int
fbtk_get_height(fbtk_widget_t * widget)460 fbtk_get_height(fbtk_widget_t *widget)
461 {
462 	return widget->height;
463 }
464 
465 /* exported function documented in fbtk.h */
466 int
fbtk_get_width(fbtk_widget_t * widget)467 fbtk_get_width(fbtk_widget_t *widget)
468 {
469 	return widget->width;
470 }
471 
472 /* exported function documented in fbtk.h */
473 bool
fbtk_get_bbox(fbtk_widget_t * widget,nsfb_bbox_t * bbox)474 fbtk_get_bbox(fbtk_widget_t *widget, nsfb_bbox_t *bbox)
475 {
476 	bbox->x0 = widget->x;
477 	bbox->y0 = widget->y;
478 	bbox->x1 = widget->x + widget->width;
479 	bbox->y1 = widget->y + widget->height;
480 
481 	widget = widget->parent;
482 	while (widget != NULL) {
483 		bbox->x0 += widget->x;
484 		bbox->y0 += widget->y;
485 		bbox->x1 += widget->x;
486 		bbox->y1 += widget->y;
487 		widget = widget->parent;
488 	}
489 
490 	return true;
491 }
492 
493 bool
fbtk_get_caret(fbtk_widget_t * widget,int * x,int * y,int * height)494 fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height)
495 {
496 	fbtk_widget_t *root = fbtk_get_root_widget(widget);
497 
498 	if (root->u.root.caret.owner == widget) {
499 		*x = root->u.root.caret.x;
500 		*y = root->u.root.caret.y;
501 		*height = root->u.root.caret.height;
502 
503 		return true;
504 
505 	} else {
506 		*x = 0;
507 		*y = 0;
508 		*height = 0;
509 
510 		return false;
511 	}
512 }
513 
514 /* exported function documented in fbtk.h */
515 fbtk_widget_t *
fbtk_get_widget_at(fbtk_widget_t * nwid,int x,int y)516 fbtk_get_widget_at(fbtk_widget_t *nwid, int x, int y)
517 {
518 	fbtk_widget_t *widget = NULL; /* found widget */
519 
520 	/* require the root widget to start */
521 	nwid = fbtk_get_root_widget(nwid);
522 
523 	while (nwid != NULL) {
524 		if ((nwid->mapped) &&
525 		    (x >= nwid->x) &&
526 		    (y >= nwid->y) &&
527 		    (x < (nwid->x + nwid->width)) &&
528 		    (y < (nwid->y + nwid->height))) {
529 			widget = nwid;
530 			x -= nwid->x;
531 			y -= nwid->y;
532 			nwid = nwid->first_child;
533 		} else {
534 			nwid = nwid->next;
535 		}
536 	}
537 
538 	return widget;
539 }
540 
541 
542 
543 
544 /* internally exported function documented in widget.h */
545 fbtk_widget_t *
fbtk_widget_new(fbtk_widget_t * parent,enum fbtk_widgettype_e type,int x,int y,int width,int height)546 fbtk_widget_new(fbtk_widget_t *parent,
547 		enum fbtk_widgettype_e type,
548 		int x,
549 		int y,
550 		int width,
551 		int height)
552 {
553 	fbtk_widget_t *neww; /* new widget */
554 
555 	if (parent == NULL)
556 		return NULL;
557 
558 	neww = calloc(1, sizeof(fbtk_widget_t));
559 	if (neww == NULL)
560 		return NULL;
561 
562 	NSLOG(fbtk, DEBUG, "creating %p %d,%d %d,%d", neww, x, y, width, height);
563 
564 	/* make new window fit inside parent */
565 	if (width == 0) {
566 		width = parent->width - x;
567 	} else if (width < 0) {
568 		width = parent->width + width - x;
569 	}
570 	if ((width + x) > parent->width) {
571 		width = parent->width - x;
572 	}
573 
574 	if (height == 0) {
575 		height = parent->height - y;
576 	} else if (height < 0) {
577 		height = parent->height + height - y;
578 	}
579 	if ((height + y) > parent->height) {
580 		height = parent->height - y;
581 	}
582 
583 	NSLOG(fbtk, DEBUG, "using %p %d,%d %d,%d", neww, x, y, width, height);
584 
585 	/* set values */
586 	neww->type = type;
587 	neww->x = x;
588 	neww->y = y;
589 	neww->width = width;
590 	neww->height = height;
591 
592 	/* insert into widget heiarchy */
593 
594 	neww->parent = parent;
595 
596 	if (parent->first_child == NULL) {
597 		/* no child widgets yet */
598 		parent->last_child = neww;
599 	} else {
600 		/* add new widget to front of sibling chain */
601 		neww->next = parent->first_child;
602 		neww->next->prev = neww;
603 	}
604 	parent->first_child = neww;
605 
606 	return neww;
607 }
608 
609 /* exported function documented in fbtk.h */
610 bool
fbtk_get_redraw_pending(fbtk_widget_t * widget)611 fbtk_get_redraw_pending(fbtk_widget_t *widget)
612 {
613 	fbtk_widget_t *root;
614 
615 	/* ensure we have the root widget */
616 	root = fbtk_get_root_widget(widget);
617 
618 	return root->redraw.needed | root->redraw.child;
619 }
620 
621 /** Perform a depth-first tree-walk, calling the redraw callback of the widgets in turn.
622  *
623  * This function makes no decisions of its own and simply walks the
624  * widget tree depth first calling widgets redraw callbacks if flagged
625  * to do so.
626  * The tree search is optimised with a flag to indicate wether the
627  * children of a node should be considered.
628  */
629 static int
do_redraw(nsfb_t * nsfb,fbtk_widget_t * widget)630 do_redraw(nsfb_t *nsfb, fbtk_widget_t *widget)
631 {
632 	nsfb_bbox_t plot_ctx;
633 	fbtk_widget_t *cwidget; /* child widget */
634 
635 	/* check if the widget requires redrawing */
636 	if (widget->redraw.needed == true) {
637 		plot_ctx.x0 = fbtk_get_absx(widget) + widget->redraw.x;
638 		plot_ctx.y0 = fbtk_get_absy(widget) + widget->redraw.y;
639 		plot_ctx.x1 = plot_ctx.x0 + widget->redraw.width;
640 		plot_ctx.y1 = plot_ctx.y0 + widget->redraw.height;
641 
642 		NSLOG(fbtk, DEBUG,
643 		      "clipping %p %d,%d %d,%d",
644 		      widget,
645 		      plot_ctx.x0, plot_ctx.y0,
646 		      plot_ctx.x1, plot_ctx.y1);
647 
648 		if (nsfb_plot_set_clip(nsfb, &plot_ctx) == true) {
649 			fbtk_post_callback(widget, FBTK_CBT_REDRAW);
650 		}
651 		widget->redraw.needed = false;
652 	}
653 
654 	/* walk the widgets children if child flag is set */
655 	if (widget->redraw.child) {
656 		cwidget = widget->last_child;
657 		while (cwidget != NULL) {
658 			do_redraw(nsfb, cwidget);
659 			cwidget = cwidget->prev;
660 		}
661 		widget->redraw.child = false;
662 	}
663 
664 	return 1;
665 }
666 
667 /* exported function documented in fbtk.h */
668 int
fbtk_redraw(fbtk_widget_t * widget)669 fbtk_redraw(fbtk_widget_t *widget)
670 {
671 	fbtk_widget_t *root;
672 
673 	/* ensure we have the root widget */
674 	root = fbtk_get_root_widget(widget);
675 
676 	return do_redraw(root->u.root.fb, root);
677 }
678 
679 /* exported function documented in fbtk.h */
680 fbtk_callback
fbtk_get_handler(fbtk_widget_t * widget,fbtk_callback_type cbt)681 fbtk_get_handler(fbtk_widget_t *widget, fbtk_callback_type cbt)
682 {
683 	if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
684 		/* type out of range, no way to report error so return NULL */
685 		return NULL;
686 	}
687 
688 	return widget->callback[cbt];
689 }
690 
691 /* exported function documented in fbtk.h */
692 fbtk_callback
fbtk_set_handler(fbtk_widget_t * widget,fbtk_callback_type cbt,fbtk_callback cb,void * context)693 fbtk_set_handler(fbtk_widget_t *widget,
694 		 fbtk_callback_type cbt,
695 		 fbtk_callback cb,
696 		 void *context)
697 {
698 	fbtk_callback prevcb;
699 
700 	if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
701 		/* type out of range, no way to report error so return NULL */
702 		return NULL;
703 	}
704 
705 	prevcb = widget->callback[cbt];
706 
707 	widget->callback[cbt] = cb;
708 	widget->callback_context[cbt] = context;
709 
710 	return prevcb;
711 }
712 
713 /* exported function docuemnted in fbtk.h */
714 int
fbtk_post_callback(fbtk_widget_t * widget,fbtk_callback_type cbt,...)715 fbtk_post_callback(fbtk_widget_t *widget, fbtk_callback_type cbt, ...)
716 {
717 	fbtk_callback_info cbi;
718 	int ret = 0;
719 	va_list ap;
720 
721 	if (widget == NULL)
722 		return -1;
723 	/* if the widget is not mapped do not attempt to post any
724 	 * events to it
725 	 */
726 	if (widget->mapped == false)
727 		return ret;
728 
729 	if (widget->callback[cbt] != NULL) {
730 		cbi.type = cbt;
731 		cbi.context = widget->callback_context[cbt];
732 
733 		va_start(ap, cbt);
734 
735 		switch (cbt) {
736 		case FBTK_CBT_SCROLLX:
737 			cbi.x = va_arg(ap,int);
738 			break;
739 
740 		case FBTK_CBT_SCROLLY:
741 			cbi.y = va_arg(ap,int);
742 			break;
743 
744 		case FBTK_CBT_CLICK:
745 			cbi.event = va_arg(ap, void *);
746 			cbi.x = va_arg(ap, int);
747 			cbi.y = va_arg(ap, int);
748 			break;
749 
750 		case FBTK_CBT_INPUT:
751 			cbi.event = va_arg(ap, void *);
752 			break;
753 
754 		case FBTK_CBT_POINTERMOVE:
755 			cbi.x = va_arg(ap, int);
756 			cbi.y = va_arg(ap, int);
757 			break;
758 
759 		case FBTK_CBT_REDRAW:
760 			break;
761 
762 		case FBTK_CBT_USER:
763 			break;
764 
765 		case FBTK_CBT_STRIP_FOCUS:
766 			break;
767 
768 		default:
769 			break;
770 		}
771 		va_end(ap);
772 
773 		ret = (widget->callback[cbt])(widget, &cbi);
774 	}
775 
776 	return ret;
777 }
778 
779 /* exported function docuemnted in fbtk.h */
780 void
fbtk_set_focus(fbtk_widget_t * widget)781 fbtk_set_focus(fbtk_widget_t *widget)
782 {
783 	fbtk_widget_t *root;
784 
785 	/* ensure we have the root widget */
786 	root = fbtk_get_root_widget(widget);
787 
788 	if (root->u.root.input != NULL &&
789 			root->u.root.input != widget) {
790 		/* inform previous holder of focus that it's being stripped
791 		 * of focus */
792 		fbtk_post_callback(root->u.root.input, FBTK_CBT_STRIP_FOCUS);
793 	}
794 
795 	root->u.root.input = widget;
796 }
797 
798 
799 
800 /* exported function docuemnted in fbtk.h */
801 nsfb_t *
fbtk_get_nsfb(fbtk_widget_t * widget)802 fbtk_get_nsfb(fbtk_widget_t *widget)
803 {
804 	fbtk_widget_t *root;
805 
806 	/* ensure we have the root widget */
807 	root = fbtk_get_root_widget(widget);
808 
809 	return root->u.root.fb;
810 }
811 
812 /* exported function docuemnted in fbtk.h */
813 fbtk_widget_t *
fbtk_init(nsfb_t * fb)814 fbtk_init(nsfb_t *fb)
815 {
816 	fbtk_widget_t *root;
817 
818 	/* create and configure root widget */
819 	root = calloc(1, sizeof(fbtk_widget_t));
820 	if (root == NULL)
821 		return NULL;
822 
823 	root->type = FB_WIDGET_TYPE_ROOT;
824 	root->u.root.fb = fb;
825 	root->u.root.caret.owner = NULL;
826 
827 	nsfb_get_geometry(fb, &root->width, &root->height, NULL);
828 
829 	root->mapped = true;
830 
831 	return root;
832 }
833 
834 /*
835  * Local Variables:
836  * c-basic-offset:8
837  * End:
838  */
839