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