summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xatari/browser.c179
-rwxr-xr-xatari/browser.h76
-rwxr-xr-xatari/gui.h121
-rwxr-xr-xatari/misc.c1
-rw-r--r--atari/osspec.c5
-rw-r--r--atari/search.c1
-rwxr-xr-xatari/statusbar.c1
-rwxr-xr-xatari/statusbar.h13
-rwxr-xr-xatari/toolbar.c1
-rwxr-xr-xatari/toolbar.h50
10 files changed, 262 insertions, 186 deletions
diff --git a/atari/browser.c b/atari/browser.c
index fd858c045..e107b88cd 100755
--- a/atari/browser.c
+++ b/atari/browser.c
@@ -87,7 +87,7 @@ struct s_browser * browser_create( struct gui_window * gw,
bw->scale = clone->scale;
else
bw->scale = 1;
-
+ bnew->redraw.areas_used = 0;
bnew->compwin = mt_WindCreate( &app, VSLIDE|HSLIDE, 1, 1, app.w, app.h);
bnew->compwin->w_u = 1;
bnew->compwin->h_u = 1;
@@ -181,21 +181,10 @@ bool browser_attach_frame( struct gui_window * container, struct gui_window * fr
container->browser->compwin->w_max = 0;
container->browser->comp->flex = 0;
container->browser->comp->size = 300;
- //container->browser->comp->bounds.max_height = 0;
- //container->browser->comp->bounds.min_height = 0;
- //WindClose( container->browser->compwin );
-
container->browser->comp->type = lt;
mt_CompAttach( &app, container->browser->comp, frame->browser->comp );
- //win_comp_attach(&app, container->browser->compwin, frame->browser->comp);
browser_update_rects( container );
- frame->browser->attached = true;
- //container->browser->attached = true;
- /*browser_update_rects( frame );
- LGRECT brect;
- browser_get_rect( frame, BR_CONTENT, &brect );
- */
-
+ frame->browser->attached = true;
}
/* find the root of an frame ( or just return gw if is already the root) */
@@ -806,20 +795,17 @@ bool browser_redraw_required( struct gui_window * gw)
}
}
}
- ret = ( (b->redraw.required && frames == 0) ||
- b->scroll.required ||
- b->caret.redraw );
+ ret = ( ((b->redraw.areas_used > 0) && frames == 0)
+ || b->scroll.required
+ || b->caret.redraw );
return( ret );
}
/* schedule a redraw of content */
/* coords are relative to the framebuffer */
-/* the box is modified to fit the current viewport if it doesn't fit in */
void browser_schedule_redraw_rect(struct gui_window * gw, short x, short y, short w, short h)
{
- int diff;
-
if( x < 0 ){
w += x;
x = 0;
@@ -832,17 +818,32 @@ void browser_schedule_redraw_rect(struct gui_window * gw, short x, short y, shor
browser_schedule_redraw( gw, x, y, x+w, y+h );
}
-/* schedule a redraw of content */
-/* coords are relative to the framebuffer */
+static inline bool bbox_intersect(BBOX * box1, BBOX * box2)
+{
+ if (box2->x1 < box1->x0)
+ return false;
+
+ if (box2->y1 < box1->y0)
+ return false;
+
+ if (box2->x0 > box1->x1)
+ return false;
+
+ if (box2->y0 > box1->y1)
+ return false;
+
+ return true;
+}
+
+/*
+ schedule a redraw of content, coords are relative to the framebuffer
+*/
void browser_schedule_redraw(struct gui_window * gw, short x0, short y0, short x1, short y1)
{
assert( gw != NULL );
CMP_BROWSER b = gw->browser;
+ int i;
LGRECT work;
- /* TODO: add rectangle to list, instead of summarizing the rect.? */
- /* otherwise it can result in large areas, altough it isnt needed. ( like 1 px in the upper left,
- and 1px in bottom right corner )
- */
if( y1 < 0 || x1 < 0 )
return;
@@ -853,53 +854,65 @@ void browser_schedule_redraw(struct gui_window * gw, short x0, short y0, short x
if( y0 > work.g_h )
return;
- /* special handling of initial call: */
- if( b->redraw.required == false ) {
- b->redraw.required = true;
- b->redraw.area.x0 = x0;
- b->redraw.area.y0 = y0;
- b->redraw.area.x1 = x1;
- b->redraw.area.y1 = y1;
- } else {
- b->redraw.area.x0 = MIN(b->redraw.area.x0, x0);
- b->redraw.area.y0 = MIN(b->redraw.area.y0, y0);
- b->redraw.area.x1 = MAX(b->redraw.area.x1, x1);
- b->redraw.area.y1 = MAX(b->redraw.area.y1, y1);
+ for( i=0; i<b->redraw.areas_used; i++) {
+ if( b->redraw.areas[i].x0 <= x0
+ && b->redraw.areas[i].x1 >= x1
+ && b->redraw.areas[i].y0 <= y0
+ && b->redraw.areas[i].y1 >= y1 ){
+ /* the area is already queued for redraw */
+ return;
+ } else {
+ BBOX area;
+ area.x0 = x0;
+ area.y0 = y0;
+ area.x1 = x1;
+ area.y1 = y1;
+ if( bbox_intersect(&b->redraw.areas[i], &area ) ){
+ b->redraw.areas[i].x0 = MIN(b->redraw.areas[i].x0, x0);
+ b->redraw.areas[i].y0 = MIN(b->redraw.areas[i].y0, y0);
+ b->redraw.areas[i].x1 = MAX(b->redraw.areas[i].x1, x1);
+ b->redraw.areas[i].y1 = MAX(b->redraw.areas[i].y1, y1);
+ return;
+ }
+ }
}
+
+ if( b->redraw.areas_used < MAX_REDRW_SLOTS ) {
+ b->redraw.areas[b->redraw.areas_used].x0 = x0;
+ b->redraw.areas[b->redraw.areas_used].x1 = x1;
+ b->redraw.areas[b->redraw.areas_used].y0 = y0;
+ b->redraw.areas[b->redraw.areas_used].y1 = y1;
+ b->redraw.areas_used++;
+ } else {
+ /*
+ we are out of available slots, merge box with last slot
+ this is dumb... but also a very rare case.
+ */
+ b->redraw.areas[MAX_REDRW_SLOTS-1].x0 = MIN(b->redraw.areas[i].x0, x0);
+ b->redraw.areas[MAX_REDRW_SLOTS-1].y0 = MIN(b->redraw.areas[i].y0, y0);
+ b->redraw.areas[MAX_REDRW_SLOTS-1].x1 = MAX(b->redraw.areas[i].x1, x1);
+ b->redraw.areas[MAX_REDRW_SLOTS-1].y1 = MAX(b->redraw.areas[i].y1, y1);
+ }
+done:
+ return;
}
static void browser_redraw_content( struct gui_window * gw, int xoff, int yoff )
{
LGRECT work;
CMP_BROWSER b = gw->browser;
- GRECT area;
struct rect clip;
LOG(("%s : %d,%d - %d,%d\n", b->bw->name, b->redraw.area.x0,
b->redraw.area.y0, b->redraw.area.x1, b->redraw.area.y1
));
- area.g_x = b->redraw.area.x0;
- area.g_y = b->redraw.area.y0;
- area.g_w = b->redraw.area.x1 - b->redraw.area.x0;
- area.g_h = b->redraw.area.y1 - b->redraw.area.y0;
current_redraw_browser = b->bw;
- clip.x0 = b->redraw.area.x0;
- clip.y0 = b->redraw.area.y0;
- clip.x1 = b->redraw.area.x1;
- clip.y1 = b->redraw.area.y1;
-
browser_window_redraw( b->bw, -b->scroll.current.x,
- -b->scroll.current.y, &clip );
+ -b->scroll.current.y, &b->redraw.area );
current_redraw_browser = NULL;
-
- /* reset redraw area */
- b->redraw.area.x0 = INT_MAX;
- b->redraw.area.y0 = INT_MAX;
- b->redraw.area.x1 = INT_MIN;
- b->redraw.area.y1 = INT_MIN;
}
@@ -961,41 +974,55 @@ void browser_redraw( struct gui_window * gw )
b->scroll.required = false;
}
- if (b->redraw.required == true && b->bw->current_content != NULL ) {
+ if ((b->redraw.areas_used > 0) && b->bw->current_content != NULL ) {
if( (plotter->flags & PLOT_FLAG_OFFSCREEN) == 0 ) {
+ int i;
GRECT area;
+ GRECT fbwork;
BBOX cliporg;
todo[0] = bwrect.g_x;
todo[1] = bwrect.g_y;
todo[2] = todo[0] + bwrect.g_w-1;
todo[3] = todo[1] + bwrect.g_h-1;
vs_clip(plotter->vdi_handle, 1, (short*)&todo[0]);
-
- area.g_x = b->redraw.area.x0;
- area.g_y = b->redraw.area.y0;
- area.g_w = b->redraw.area.x1 - b->redraw.area.x0;
- area.g_h = b->redraw.area.y1 - b->redraw.area.y0;
if( wind_get(gw->root->handle->handle, WF_FIRSTXYWH,
&todo[0], &todo[1], &todo[2], &todo[3] )!=0 ) {
while (todo[2] && todo[3]) {
/* convert screen to framebuffer coords: */
- todo[0] -= bwrect.g_x;
- todo[1] -= bwrect.g_y;
- if( todo[0] < 0 ){
- todo[2] = todo[2] + todo[0];
- todo[0] = 0;
+ fbwork.g_x = todo[0] - bwrect.g_x;
+ fbwork.g_y = todo[1] - bwrect.g_y;
+ if( fbwork.g_x < 0 ){
+ fbwork.g_w = todo[2] + todo[0];
+ fbwork.g_x = 0;
+ } else {
+ fbwork.g_w = todo[2];
}
- if( todo[1] < 0 ){
- todo[3] = todo[3] + todo[1];
- todo[1] = 0;
+ if( fbwork.g_y < 0 ){
+ fbwork.g_h = todo[3] + todo[1];
+ fbwork.g_y = 0;
+ } else {
+ fbwork.g_h = todo[3];
}
-
- if (rc_intersect((GRECT *)&area,(GRECT *)&todo)) {
- b->redraw.area.x0 = todo[0];
- b->redraw.area.y0 = todo[1];
- b->redraw.area.x1 = b->redraw.area.x0 + todo[2];
- b->redraw.area.y1 = b->redraw.area.y0 + todo[3];
- browser_redraw_content( gw, 0, 0 );
+ /* walk the redraw requests: */
+ for( i=0; i<b->redraw.areas_used; i++ ){
+ area.g_x = b->redraw.areas[i].x0;
+ area.g_y = b->redraw.areas[i].y0;
+ area.g_w = b->redraw.areas[i].x1 - b->redraw.areas[i].x0;
+ area.g_h = b->redraw.areas[i].y1 - b->redraw.areas[i].y0;
+ if (rc_intersect((GRECT *)&fbwork,(GRECT *)&area)) {
+
+ b->redraw.area.x0 = area.g_x; //todo[0];
+ b->redraw.area.y0 = area.g_y; //todo[1];
+ b->redraw.area.x1 = area.g_x + area.g_w; //todo[0] + todo[2];
+ b->redraw.area.y1 = area.g_y + area.g_h; //todo[1] + todo[3];
+ browser_redraw_content( gw, 0, 0 );
+ } else {
+ /*
+ the area should be kept scheduled for later redraw, but because this
+ is onscreen plotter, it doesn't make much sense anyway...
+ */
+ }
+
}
if (wind_get(gw->root->handle->handle, WF_NEXTXYWH,
&todo[0], &todo[1], &todo[2], &todo[3])==0) {
@@ -1007,7 +1034,7 @@ void browser_redraw( struct gui_window * gw )
} else {
/* its save to do a complete redraw :) */
}
- b->redraw.required = false;
+ b->redraw.areas_used = 0;
}
if( b->caret.redraw == true && b->bw->current_content != NULL ) {
GRECT area;
diff --git a/atari/browser.h b/atari/browser.h
index 44d9ac8e1..c5923a125 100755
--- a/atari/browser.h
+++ b/atari/browser.h
@@ -24,7 +24,19 @@
which cosnist mainly of an WinDom COMPONENT.
*/
-#define BROWSER_SCROLL_SVAL 64 /* The small scroll inc. value */
+/*
+ BROWSER_SCROLL_SVAL
+ The small scroll inc. value (used by scroll-wheel, arrow click):
+*/
+#define BROWSER_SCROLL_SVAL 64
+
+/*
+ MAX_REDRW_SLOTS
+ This is the number of redraw requests that an browser window can queue.
+ If a redraw is scheduled and all slots are used, the rectangle will
+ be merged to one of the existing slots.
+ */
+#define MAX_REDRW_SLOTS 32
enum browser_type
{
@@ -42,6 +54,56 @@ enum browser_rect
BR_VSLIDER = 4
};
+
+/*
+ This struct contains info of current browser viewport scroll
+ and the scroll which is requested. If a scroll is requested,
+ the field required is set to true.
+*/
+struct s_scroll_info
+{
+ POINT requested;
+ POINT current;
+ bool required;
+};
+
+/*
+ This struct holds information of the cursor within the browser
+ viewport.
+*/
+struct s_caret
+{
+ GRECT requested;
+ GRECT current;
+ bool redraw;
+};
+
+/*
+ This struct holds scheduled redraw requests.
+*/
+struct s_browser_redrw_info
+{
+ BBOX areas[MAX_REDRW_SLOTS];
+ short areas_used;
+ BBOX area; /* used for clipping of content redraw */
+};
+
+/*
+ This is the actual browser widget, containings GUI elements and
+ the current state of the browser widget.
+*/
+struct s_browser
+{
+ int type;
+ COMPONENT * comp;
+ WINDOW * compwin;
+ struct browser_window * bw;
+ struct s_scroll_info scroll;
+ struct s_browser_redrw_info redraw;
+ struct s_caret caret;
+ bool attached;
+};
+
struct s_browser * browser_create( struct gui_window * gw, struct browser_window * clone, struct browser_window *bw, enum browser_type, int lt, int w, int flex );
bool browser_destroy( struct s_browser * b );
void browser_get_rect( struct gui_window * gw, enum browser_rect type, LGRECT * out);
@@ -53,6 +115,18 @@ bool browser_attach_frame( struct gui_window * container, struct gui_window * fr
struct gui_window * browser_find_root( struct gui_window * gw );
static void browser_process_scroll( struct gui_window * gw, LGRECT bwrect );
bool browser_redraw_required( struct gui_window * gw);
+
+/*
+ This queues an redraw to one of the slots.
+ The following strategy is used:
+ 1. It checks if the rectangle to be scheduled is within one of the
+ already queued bboxes. If yes, it will return.
+ 2. It checks for an intersection, and it will merge the rectangle to
+ already queued rectangle where it fits best.
+ 3. it tries to put the rectangle into one available slot.
+ 4. if no slot is available, it will search for the nearest rectangle
+ and summarize it within that slot.
+*/
void browser_redraw_caret( struct gui_window * gw, GRECT * area );
static void browser_redraw_content( struct gui_window * gw, int xoff, int yoff );
diff --git a/atari/gui.h b/atari/gui.h
index 24a71a1cb..df9d782ee 100755
--- a/atari/gui.h
+++ b/atari/gui.h
@@ -68,28 +68,6 @@ struct s_gem_cursors {
MFORM_EX arrow;
} gem_cursors;
-/* maybe its better to have an linked
- list of redraw areas, so that there
- is no such an overhead when 2 (or more)
- SMALL rectangles far away from each other
- need an redraw!
- Currently these rects get summarized into
- one big redraw area!
-*/
-struct s_browser_redrw_info
-{
- BBOX area; /* this is an box which describes the area to redraw */
- /* from netsurfs point of view */
- bool required;
-};
-
-struct s_scroll_info
-{
- POINT requested;
- POINT current;
- bool required;
-};
-
enum focus_element_type {
WIDGET_NONE=0,
URL_WIDGET,
@@ -113,101 +91,28 @@ struct s_gui_input_state {
} prev_inp_state;
*/
-#define TB_BUTTON_WIDTH 32
-#define TB_BUTTON_HEIGHT 21 /* includes 1px 3d effect */
-#define TOOLBAR_HEIGHT 25
-#define URLBOX_HEIGHT 21
-#define STATUSBAR_HEIGHT 16
-#define STATUSBAR_MAX_SLEN 255
-#define MOVER_WH 16
-#define THROBBER_WIDTH 32
-
-
/* defines for data attached to components: */
#define CDT_OBJECT 0x004f424aUL
#define CDT_OWNER 0x03UL
#define CDT_ICON 0x04UL
#define CDT_ICON_TYPE 0x05UL
-/*
- URL Widget Block size: size of memory block to allocated
- when input takes more memory than currently allocated:
-*/
-#define URL_WIDGET_BSIZE 64
-#define URL_WIDGET_MAX_MEM 60000
-struct s_url_widget
-{
- short selection_len; /* len & direction of selection */
- short caret_pos; /* cursor pos */
- short char_size; /* size of one character (width & hight) */
- short scrollx; /* current scroll position */
- bool redraw; /* widget is only redrawn when this flag is set */
- char * text; /* dynamicall allocated URL string*/
- unsigned short allocated;
- unsigned short used; /* memory used by URL (strlen + 1) */
- COMPONENT * comp;
-};
-
-struct s_throbber_widget
-{
- COMPONENT * comp;
- short index;
- short max_index;
- bool running;
-};
struct gui_window;
-
-struct s_tb_button
-{
- short rsc_id;
- void (*cb_click)(struct gui_window * gw);
- COMPONENT * comp;
-};
-
-struct s_toolbar
-{
- COMPONENT * comp;
- struct gui_window * owner;
- struct s_url_widget url;
- struct s_throbber_widget throbber;
- GRECT btdim; /* size & location of buttons */
- struct s_tb_button * buttons;
- int btcnt;
- /* buttons are defined in toolbar.c */
-};
-
-struct s_statusbar
-{
- COMPONENT * comp;
- char text[STATUSBAR_MAX_SLEN+1];
- size_t textlen;
- bool attached;
-};
-
-struct s_caret
-{
- GRECT requested;
- GRECT current;
- bool redraw;
-};
-
-struct s_browser
-{
- int type;
- COMPONENT * comp;
- WINDOW * compwin;
- struct browser_window * bw;
- struct s_scroll_info scroll;
- struct s_browser_redrw_info redraw;
- struct s_caret caret;
- bool attached;
-};
+struct s_browser;
+struct s_statusbar;
+struct s_toolbar;
typedef struct s_toolbar * CMP_TOOLBAR;
typedef struct s_statusbar * CMP_STATUSBAR;
typedef struct s_browser * CMP_BROWSER;
+/*
+ This is the "main" window. It can consist of several components
+ and also holds information shared by several frames within
+ the window. Each frame, no matter how deep nested,
+ knows about it's root (GEM window).
+*/
struct s_gui_win_root
{
WINDOW * handle;
@@ -222,6 +127,13 @@ struct s_gui_win_root
GRECT loc; /* current size of window on screen */
};
+/*
+ This is the part of the gui which is known by netsurf core.
+ You must implement it. Altough, you are free how to do it.
+ Each of the browser "viewports" managed by netsurf are bound
+ to this structure. gui_window does not mean that it is an
+ comple window - also frames own an gui_window.
+*/
struct gui_window {
struct s_gui_win_root * root;
CMP_BROWSER browser;
@@ -233,5 +145,4 @@ extern struct gui_window *window_list;
#define MOUSE_IS_DRAGGING() (mouse_hold_start[0] || mouse_hold_start[1])
-
#endif
diff --git a/atari/misc.c b/atari/misc.c
index fcefee4e5..35f05d760 100755
--- a/atari/misc.c
+++ b/atari/misc.c
@@ -33,6 +33,7 @@
#include "content/fetch.h"
#include "atari/gui.h"
#include "atari/toolbar.h"
+#include "atari/browser.h"
#include "atari/misc.h"
extern void * h_gem_rsrc;
diff --git a/atari/osspec.c b/atari/osspec.c
index a67e6f164..bbceec144 100644
--- a/atari/osspec.c
+++ b/atari/osspec.c
@@ -116,8 +116,6 @@ char * gemdos_realpath(const char * path, char * rpath)
char * work_ptr;
size_t l;
- printf("gdos rpath in: %s\n", path);
-
if( rpath == NULL ){
return( NULL );
}
@@ -125,6 +123,7 @@ char * gemdos_realpath(const char * path, char * rpath)
return( realpath(path, rpath) );
}
+ LOG(("gdos rpath in: %s\n", path));
memset( rpath, 0, PATH_MAX );
/* first, absolutize relative path: */
@@ -186,7 +185,7 @@ char * gemdos_realpath(const char * path, char * rpath)
strcpy( rpath, work_ptr );
}
l = strlen( rpath );
- printf("gdos rpath out: %s\n", rpath);
+ LOG(("gdos rpath out: %s\n", rpath));
return( rpath );
}
diff --git a/atari/search.c b/atari/search.c
index 37013e92c..668d7c76d 100644
--- a/atari/search.c
+++ b/atari/search.c
@@ -14,6 +14,7 @@
#include "utils/messages.h"
#include "atari/gui.h"
#include "atari/misc.h"
+#include "atari/browser.h"
#include "atari/search.h"
#include "atari/res/netsurf.rsh"
diff --git a/atari/statusbar.c b/atari/statusbar.c
index 85c483b71..7a7582532 100755
--- a/atari/statusbar.c
+++ b/atari/statusbar.c
@@ -58,7 +58,6 @@ void __CDECL evnt_sb_redraw( COMPONENT *c, long buff[8] )
if( sb == NULL )
return;
- assert( sb->attached != false );
if( sb->attached == false )
return;
diff --git a/atari/statusbar.h b/atari/statusbar.h
index ef6f1f040..6daf62951 100755
--- a/atari/statusbar.h
+++ b/atari/statusbar.h
@@ -19,6 +19,19 @@
#ifndef NS_ATARI_STATUSBAR
#define NS_ATARI_STATUSBAR
+#define STATUSBAR_HEIGHT 16
+#define STATUSBAR_MAX_SLEN 255
+#define MOVER_WH 16
+
+struct s_statusbar
+{
+ COMPONENT * comp;
+ char text[STATUSBAR_MAX_SLEN+1];
+ size_t textlen;
+ bool attached;
+};
+
+
CMP_STATUSBAR sb_create( struct gui_window * gw );
void sb_destroy( CMP_STATUSBAR s );
void sb_set_text( CMP_STATUSBAR sb , char * text );
diff --git a/atari/toolbar.c b/atari/toolbar.c
index da8e72176..360d2e66c 100755
--- a/atari/toolbar.c
+++ b/atari/toolbar.c
@@ -40,6 +40,7 @@
#include "atari/gui.h"
#include "atari/toolbar.h"
#include "atari/browser_win.h"
+#include "atari/browser.h"
#include "atari/clipboard.h"
#include "atari/misc.h"
#include "atari/global_evnt.h"
diff --git a/atari/toolbar.h b/atari/toolbar.h
index ecf6ebe7b..851609bc4 100755
--- a/atari/toolbar.h
+++ b/atari/toolbar.h
@@ -19,10 +19,60 @@
#ifndef NS_ATARI_TOOLBAR_H
#define NS_ATARI_TOOLBAR_H
+#define TB_BUTTON_WIDTH 32
+#define TB_BUTTON_HEIGHT 21 /* includes 1px 3d effect */
+#define TOOLBAR_HEIGHT 25
+#define THROBBER_WIDTH 32
#define THROBBER_MIN_INDEX 1
#define THROBBER_MAX_INDEX 12
#define THROBBER_INACTIVE_INDEX 13
+#define URLBOX_HEIGHT 21
+/*
+ URL Widget Block size: size of memory block to allocated
+ when input takes more memory than currently allocated:
+*/
+#define URL_WIDGET_BSIZE 64
+#define URL_WIDGET_MAX_MEM 60000
+
+struct s_tb_button
+{
+ short rsc_id;
+ void (*cb_click)(struct gui_window * gw);
+ COMPONENT * comp;
+};
+
+
+struct s_url_widget
+{
+ short selection_len; /* len & direction of selection */
+ short caret_pos; /* cursor pos */
+ short char_size; /* size of one character (width & hight) */
+ short scrollx; /* current scroll position */
+ bool redraw; /* widget is only redrawn when this flag is set */
+ char * text; /* dynamicall allocated URL string */
+ unsigned short allocated;
+ unsigned short used; /* memory used by URL (strlen + 1) */
+ COMPONENT * comp;
+};
+
+struct s_throbber_widget
+{
+ COMPONENT * comp;
+ short index;
+ short max_index;
+ bool running;
+};
+struct s_toolbar
+{
+ COMPONENT * comp;
+ struct gui_window * owner;
+ struct s_url_widget url;
+ struct s_throbber_widget throbber;
+ GRECT btdim; /* size & location of buttons */
+ struct s_tb_button * buttons;
+ int btcnt;
+};
CMP_TOOLBAR tb_create( struct gui_window * gw );
void tb_destroy( CMP_TOOLBAR tb );