2.5: WM Compositing
[blender-staging.git] / source / blender / windowmanager / intern / wm_draw.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <GL/glew.h>
32
33 #include "DNA_listBase.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_windowmanager_types.h"
36 #include "DNA_userdef_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44
45 #include "ED_screen.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49 #include "wm.h"
50 #include "wm_draw.h"
51 #include "wm_window.h"
52 #include "wm_event_system.h"
53
54 /* swap */
55 #define WIN_NONE_OK             0
56 #define WIN_BACK_OK     1
57 #define WIN_FRONT_OK    2
58 #define WIN_BOTH_OK             3
59
60 /* ********************* drawing, swap ****************** */
61
62 static void wm_paintcursor_draw(bContext *C, ARegion *ar)
63 {
64         wmWindowManager *wm= CTX_wm_manager(C);
65         
66         if(wm->paintcursors.first) {
67                 wmWindow *win= CTX_wm_window(C);
68                 bScreen *screen= win->screen;
69                 wmPaintCursor *pc;
70
71                 if(screen->subwinactive == ar->swinid) {
72                         for(pc= wm->paintcursors.first; pc; pc= pc->next) {
73                                 if(pc->poll(C)) {
74                                         ARegion *ar= CTX_wm_region(C);
75                                         pc->draw(C, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin);
76                                 }
77                         }
78                 }
79         }
80 }
81
82 /********************** draw all **************************/
83 /* - reference method, draw all each time                 */
84
85 static void wm_method_draw_full(bContext *C, wmWindow *win)
86 {
87         bScreen *screen= win->screen;
88         ScrArea *sa;
89         ARegion *ar;
90
91         /* draw area regions */
92         for(sa= screen->areabase.first; sa; sa= sa->next) {
93                 CTX_wm_area_set(C, sa);
94
95                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
96                         if(ar->swinid) {
97                                 CTX_wm_region_set(C, ar);
98                                 ED_region_do_draw(C, ar);
99                                 wm_paintcursor_draw(C, ar);
100                                 ED_area_overdraw_flush(C, sa, ar);
101                                 CTX_wm_region_set(C, NULL);
102                         }
103                 }
104                 
105                 CTX_wm_area_set(C, NULL);
106         }
107
108         ED_screen_draw(win);
109         ED_area_overdraw(C);
110
111         /* draw overlapping regions */
112         for(ar=screen->regionbase.first; ar; ar= ar->next) {
113                 if(ar->swinid) {
114                         CTX_wm_region_set(C, ar);
115                         ED_region_do_draw(C, ar);
116                         CTX_wm_region_set(C, NULL);
117                 }
118         }
119
120         if(screen->do_draw_gesture)
121                 wm_gesture_draw(win);
122 }
123
124 /****************** draw overlap all **********************/
125 /* - redraw marked areas, and anything that overlaps it   */
126 /* - it also handles swap exchange optionally, assuming   */
127 /*   that on swap no clearing happens and we get back the */
128 /*   same buffer as we swapped to the front               */
129
130 /* mark area-regions to redraw if overlapped with rect */
131 static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
132 {
133         ScrArea *sa;
134         ARegion *ar;
135
136         for(sa= screen->areabase.first; sa; sa= sa->next) {
137                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
138                         if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
139                                 ar->do_draw= 1;
140                                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
141                                 ar->swap= WIN_NONE_OK;
142                         }
143                 }
144         }
145 }
146
147 /* mark menu-regions to redraw if overlapped with rect */
148 static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
149 {
150         ARegion *ar;
151         
152         for(ar= screen->regionbase.first; ar; ar= ar->next) {
153                 if(BLI_isect_rcti(dirty, &ar->winrct, NULL)) {
154                         ar->do_draw= 1;
155                         memset(&ar->drawrct, 0, sizeof(ar->drawrct));
156                         ar->swap= WIN_NONE_OK;
157                 }
158         }
159 }
160
161 static void wm_method_draw_overlap_all(bContext *C, wmWindow *win)
162 {
163         bScreen *screen= win->screen;
164         ScrArea *sa;
165         ARegion *ar;
166         int exchange= (G.f & G_SWAP_EXCHANGE);
167
168         /* flush overlapping regions */
169         if(screen->regionbase.first) {
170                 /* flush redraws of area regions up to overlapping regions */
171                 for(sa= screen->areabase.first; sa; sa= sa->next)
172                         for(ar= sa->regionbase.first; ar; ar= ar->next)
173                                 if(ar->swinid && ar->do_draw)
174                                         wm_flush_regions_up(screen, &ar->winrct);
175                 
176                 /* flush between overlapping regions */
177                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
178                         if(ar->swinid && ar->do_draw)
179                                 wm_flush_regions_up(screen, &ar->winrct);
180                 
181                 /* flush redraws of overlapping regions down to area regions */
182                 for(ar= screen->regionbase.last; ar; ar= ar->prev)
183                         if(ar->swinid && ar->do_draw)
184                                 wm_flush_regions_down(screen, &ar->winrct);
185         }
186
187         /* draw marked area regions */
188         for(sa= screen->areabase.first; sa; sa= sa->next) {
189                 CTX_wm_area_set(C, sa);
190
191                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
192                         if(ar->swinid) {
193                                 if(ar->do_draw) {
194                                         CTX_wm_region_set(C, ar);
195                                         ED_region_do_draw(C, ar);
196                                         wm_paintcursor_draw(C, ar);
197                                         ED_area_overdraw_flush(C, sa, ar);
198                                         CTX_wm_region_set(C, NULL);
199
200                                         if(exchange)
201                                                 ar->swap= WIN_FRONT_OK;
202                                 }
203                                 else if(exchange) {
204                                         if(ar->swap == WIN_FRONT_OK) {
205                                                 CTX_wm_region_set(C, ar);
206                                                 ED_region_do_draw(C, ar);
207                                                 wm_paintcursor_draw(C, ar);
208                                                 ED_area_overdraw_flush(C, sa, ar);
209                                                 CTX_wm_region_set(C, NULL);
210
211                                                 ar->swap= WIN_BOTH_OK;
212                                                 printf("draws swap exchange %d\n", ar->swinid);
213                                         }
214                                         else if(ar->swap == WIN_BACK_OK)
215                                                 ar->swap= WIN_FRONT_OK;
216                                         else if(ar->swap == WIN_BOTH_OK)
217                                                 ar->swap= WIN_BOTH_OK;
218                                 }
219                         }
220                 }
221                 
222                 CTX_wm_area_set(C, NULL);
223         }
224
225         /* after area regions so we can do area 'overlay' drawing */
226         if(screen->do_draw) {
227                 ED_screen_draw(win);
228
229                 if(exchange)
230                         screen->swap= WIN_FRONT_OK;
231         }
232         else if(exchange) {
233                 if(screen->swap==WIN_FRONT_OK) {
234                         ED_screen_draw(win);
235                         screen->swap= WIN_BOTH_OK;
236                 }
237                 else if(screen->swap==WIN_BACK_OK)
238                         screen->swap= WIN_FRONT_OK;
239                 else if(screen->swap==WIN_BOTH_OK)
240                         screen->swap= WIN_BOTH_OK;
241         }
242
243         ED_area_overdraw(C);
244
245         /* draw marked overlapping regions */
246         for(ar=screen->regionbase.first; ar; ar= ar->next) {
247                 if(ar->swinid && ar->do_draw) {
248                         CTX_wm_region_set(C, ar);
249                         ED_region_do_draw(C, ar);
250                         CTX_wm_region_set(C, NULL);
251                 }
252         }
253
254         if(screen->do_draw_gesture)
255                 wm_gesture_draw(win);
256 }
257
258 #if 0
259 /******************** draw damage ************************/
260 /* - not implemented                                      */
261
262 static void wm_method_draw_damage(bContext *C, wmWindow *win)
263 {
264         wm_method_draw_all(C, win);
265 }
266 #endif
267
268 /****************** draw triple buffer ********************/
269 /* - area regions are written into a texture, without any */
270 /*   of the overlapping menus, brushes, gestures. these   */
271 /*   are redrawn each time.                               */
272 /*                                                        */
273 /* - if non-power of two textures are supported, that is  */
274 /*   used. if not, multiple smaller ones are used, with   */
275 /*   worst case wasted space being 23.4% for 3x3 textures */
276
277 #define MAX_N_TEX 3
278
279 typedef struct wmDrawTriple {
280         GLuint bind[MAX_N_TEX*MAX_N_TEX];
281         int x[MAX_N_TEX], y[MAX_N_TEX];
282         int nx, ny;
283         GLenum target;
284 } wmDrawTriple;
285
286 static int is_pow2(int n)
287 {
288         return ((n)&(n-1))==0;
289 }
290
291 static int smaller_pow2(int n)
292 {
293     while (!is_pow2(n))
294                 n= n&(n-1);
295
296         return n;
297 }
298
299 static int larger_pow2(int n)
300 {
301         if (is_pow2(n))
302                 return n;
303
304         while(!is_pow2(n))
305                 n= n&(n-1);
306
307         return n*2;
308 }
309
310 static void split_width(int x, int n, int *splitx, int *nx)
311 {
312         int a, newnx, waste;
313
314         /* if already power of two just use it */
315         if(is_pow2(x)) {
316                 splitx[0]= x;
317                 (*nx)++;
318                 return;
319         }
320
321         if(n == 1) {
322                 /* last part, we have to go larger */
323                 splitx[0]= larger_pow2(x);
324                 (*nx)++;
325         }
326         else {
327                 /* two or more parts to go, use smaller part */
328                 splitx[0]= smaller_pow2(x);
329                 newnx= ++(*nx);
330                 split_width(x-splitx[0], n-1, splitx+1, &newnx);
331
332                 for(waste=0, a=0; a<n; a++)
333                         waste += splitx[a];
334
335                 /* if we waste more space or use the same amount,
336                  * revert deeper splits and just use larger */
337                 if(waste >= larger_pow2(x)) {
338                         splitx[0]= larger_pow2(x);
339                         memset(splitx+1, 0, sizeof(int)*(n-1));
340                 }
341                 else
342                         *nx= newnx;
343         }
344 }
345
346 static void wm_draw_triple_free(wmWindow *win)
347 {
348         if(win->drawdata) {
349                 wmDrawTriple *triple= win->drawdata;
350
351                 glDeleteTextures(triple->nx*triple->ny, triple->bind);
352                 MEM_freeN(triple);
353
354                 win->drawdata= NULL;
355         }
356 }
357
358 static void wm_draw_triple_fail(bContext *C, wmWindow *win)
359 {
360         wm_draw_window_clear(win);
361
362         win->drawfail= 1;
363         wm_method_draw_overlap_all(C, win);
364 }
365
366 static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
367 {
368         GLint format;
369         int x, y;
370
371         /* compute texture sizes */
372         if(GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
373                 triple->target= GL_TEXTURE_RECTANGLE_ARB;
374                 triple->nx= 1;
375                 triple->ny= 1;
376                 triple->x[0]= win->sizex;
377                 triple->y[0]= win->sizey;
378         }
379         else if(GLEW_ARB_texture_non_power_of_two) {
380                 triple->target= GL_TEXTURE_2D;
381                 triple->nx= 1;
382                 triple->ny= 1;
383                 triple->x[0]= win->sizex;
384                 triple->y[0]= win->sizey;
385         }
386         else {
387                 triple->target= GL_TEXTURE_2D;
388                 triple->nx= 0;
389                 triple->ny= 0;
390                 split_width(win->sizex, MAX_N_TEX, triple->x, &triple->nx);
391                 split_width(win->sizey, MAX_N_TEX, triple->y, &triple->ny);
392         }
393
394         /* generate texture names */
395         glGenTextures(triple->nx*triple->ny, triple->bind);
396
397         if(!triple->bind[0]) {
398                 /* not the typical failure case but we handle it anyway */
399                 printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
400                 return 0;
401         }
402
403         for(y=0; y<triple->ny; y++) {
404                 for(x=0; x<triple->nx; x++) {
405                         /* proxy texture is only guaranteed to test for the cases that
406                          * there is only one texture in use, which may not be the case */
407                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
408                         glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
409                         glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
410
411                         if(format != GL_RGB8) {
412                                 glBindTexture(triple->target, 0);
413                                 printf("WM: failed to allocate texture for triple buffer drawing (GL_PROXY_TEXTURE_2D).\n");
414                                 return 0;
415                         }
416
417                         /* setup actual texture */
418                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
419                         glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
420                         glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
421                         glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
422                         // glColor still used with this enabled?
423                         // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE);
424                         glBindTexture(triple->target, 0);
425
426                         /* not sure if this works everywhere .. */
427                         if(glGetError() == GL_OUT_OF_MEMORY) {
428                                 printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
429                                 return 0;
430                         }
431                 }
432         }
433
434         return 1;
435 }
436
437 static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple)
438 {
439         float halfx, halfy, ratiox, ratioy;
440         int x, y, sizex, sizey, offx, offy;
441
442         glEnable(triple->target);
443
444         for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
445                 for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
446                         sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
447                         sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
448
449                         /* wmOrtho for the screen has this same offset */
450                         ratiox= sizex;
451                         ratioy= sizey;
452                         halfx= 0.375f;
453                         halfy= 0.375f;
454
455                         /* texture rectangle has unnormalized coordinates */
456                         if(triple->target == GL_TEXTURE_2D) {
457                                 ratiox /= triple->x[x];
458                                 ratioy /= triple->y[y];
459                                 halfx /= triple->x[x];
460                                 halfy /= triple->y[y];
461                         }
462
463                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
464
465                         glColor3f(1.0f, 1.0f, 1.0f);
466                         glBegin(GL_QUADS);
467                                 glTexCoord2f(halfx, halfy);
468                                 glVertex2f(offx, offy);
469
470                                 glTexCoord2f(ratiox+halfx, halfy);
471                                 glVertex2f(offx+sizex, offy);
472
473                                 glTexCoord2f(ratiox+halfx, ratioy+halfy);
474                                 glVertex2f(offx+sizex, offy+sizey);
475
476                                 glTexCoord2f(halfx, ratioy+halfy);
477                                 glVertex2f(offx, offy+sizey);
478                         glEnd();
479                 }
480         }
481
482         glBindTexture(triple->target, 0);
483         glDisable(triple->target);
484 }
485
486 static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
487 {
488         int x, y, sizex, sizey, offx, offy;
489
490         for(y=0, offy=0; y<triple->ny; offy+=triple->y[y], y++) {
491                 for(x=0, offx=0; x<triple->nx; offx+=triple->x[x], x++) {
492                         sizex= (x == triple->nx-1)? win->sizex-offx: triple->x[x];
493                         sizey= (y == triple->ny-1)? win->sizey-offy: triple->y[y];
494
495                         glBindTexture(triple->target, triple->bind[x + y*triple->nx]);
496                         glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey);
497                 }
498         }
499
500         glBindTexture(triple->target, 0);
501 }
502
503 static void wm_method_draw_triple(bContext *C, wmWindow *win)
504 {
505         wmWindowManager *wm= CTX_wm_manager(C);
506         wmDrawTriple *triple;
507         bScreen *screen= win->screen;
508         ScrArea *sa;
509         ARegion *ar;
510         int copytex= 0;
511
512         if(win->drawdata) {
513                 glClearColor(0, 0, 0, 0);
514                 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
515
516                 wmSubWindowSet(win, screen->mainwin);
517
518                 wm_triple_draw_textures(win, win->drawdata);
519
520                 triple= win->drawdata;
521         }
522         else {
523                 win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
524
525                 if(!wm_triple_gen_textures(win, win->drawdata)) {
526                         wm_draw_triple_fail(C, win);
527                         return;
528                 }
529         }
530
531         triple= win->drawdata;
532
533         /* draw marked area regions */
534         for(sa= screen->areabase.first; sa; sa= sa->next) {
535                 CTX_wm_area_set(C, sa);
536
537                 for(ar=sa->regionbase.first; ar; ar= ar->next) {
538                         if(ar->swinid && ar->do_draw) {
539                                 CTX_wm_region_set(C, ar);
540                                 ED_region_do_draw(C, ar);
541                                 ED_area_overdraw_flush(C, sa, ar);
542                                 CTX_wm_region_set(C, NULL);
543                                 copytex= 1;
544                         }
545                 }
546                 
547                 CTX_wm_area_set(C, NULL);
548         }
549
550         if(copytex) {
551                 wmSubWindowSet(win, screen->mainwin);
552                 ED_area_overdraw(C);
553
554                 wm_triple_copy_textures(win, triple);
555         }
556
557         /* after area regions so we can do area 'overlay' drawing */
558         ED_screen_draw(win);
559
560         /* draw overlapping regions */
561         for(ar=screen->regionbase.first; ar; ar= ar->next) {
562                 if(ar->swinid) {
563                         CTX_wm_region_set(C, ar);
564                         ED_region_do_draw(C, ar);
565                         CTX_wm_region_set(C, NULL);
566                 }
567         }
568
569         if(win->screen->do_draw_gesture)
570                 wm_gesture_draw(win);
571
572         if(wm->paintcursors.first) {
573                 for(sa= screen->areabase.first; sa; sa= sa->next) {
574                         for(ar=sa->regionbase.first; ar; ar= ar->next) {
575                                 if(ar->swinid == screen->subwinactive) {
576                                         CTX_wm_area_set(C, sa);
577                                         CTX_wm_region_set(C, ar);
578
579                                         wmSubWindowSet(win, ar->swinid);
580                                         ED_region_pixelspace(ar);
581                                         wm_paintcursor_draw(C, ar);
582
583                                         CTX_wm_region_set(C, NULL);
584                                         CTX_wm_area_set(C, NULL);
585                                 }
586                         }
587                 }
588
589                 wmSubWindowSet(win, screen->mainwin);
590         }
591 }
592
593 /****************** main update call **********************/
594
595 /* quick test to prevent changing window drawable */
596 static int wm_draw_update_test_window(wmWindow *win)
597 {
598         ScrArea *sa;
599         ARegion *ar;
600         
601         if(win->screen->do_refresh)
602                 return 1;
603         if(win->screen->do_draw)
604                 return 1;
605         if(win->screen->do_draw_gesture)
606                 return 1;
607         if(win->screen->do_draw_paintcursor)
608                 return 1;
609         
610         for(ar= win->screen->regionbase.first; ar; ar= ar->next)
611                 if(ar->swinid && ar->do_draw)
612                         return 1;
613                 
614         for(sa= win->screen->areabase.first; sa; sa= sa->next)
615                 for(ar=sa->regionbase.first; ar; ar= ar->next)
616                         if(ar->swinid && ar->do_draw)
617                                 return 1;
618
619         return 0;
620 }
621
622 void wm_draw_update(bContext *C)
623 {
624         wmWindowManager *wm= CTX_wm_manager(C);
625         wmWindow *win;
626         
627         for(win= wm->windows.first; win; win= win->next) {
628                 if(win->drawmethod != U.wmdrawmethod) {
629                         wm_draw_window_clear(win);
630                         win->drawmethod= U.wmdrawmethod;
631                 }
632
633                 if(wm_draw_update_test_window(win)) {
634                         CTX_wm_window_set(C, win);
635                         
636                         /* sets context window+screen */
637                         wm_window_make_drawable(C, win);
638
639                         /* notifiers for screen redraw */
640                         if(win->screen->do_refresh)
641                                 ED_screen_refresh(wm, win);
642
643                         if(win->drawfail)
644                                 wm_method_draw_overlap_all(C, win);
645                         else if(win->drawmethod == USER_DRAW_FULL)
646                                 wm_method_draw_full(C, win);
647                         else if(win->drawmethod == USER_DRAW_OVERLAP)
648                                 wm_method_draw_overlap_all(C, win);
649                         /*else if(win->drawmethod == USER_DRAW_DAMAGE)
650                                 wm_method_draw_damage(C, win);*/
651                         else // if(win->drawmethod == USER_DRAW_TRIPLE)
652                                 wm_method_draw_triple(C, win);
653
654                         win->screen->do_draw_gesture= 0;
655                         win->screen->do_draw_paintcursor= 0;
656                 
657                         wm_window_swap_buffers(win);
658
659                         CTX_wm_window_set(C, NULL);
660                 }
661         }
662 }
663
664 void wm_draw_window_clear(wmWindow *win)
665 {
666         bScreen *screen= win->screen;
667         ScrArea *sa;
668         ARegion *ar;
669
670         if(win->drawmethod == USER_DRAW_TRIPLE)
671                 wm_draw_triple_free(win);
672
673         /* clear screen swap flags */
674         if(screen) {
675                 for(sa= screen->areabase.first; sa; sa= sa->next)
676                         for(ar=sa->regionbase.first; ar; ar= ar->next)
677                                 ar->swap= WIN_NONE_OK;
678                 
679                 screen->swap= WIN_NONE_OK;
680         }
681 }
682
683 void wm_draw_region_clear(wmWindow *win, ARegion *ar)
684 {
685         if(win->drawmethod == USER_DRAW_OVERLAP)
686                 wm_flush_regions_down(win->screen, &ar->winrct);
687
688         win->screen->do_draw= 1;
689 }
690