From: John Tsiombikas Date: Tue, 23 Nov 2021 05:34:15 +0000 (+0200) Subject: dirty redraw and SDL framebuffer example X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=windtk;a=commitdiff_plain;h=492a32903dd07d3736bb878e81eb95f351556bac dirty redraw and SDL framebuffer example --- diff --git a/.gitignore b/.gitignore index 2a4e0bf..2865d40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *.d *.swp -example +example_gl +example_sdl diff --git a/Makefile b/Makefile index adce8a2..289aabf 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,24 @@ -src = $(wildcard src/*.c) example.c +src = $(wildcard src/*.c) obj = $(src:.c=.o) -dep = $(src:.c=.d) -bin = example +dep = $(src:.c=.d) example_gl.d example_sdl.d CFLAGS = -pedantic -Wall -g -Isrc -MMD -LDFLAGS = -lGL -lglut -$(bin): $(obj) - $(CC) -o $@ $(obj) $(LDFLAGS) +.PHONY: all +all: example_gl example_sdl + +example_gl: $(obj) example_gl.o + $(CC) -o $@ $^ $(LDFLAGS) -lGL -lglut + +example_sdl: $(obj) example_sdl.o + $(CC) -o $@ $^ $(LDFLAGS) -lSDL -include $(dep) .PHONY: clean clean: - rm -f $(obj) + rm -f $(obj) *.o example_gl example_sdl + +.PHONY: cleandep +cleandep: + rm -f $(dep) *.d diff --git a/example.c b/example.c deleted file mode 100644 index 4ff5bdc..0000000 --- a/example.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include "windtk.h" - -static void display(void); -static void reshape(int x, int y); -static void keypress(unsigned char key, int x, int y); -static void keyrelease(unsigned char key, int x, int y); -static void mouse(int bn, int st, int x, int y); -static void motion(int x, int y); - -static int gfx_newcol(int r, int g, int b); -static void gfx_color(int c); -static void gfx_fillrect(struct wt_rect *r); -static void gfx_line(int x0, int y0, int x1, int y1); - -static struct wt_graphics gfx = { - gfx_newcol, gfx_color, - gfx_fillrect, - gfx_line -}; - -int main(int argc, char **argv) -{ - glutInit(&argc, argv); - glutInitWindowSize(800, 600); - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); - glutCreateWindow("windtk example"); - - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutKeyboardFunc(keypress); - glutKeyboardUpFunc(keyrelease); - glutMouseFunc(mouse); - glutMotionFunc(motion); - glutPassiveMotionFunc(motion); - - glClearColor(0.6, 0.6, 0.6, 1); - - if(wt_init(800, 600, &gfx)) { - return 1; - } - wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200); - - glutMainLoop(); - return 0; -} - -static void display(void) -{ - glClear(GL_COLOR_BUFFER_BIT); - - wt_draw(); - - glutSwapBuffers(); -} - -static void reshape(int x, int y) -{ - glViewport(0, 0, x, y); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, x, y, 0, -1, 1); - - wt_viewport(0, 0, x, y); -} - -static void keypress(unsigned char key, int x, int y) -{ - if(key == 27) exit(0); - - wt_inp_key(key, 1); -} - -static void keyrelease(unsigned char key, int x, int y) -{ - wt_inp_key(key, 0); -} - -static void mouse(int bn, int st, int x, int y) -{ - wt_inp_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y); -} - -static void motion(int x, int y) -{ - wt_inp_motion(x, y); -} - -/* ------ graphics callbacks -------- */ -static float colors[32][3]; -static int maxcol; - -static int gfx_newcol(int r, int g, int b) -{ - if(maxcol >= 32) return -1; - colors[maxcol][0] = r / 255.0f; - colors[maxcol][1] = g / 255.0f; - colors[maxcol][2] = b / 255.0f; - return maxcol++; -} - -static void gfx_color(int c) -{ - glColor3fv(colors[c]); -} - -static void gfx_fillrect(struct wt_rect *r) -{ - glBegin(GL_QUADS); - glVertex2f(r->x, r->y); - glVertex2f(r->x + r->width, r->y); - glVertex2f(r->x + r->width, r->y + r->height); - glVertex2f(r->x, r->y + r->height); - glEnd(); -} - -static void gfx_line(int x0, int y0, int x1, int y1) -{ - glBegin(GL_LINES); - glVertex2f(x0, y0); - glVertex2f(x1, y1); - glEnd(); -} diff --git a/example_gl.c b/example_gl.c new file mode 100644 index 0000000..17ed974 --- /dev/null +++ b/example_gl.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include "windtk.h" + +static void display(void); +static void reshape(int x, int y); +static void keypress(unsigned char key, int x, int y); +static void keyrelease(unsigned char key, int x, int y); +static void mouse(int bn, int st, int x, int y); +static void motion(int x, int y); + +static int gfx_newcol(int r, int g, int b); +static void gfx_color(int c); +static void gfx_fillrect(struct wt_rect *r); +static void gfx_line(int x0, int y0, int x1, int y1); + +static struct wt_graphics gfx = { + WT_GFX_NODIRTY, + gfx_newcol, gfx_color, + gfx_fillrect, + gfx_line +}; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(800, 600); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("windtk example"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keypress); + glutKeyboardUpFunc(keyrelease); + glutMouseFunc(mouse); + glutMotionFunc(motion); + glutPassiveMotionFunc(motion); + + glClearColor(0.6, 0.6, 0.6, 1); + + if(wt_init(800, 600, &gfx) == -1) { + return 1; + } + wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200); + + glutMainLoop(); + return 0; +} + +static void display(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + wt_draw(); + + glutSwapBuffers(); +} + +static void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, x, y, 0, -1, 1); + + wt_viewport(0, 0, x, y); +} + +static void keypress(unsigned char key, int x, int y) +{ + if(key == 27) exit(0); + + wt_inp_key(key, 1); +} + +static void keyrelease(unsigned char key, int x, int y) +{ + wt_inp_key(key, 0); +} + +static void mouse(int bn, int st, int x, int y) +{ + wt_inp_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y); +} + +static void motion(int x, int y) +{ + wt_inp_motion(x, y); +} + +/* ------ graphics callbacks -------- */ +static unsigned char colors[32][3]; +static int maxcol; + +static int gfx_newcol(int r, int g, int b) +{ + int i; + + for(i=0; i= 32) return -1; + + colors[maxcol][0] = r; + colors[maxcol][1] = g; + colors[maxcol][2] = b; + return maxcol++; +} + +static void gfx_color(int c) +{ + glColor3ubv(colors[c]); +} + +static void gfx_fillrect(struct wt_rect *r) +{ + glBegin(GL_QUADS); + glVertex2f(r->x, r->y); + glVertex2f(r->x + r->w, r->y); + glVertex2f(r->x + r->w, r->y + r->h); + glVertex2f(r->x, r->y + r->h); + glEnd(); +} + +static void gfx_line(int x0, int y0, int x1, int y1) +{ + glBegin(GL_LINES); + glVertex2f(x0, y0); + glVertex2f(x1, y1); + glEnd(); +} diff --git a/example_sdl.c b/example_sdl.c new file mode 100644 index 0000000..deb7fce --- /dev/null +++ b/example_sdl.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include "windtk.h" + +static int gfx_newcol(int r, int g, int b); +static void gfx_color(int c); +static void gfx_fillrect(struct wt_rect *r); +static void gfx_line(int x0, int y0, int x1, int y1); + +static struct wt_graphics gfx = { + 0, + gfx_newcol, gfx_color, + gfx_fillrect, + gfx_line +}; + +static SDL_Surface *fbsurf; +static SDL_PixelFormat *pfmt; +static int fb_width = 800, fb_height = 600; +static uint32_t *fb; + +int main(void) +{ + int i, num_upd; + struct wt_rect *rect; + SDL_Event ev; + + if(SDL_Init(SDL_INIT_VIDEO) == -1) { + fprintf(stderr, "failed to initialize SDL\n"); + return 1; + } + + if(!(fbsurf = SDL_SetVideoMode(fb_width, fb_height, 32, SDL_SWSURFACE | SDL_RESIZABLE))) { + fprintf(stderr, "failed to set video mode\n"); + SDL_Quit(); + return 1; + } + pfmt = fbsurf->format; + + SDL_FillRect(fbsurf, 0, 0); + + if(wt_init(fb_width, fb_height, &gfx) == -1) { + return 1; + } + wt_window(0, "foo", WT_WS_DEFAULT, 100, 100, 200, 200); + + while(SDL_WaitEvent(&ev)) { + switch(ev.type) { + case SDL_QUIT: + goto end; + + case SDL_KEYDOWN: + case SDL_KEYUP: + if(ev.key.keysym.sym == SDLK_ESCAPE) { + goto end; + } + wt_inp_key(ev.key.keysym.sym, ev.key.state == SDL_PRESSED); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + wt_inp_mouse(ev.button.button - SDL_BUTTON_LEFT, ev.button.state == SDL_PRESSED, + ev.button.x, ev.button.y); + break; + + case SDL_MOUSEMOTION: + wt_inp_motion(ev.motion.x, ev.motion.y); + break; + + case SDL_VIDEORESIZE: + fb_width = ev.resize.w; + fb_height = ev.resize.h; + wt_viewport(0, 0, ev.resize.w, ev.resize.h); + break; + + default: + break; + } + + if(SDL_MUSTLOCK(fbsurf)) { + SDL_LockSurface(fbsurf); + } + fb = fbsurf->pixels; + wt_draw(); + if(SDL_MUSTLOCK(fbsurf)) { + SDL_UnlockSurface(fbsurf); + } + + num_upd = wt_num_upd(); + for(i=0; ix, rect->y, rect->w, rect->h); + } + } + +end: + wt_destroy(); + SDL_Quit(); + return 0; +} + +/* ------ graphics callbacks -------- */ +static uint32_t colors[32]; +static int maxcol, curcol; + +static int gfx_newcol(int r, int g, int b) +{ + int i; + uint32_t pcol; + + pcol = ((r >> pfmt->Rloss) << pfmt->Rshift) & pfmt->Rmask; + pcol |= ((g >> pfmt->Gloss) << pfmt->Gshift) & pfmt->Gmask; + pcol |= ((b >> pfmt->Bloss) << pfmt->Bshift) & pfmt->Bmask; + + for(i=0; i= 32) return -1; + + colors[maxcol] = pcol; + return maxcol++; +} + +static void gfx_color(int c) +{ + curcol = c; +} + +static void gfx_fillrect(struct wt_rect *r) +{ + int i, j, x, y, w, h; + uint32_t pcol = colors[curcol]; + uint32_t *fbptr; + + w = r->w; + h = r->h; + x = r->x; + y = r->y; + + if(x < 0) { + w += x; + x = 0; + } + if(y < 0) { + h += y; + y = 0; + } + if(x + w >= fb_width) { + w = fb_width - x; + } + if(y + h >= fb_height) { + h = fb_height - y; + } + + fbptr = fb + y * (fbsurf->pitch >> 2) + x; + for(i=0; ipitch >> 2; + } +} + +static void gfx_line(int x0, int y0, int x1, int y1) +{ +} diff --git a/src/widget.c b/src/widget.c index 96be755..02c3ff0 100644 --- a/src/widget.c +++ b/src/widget.c @@ -9,6 +9,7 @@ wt_widget *wt_alloc_widget(wt_widget *par) return 0; } w->type = WT_TYPE_WIDGET; + w->dirty = 1; if(!par) par = wt->root; wt_add_child(par, w); @@ -36,6 +37,17 @@ void wt_free_tree(wt_widget *tree) wt_free_widget(tree); } +void wt_dirty_widget(wt_widget *w) +{ + int i; + + w->dirty = 1; + + for(i=0; inum_child; i++) { + wt_dirty_widget(w->child[i]); + } +} + int wt_type(wt_widget *w) { return w->type; @@ -156,8 +168,8 @@ void wt_move(wt_widget *w, int x, int y) void wt_resize(wt_widget *w, int x, int y) { - w->rect.width = x; - w->rect.height = y; + w->rect.w = x; + w->rect.h = y; /* TODO: invalidate something */ } @@ -170,15 +182,15 @@ int *wt_position(wt_widget *w, int *xret, int *yret) int *wt_size(wt_widget *w, int *xret, int *yret) { - if(xret) *xret = w->rect.width; - if(yret) *yret = w->rect.height; - return &w->rect.width; + if(xret) *xret = w->rect.w; + if(yret) *yret = w->rect.h; + return &w->rect.w; } int wt_hittest(wt_widget *w, int x, int y) { - return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.width && - y < w->rect.y + w->rect.height; + return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.w && + y < w->rect.y + w->rect.h; } wt_widget *wt_widget_at(int x, int y) diff --git a/src/widget.h b/src/widget.h index c174f43..e7c44dc 100644 --- a/src/widget.h +++ b/src/widget.h @@ -16,6 +16,8 @@ struct wt_widget { wt_callback_func cb[WT_NUM_CALLBACKS]; void *cbcls[WT_NUM_CALLBACKS]; + int dirty; /* redraw pending */ + wt_draw_func draw; void (*click)(struct wt_widget *w); void (*keypress)(struct wt_widget *w, int key); diff --git a/src/window.c b/src/window.c index cd39284..9925db4 100644 --- a/src/window.c +++ b/src/window.c @@ -26,6 +26,14 @@ wt_widget *wt_window(wt_widget *par, const char *title, int style, int x, int y, #define TBARTHICK 12 /* TODO: base it on font metrics */ #define TBAROFFS (TBARTHICK + FRMBEVEL * 2) +void calc_window_rect(struct wt_rect *r, wt_widget *w) +{ + r->x = w->rect.x - FRMOFFS; + r->y = w->rect.y - TBAROFFS - FRMOFFS; + r->w = w->rect.w + FRMOFFS * 2; + r->h = w->rect.h + TBAROFFS + FRMOFFS * 2; +} + static void draw_win(wt_widget *w, struct wt_graphics *gfx) { struct wt_rect fr, tmprect; @@ -34,10 +42,7 @@ static void draw_win(wt_widget *w, struct wt_graphics *gfx) wt_gfx_color(COL_BG); wt_gfx_fillrect(&w->rect); - fr.x = w->rect.x - FRMOFFS; - fr.y = w->rect.y - TBAROFFS - FRMOFFS; - fr.width = w->rect.width + FRMOFFS * 2; - fr.height = w->rect.height + TBAROFFS + FRMOFFS * 2; + calc_window_rect(&fr, w); wt_gfx_frame(&fr, FRM_OUT | FRM_NOFILL, frmcol); /* outer bevel */ @@ -46,35 +51,35 @@ static void draw_win(wt_widget *w, struct wt_graphics *gfx) fr.x += FRMBEVEL; fr.y += FRMBEVEL; - fr.width -= FRMBEVEL * 2; - fr.height -= FRMBEVEL * 2; + fr.w -= FRMBEVEL * 2; + fr.h -= FRMBEVEL * 2; tmprect = fr; - tmprect.width = FRMTHICK; + tmprect.w = FRMTHICK; wt_gfx_fillrect(&tmprect); /* left bar */ - tmprect.x += fr.width - FRMTHICK; + tmprect.x += fr.w - FRMTHICK; wt_gfx_fillrect(&tmprect); /* right bar */ tmprect = fr; - tmprect.height = FRMTHICK; + tmprect.h = FRMTHICK; tmprect.x += FRMTHICK; - tmprect.width -= FRMTHICK * 2; + tmprect.w -= FRMTHICK * 2; wt_gfx_fillrect(&tmprect); /* top bar */ - tmprect.y += fr.height - FRMTHICK; + tmprect.y += fr.h - FRMTHICK; wt_gfx_fillrect(&tmprect); /* bottom bar */ /* inner bevel */ fr.x += FRMTHICK; fr.y += FRMTHICK; - fr.width -= FRMTHICK * 2; - fr.height -= FRMTHICK * 2; + fr.w -= FRMTHICK * 2; + fr.h -= FRMTHICK * 2; wt_gfx_frame(&fr, FRM_IN | FRM_NOFILL, frmcol); /* titlebar */ fr.x = w->rect.x; - fr.width = w->rect.width; + fr.w = w->rect.w; fr.y += FRMBEVEL; - fr.height = TBARTHICK + FRMBEVEL * 2; + fr.h = TBARTHICK + FRMBEVEL * 2; wt_gfx_frame(&fr, FRM_OUT, frmcol); } diff --git a/src/windtk.c b/src/windtk.c index c34dc42..69ad9fa 100644 --- a/src/windtk.c +++ b/src/windtk.c @@ -124,19 +124,76 @@ void wt_draw_tree(wt_widget *tree) int i; if(tree->draw) { - tree->draw(tree, &wt->gfx); + if(wt->gfx.flags & WT_GFX_NODIRTY) { + tree->draw(tree, &wt->gfx); + } else { + if(tree->dirty) { + tree->draw(tree, &wt->gfx); + + if(!tree->parent || !tree->parent->dirty) { + /* topmost dirty widget should update rects */ + if(tree->type == WT_TYPE_WINDOW) { + struct wt_rect r; + calc_window_rect(&r, tree); + wt_add_upd_rect(&r); + } else { + wt_add_upd_rect(&tree->rect); + } + } + } + } } for(i=0; inum_child; i++) { wt_draw_tree(tree->child[i]); } + + tree->dirty = 0; } void wt_draw(void) { + wt->num_upd = 0; wt_draw_tree(wt->root); } +int wt_num_upd(void) +{ + return wt->num_upd; +} + +struct wt_rect *wt_upd_rect(int idx) +{ + if(idx < 0 || idx >= wt->num_upd) { + return 0; + } + return wt->upd + idx; +} + +void wt_add_upd_rect(struct wt_rect *r) +{ + int i; + struct wt_rect rect; + + for(i=0; inum_upd; i++) { + if(wt_rect_overlap(wt->upd + i, r)) { + rect = wt->upd[i]; + wt->upd[i] = wt->upd[--wt->num_upd]; + wt_rect_union(&rect, r); + wt_add_upd_rect(&rect); + return; + } + } + + /* no overlaps found, add it if there is space, or union with existing if not */ + if(wt->num_upd >= MAX_UPD_RECTS) { + wt_rect_union(wt->upd, r); + } else { + wt->upd[wt->num_upd++] = *r; + } +} + + void wt_gfx_color(int cidx) { wt->gfx.color(wt->colors[cidx]); @@ -161,11 +218,11 @@ void wt_gfx_frame(struct wt_rect *r, int style, int basecol) wt_gfx_fillrect(r); } wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 2 : basecol + 1); - wt_gfx_fillrect4i(r->x + 1, r->y + r->height - 1, r->width - 2, 1); - wt_gfx_fillrect4i(r->x + r->width - 1, r->y, 1, r->height); + wt_gfx_fillrect4i(r->x + 1, r->y + r->h - 1, r->w - 2, 1); + wt_gfx_fillrect4i(r->x + r->w - 1, r->y, 1, r->h); wt_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 1 : basecol + 2); - wt_gfx_fillrect4i(r->x + 1, r->y, r->width - 2, 1); - wt_gfx_fillrect4i(r->x, r->y, 1, r->height); + wt_gfx_fillrect4i(r->x + 1, r->y, r->w - 2, 1); + wt_gfx_fillrect4i(r->x, r->y, 1, r->h); } void wt_gfx_line(int x0, int y0, int x1, int y1) @@ -177,6 +234,31 @@ void wt_rect(struct wt_rect *r, int x, int y, int w, int h) { r->x = x; r->y = y; - r->width = w; - r->height = h; + r->w = w; + r->h = h; +} + +void wt_rect_union(struct wt_rect *a, struct wt_rect *b) +{ + int x1, y1; + + x1 = a->x + a->w; + y1 = a->y + a->h; + + if(b->x < a->x) a->x = b->x; + if(b->y < a->y) a->y = b->y; + if(b->x + b->w > x1) x1 = b->x + b->w; + if(b->y + b->h > y1) y1 = b->y + b->h; + + a->w = x1 - a->x; + a->h = y1 - a->y; +} + +int wt_rect_overlap(struct wt_rect *a, struct wt_rect *b) +{ + if(a->x > b->x + b->w) return 0; + if(b->x > a->x + a->w) return 0; + if(a->y > b->y + b->h) return 0; + if(b->y > a->x + a->h) return 0; + return 1; } diff --git a/src/windtk.h b/src/windtk.h index 0435e6f..996d473 100644 --- a/src/windtk.h +++ b/src/windtk.h @@ -49,10 +49,18 @@ struct wt_image { }; struct wt_rect { - int x, y, width, height; + int x, y, w, h; +}; + +/* graphics flags */ +enum { + WT_GFX_RGB = 1, /* RGB mode, calls newcolor to set current, not to allocate */ + WT_GFX_NODIRTY = 2 /* don't use dirty rects, always redraw completely */ }; struct wt_graphics { + unsigned int flags; + int (*newcolor)(int r, int g, int b); void (*color)(int c); @@ -100,10 +108,17 @@ void wt_inp_motion(int x, int y); void wt_draw(void); +/* screen regions updated by the last wt_draw */ +int wt_num_upd(void); +struct wt_rect *wt_upd_rect(int idx); +void wt_add_upd_rect(struct wt_rect *r); + wt_widget *wt_alloc_widget(wt_widget *par); void wt_free_widget(wt_widget *w); void wt_free_tree(wt_widget *tree); +void wt_dirty_widget(wt_widget *w); /* propagates to children */ + wt_widget *wt_window(wt_widget *par, const char *title, int style, int x, int y, int width, int height); wt_widget *wt_label(wt_widget *par, const char *text, int x, int y); wt_widget *wt_button(wt_widget *par, const char *text, int x, int y, int width, int height); @@ -154,5 +169,7 @@ int wt_isenabled(wt_widget *w); void wt_callback(wt_widget *w, int type, wt_callback_func func, void *cls); void wt_rect(struct wt_rect *r, int x, int y, int w, int h); +void wt_rect_union(struct wt_rect *a, struct wt_rect *b); +int wt_rect_overlap(struct wt_rect *a, struct wt_rect *b); #endif /* WINDTK_H_ */ diff --git a/src/wtimpl.h b/src/wtimpl.h index 76e51f1..d0c2ea4 100644 --- a/src/wtimpl.h +++ b/src/wtimpl.h @@ -23,6 +23,8 @@ enum { enum { FRM_OUT, FRM_IN, FRM_NOFILL = 0x8000 }; #define FRMSTYLE(x) ((x) & 0xff) +#define MAX_UPD_RECTS 16 + struct wt_context { struct wt_graphics gfx; struct wt_rect vp; @@ -32,6 +34,9 @@ struct wt_context { int colors[NUM_COLORS]; wt_widget *focuswin; + + struct wt_rect upd[MAX_UPD_RECTS]; + int num_upd; }; extern struct wt_context *wt_curctx_; @@ -47,4 +52,6 @@ void wt_gfx_fillrect(struct wt_rect *r); void wt_gfx_frame(struct wt_rect *r, int style, int basecol); void wt_gfx_line(int x0, int y0, int x1, int y1); +void calc_window_rect(struct wt_rect *r, wt_widget *w); + #endif /* WTIMPL_H_ */