60bf34a04f893c6371da048681358cfb573984bd
[blender.git] / source / blender / src / editscreen.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * All screen functions that are related to the interface
32  * handling and drawing. Might be split up as well later...
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifdef WIN32
40 #include "BLI_winstuff.h"
41 #endif   
42
43 #include "nla.h"
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <math.h>
49
50 #include "MEM_guardedalloc.h"
51
52 #include "PIL_time.h"
53
54 #include "BMF_Api.h"
55
56 #include "BLI_blenlib.h"
57 #include "BLI_arithb.h"
58
59 #include "IMB_imbuf_types.h"
60 #include "IMB_imbuf.h"
61
62 #include "DNA_action_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_screen_types.h"
65 #include "DNA_space_types.h"
66 #include "DNA_sound_types.h"
67 #include "DNA_view3d_types.h"
68 #include "DNA_userdef_types.h"
69
70 #include "BLO_writefile.h"
71
72 #include "BKE_utildefines.h"
73 #include "BKE_global.h"
74 #include "BKE_library.h"
75 #include "BKE_main.h"
76 #include "BKE_blender.h"
77 #include "BKE_screen.h"
78
79 #include "BIF_editsound.h"
80 #include "BIF_glutil.h"
81 #include "BIF_gl.h"
82 #include "BIF_graphics.h"
83 #include "BIF_interface.h"
84 #include "BIF_mainqueue.h"
85 #include "BIF_mywindow.h"
86 #include "BIF_renderwin.h"
87 #include "BIF_screen.h"
88 #include "BIF_space.h"
89 #include "BIF_toets.h"
90 #include "BIF_toolbox.h"
91 #include "BIF_usiblender.h"
92 #include "BIF_keyval.h"
93
94 #include "BSE_edit.h"
95 #include "BSE_filesel.h"
96 #include "BSE_headerbuttons.h"
97 #include "BSE_view.h"
98
99 #include "interface.h"
100 #include "mydevice.h"
101 #include "blendef.h"
102 #include "render.h"
103
104 #include "winlay.h"
105
106 /* TIPS:
107  * 
108  * - WATCH THE EDGES,  VERTICES HAVE TO BE IN ORDER...
109          (lowest pointer first). Otherwise unpredictable effects!
110  * - problem: flags here are not nicely implemented. After usage
111          always reset to zero.
112  */
113
114 static void testareas(void);
115 static void area_autoplayscreen(void);
116 static void wait_for_event(void);
117
118 /* ********* Globals *********** */
119
120 static Window *mainwin= NULL;
121 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, start_maximized= 1, start_fullscreen = 0;
122 static short dodrawscreen= 0;
123 static ScrArea *areawinar[MAXWIN];
124 static ScrArea *g_activearea= NULL;
125 short winqueue_break= 0;
126 ScrArea *curarea= 0;
127
128 /**********************************************************************/
129
130 static void screen_set_cursor(bScreen *sc) 
131 {
132         if (sc->winakt>3) {
133                 ScrArea *sa= areawinar[sc->winakt];
134
135                 set_cursor(sa->cursor);
136         } else {
137                 set_cursor(CURSOR_STD);
138         }
139 }
140
141 void waitcursor(int val)
142 {
143         if(val) {
144                 set_cursor(CURSOR_WAIT);
145         } else {
146                 screen_set_cursor(G.curscreen);
147         }
148 }
149
150 static int choose_cursor(ScrArea *sa)
151 {
152         if (sa->spacetype==SPACE_VIEW3D) {
153                 if(G.obedit) return CURSOR_EDIT;
154                 else if(G.f & G_VERTEXPAINT) return CURSOR_VPAINT;
155                 else if(G.f & G_WEIGHTPAINT) return CURSOR_VPAINT;
156                 else if(G.f & G_FACESELECT) return CURSOR_FACESEL;
157                 else return CURSOR_STD;
158         } else {
159                 return CURSOR_STD;
160         }
161 }
162
163 void wich_cursor(ScrArea *sa)
164 {
165         sa->cursor= choose_cursor(sa);
166
167         screen_set_cursor(G.curscreen);
168 }
169
170
171 void setcursor_space(int spacetype, short cur)
172 {
173         bScreen *sc;
174         ScrArea *sa;
175
176         for (sc= G.main->screen.first; sc; sc= sc->id.next)
177                 for (sa= sc->areabase.first; sa; sa= sa->next)
178                         if(sa->spacetype==spacetype)
179                                 sa->cursor= cur;
180
181         screen_set_cursor(G.curscreen);
182 }
183
184
185 /* *********  IN/OUT  ************* */
186
187 void getmouseco_sc(short *mval)         /* screen coordinates */
188 {
189         getmouse(mval);
190 }
191
192 void getmouseco_areawin(short *mval)            /* internal area coordinates */
193 {
194         getmouseco_sc(mval);
195         
196         if(g_activearea && g_activearea->win) {
197                 mval[0]-= g_activearea->winrct.xmin;
198                 mval[1]-= g_activearea->winrct.ymin;
199         }
200 }
201
202 void getmouseco_headwin(short *mval)            /* internal area coordinates */
203 {
204         getmouseco_sc(mval);
205         
206         if(g_activearea && g_activearea->headwin) {
207                 mval[0]-= g_activearea->headrct.xmin;
208                 mval[1]-= g_activearea->headrct.ymin;
209         }
210 }
211
212 /* *********** STUFF ************** */
213
214 static int scredge_is_horizontal(ScrEdge *se)
215 {
216         return (se->v1->vec.y == se->v2->vec.y);
217 }
218
219 static ScrEdge *screen_find_active_scredge(bScreen *sc, short *mval)
220 {
221         ScrEdge *se;
222         
223         for (se= sc->edgebase.first; se; se= se->next) {
224                 if (scredge_is_horizontal(se)) {
225                         if (abs(mval[1]-se->v1->vec.y)<=EDGEWIDTH2 &&
226                                         abs(mval[0]-se->v1->vec.x)<=abs(se->v2->vec.x-se->v1->vec.x))
227                                 return se;
228                 } else {
229                         if (abs(mval[0]-se->v1->vec.x)<=EDGEWIDTH2 &&
230                                         abs(mval[1]-se->v1->vec.y)<=abs(se->v2->vec.y-se->v1->vec.y))
231                                 return se;
232                 }
233         }
234         
235         return NULL;
236 }
237
238 void areawinset(short win)
239 {
240         if(win>3) {
241                 curarea= areawinar[win];
242                 if(curarea==0) {
243                         printf("error in areawinar %d ,areawinset\n", win);
244                         return;
245                 }
246                 
247                 switch(curarea->spacetype) {
248                 case SPACE_VIEW3D:
249                         G.vd= curarea->spacedata.first;
250                         break;
251                 case SPACE_IPO:
252                         if(G.sipo != curarea->spacedata.first) allqueue(REDRAWBUTSANIM, 0);
253                         G.sipo= curarea->spacedata.first;
254                         G.v2d= &G.sipo->v2d;
255                         break;
256                 case SPACE_BUTS:
257                         G.buts= curarea->spacedata.first;
258                         G.v2d= &G.buts->v2d;
259                         break;
260                 case SPACE_SEQ: {
261                         SpaceSeq *sseq= curarea->spacedata.first;
262                         G.v2d= &sseq->v2d;
263                         break;
264                 }
265                 case SPACE_OOPS:
266                         G.soops= curarea->spacedata.first;
267                         G.v2d= &G.soops->v2d;
268                         break;
269                 case SPACE_IMAGE:
270                         G.sima= curarea->spacedata.first;
271                         G.v2d= &G.sima->v2d;
272                 case SPACE_SOUND:
273                         G.ssound= curarea->spacedata.first;
274                         G.v2d= &G.ssound->v2d;
275                         break;
276                 case SPACE_ACTION:
277                         G.saction= curarea->spacedata.first;
278                         G.v2d= &G.saction->v2d;
279                         break;
280                 case SPACE_NLA:
281                         G.snla= curarea->spacedata.first;
282                         G.v2d= &G.snla->v2d;
283                         break;
284                 default:
285                         break;
286                 }
287         }
288         
289         if(win) mywinset(win);
290 }
291
292 void headerbox(int selcol, int width)
293 {
294         if(selcol) glClearColor(.75, .75, .75, 0.0);
295         else glClearColor(.65, .65, .65, 0.0);
296         
297         glClear(GL_COLOR_BUFFER_BIT);
298
299         glColor3ub(0, 0, 0);
300         sdrawbox(0,  0,  width,  HEADERY);
301
302         glColor3ub(220, 220, 220);
303         sdrawline(0,  HEADERY-1,  width,  HEADERY-1);
304         
305         glColor3ub(176, 176, 176);
306         sdrawline(0,  HEADERY-2,  width,  HEADERY-2);
307         
308         glColor3ub(128, 128, 128);
309         sdrawline(0,  2,  width,  2);
310         
311         glColor3ub(64, 64, 64);
312         sdrawline(0,  1,  width,  1);
313         
314         glColor3ub(0, 0, 0);
315         sdrawline(0,  0,  width,  0);
316 }
317
318 int area_is_active_area(ScrArea *area)
319 {
320         return (g_activearea && area==g_activearea);
321 }
322
323 void scrarea_do_headdraw(ScrArea *area)
324 {
325         areawinset(area->headwin);
326
327         headerbox(area_is_active_area(area), area->winx+100);
328
329         switch(area->spacetype) {
330         case SPACE_FILE:        file_buttons();         break;
331         case SPACE_INFO:        info_buttons();         break;
332         case SPACE_VIEW3D:      view3d_buttons();       break;
333         case SPACE_IPO:         ipo_buttons();          break;
334         case SPACE_BUTS:        buts_buttons();         break;
335         case SPACE_SEQ:         seq_buttons();          break;
336         case SPACE_IMAGE:       image_buttons();        break;
337         case SPACE_IMASEL:      imasel_buttons();       break;
338         case SPACE_OOPS:        oops_buttons();         break;
339         case SPACE_TEXT:        text_buttons();         break;
340         case SPACE_SOUND:       sound_buttons();        break;
341         case SPACE_ACTION:      action_buttons();       break;
342         case SPACE_NLA:         nla_buttons();          break;
343         }
344
345         area->head_swap= WIN_BACK_OK;
346 }
347 void scrarea_do_headchange(ScrArea *area)
348 {
349         float ofs= area->headbutofs;
350
351         if (area->headertype==HEADERDOWN) {
352                 bwin_ortho2(area->headwin, 0.5+ofs, area->headrct.xmax-area->headrct.xmin-0.5+ofs, +0.6, area->headrct.ymax-area->headrct.ymin+0.6);
353         } else {
354                 bwin_ortho2(area->headwin, -0.5+ofs, area->headrct.xmax-area->headrct.xmin-0.5+ofs, -0.5, area->headrct.ymax-area->headrct.ymin-0.5);
355         }
356 }
357
358
359 static void openheadwin(ScrArea *sa);
360 static void closeheadwin(ScrArea *sa);
361
362 static void scrarea_change_headertype(ScrArea *sa, int newtype) 
363 {
364         sa->headertype= newtype;
365
366         if (!newtype) {
367                 if (sa->headwin) {
368                         uiFreeBlocksWin(&sa->uiblocks, sa->headwin);
369                         closeheadwin(sa);
370                 }
371         } else {
372                 if (!sa->headwin) {
373                         openheadwin(sa);
374                 }
375         }
376
377         testareas();
378         winqueue_break= 1;
379 }
380
381 static void headmenu(ScrArea *sa)
382 {
383         short val= pupmenu("Header %t|Top%x2|Bottom %x1|No Header %x0");
384         
385         if(val> -1) {
386                 scrarea_change_headertype(sa, val);
387         }
388 }
389
390 static void addqueue_ext(short win, unsigned short event, short val, char ascii)
391 {
392         if (win<4 || !areawinar[win]) {
393                 printf("bad call to addqueue: %d (%d, %d)\n", win, event, val);
394         } else {
395                 BWinEvent evt;
396                 evt.event= event;
397                 evt.val= val;
398                 evt.ascii= ascii;
399                 bwin_qadd(win, &evt);
400         }
401 }
402
403 void addqueue(short win, unsigned short event, short val)
404 {
405         addqueue_ext(win, event, val, 0);
406 }
407
408 void scrarea_queue_winredraw(ScrArea *area)
409 {
410         addqueue(area->win, REDRAW, 1);
411 }
412 void scrarea_queue_headredraw(ScrArea *area)
413 {
414         if (area->headwin) addqueue(area->headwin, REDRAW, 1);
415 }
416 void scrarea_queue_redraw(ScrArea *area)
417 {
418         scrarea_queue_winredraw(area);
419         scrarea_queue_headredraw(area);
420 }
421
422 static void scrollheader(ScrArea *area);
423 static void scrarea_dispatch_header_events(ScrArea *sa)
424 {
425         ScrArea *tempsa;
426         BWinEvent evt;
427         short do_redraw=0, do_change=0;
428         
429         areawinset(sa->headwin);
430         
431         while(bwin_qread(sa->headwin, &evt)) {
432                 if(evt.val) {
433                         if( uiDoBlocks(&curarea->uiblocks, evt.event)!=UI_NOTHING ) evt.event= 0;
434
435                         switch(evt.event) {
436                         case UI_BUT_EVENT:
437                                 do_headerbuttons(evt.val);
438                                 break;
439                         
440                         case LEFTMOUSE:
441                                 if (G.qual & LR_CTRLKEY) {
442                                         window_lower(mainwin);
443                                 } else {
444                                         window_raise(mainwin);
445                                 }
446                                 break;
447
448                         case MIDDLEMOUSE:
449                                 scrollheader(sa);
450                                 break;
451                         case RIGHTMOUSE:
452                                 headmenu(sa);
453                                 break;
454                         case REDRAW:
455                                 do_redraw= 1;
456                                 break;
457                         case CHANGED:
458                                 sa->head_swap= 0;
459                                 do_change= 1;
460                                 do_redraw= 1;
461                                 break;
462                         default:
463                                 if (winqueue_break == 0) {
464                                         scrarea_do_winhandle(sa, &evt);
465                                         if (winqueue_break == 0) areawinset(sa->headwin);
466                                 }
467                         }
468                         
469                         if(winqueue_break) return;
470                 }
471         }
472
473         /* test: does window still exist? */    
474         tempsa= areawinar[sa->headwin];
475         if(tempsa==0) return;
476         
477         /* this functional separation does not work as well as i expected... */
478         if(do_change) scrarea_do_headchange(sa);
479         if(do_redraw) scrarea_do_headdraw(sa);
480 }
481
482 static void scrarea_dispatch_events(ScrArea *sa)
483 {
484         ScrArea *tempsa;
485         BWinEvent evt;
486         short do_redraw=0, do_change=0;
487         
488         if(sa!=curarea || sa->win!=mywinget()) areawinset(sa->win);
489
490         while(bwin_qread(sa->win, &evt)) {
491                 if(evt.event==REDRAW) {
492                         do_redraw= 1;
493                 }
494                 else if(evt.event==CHANGED) {
495                         sa->win_swap= 0;
496                         do_change= 1;
497                         do_redraw= 1;
498                 }
499                 else {
500                         scrarea_do_winhandle(sa, &evt);
501                 }
502                 
503                 if(winqueue_break) return;
504         }
505
506         /* test: does window still exist */     
507         tempsa= areawinar[sa->win];
508         if(tempsa==0) return;
509
510         if (do_change || do_redraw) {
511                 areawinset(sa->win);
512                 if(do_change)
513                         scrarea_do_winchange(curarea);
514                 if(do_redraw)
515                         scrarea_do_windraw(curarea);
516         }
517 }
518
519 /***/
520
521
522 void markdirty_all()
523 {
524         ScrArea *sa;
525
526         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
527                 scrarea_queue_winredraw(sa);
528                 sa->win_swap &= ~WIN_FRONT_OK;
529                 
530                 scrarea_queue_headredraw(sa);
531                 sa->head_swap &= ~WIN_FRONT_OK;
532         }
533 }
534
535 int is_allowed_to_change_screen(bScreen *new)
536 {
537         /* not when curscreen is full
538          * not when obedit && old->scene!=new->scene
539          */
540         
541         if(new==0) return 0;
542         if(G.curscreen->full != SCREENNORMAL) return 0;
543         if(curarea->full) return 0;
544         if(G.obedit) {
545                 if(G.curscreen->scene!=new->scene) return 0;
546         }
547         return 1;
548 }
549
550 void splash(void *data, int datasize, char *string)
551 {
552         ImBuf *bbuf;
553         int oldwin;
554         short val;
555
556         bbuf= IMB_ibImageFromMemory((int *)data, datasize, IB_rect);
557
558         if (bbuf) {
559
560                 oldwin = mywinget();
561                 mywinset(G.curscreen->mainwin);
562                 
563                 if (string) {
564                         int x, y, maxy;
565                         unsigned int *rect;
566                         
567                         rect = bbuf->rect;
568                         maxy = MIN2(bbuf->y, 18);
569
570                         for (y = 0; y < maxy; y++) {
571                                 for (x = 0; x < bbuf->x; x++) {
572                                         *rect = 0xffffffff;
573                                         rect++;
574                                 }
575                         }
576                 }
577                 glDrawBuffer(GL_FRONT);
578                 
579                 /*
580                 // this dims the whole screen a bit. I didn't like it afterall
581                 glEnable(GL_BLEND);
582                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
583                 glColor4f(0.0,0.0,0.0,0.3);
584                 glRecti(0, 0, G.curscreen->sizex, G.curscreen->sizey);
585                 glDisable(GL_BLEND);
586                 */
587                 
588                 glRasterPos2i((prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2);      
589                 glDrawPixels(bbuf->x, bbuf->y, GL_RGBA, GL_UNSIGNED_BYTE, bbuf->rect);
590
591                 if (string) {
592                         void *font;
593                         int width;                      
594                         
595                         if (BMF_GetStringWidth(font= G.font, string) > bbuf->x)
596                                 if (BMF_GetStringWidth(font= G.fonts, string) > bbuf->x)
597                                         font= G.fontss;
598                         
599                         width= BMF_GetStringWidth(font, string);
600                                                 
601                         glColor3ub(0, 0, 0);
602                         glRasterPos2i((prefsizx-width)/2, (prefsizy-bbuf->y)/2 + 6);
603                         BMF_DrawString(font, string);
604                 }
605
606                 glFinish();
607                 glDrawBuffer(GL_BACK);
608                 
609                 IMB_freeImBuf(bbuf);
610                 
611                 // flush input buffers ....
612                 // this might break some things
613
614                 while (get_mbut()) {
615                         BIF_wait_for_statechange();
616                 }
617                 while(qtest()) {
618                         extern_qread(&val);
619                 }
620
621                 wait_for_event();
622                 
623                 mywinset(oldwin);
624                 markdirty_all();
625                 mainqenter(DRAWEDGES, 1);
626         }
627 }
628
629 static void moveareas(ScrEdge *edge);
630 static void joinarea(ScrArea *sa, ScrEdge *onedge);
631 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge);
632
633 static void screen_edge_edit_event(ScrArea *actarea, ScrEdge *actedge, short evt, short val) {
634         if (val) {
635                         // don't allow users to edit full screens
636                 if (actarea && actarea->full) {
637                         return;
638                 }
639         
640                 if (evt==LEFTMOUSE) {
641                         moveareas(actedge);
642                 } else if (evt==MIDDLEMOUSE || evt==RIGHTMOUSE) {
643                         int edgeop;
644                 
645                         if (!actarea->headertype) {
646                                 edgeop= pupmenu("Split Area|Join Areas|Add header");
647                         } else {
648                                 edgeop= pupmenu("Split Area|Join Areas|No header");
649                         }
650
651                         if (edgeop==1) {
652                                 splitarea_interactive(actarea, actedge);
653                         } else if (edgeop==2) {
654                                 joinarea(actarea, actedge);
655                         } else if (edgeop==3) {
656                                 scrarea_change_headertype(actarea, actarea->headertype?0:HEADERDOWN);
657                         }
658                 }
659         }
660 }
661
662 /***/
663
664 void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey);
665 void test_scale_screen(bScreen *);
666
667 static void resize_screens(int x, int y, int w, int h) {
668         prefstax= x;
669         prefstay= y;
670         prefsizx= w;
671         prefsizy= h;
672
673         test_scale_screen(G.curscreen);
674         testareas();
675 }
676
677 static void init_mainwin(void)
678 {
679         int orx, ory, sizex, sizey;
680         
681         glEnable(GL_SCISSOR_TEST);
682
683         window_get_position(mainwin, &orx, &ory);
684         window_get_size(mainwin, &sizex, &sizey);
685
686                 /* XXX, temporary stupid fix for minimize at windows */
687         if (!sizex && !sizey) {
688                 return;
689         }
690
691         mywindow_init_mainwin(mainwin, orx, ory, sizex, sizey);
692         resize_screens(orx, ory, sizex, sizey);
693 }
694
695 /***/
696
697 static short afterqueue[MAXQUEUE][3];
698 static int nafterqitems= 0;
699
700 void addafterqueue(short win, unsigned short evt, short val)
701 {
702         if (nafterqitems<MAXQUEUE) {
703                 afterqueue[nafterqitems][0]= win;
704                 afterqueue[nafterqitems][1]= evt;
705                 afterqueue[nafterqitems][2]= val;
706                 nafterqitems++;
707         }
708 }
709
710 static void append_afterqueue(void)
711 {
712         while (nafterqitems) {
713                 short win= afterqueue[nafterqitems-1][0];
714                 unsigned short evt= afterqueue[nafterqitems-1][1];
715                 short val= afterqueue[nafterqitems-1][2];
716
717                 addqueue(win, evt, val);
718                 
719                 nafterqitems--;
720         }
721 }
722
723 static char ext_load_str[256]= {0, 0};
724 void add_readfile_event(char *filename)
725 {       
726         mainqenter(LOAD_FILE, 1);
727         strcpy(ext_load_str, filename);
728         BLI_convertstringcode(ext_load_str, G.sce, G.scene->r.cfra);
729 }
730
731 static short ext_reshape= 0, ext_redraw=0, ext_inputchange=0, ext_mousemove=0;
732
733 static void flush_extqd_events(void) {
734         if (ext_inputchange) {
735                 mainqenter(INPUTCHANGE, ext_inputchange);
736         } else if (ext_reshape) {
737                 mainqenter(RESHAPE, ext_redraw);
738         } else if (ext_redraw) {
739                 mainqenter(REDRAW, ext_redraw);
740         } else if (ext_mousemove) {
741                 short mouse[2];
742                 
743                 getmouseco_sc(mouse);
744                 
745                 mainqenter(MOUSEX, mouse[0]);
746                 mainqenter(MOUSEY, mouse[1]);
747         }
748         
749         ext_inputchange= ext_reshape= ext_redraw= ext_mousemove= 0;
750 }
751
752 unsigned short qtest(void)
753 {
754         if (!mainqtest()) {
755                 winlay_process_events(0);
756         }
757         
758         return mainqtest();
759 }
760
761         /* return true if events are waiting anywhere */
762 int anyqtest(void)
763 {
764         ScrArea *sa;
765
766         if (nafterqitems || qtest()) return 1;
767
768         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
769                 if (bwin_qtest(sa->win)) return 1;
770                 if (sa->headwin && bwin_qtest(sa->headwin)) return 1;
771         }
772
773         return 0;
774 }
775
776 static void wait_for_event(void)
777 {
778         while (!mainqtest()) {
779                 winlay_process_events(1);
780         }
781 }
782
783 unsigned short screen_qread(short *val, char *ascii)
784 {
785         unsigned short event;
786
787         wait_for_event();
788
789         event= mainqread(val, ascii);
790         
791         if(event==RIGHTSHIFTKEY || event==LEFTSHIFTKEY) {
792                 if(*val) G.qual |= LR_SHIFTKEY;
793                 else G.qual &= ~LR_SHIFTKEY;
794         }
795         else if(event==RIGHTALTKEY || event==LEFTALTKEY) {
796                 if(*val) G.qual |= LR_ALTKEY;
797                 else G.qual &= ~LR_ALTKEY;
798         }
799         else if(event==RIGHTCTRLKEY || event==LEFTCTRLKEY) {
800                 if(*val) G.qual |= LR_CTRLKEY;
801                 else G.qual &= ~LR_CTRLKEY;
802         }
803
804         return event;
805 }
806
807 unsigned short extern_qread_ext(short *val, char *ascii)
808 {
809         /* stores last INPUTCHANGE and last REDRAW */
810         unsigned short event;
811         
812         event= screen_qread(val, ascii);
813         if(event==RESHAPE) ext_reshape= *val;
814         else if(event==REDRAW) ext_redraw= *val;
815         else if(event==INPUTCHANGE) ext_inputchange= *val;
816         else if(event==MOUSEY || event==MOUSEX) ext_mousemove= 1;
817         else if((G.qual & LR_CTRLKEY) && event==F3KEY) {
818                 BIF_screendump();
819         }
820
821         return event;
822 }
823 unsigned short extern_qread(short *val)
824 {
825         char ascii;
826         return extern_qread_ext(val, &ascii);
827 }
828
829 int blender_test_break(void)
830 {
831         if (!G.background) {
832                 static double ltime= 0;
833                 double curtime= PIL_check_seconds_timer();
834
835                         /* only check for breaks every 10 milliseconds
836                          * if we get called more often.
837                          */
838                 if ((curtime-ltime)>.001) {
839                         ltime= curtime;
840
841                         while(qtest()) {
842                                 short val;
843                                 if (extern_qread(&val) == ESCKEY) {
844                                         G.afbreek= 1;
845                                 }
846                         }
847                 }
848         }
849
850         return (G.afbreek==1);
851 }
852
853 void reset_autosave(void) {
854         window_set_timer(mainwin, U.savetime*60*1000, AUTOSAVE_FILE);
855 }
856
857 static void screen_dispatch_events(void) {
858         int events_remaining= 1;
859         ScrArea *sa;
860
861         while (events_remaining) {
862                 events_remaining= 0;
863                                 
864                 winqueue_break= 0;
865                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
866                                 /* first check header, then rest. Header sometimes has initialization code */
867                         if (sa->headwin && bwin_qtest(sa->headwin)) {
868                                 scrarea_dispatch_header_events(sa);
869                                 events_remaining= 1;
870                         }
871                         if (winqueue_break) break;
872
873                         if (bwin_qtest(sa->win)) {
874                                 scrarea_dispatch_events(sa);
875                                 events_remaining= 1;
876                         }
877                         if (winqueue_break) break;
878                 }
879
880                 if (winqueue_break) break;
881         }
882
883         if (dodrawscreen) {
884                 drawscreen();
885                 dodrawscreen= 0;
886         }
887         
888         screen_swapbuffers();
889 }
890
891 static ScrArea *screen_find_area_for_pt(bScreen *sc, short *mval) 
892 {
893         ScrArea *sa;
894         
895         for (sa= sc->areabase.first; sa; sa= sa->next)
896                 if (BLI_in_rcti(&sa->totrct, mval[0], mval[1]))
897                         return sa;
898         
899         return NULL;
900 }
901
902 void screenmain(void)
903 {
904         int has_input= 1;
905         int firsttime = 1;
906         while (1) {
907                 unsigned short event;
908                 short val, towin;
909                 char ascii;
910
911                 flush_extqd_events();
912                 if (nafterqitems && !qtest()) {
913                         append_afterqueue();
914                         event= val= ascii= 0;
915                 } else {
916                         event= screen_qread(&val, &ascii);
917                 }
918                 
919                 window_make_active(mainwin);
920                 
921                 if (event==INPUTCHANGE) {
922                         has_input= val;
923                 }
924                 
925                         /* If the main window is active, find the current active ScrArea
926                          * underneath the mouse cursor, updating the headers & cursor for
927                          * the appropriate internal window if things have changed.
928                          * 
929                          * If the main window is not active, deactivate the internal 
930                          * window.
931                          */
932                 if (has_input) {
933                         ScrArea *newactarea;
934                         int newactwin;
935                         short mval[2];
936
937                         getmouseco_sc(mval);
938                         newactarea= screen_find_area_for_pt(G.curscreen, mval);                 
939
940                         if (newactarea) {
941                                 if (BLI_in_rcti(&newactarea->headrct, mval[0], mval[1])) {
942                                         newactwin= newactarea->headwin;
943                                 } else {
944                                         newactwin= newactarea->win;
945                                 }
946                         } else {
947                                 newactwin= 0;
948                         }
949
950                         if (newactarea && (newactarea != g_activearea)) {
951                                 if (g_activearea) scrarea_queue_headredraw(g_activearea);
952                                 scrarea_queue_headredraw(newactarea);
953                                 set_cursor(newactarea->cursor);
954                                 g_activearea= newactarea;
955                         }
956
957                         G.curscreen->winakt= newactwin;
958                         if (G.curscreen->winakt) {
959                                 areawinset(G.curscreen->winakt);
960                                 set_cursor(choose_cursor(g_activearea));
961                         }
962                 } else {
963                         if (g_activearea) {
964                                 scrarea_queue_headredraw(g_activearea);
965                         }
966                         g_activearea= NULL;
967                         G.curscreen->winakt= 0;
968                 }
969
970                 towin= 0;
971                 if (event==WINCLOSE) {
972                         exit_usiblender();
973                 } 
974                 else if (event==DRAWEDGES) {
975                         dodrawscreen= 1;
976                 }
977                 else if (event==RESHAPE) {
978                         init_mainwin();
979                         markdirty_all();
980                         dodrawscreen= 1;
981                 }
982                 else if (event==REDRAW) {
983                         markdirty_all();
984                         dodrawscreen= 1;
985                 }
986                 else if (event==AUTOSAVE_FILE) {
987                         BIF_write_autosave();
988                 }
989                 else if (event==LOAD_FILE) {
990                         BIF_read_file(ext_load_str);
991                         sound_initialize_sounds();
992                 }
993                 else {
994                         towin= 1;
995                 }
996
997                 if (!g_activearea) {
998                         towin= 0;
999                 }
1000                 else if (!G.curscreen->winakt) {
1001                         ScrEdge *actedge;
1002                         short mval[2];
1003
1004                         getmouseco_sc(mval);
1005                         actedge= screen_find_active_scredge(G.curscreen, mval);
1006
1007                         if (actedge) {
1008                                 if (scredge_is_horizontal(actedge)) {
1009                                         set_cursor(CURSOR_Y_MOVE);
1010                                 } else {
1011                                         set_cursor(CURSOR_X_MOVE);
1012                                 }
1013
1014                                 screen_edge_edit_event(g_activearea, actedge, event, val);
1015                         } else {
1016                                 set_cursor(CURSOR_STD);
1017                         }
1018                         
1019                         towin= 0;
1020                 }
1021                 else if (event==QKEY) {
1022                         if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT);
1023                         else {
1024                                 if(val && okee("QUIT BLENDER")) exit_usiblender();
1025                                 towin= 0;
1026                         }
1027                 }
1028                 else if (event==ZKEY) {
1029                         if(val && G.qual==(LR_ALTKEY|LR_SHIFTKEY|LR_CTRLKEY)) {
1030                                 extern void set_debug_swapbuffers_ovveride(bScreen *sc, int mode);
1031
1032                                 int which= pupmenu("Swapbuffers%t|Simple|Debug|DebugSwap|Redraw|Default|KillSwap");
1033                                         
1034                                 switch (which) {
1035                                 case 1: set_debug_swapbuffers_ovveride(G.curscreen, 's'); break;
1036                                 case 2: set_debug_swapbuffers_ovveride(G.curscreen, 'd'); break;
1037                                 case 3: set_debug_swapbuffers_ovveride(G.curscreen, 'f'); break;
1038                                 case 4: set_debug_swapbuffers_ovveride(G.curscreen, 'r'); break;
1039                                 case 5: set_debug_swapbuffers_ovveride(G.curscreen, 0); break;
1040                                 case 6: 
1041                                         if (g_activearea) {
1042                                                 g_activearea->head_swap= 0;
1043                                                 g_activearea->win_swap= 0;
1044                                         }
1045                                         break;
1046                                 }
1047                                 towin= 0;
1048                         }
1049                 }
1050                 else if (event==SPACEKEY) {
1051                         if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT);
1052                         else {
1053                                 if(val) toolbox();
1054                                 towin= 0;
1055                         }
1056                 }
1057                 else if(ELEM(event, LEFTARROWKEY, RIGHTARROWKEY)) {
1058                         if(val && (G.qual & LR_CTRLKEY)) {
1059                                 bScreen *sc= (event==LEFTARROWKEY)?G.curscreen->id.prev:G.curscreen->id.next;
1060                                 if(is_allowed_to_change_screen(sc)) setscreen(sc);
1061                                 g_activearea= NULL;
1062                                 towin= 0;
1063                         }
1064                 }
1065                 else if(ELEM(event, UPARROWKEY, DOWNARROWKEY)) {
1066                         if(val && (G.qual & LR_CTRLKEY)) {
1067                                 area_fullscreen();
1068                                 g_activearea= NULL;
1069                                 towin= 0;
1070                         }
1071                 }
1072                 
1073                 if (towin && event) {
1074                         if (blenderqread(event, val))
1075                                 addqueue_ext(G.curscreen->winakt, event, val, ascii);
1076                 }
1077
1078                         /* only process subwindow queue's once the
1079                          * main queue has been emptyied.
1080                          */
1081                 event= qtest();
1082                 if (event==0 || event==EXECUTE) {
1083                         screen_dispatch_events();
1084                 }
1085
1086                 /* Bizar hack. The event queue has mutated... */
1087                 if ( (firsttime) && (event == 0) ) {
1088                         if (G.fileflags & G_FILE_AUTOPLAY) {
1089                                 // SET AUTOPLAY in G.flags for
1090                                 // other fileloads
1091
1092                                 G.flags |= G_FLAGS_AUTOPLAY;
1093                                 area_autoplayscreen();
1094
1095                                 // Let The Games Begin
1096                                 // fake a 'p' keypress
1097
1098                                 mainqenter(PKEY, 1);
1099                         } else {
1100                                 extern char datatoc_splash_jpg[];
1101                                 extern int datatoc_splash_jpg_size;
1102
1103                                 if (! ((G.main->versionfile >= G.version)
1104                                        || G.save_over)) {
1105                                         splash((void *)datatoc_splash_jpg,
1106                                                datatoc_splash_jpg_size, NULL);
1107                                 }
1108                         }
1109                         firsttime = 0;
1110                 }
1111         }
1112 }
1113
1114 void mainwindow_raise(void) {
1115         window_raise(mainwin);
1116 }
1117 void mainwindow_make_active(void) {
1118         window_make_active(mainwin);
1119 }
1120 void mainwindow_close(void) {
1121         window_destroy(mainwin);
1122         mainwin= NULL;
1123 }
1124
1125 /* *********  AREAS  ************* */
1126
1127 void setfullscreen()
1128 {
1129         start_fullscreen = 1;   
1130 }
1131
1132 void setprefsize(int stax, int stay, int sizx, int sizy)
1133 {
1134         int scrwidth, scrheight;
1135         
1136         winlay_get_screensize(&scrwidth, &scrheight);
1137         
1138         if(stax<0) stax= 0;
1139         if(stay<0) stay= 0;
1140         if(sizx<320) sizx= 320;
1141         if(sizy<256) sizy= 256;
1142
1143         if(stax+sizx>scrwidth) sizx= scrwidth-stax;
1144         if(stay+sizy>scrheight) sizy= scrheight-stay;
1145         if(sizx<320 || sizy<256) {
1146                 printf("ERROR: illegal prefsize\n");
1147                 return;
1148         }
1149         
1150         prefstax= stax;
1151         prefstay= stay;
1152         prefsizx= sizx;
1153         prefsizy= sizy;
1154
1155         start_maximized= 0;
1156 }
1157
1158
1159 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
1160 {
1161         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
1162         sv->vec.x= x;
1163         sv->vec.y= y;
1164         
1165         BLI_addtail(&sc->vertbase, sv);
1166         return sv;
1167 }
1168
1169 static void sortscrvert(ScrVert **v1, ScrVert **v2)
1170 {
1171         ScrVert *tmp;
1172         
1173         if ((long)*v1 > (long)*v2) {
1174                 tmp= *v1;
1175                 *v1= *v2;
1176                 *v2= tmp;       
1177         }
1178 }
1179
1180 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1181 {
1182         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
1183
1184         sortscrvert(&v1, &v2);
1185         se->v1= v1;
1186         se->v2= v2;
1187         
1188         BLI_addtail(&sc->edgebase, se);
1189         return se;
1190 }
1191
1192 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1193 {
1194         ScrEdge *se;
1195
1196         sortscrvert(&v1, &v2);
1197         for (se= sc->edgebase.first; se; se= se->next)
1198                 if(se->v1==v1 && se->v2==v2)
1199                         return se;
1200
1201         return NULL;
1202 }
1203
1204 static void removedouble_scrverts(void)
1205 {
1206         ScrVert *v1, *verg;
1207         ScrEdge *se;
1208         ScrArea *sa;
1209         
1210         verg= G.curscreen->vertbase.first;
1211         while(verg) {
1212                 if(verg->newv==0) {     /* !!! */
1213                         v1= verg->next;
1214                         while(v1) {
1215                                 if(v1->newv==0) {       /* !?! */
1216                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
1217                                                 /* printf("doublevert\n"); */
1218                                                 v1->newv= verg;
1219                                         }
1220                                 }
1221                                 v1= v1->next;
1222                         }
1223                 }
1224                 verg= verg->next;
1225         }
1226         
1227         /* replace pointers in edges and faces */
1228         se= G.curscreen->edgebase.first;
1229         while(se) {
1230                 if(se->v1->newv) se->v1= se->v1->newv;
1231                 if(se->v2->newv) se->v2= se->v2->newv;
1232                 /* edges changed: so.... */
1233                 sortscrvert(&(se->v1), &(se->v2));
1234                 se= se->next;
1235         }
1236         sa= G.curscreen->areabase.first;
1237         while(sa) {
1238                 if(sa->v1->newv) sa->v1= sa->v1->newv;
1239                 if(sa->v2->newv) sa->v2= sa->v2->newv;
1240                 if(sa->v3->newv) sa->v3= sa->v3->newv;
1241                 if(sa->v4->newv) sa->v4= sa->v4->newv;
1242                 sa= sa->next;
1243         }
1244         
1245         /* remove */
1246         verg= G.curscreen->vertbase.first;
1247         while(verg) {
1248                 v1= verg->next;
1249                 if(verg->newv) {
1250                         BLI_remlink(&G.curscreen->vertbase, verg);
1251                         MEM_freeN(verg);
1252                 }
1253                 verg= v1;
1254         }
1255         
1256 }
1257
1258 static void removenotused_scrverts(void)
1259 {
1260         ScrVert *sv, *svn;
1261         ScrEdge *se;
1262
1263         /* we assume edges are ok */
1264         
1265         se= G.curscreen->edgebase.first;
1266         while(se) {
1267                 se->v1->flag= 1;
1268                 se->v2->flag= 1;
1269                 se= se->next;
1270         }
1271         
1272         sv= G.curscreen->vertbase.first;
1273         while(sv) {
1274                 svn= sv->next;
1275                 if(sv->flag==0) {
1276                         BLI_remlink(&G.curscreen->vertbase, sv);
1277                         MEM_freeN(sv);
1278                 }
1279                 else sv->flag= 0;
1280                 sv= svn;
1281         }
1282 }
1283
1284 static void removedouble_scredges(void)
1285 {
1286         ScrEdge *verg, *se, *sn;
1287         
1288         /* compare */
1289         verg= G.curscreen->edgebase.first;
1290         while(verg) {
1291                 se= verg->next;
1292                 while(se) {
1293                         sn= se->next;
1294                         if(verg->v1==se->v1 && verg->v2==se->v2) {
1295                                 BLI_remlink(&G.curscreen->edgebase, se);
1296                                 MEM_freeN(se);
1297                         }
1298                         se= sn;
1299                 }
1300                 verg= verg->next;
1301         }
1302 }
1303
1304 static void removenotused_scredges(void)
1305 {
1306         ScrEdge *se, *sen;
1307         ScrArea *sa;
1308         int a=0;
1309         
1310         /* sets flags when edge is used in area */
1311         sa= G.curscreen->areabase.first;
1312         while(sa) {
1313                 se= screen_findedge(G.curscreen, sa->v1, sa->v2);
1314                 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
1315                 else se->flag= 1;
1316                 se= screen_findedge(G.curscreen, sa->v2, sa->v3);
1317                 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
1318                 else se->flag= 1;
1319                 se= screen_findedge(G.curscreen, sa->v3, sa->v4);
1320                 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
1321                 else se->flag= 1;
1322                 se= screen_findedge(G.curscreen, sa->v4, sa->v1);
1323                 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
1324                 else se->flag= 1;
1325                 sa= sa->next;
1326                 a++;
1327         }
1328         se= G.curscreen->edgebase.first;
1329         while(se) {
1330                 sen= se->next;
1331                 if(se->flag==0) {
1332                         BLI_remlink(&G.curscreen->edgebase, se);
1333                         MEM_freeN(se);
1334                 }
1335                 else se->flag= 0;
1336                 se= sen;
1337         }
1338 }
1339
1340 void calc_arearcts(ScrArea *sa)
1341 {
1342
1343         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+EDGEWIDTH2+1;
1344         else sa->totrct.xmin= sa->v1->vec.x;
1345         if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-EDGEWIDTH2-1;
1346         else sa->totrct.xmax= sa->v4->vec.x;
1347         
1348         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+EDGEWIDTH2+1;
1349         else sa->totrct.ymin= sa->v1->vec.y;
1350         if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-EDGEWIDTH2-1;
1351         else sa->totrct.ymax= sa->v2->vec.y;
1352         
1353         sa->winrct= sa->totrct;
1354         if(sa->headertype) {
1355                 sa->headrct= sa->totrct;
1356                 if(sa->headertype==HEADERDOWN) {
1357                         sa->headrct.ymax= sa->headrct.ymin+HEADERY-1;
1358                         sa->winrct.ymin= sa->headrct.ymax+1;
1359                 }
1360                 else if(sa->headertype==HEADERTOP) {
1361                         sa->headrct.ymin= sa->headrct.ymax-HEADERY+1;
1362                         sa->winrct.ymax= sa->headrct.ymin-1;
1363                 }
1364         }
1365         if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
1366         
1367         /* for speedup */
1368         sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
1369         sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
1370 }
1371
1372 static void openheadwin(ScrArea *sa)
1373 {
1374         sa->headwin= myswinopen(G.curscreen->mainwin,
1375                 sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1376
1377         glMatrixMode(GL_MODELVIEW);
1378         
1379         areawinar[sa->headwin]= sa;     /* oterwise addqueue does not work */
1380         addqueue(sa->headwin, CHANGED, 1);
1381 }
1382
1383 static void openareawin(ScrArea *sa)
1384 {
1385         sa->win= myswinopen(G.curscreen->mainwin, 
1386                 sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1387
1388         areawinar[sa->win]= sa; /* otherwise addqueue does not work */
1389         addqueue(sa->win, CHANGED, 1);
1390 }
1391
1392 static void closeheadwin(ScrArea *sa)
1393 {
1394         if(sa->headwin) mywinclose(sa->headwin);
1395         sa->headwin= 0;
1396 }
1397
1398 static void closeareawin(ScrArea *sa)
1399 {
1400         uiFreeBlocksWin(&sa->uiblocks, sa->win);
1401
1402         if(sa->win) mywinclose(sa->win);
1403         sa->win= 0;
1404 }
1405
1406 static void del_area(ScrArea *sa)
1407 {
1408         closeareawin(sa);
1409         closeheadwin(sa);
1410
1411         freespacelist(&sa->spacedata);
1412         
1413         uiFreeBlocks(&sa->uiblocks);
1414         
1415         if(sa==curarea) curarea= 0;
1416         if(sa==g_activearea) g_activearea= 0;
1417 }
1418
1419 static void copy_areadata(ScrArea *sa1, ScrArea *sa2)
1420 {
1421         sa1->headertype= sa2->headertype;
1422         sa1->spacetype= sa2->spacetype;
1423         Mat4CpyMat4(sa1->winmat, sa2->winmat);
1424         
1425         freespacelist(&sa1->spacedata);
1426         
1427         duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
1428 }
1429
1430 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
1431 {
1432         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
1433         sa->cursor= CURSOR_STD;
1434         sa->v1= v1;
1435         sa->v2= v2;
1436         sa->v3= v3;
1437         sa->v4= v4;
1438         sa->headertype= headertype;
1439         sa->spacetype= spacetype;
1440
1441         calc_arearcts(sa);
1442
1443         if (sa->headertype) openheadwin(sa);
1444         openareawin(sa);
1445
1446         BLI_addtail(&sc->areabase, sa);
1447         return sa;
1448 }
1449
1450 static int rcti_eq(rcti *a, rcti *b) {
1451         return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
1452                         (a->ymin==b->ymin && a->ymax==b->ymax));
1453 }
1454
1455 static void testareas(void)
1456 {
1457         ScrArea *sa;
1458
1459         /* test for header, if removed, or moved */
1460         /* testen for window, if removed, or moved */
1461
1462         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1463                 rcti oldhr= sa->headrct;
1464                 rcti oldwr= sa->winrct;
1465                 
1466                 calc_arearcts(sa);
1467
1468                         /* test header */
1469                 if (sa->headwin) {
1470                         if (!rcti_eq(&oldhr, &sa->headrct)) {
1471                                 mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1472                                 addqueue(sa->headwin, CHANGED, 1);
1473                         }
1474                                 
1475                         if(sa->headbutlen<sa->winx) {
1476                                 sa->headbutofs= 0;
1477                                 addqueue(sa->headwin, CHANGED, 1);
1478                         }
1479                         else if(sa->headbutofs+sa->winx > sa->headbutlen) {
1480                                 sa->headbutofs= sa->headbutlen-sa->winx;
1481                                 addqueue(sa->headwin, CHANGED, 1);
1482                         }
1483                 }
1484
1485                 if (!rcti_eq(&oldwr, &sa->winrct)) {
1486                         mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1487                         addqueue(sa->win, CHANGED, 1);
1488                 }
1489         }
1490         
1491                 /* remake global windowarray */
1492         memset(areawinar, 0, sizeof(void *)*MAXWIN);
1493         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1494                 areawinar[sa->headwin]= sa;
1495                 areawinar[sa->win]= sa;
1496         }
1497         
1498                 /* test if winakt is OK */      
1499         if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
1500 }
1501
1502 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
1503 {
1504         /* test if edge is in area, if not, 
1505            then find an area that has it */
1506   
1507         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
1508         
1509         if(sa) {
1510                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1511                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1512                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1513                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1514         }
1515         if(se1!=se && se2!=se && se3!=se && se4!=se) {
1516                 
1517                 sa= G.curscreen->areabase.first;
1518                 while(sa) {
1519                         /* a bit optimise? */
1520                         if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
1521                                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1522                                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1523                                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1524                                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1525                                 if(se1==se || se2==se || se3==se || se4==se) return sa;
1526                         }
1527                         sa= sa->next;
1528                 }
1529         }
1530
1531         return sa;      /* is null when not find */
1532 }
1533
1534 ScrArea *closest_bigger_area(void)
1535 {
1536         ScrArea *sa, *big=0;
1537         float cent[3], vec[3],len, len1, len2, len3, dist=1000;
1538         short mval[2];
1539         
1540         getmouseco_sc(mval);
1541         
1542         cent[0]= mval[0];
1543         cent[1]= mval[1];
1544         cent[2]= vec[2]= 0;
1545
1546         sa= G.curscreen->areabase.first;
1547         while(sa) {
1548                 if(sa!=curarea) {
1549                         if(sa->winy>=curarea->winy) {
1550                         
1551                                 /* mimimum of the 4 corners */
1552                                 vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
1553                                 len= VecLenf(vec, cent);
1554                                 vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
1555                                 len1= VecLenf(vec, cent);
1556                                 vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
1557                                 len2= VecLenf(vec, cent);
1558                                 vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
1559                                 len3= VecLenf(vec, cent);
1560                                 
1561                                 len= MIN4(len, len1, len2, len3);
1562                                 
1563                                 /* plus centre */
1564                                 vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
1565                                 vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
1566
1567                                 len+= 0.5*VecLenf(vec, cent);
1568                                 
1569                                 /* min size */
1570                                 len-= sa->winy+sa->winx;
1571                                 
1572                                 if(len<dist) {
1573                                         dist= len;
1574                                         big= sa;
1575                                 }
1576                         }
1577                 }
1578                 sa= sa->next;
1579         }
1580         
1581         if(big) return big;
1582         else return curarea;
1583 }
1584
1585 /* ************ SCREEN MANAGEMENT ************** */
1586
1587 static int statechanged= 0;
1588 void BIF_wait_for_statechange(void)
1589 {
1590         if (!statechanged) {
1591                         /* Safety, don't wait more than 0.1 seconds */
1592                 double stime= PIL_check_seconds_timer();
1593                 while (!statechanged) {
1594                         winlay_process_events(1);
1595                         if ((PIL_check_seconds_timer()-stime)>0.1) break;
1596                 }
1597                 statechanged= 0;
1598         }
1599 }
1600 void getmouse(short *mval)
1601 {
1602         winlay_process_events(0);
1603         window_get_mouse(mainwin, mval);
1604 }
1605 short get_qual(void)
1606 {
1607         winlay_process_events(0);
1608         return window_get_qual(mainwin);
1609 }
1610 short get_mbut(void)
1611 {
1612         winlay_process_events(0);
1613         return window_get_mbut(mainwin);
1614 }
1615
1616 static unsigned short convert_for_nonumpad(unsigned short event)
1617 {
1618         if (event>=ZEROKEY && event<=NINEKEY) {
1619                 return event - ZEROKEY + PAD0;
1620         } else if (event==MINUSKEY) {
1621                 return PADMINUS;
1622         } else if (event==EQUALKEY) {
1623                 return PADPLUSKEY;
1624         } else if (event==BACKSLASHKEY) {
1625                 return PADSLASHKEY;
1626         } else {
1627                 return event;
1628         }
1629 }
1630
1631 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
1632 {
1633         short qual= window_get_qual(win);
1634
1635         statechanged= 1;
1636
1637         if (U.flag&NONUMPAD) {
1638                 evt= convert_for_nonumpad(evt);
1639         }
1640         
1641                 /* enforce some guarentees about ascii values... these should
1642                  * be enforced in ghost probably - zr
1643                  */
1644
1645         if (!val || !isprint(ascii) || (qual&~LR_SHIFTKEY)) {
1646                 ascii= '\0';
1647         }
1648
1649         mainqenter_ext(evt, val, ascii);
1650 }
1651
1652 static bScreen *addscreen(char *name)           /* use setprefsize() if you want something else than a full windpw */
1653 {
1654         /* this function sets variabele G.curscreen,
1655          * that global is about used everywhere!
1656          */
1657         bScreen *sc;
1658         ScrVert *sv1, *sv2, *sv3, *sv4;
1659         short startx, starty, endx, endy;       
1660         
1661         sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
1662
1663         if (!prefsizx) {
1664                 prefstax= 0;
1665                 prefstay= 0;
1666                 
1667                 winlay_get_screensize(&prefsizx, &prefsizy);
1668         }
1669
1670         startx= prefstax;
1671         starty= prefstay;
1672         endx= prefstax+prefsizx-1;
1673         endy= prefstay+prefsizy-1;
1674
1675         sc->startx= startx;     sc->starty= starty;
1676         sc->endx= endx; sc->endy= endy;
1677         sc->sizex= sc->endx-sc->startx+1;
1678         sc->sizey= sc->endy-sc->starty+1;
1679         
1680         sc->scene= G.scene;
1681         
1682         if (!mainwin) {
1683                 if (start_fullscreen)
1684                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, 2);
1685                 else
1686                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
1687                 
1688                 if (!mainwin) {
1689                         printf("ERROR: Unable to open Blender window\n");
1690                         exit(1);
1691                 }
1692                 
1693                 window_set_handler(mainwin, add_to_mainqueue, NULL);
1694                 init_mainwin();
1695                 mywinset(1);
1696         
1697                 glMatrixMode(GL_PROJECTION);
1698                 glLoadIdentity();
1699                 myortho2(-0.5, sc->sizex-0.5, -0.5, sc->sizey-0.5);
1700                 glMatrixMode(GL_MODELVIEW);
1701                 glLoadIdentity();
1702
1703                 glDrawBuffer(GL_FRONT);
1704                 glClearColor(.45, .45, .45, 0.0);
1705                 glClear(GL_COLOR_BUFFER_BIT);
1706                 glDrawBuffer(GL_BACK);
1707                 
1708                 warp_pointer(sc->sizex/2,  sc->sizey/2);
1709                 
1710                 mainqenter(REDRAW, 1);
1711         }
1712
1713         sc->mainwin= 1;
1714         
1715         sv1= screen_addvert(sc, 0, 0);
1716         sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
1717         sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
1718         sv4= screen_addvert(sc, sc->sizex-1, 0);
1719         
1720         screen_addedge(sc, sv1, sv2);
1721         screen_addedge(sc, sv2, sv3);
1722         screen_addedge(sc, sv3, sv4);
1723         screen_addedge(sc, sv4, sv1);
1724
1725         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
1726         
1727         G.curscreen= sc;
1728
1729         return sc;
1730 }
1731
1732 void setscreen(bScreen *sc)
1733 {
1734         bScreen *sc1;
1735         ScrArea *sa;
1736         short mval[2];
1737         
1738         if(sc->full) {                          /* find associated full */
1739                 sc1= G.main->screen.first;
1740                 while(sc1) {
1741                         sa= sc1->areabase.first;
1742                         if(sa->full==sc) {
1743                                 sc= sc1;
1744                                 break;
1745                         }
1746                         sc1= sc1->id.next;
1747                 }
1748                 if(sc1==0) printf("setscreen error\n");
1749         }
1750
1751         /* de-activate G.curscreen */
1752         if (G.curscreen && G.curscreen != sc) {
1753                 sa= G.curscreen->areabase.first;
1754                 while(sa) {
1755                         if(sa->win) mywinclose(sa->win);
1756                         sa->win= 0;
1757                         if(sa->headwin) mywinclose(sa->headwin);
1758                         sa->headwin= 0;
1759                         
1760                         uiFreeBlocks(&sa->uiblocks);
1761                         
1762                         sa= sa->next;
1763                 }               
1764         }
1765
1766         if (G.curscreen != sc) {
1767                 mywinset(sc->mainwin);
1768         }
1769         
1770         G.curscreen= sc;
1771
1772         for (sa= sc->areabase.first; sa; sa= sa->next) {
1773                         /* XXX, fixme zr */
1774 /*              if (sa->win || sa->headwin) */
1775 /*                      printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
1776                 if (!sa->win)
1777                         openareawin(sa);
1778                 if (!sa->headwin && sa->headertype)
1779                         openheadwin(sa);
1780         }
1781
1782         /* recalculate winakt */
1783         getmouseco_sc(mval);
1784
1785         test_scale_screen(sc);
1786         testareas();
1787         
1788         for (sa= sc->areabase.first; sa; sa= sa->next) {
1789                 SpaceLink *sl;
1790
1791                 for (sl= sa->spacedata.first; sl; sl= sl->next) {
1792                         sl->area= sa;
1793
1794                         if (sl->spacetype==SPACE_OOPS) {
1795                                 SpaceOops *soops= (SpaceOops*) sl;
1796
1797                                 /* patch for old files */
1798                                 if (soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
1799                                         extern void init_v2d_oops(View2D*);
1800                                         init_v2d_oops(&soops->v2d);
1801                                 }
1802                         }
1803                 }
1804                 
1805                 sa->cursor= CURSOR_STD;
1806         }
1807
1808         G.scene= sc->scene;
1809         countall();
1810         
1811         G.curscreen->winakt= 0;
1812         curarea= sc->areabase.first;
1813         
1814         mainqenter(DRAWEDGES, 1);
1815         dodrawscreen= 1;                /* patch! even gets lost,,,? */
1816
1817         winqueue_break= 1;              /* means leave queue everywhere */
1818 }
1819
1820 static void splitarea(ScrArea *sa, char dir, float fac);
1821
1822 void area_fullscreen(void)      /* with curarea */
1823 {
1824         /* this function toggles: if area is full then the parent will be restored */
1825         bScreen *sc, *oldscreen;
1826         ScrArea *newa, *old;
1827         short headertype, fulltype;
1828         
1829         if(curarea->full) {
1830                 sc= curarea->full;      /* the old screen */
1831                 fulltype = sc->full;
1832
1833                 // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
1834                 // is set
1835
1836                 if (fulltype != SCREENAUTOPLAY || (G.flags & G_FLAGS_AUTOPLAY) == 0) {
1837                         sc->full= 0;
1838                 
1839                         /* find old area */
1840                         old= sc->areabase.first;
1841                         while(old) {
1842                                 if(old->full) break;
1843                                 old= old->next;
1844                         }
1845                         if(old==0) {error("something wrong in areafullscreen"); return;}
1846                 
1847                         if (fulltype == SCREENAUTOPLAY) {
1848                                 // in autoplay screens the headers are disabled by 
1849                                 // default. So use the old headertype instead
1850                                 headertype = old->headertype;
1851                         } else {
1852                                 // normal fullscreen. Use current headertype
1853                                 headertype = curarea->headertype;
1854                         }
1855
1856                         copy_areadata(old, curarea);
1857                         old->headertype = headertype;
1858
1859                         old->full= 0;
1860                 
1861                         unlink_screen(G.curscreen);
1862                         free_libblock(&G.main->screen, G.curscreen);
1863                         G.curscreen= NULL;
1864
1865                         setscreen(sc);
1866                 }
1867                 
1868         }
1869         else {
1870                 /* is there only 1 area? */
1871                 if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
1872                 if(curarea->spacetype==SPACE_INFO) return;
1873                 
1874                 G.curscreen->full = SCREENFULL;
1875                 
1876                 old= curarea;           
1877                 oldscreen= G.curscreen;
1878                 sc= addscreen("temp");          /* this sets G.curscreen */
1879
1880                 splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
1881                 newa= sc->areabase.first;
1882                 newspace(newa->next, SPACE_INFO);
1883                 
1884                 curarea= old;
1885                 G.curscreen= oldscreen; /* needed because of setscreen */
1886                 
1887                 /* vopy area */
1888                 copy_areadata(newa, curarea);
1889                 
1890                 curarea->full= oldscreen;
1891                 newa->full= oldscreen;
1892                 newa->next->full= oldscreen;
1893                 
1894                 setscreen(sc);
1895                 wich_cursor(newa);
1896         }
1897 }
1898
1899 static void area_autoplayscreen(void)
1900 {
1901         bScreen *sc, *oldscreen;
1902         ScrArea *newa, *old, *sa;
1903         
1904         if (curarea->full) {
1905                 area_fullscreen();
1906         }
1907
1908         if (curarea->full == NULL) { 
1909                 sa = G.curscreen->areabase.first;
1910                 while (sa) {
1911                         if (sa->spacetype == SPACE_VIEW3D) {
1912                                 break;
1913                         }
1914                         sa= sa->next;
1915                 }
1916
1917                 if (sa) {
1918                         areawinset(sa->win);
1919                         G.curscreen->full = SCREENAUTOPLAY;
1920                         
1921                         old= curarea;           
1922                         oldscreen= G.curscreen;
1923                         sc= addscreen("temp");          /* this sets G.curscreen */
1924         
1925                         newa= sc->areabase.first;
1926                         
1927                         curarea= old;
1928                         G.curscreen= oldscreen; /* because of setscreen */
1929                         
1930                         /* copy area settings */
1931                         copy_areadata(newa, curarea);
1932                         newa->headertype= 0;
1933                         
1934                         curarea->full= oldscreen;
1935                         newa->full= oldscreen;
1936         
1937                         setscreen(sc);
1938                         wich_cursor(newa);
1939                 }
1940         }
1941 }
1942
1943 static void copy_screen(bScreen *to, bScreen *from)
1944 {
1945         ScrVert *s1, *s2;
1946         ScrEdge *se;
1947         ScrArea *sa;
1948         ListBase lbase;
1949
1950         /* free 'to' */
1951         free_screen(to);
1952         winqueue_break= 1;      /* leave queues everywhere */
1953         
1954         duplicatelist(&to->vertbase, &from->vertbase);
1955         duplicatelist(&to->edgebase, &from->edgebase);
1956         duplicatelist(&to->areabase, &from->areabase);
1957         
1958         s1= from->vertbase.first;
1959         s2= to->vertbase.first;
1960         while(s1) {
1961                 s1->newv= s2;
1962                 s2= s2->next;
1963                 s1= s1->next;
1964         }
1965         se= to->edgebase.first;
1966         while(se) {
1967                 se->v1= se->v1->newv;
1968                 se->v2= se->v2->newv;
1969                 sortscrvert(&(se->v1), &(se->v2));
1970                 se= se->next;
1971         }
1972
1973         sa= to->areabase.first;
1974         while(sa) {
1975                 sa->v1= sa->v1->newv;
1976                 sa->v2= sa->v2->newv;
1977                 sa->v3= sa->v3->newv;
1978                 sa->v4= sa->v4->newv;
1979                 sa->win= 0;
1980                 sa->headwin= 0;
1981                 
1982                 sa->uiblocks.first= sa->uiblocks.last= NULL;
1983                 
1984                 duplicatespacelist(sa, &lbase, &sa->spacedata);
1985                 sa->spacedata= lbase;
1986                 
1987                 sa= sa->next;
1988         }
1989         
1990         /* put at zero (needed?) */
1991         s1= from->vertbase.first;
1992         while(s1) {
1993                 s1->newv= 0;
1994                 s1= s1->next;
1995         }
1996 }
1997
1998 void duplicate_screen(void)
1999 {
2000         bScreen *sc, *oldscreen;
2001         
2002         if(G.curscreen->full != SCREENNORMAL) return;
2003         
2004         /* make new screen: */
2005
2006         oldscreen= G.curscreen;
2007         sc= addscreen(oldscreen->id.name+2);    /* this sets G.curscreen */
2008         copy_screen(sc, oldscreen);
2009
2010         G.curscreen= oldscreen;
2011         setscreen(sc);
2012
2013 }
2014
2015
2016 /* ************ END SCREEN MANAGEMENT ************** */
2017 /* ************  JOIN/SPLIT/MOVE ************** */
2018
2019 static void joinarea(ScrArea *sa, ScrEdge *onedge)
2020 {
2021         ScrArea *sa2;
2022         ScrArea *up=0, *down=0, *right=0, *left=0;
2023         ScrEdge *setest;
2024         short val=0;
2025         
2026         sa= test_edge_area(sa, onedge);
2027         if (sa==0) return;
2028
2029         /* which edges? */
2030         /* find directions with same edge */
2031         sa2= G.curscreen->areabase.first;
2032         while(sa2) {
2033                 if(sa2 != sa) {
2034                         setest= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
2035                         if(onedge==setest) right= sa2;
2036                         setest= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
2037                         if(onedge==setest) down= sa2;
2038                         setest= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
2039                         if(onedge==setest) left= sa2;
2040                         setest= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
2041                         if(onedge==setest) up= sa2;
2042                 }
2043                 sa2= sa2->next;
2044         }
2045         
2046         sa2= 0;
2047         setest= 0;
2048         
2049         if(left) val++;
2050         if(up) val++;
2051         if(right) val++;
2052         if(down) val++;
2053         
2054         if(val==0) return;
2055         else if(val==1) {
2056                 if(left) sa2= left;
2057                 else if(up) sa2= up;
2058                 else if(right) sa2= right;
2059                 else if(down) sa2= down;
2060         }
2061         
2062         
2063         if(sa2) {
2064                 /* new area is old sa */
2065                 if(sa2==left) {
2066                         sa->v1= sa2->v1;
2067                         sa->v2= sa2->v2;
2068                         screen_addedge(G.curscreen, sa->v2, sa->v3);
2069                         screen_addedge(G.curscreen, sa->v1, sa->v4);
2070                 }
2071                 else if(sa2==up) {
2072                         sa->v2= sa2->v2;
2073                         sa->v3= sa2->v3;
2074                         screen_addedge(G.curscreen, sa->v1, sa->v2);
2075                         screen_addedge(G.curscreen, sa->v3, sa->v4);
2076                 }
2077                 else if(sa2==right) {
2078                         sa->v3= sa2->v3;
2079                         sa->v4= sa2->v4;
2080                         screen_addedge(G.curscreen, sa->v2, sa->v3);
2081                         screen_addedge(G.curscreen, sa->v1, sa->v4);
2082                 }
2083                 else if(sa2==down) {
2084                         sa->v1= sa2->v1;
2085                         sa->v4= sa2->v4;
2086                         screen_addedge(G.curscreen, sa->v1, sa->v2);
2087                         screen_addedge(G.curscreen, sa->v3, sa->v4);
2088                 }
2089         
2090                 /* remove edge and area */
2091                 /* remlink(&G.curscreen->edgebase, setest); */
2092                 /* freeN(setest); */
2093                 del_area(sa2);
2094                 BLI_remlink(&G.curscreen->areabase, sa2);
2095                 MEM_freeN(sa2);
2096                 
2097                 removedouble_scredges();
2098                 removenotused_scredges();
2099                 removenotused_scrverts();       /* as last */
2100                 
2101                 testareas();
2102                 mainqenter(DRAWEDGES, 1);
2103                         /* test cursor en inputwindow */
2104                 mainqenter(MOUSEY, -1);         
2105         }
2106 }
2107
2108 static short testsplitpoint(ScrArea *sa, char dir, float fac)
2109 /* return 0: no split possible */
2110 /* else return (integer) screencoordinate split point */
2111 {
2112         short x, y;
2113         
2114         /* area big enough? */
2115         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
2116         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
2117
2118         /* to be sure */
2119         if(fac<0.0) fac= 0.0;
2120         if(fac>1.0) fac= 1.0;
2121         
2122         if(dir=='h') {
2123                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
2124                 
2125                 if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY+EDGEWIDTH2) 
2126                         y= sa->v2->vec.y- HEADERY-EDGEWIDTH2;
2127
2128                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY+EDGEWIDTH2)
2129                         y= sa->v1->vec.y+ HEADERY+EDGEWIDTH2;
2130
2131                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
2132                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
2133                 else y-= (y % AREAGRID);
2134
2135                 return y;
2136         }
2137         else {
2138                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
2139                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
2140                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
2141                 else x-= (x % AREAGRID);
2142
2143                 return x;
2144         }
2145 }
2146
2147 static void splitarea(ScrArea *sa, char dir, float fac)
2148 {
2149         bScreen *sc;
2150         ScrArea *newa;
2151         ScrVert *sv1, *sv2;
2152         short split;
2153         
2154         if(sa==0) return;
2155         
2156         split= testsplitpoint(sa, dir, fac);
2157         if(split==0) return;
2158         
2159         sc= G.curscreen;
2160         
2161         areawinset(sa->win);
2162         
2163         if(dir=='h') {
2164                 /* new vertices */
2165                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
2166                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
2167                 
2168                 /* new edges */
2169                 screen_addedge(sc, sa->v1, sv1);
2170                 screen_addedge(sc, sv1, sa->v2);
2171                 screen_addedge(sc, sa->v3, sv2);
2172                 screen_addedge(sc, sv2, sa->v4);
2173                 screen_addedge(sc, sv1, sv2);
2174                 
2175                 /* new areas: top */
2176                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
2177                 copy_areadata(newa, sa);
2178
2179                 /* area below */
2180                 sa->v2= sv1;
2181                 sa->v3= sv2;
2182                 
2183         }
2184         else {
2185                 /* new vertices */
2186                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
2187                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
2188                 
2189                 /* new edges */
2190                 screen_addedge(sc, sa->v1, sv1);
2191                 screen_addedge(sc, sv1, sa->v4);
2192                 screen_addedge(sc, sa->v2, sv2);
2193                 screen_addedge(sc, sv2, sa->v3);
2194                 screen_addedge(sc, sv1, sv2);
2195                 
2196                 /* new areas: left */
2197                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
2198                 copy_areadata(newa, sa);
2199
2200                 /* area right */
2201                 sa->v1= sv1;            
2202                 sa->v2= sv2;
2203         }
2204         
2205         /* remove double vertices en edges */
2206         removedouble_scrverts();
2207         removedouble_scredges();
2208         removenotused_scredges();
2209         
2210         mainqenter(DRAWEDGES, 1);
2211         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2212         testareas();
2213 }
2214
2215 static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
2216 {
2217         int split= testsplitpoint(sa, dir, fac);
2218
2219         if (split) {
2220                 if(dir=='h') {
2221                         glutil_draw_front_xor_line(sa->totrct.xmin, split, sa->totrct.xmax, split);
2222                         glutil_draw_front_xor_line(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
2223                 } else {
2224                         glutil_draw_front_xor_line(split, sa->totrct.ymin, split, sa->totrct.ymax);
2225                         glutil_draw_front_xor_line(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
2226                 }
2227         }
2228 }
2229
2230 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
2231 {
2232         ScrArea *sa= area;
2233         float fac;
2234         unsigned short event;
2235         short ok= 0, val, split = 0, mval[2], mvalo[2], first= 1;
2236         char dir;
2237         
2238         if(sa->win==0) return;
2239         if(sa->full) return;
2240
2241         dir= scredge_is_horizontal(onedge)?'v':'h';
2242         
2243         mywinset(G.curscreen->mainwin);
2244         /* should already have a good matrix */
2245
2246         /* keep track of grid and minsize */
2247         while(ok==0) {
2248                 getmouseco_sc(mval);
2249                 
2250                 if (first || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2251                         if (!first) {
2252                                 scrarea_draw_splitpoint(sa, dir, fac);
2253                         }
2254
2255                         if(dir=='h') {
2256                                 fac= mval[1]- (sa->v1->vec.y);
2257                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2258                         } else {
2259                                 fac= mval[0]- sa->v1->vec.x;
2260                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2261                         }
2262
2263                         split= testsplitpoint(sa, dir, fac);
2264                         if (split) {
2265                                 scrarea_draw_splitpoint(sa, dir, fac);
2266                         } else {
2267                                 ok= -1;
2268                         }
2269
2270                         mvalo[0]= mval[0];
2271                         mvalo[1]= mval[1];
2272                         first= 0;                       
2273                 }
2274                 
2275                 event= extern_qread(&val);
2276                 if(val && event==LEFTMOUSE) {
2277                         if(dir=='h') {
2278                                 fac= split- (sa->v1->vec.y);
2279                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2280                         }
2281                         else {
2282                                 fac= split- sa->v1->vec.x;
2283                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2284                         }
2285                         ok= 1;
2286                 }
2287                 if(val && event==ESCKEY) {
2288                         ok= -1;
2289                 }
2290         }
2291
2292         if (!first) {
2293                 scrarea_draw_splitpoint(sa, dir, fac);
2294         }
2295
2296         if(ok==1) {
2297                 splitarea(sa, dir, fac);
2298                 mainqenter(DRAWEDGES, 1);
2299                 dodrawscreen= 1;                /* patch! event gets lost,,,? */
2300         }
2301 }
2302
2303 View3D *find_biggest_view3d(void)
2304 {
2305         ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
2306         
2307         if (sa) {
2308                 return (View3D*) sa->spacedata.first;
2309         } else {
2310                 return NULL;
2311         }
2312 }
2313
2314 ScrArea *find_biggest_area_of_type(int spacecode)
2315 {
2316         ScrArea *sa, *biggest= NULL;
2317         int bigsize;
2318         
2319         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2320                 if (spacecode==0 || sa->spacetype==spacecode) {
2321                         int x= sa->v3->vec.x - sa->v1->vec.x;
2322                         int y= sa->v3->vec.y - sa->v1->vec.y;
2323                         int size= x*x + y*y;
2324                 
2325                         if (!biggest || size>bigsize) {
2326                                 biggest= sa;
2327                                 bigsize= size;
2328                         }
2329                 }
2330         }
2331         
2332         return biggest;
2333 }
2334
2335 ScrArea *find_biggest_area(void)
2336 {
2337         return find_biggest_area_of_type(0);
2338 }
2339
2340 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
2341 {
2342         ScrEdge *se;
2343         ScrVert *sv;
2344         int oneselected;
2345         char dir;
2346         
2347         /* select connected, only in the right direction */
2348         /* 'dir' is the direction of EDGE */
2349
2350         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
2351         else dir= 'h';
2352
2353         sv= sc->vertbase.first;
2354         while(sv) {
2355                 sv->flag= 0;
2356                 sv= sv->next;
2357         }
2358
2359         edge->v1->flag= 1;
2360         edge->v2->flag= 1;
2361
2362         oneselected= 1;
2363         while(oneselected) {
2364                 se= sc->edgebase.first;
2365                 oneselected= 0;
2366                 while(se) {
2367                         if(se->v1->flag + se->v2->flag==1) {
2368                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
2369                                         se->v1->flag= se->v2->flag= 1;
2370                                         oneselected= 1;
2371                                 }
2372                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
2373                                         se->v1->flag= se->v2->flag= 1;
2374                                         oneselected= 1;
2375                                 }
2376                         }
2377                         se= se->next;
2378                 }
2379         }
2380 }
2381
2382 void test_scale_screen(bScreen *sc)
2383 /* test if screen vertices should be scaled */
2384 /* also check offset */
2385 {
2386         ScrVert *sv=0;
2387         ScrEdge *se;
2388         ScrArea *sa, *san;
2389         int yval;
2390         float facx, facy, tempf, min[2], max[2];
2391
2392         sc->startx= prefstax;
2393         sc->starty= prefstay;
2394         sc->endx= prefstax+prefsizx-1;
2395         sc->endy= prefstay+prefsizy-1;
2396
2397         /* calculate size */
2398         sv= sc->vertbase.first;
2399         min[0]= min[1]= 0.0;
2400         max[0]= sc->sizex;
2401         max[1]= sc->sizey;
2402         while(sv) {
2403                 min[0]= MIN2(min[0], sv->vec.x);
2404                 min[1]= MIN2(min[1], sv->vec.y);
2405                 max[0]= MAX2(max[0], sv->vec.x);
2406                 max[1]= MAX2(max[1], sv->vec.y);
2407                 sv= sv->next;
2408         }
2409
2410         /* always make 0.0 left under */
2411         sv= sc->vertbase.first;
2412         while(sv) {
2413                 sv->vec.x -= min[0];
2414                 sv->vec.y -= min[1];
2415                 sv= sv->next;
2416         }
2417         
2418
2419         sc->sizex= max[0]-min[0];
2420         sc->sizey= max[1]-min[1];
2421
2422         if(sc->sizex!= prefsizx || sc->sizey!= prefsizy) {
2423                 facx= prefsizx;
2424                 facx/= (float)sc->sizex;
2425                 facy= prefsizy;
2426                 facy/= (float)sc->sizey;
2427
2428                 /* make sure it fits! */
2429                 sv= sc->vertbase.first;
2430                 while(sv) {
2431                         tempf= ((float)sv->vec.x)*facx;
2432                         sv->vec.x= (short)(tempf+0.5);
2433                         sv->vec.x+= AREAGRID-1;
2434                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
2435                         
2436                         CLAMP(sv->vec.x, 0, prefsizx);
2437
2438                         tempf= ((float)sv->vec.y )*facy;
2439                         sv->vec.y= (short)(tempf+0.5);
2440                         sv->vec.y+= AREAGRID-1;
2441                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
2442                         
2443                         CLAMP(sv->vec.y, 0, prefsizy);
2444
2445                         sv= sv->next;
2446                 }
2447                 
2448                 sc->sizex= prefsizx;
2449                 sc->sizey= prefsizy;
2450         }
2451
2452         /* test for collapsed areas. This could happen in some blender version... */
2453         sa= sc->areabase.first;
2454         while(sa) {
2455                 san= sa->next;
2456                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
2457                         del_area(sa);
2458                         BLI_remlink(&sc->areabase, sa);
2459                         MEM_freeN(sa);
2460                 }
2461                 sa= san;
2462         }
2463
2464         /* make each window at least HEADERY high */
2465
2466         sa= sc->areabase.first;
2467         while(sa) {
2468
2469                 if(sa->v1->vec.y+HEADERY > sa->v2->vec.y) {
2470                         /* lower edge */
2471                         se= screen_findedge(sc, sa->v4, sa->v1);
2472                         if(se && sa->v1!=sa->v2 ) {
2473                                 select_connected_scredge(sc, se);
2474                                 
2475                                 /* all selected vertices get the right offset */
2476                                 yval= sa->v2->vec.y-HEADERY;
2477                                 sv= sc->vertbase.first;
2478                                 while(sv) {
2479                                         /* if is a collapsed area */
2480                                         if(sv!=sa->v2 && sv!=sa->v3) {
2481                                                 if(sv->flag) sv->vec.y= yval;
2482                                         }
2483                                         sv= sv->next;
2484                                 }
2485                         }
2486                 }
2487
2488                 sa= sa->next;
2489         }
2490
2491 }
2492
2493 static void draw_front_xor_dirdist_line(char dir, int dist, int start, int end)
2494 {
2495         if (dir=='h') {
2496                 glutil_draw_front_xor_line(start, dist, end, dist);
2497                 glutil_draw_front_xor_line(start, dist+1, end, dist+1);
2498         } else {
2499                 glutil_draw_front_xor_line(dist, start, dist, end);
2500                 glutil_draw_front_xor_line(dist+1, start, dist+1, end);
2501         }
2502 }
2503
2504 static void moveareas(ScrEdge *edge)
2505 {
2506         ScrVert *v1;
2507         ScrArea *sa;
2508         short mvalo[2];
2509         short edge_start, edge_end, edge_position;
2510         short bigger, smaller, headery, areaminy;
2511         int delta, doit;
2512         char dir;
2513         
2514         if(edge->border) return;
2515
2516         dir= scredge_is_horizontal(edge)?'h':'v';
2517         
2518         select_connected_scredge(G.curscreen, edge);
2519
2520         edge_position= (dir=='h')?edge->v1->vec.y:edge->v1->vec.x;
2521         edge_start= 10000;
2522         edge_end= -10000;
2523         for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
2524                 if (v1->flag) {
2525                         if (dir=='h') {
2526                                 edge_start= MIN2(edge_start, v1->vec.x);
2527                                 edge_end= MAX2(edge_end, v1->vec.x);
2528                         } else {
2529                                 edge_start= MIN2(edge_start, v1->vec.y);
2530                                 edge_end= MAX2(edge_end, v1->vec.y);
2531                         }
2532                 }
2533         }
2534
2535         /* now all verices with 'flag==1' are the ones that can be moved. */
2536         /* we check all areas and test for free space with MINSIZE */
2537         bigger= smaller= 10000;
2538         sa= G.curscreen->areabase.first;
2539         while(sa) {
2540                 if(dir=='h') {  /* if top or down edge selected, test height */
2541                         if(sa->headertype) {
2542                                 headery= HEADERY;
2543                                 areaminy= AREAMINY;
2544                         }
2545                         else {
2546                                 headery= 0;
2547                                 areaminy= EDGEWIDTH;
2548                         }
2549
2550                         if(sa->v1->flag && sa->v4->flag) {
2551                                 int y1;
2552                                 if(sa->v2->vec.y==G.curscreen->sizey-1) /* top edge */
2553                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
2554                                 else 
2555                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
2556                                 bigger= MIN2(bigger, y1);
2557                         }
2558                         else if(sa->v2->flag && sa->v3->flag) {
2559                                 int y1;
2560                                 if(sa->v1->vec.y==0)    /* bottom edge */
2561                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
2562                                 else
2563                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
2564                                 smaller= MIN2(smaller, y1);
2565                         }
2566                 }
2567                 else {  /* if left or right edge selected, test width */
2568                         if(sa->v1->flag && sa->v2->flag) {
2569                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
2570                                 bigger= MIN2(bigger, x1);
2571                         }
2572                         else if(sa->v3->flag && sa->v4->flag) {
2573                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
2574                                 smaller= MIN2(smaller, x1);
2575                         }
2576                 }
2577                 sa= sa->next;
2578         }
2579         
2580         mywinset(G.curscreen->mainwin);
2581
2582         doit= delta= 0;
2583         getmouseco_sc(mvalo);
2584         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2585         while (!doit) {
2586                 short val;
2587                 unsigned short event= extern_qread(&val);
2588                 
2589                 if (event==MOUSEY) {
2590                         short mval[2];
2591                         
2592                         getmouseco_sc(mval);
2593                         
2594                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2595
2596                         delta= (dir=='h')?(mval[1]-mvalo[1]):(mval[0]-mvalo[0]);
2597                         delta= CLAMPIS(delta, -smaller, bigger);
2598                         
2599                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2600                 } else if (event==LEFTMOUSE) {
2601                         doit= 1;
2602                 } else if (val) {
2603                         if (ELEM(event, ESCKEY, RIGHTMOUSE))
2604                                 doit= -1;
2605                         else if (ELEM(event, SPACEKEY, RETKEY))
2606                                 doit= 1;
2607                 }
2608         }
2609         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2610
2611         if (doit==1) {
2612                 for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
2613                         if (v1->flag) {
2614                                         /* that way a nice AREAGRID  */
2615                                 if((dir=='v') && v1->vec.x>0 && v1->vec.x<G.curscreen->sizex-1) {
2616                                         v1->vec.x+= delta;
2617                                         if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
2618                                 }
2619                                 if((dir=='h') && v1->vec.y>0 && v1->vec.y<G.curscreen->sizey-1) {
2620                                         v1->vec.y+= delta;
2621                                         
2622                                         /* with these lines commented out you can pull the top bar exact to the screen border. */
2623                                         /* if(delta != bigger && delta != -smaller) { */
2624                                                 v1->vec.y+= AREAGRID-1;
2625                                                 v1->vec.y-= (v1->vec.y % AREAGRID);
2626                                         
2627                                         /* } */
2628                                 }
2629                         }
2630                         v1->flag= 0;
2631                 }
2632                 
2633                 removedouble_scrverts();
2634                 removedouble_scredges();
2635                 testareas();
2636         }
2637         
2638         glDrawBuffer(GL_BACK);
2639         mainqenter(DRAWEDGES, 1);
2640         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2641 }
2642
2643 static void scrollheader(ScrArea *area)
2644 {
2645         short mval[2], mvalo[2];
2646         
2647         if(area->headbutlen<area->winx) {
2648                 area->headbutofs= 0;
2649         }
2650         else if(area->headbutofs+area->winx > area->headbutlen) {
2651                 area->headbutofs= area->headbutlen-area->winx;
2652         }
2653
2654         getmouseco_sc(mvalo);
2655
2656         while(get_mbut() & M_MOUSE) {
2657                 getmouseco_sc(mval);
2658                 if(mval[0]!=mvalo[0]) {
2659                         area->headbutofs-= (mval[0]-mvalo[0]);
2660
2661                         if(area->headbutlen-area->winx < area->headbutofs) area->headbutofs= area->headbutlen-area->winx;
2662                         if(area->headbutofs<0) area->headbutofs= 0;
2663
2664                         scrarea_do_headchange(area);
2665                         scrarea_do_headdraw(area);
2666
2667                         screen_swapbuffers();
2668                         
2669                         mvalo[0]= mval[0];
2670                 } else {
2671                         BIF_wait_for_statechange();
2672                 }
2673         }
2674 }
2675
2676 int select_area(int spacetype)
2677 {
2678         /* call from edit routines, when there are more areas
2679          * of type 'spacetype', you can indicate an area manually
2680          */
2681         ScrArea *sa, *sact = NULL;
2682         int tot=0;
2683         unsigned short event = 0;
2684         short val, mval[2];
2685         
2686         sa= G.curscreen->areabase.first;
2687         while(sa) {
2688                 if(sa->spacetype==spacetype) {
2689                         sact= sa;
2690                         tot++;
2691                 }
2692                 sa= sa->next;
2693         } 
2694         
2695         if(tot==0) {
2696                 error("Can't do this! Open correct window");
2697                 return 0;
2698         }
2699         
2700         if(tot==1) {
2701                 if(curarea!=sact) areawinset(sact->win);
2702                 return 1;
2703         }
2704         else if(tot>1) {
2705                 set_cursor(CURSOR_HELP);
2706                 while(1) {
2707                         event= extern_qread(&val);
2708                         
2709                         if (val) {
2710                                 if(event==ESCKEY) break;
2711                                 if(event==LEFTMOUSE) break;
2712                                 if(event==SPACEKEY) break;
2713                         } else {
2714                                 BIF_wait_for_statechange();
2715                         }
2716                 }
2717                 screen_set_cursor(G.curscreen);
2718                 
2719                 /* recalculate winakt */
2720                 getmouseco_sc(mval);
2721                 
2722                 if(event==LEFTMOUSE) {
2723                         ScrArea *sa= screen_find_area_for_pt(G.curscreen, mval);
2724                         
2725                         if (sa &&sa->spacetype==spacetype) {
2726                                 G.curscreen->winakt= sa->win;
2727                                 areawinset(G.curscreen->winakt);
2728                         } else {
2729                                 error("wrong window");
2730                                 return 0;
2731                         }
2732                 }
2733         }
2734         
2735         if(event==LEFTMOUSE) return 1;
2736         else return 0;
2737 }
2738
2739 /* ************  END JOIN/SPLIT/MOVE ************** */
2740 /* **************** DRAW SCREENEDGES ***************** */
2741
2742 #define EDGE_EXTEND 3
2743
2744 void drawedge(short x1, short y1, short x2, short y2)
2745 {
2746         static unsigned int edcol[EDGEWIDTH]= {0x0, 0x505050, 0x909090, 0xF0F0F0, 0x0};
2747         int a;
2748         
2749         if(x1==x2) {            /* vertical */
2750                 if (y2<y1)
2751                         y1^= y2^= y1^= y2;
2752                 
2753                 if (y1==0) y1-= EDGE_EXTEND;
2754                 if (y2==G.curscreen->sizey) y2+= EDGE_EXTEND;
2755                 
2756                 x1+= EDGEWIDTH2;
2757                 x2+= EDGEWIDTH2;
2758
2759                 glBegin(GL_LINES);              
2760                 for(a=0; a<EDGEWIDTH; a++) {
2761                         int rounding= abs(a-EDGEWIDTH2);
2762                         
2763                         cpack(edcol[a]);
2764                         glVertex2i(x1-a, y1+rounding);
2765                         glVertex2i(x2-a, y2-rounding);
2766                 }
2767                 glEnd();
2768         }
2769         else {                          /* horizontal */
2770                 if (x2<x1)
2771                         x1^= x2^= x1^= x2;
2772                 
2773                 if (x1==0) x1-= EDGE_EXTEND;
2774                 if (x2==G.curscreen->sizex) x2+= EDGE_EXTEND;
2775
2776                 y1-= EDGEWIDTH2;
2777                 y2-= EDGEWIDTH2;
2778                 
2779                 glBegin(GL_LINES);
2780                 for(a=0; a<EDGEWIDTH; a++) {
2781                         int rounding= abs(a-EDGEWIDTH2);
2782                         
2783                         cpack(edcol[a]);
2784                         glVertex2i(x1+rounding, y1+a);
2785                         glVertex2i(x2-rounding, y2+a);
2786                 }
2787                 glEnd();
2788         }
2789 }
2790
2791 static void drawscredge(ScrEdge *se)
2792 {
2793         bScreen *sc;
2794         vec2s *v1, *v2;
2795         
2796         sc= G.curscreen;
2797         
2798         v1= &(se->v1->vec);
2799         v2= &(se->v2->vec);
2800         
2801         /* do not draw borders screen© */
2802         /* bcause of different framebuffer resoltions (PC/SGI etc files) 
2803          * a bit rounding here? should be looked at further...
2804          */
2805         se->border= 1;
2806         if(v1->x<=1 && v2->x<=1) return;
2807         if(v1->x>=sc->sizex-2 && v2->x>=sc->sizex-2) return;
2808         if(v1->y<=1 && v2->y<=1) return;
2809         if(v1->y>=sc->sizey-2 && v2->y>=sc->sizey-2) return;
2810         se->border= 0;
2811
2812         drawedge(v1->x, v1->y, v2->x, v2->y);
2813 }
2814
2815 void drawscreen(void)
2816 {
2817         ScrEdge *se;
2818         
2819         mywinset(G.curscreen->mainwin);
2820         myortho2(-0.5, (float)G.curscreen->sizex-0.5, -0.6, (float)G.curscreen->sizey-0.6);
2821
2822         /* two times, because there is no 'win_swap' for this  available */
2823         glDrawBuffer(GL_FRONT);
2824         se= G.curscreen->edgebase.first;
2825         while(se) {
2826                 drawscredge(se);
2827                 se= se->next;
2828         }
2829
2830         glDrawBuffer(GL_BACK);
2831         se= G.curscreen->edgebase.first;
2832         while(se) {
2833                 drawscredge(se);
2834                 se= se->next;
2835         }
2836 }
2837
2838 /* ********************************* */
2839
2840 bScreen *default_twosplit() 
2841 {
2842         bScreen *sc= addscreen("screen");
2843         ScrArea *sa;
2844
2845         splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
2846         sa= sc->areabase.first;
2847         newspace(sa, SPACE_VIEW3D);
2848         newspace(sa->next, SPACE_INFO);
2849         
2850         return sc;
2851 }
2852
2853 void initscreen(void)
2854 {
2855         default_twosplit();
2856 }
2857
2858 /***/
2859
2860 void screen_draw_info_text(bScreen *sc, char *text) {
2861         Window *oldactwin= winlay_get_active_window();
2862         ScrArea *sa;
2863         
2864                 /*
2865                  * Because this is called from within rendering
2866                  * internals it is possible our window is not
2867                  * active.
2868                  */
2869         window_make_active(mainwin);
2870         
2871         for (sa= sc->areabase.first; sa; sa= sa->next) {
2872                 if (sa->spacetype==SPACE_INFO) {
2873                         int x= sa->headbutlen - 28;
2874                         int y= 6;
2875                         
2876                         areawinset(sa->headwin);
2877                         glDrawBuffer(GL_FRONT);
2878
2879                         cpack(0xA08060);
2880                         glRecti(x-11,  y-6,  x+55,  y+13);
2881                         
2882                         cpack(0x909090);
2883                         glRecti(x+55,  y-6,  x+1280,  y+14);
2884                         
2885                         cpack(0x0);
2886                         glRasterPos2i(x,  y);
2887                         BMF_DrawString(G.fonts, text);
2888                         
2889                         glFinish();
2890                         glDrawBuffer(GL_BACK);
2891                         
2892                         sa->head_swap= WIN_FRONT_OK;
2893                 }
2894         }
2895         
2896         if (oldactwin && oldactwin!=mainwin) window_make_active(oldactwin);
2897 }
2898
2899 static int curcursor;
2900
2901 int get_cursor(void) {
2902         return curcursor;
2903 }
2904
2905 void set_cursor(int curs) {
2906         if (!(R.flag & R_RENDERING)) {
2907                 if (curs!=curcursor) {
2908                         curcursor= curs;
2909                         window_set_cursor(mainwin, curs);
2910                 }
2911         }
2912 }
2913
2914 void unlink_screen(bScreen *sc) {
2915         ScrArea *sa;
2916         
2917         for (sa= sc->areabase.first; sa; sa= sa->next)  
2918                 del_area(sa);
2919 }
2920
2921 void warp_pointer(int x, int y)
2922 {
2923         window_warp_pointer(mainwin, x, y);
2924 }
2925
2926 void set_timecursor(int nr)
2927 {
2928                 /* 10 8x8 digits */
2929         static char number_bitmaps[10][8]= {
2930                 {0,  56,  68,  68,  68,  68,  68,  56}, 
2931                 {0,  24,  16,  16,  16,  16,  16,  56}, 
2932                 {0,  60,  66,  32,  16,   8,   4, 126}, 
2933                 {0, 124,  32,  16,  56,  64,  66,  60}, 
2934                 {0,  32,  48,  40,  36, 126,  32,  32}, 
2935                 {0, 124,   4,  60,  64,  64,  68,  56}, 
2936                 {0,  56,   4,   4,  60,  68,  68,  56}, 
2937                 {0, 124,  64,  32,  16,   8,   8,   8}, 
2938                 {0,  60,  66,  66,  60,  66,  66,  60}, 
2939                 {0,  56,  68,  68, 120,  64,  68,  56} 
2940         };
2941         unsigned char mask[16][2];
2942         unsigned char bitmap[16][2];
2943         int i, idx;
2944
2945         memset(&bitmap, 0x00, sizeof(bitmap));
2946         memset(&mask, 0xFF, sizeof(mask));
2947         
2948                 /* print number bottom right justified */
2949         for (idx= 3; nr && idx>=0; idx--) {
2950                 char *digit= number_bitmaps[nr%10];
2951                 int x = idx%2;
2952                 int y = idx/2;
2953                 
2954                 for (i=0; i<8; i++)
2955                         bitmap[i + y*8][x]= digit[i];
2956                 nr/= 10;
2957         }
2958
2959         curcursor= CURSOR_NONE;
2960         window_set_custom_cursor(mainwin, mask, bitmap);
2961         BIF_renderwin_set_custom_cursor(mask, bitmap);
2962 }
2963