added a fullscreen button in the top header (windows only)
[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;
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 #ifdef _WIN32   // FULLSCREEN
1115 void mainwindow_toggle_fullscreen(int fullscreen){
1116         if (fullscreen) U.uiflag |= FLIPFULLSCREEN;
1117         else U.uiflag &= ~FLIPFULLSCREEN;
1118
1119         window_toggle_fullscreen(mainwin, fullscreen);
1120 }
1121 #endif
1122
1123 void mainwindow_raise(void) {
1124         window_raise(mainwin);
1125 }
1126 void mainwindow_make_active(void) {
1127         window_make_active(mainwin);
1128 }
1129 void mainwindow_close(void) {
1130         window_destroy(mainwin);
1131         mainwin= NULL;
1132 }
1133
1134 /* *********  AREAS  ************* */
1135
1136 void setprefsize(int stax, int stay, int sizx, int sizy)
1137 {
1138         int scrwidth, scrheight;
1139         
1140         winlay_get_screensize(&scrwidth, &scrheight);
1141         
1142         if(stax<0) stax= 0;
1143         if(stay<0) stay= 0;
1144         if(sizx<320) sizx= 320;
1145         if(sizy<256) sizy= 256;
1146
1147         if(stax+sizx>scrwidth) sizx= scrwidth-stax;
1148         if(stay+sizy>scrheight) sizy= scrheight-stay;
1149         if(sizx<320 || sizy<256) {
1150                 printf("ERROR: illegal prefsize\n");
1151                 return;
1152         }
1153         
1154         prefstax= stax;
1155         prefstay= stay;
1156         prefsizx= sizx;
1157         prefsizy= sizy;
1158
1159         start_maximized= 0;
1160 }
1161
1162
1163 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
1164 {
1165         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
1166         sv->vec.x= x;
1167         sv->vec.y= y;
1168         
1169         BLI_addtail(&sc->vertbase, sv);
1170         return sv;
1171 }
1172
1173 static void sortscrvert(ScrVert **v1, ScrVert **v2)
1174 {
1175         ScrVert *tmp;
1176         
1177         if ((long)*v1 > (long)*v2) {
1178                 tmp= *v1;
1179                 *v1= *v2;
1180                 *v2= tmp;       
1181         }
1182 }
1183
1184 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1185 {
1186         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
1187
1188         sortscrvert(&v1, &v2);
1189         se->v1= v1;
1190         se->v2= v2;
1191         
1192         BLI_addtail(&sc->edgebase, se);
1193         return se;
1194 }
1195
1196 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1197 {
1198         ScrEdge *se;
1199
1200         sortscrvert(&v1, &v2);
1201         for (se= sc->edgebase.first; se; se= se->next)
1202                 if(se->v1==v1 && se->v2==v2)
1203                         return se;
1204
1205         return NULL;
1206 }
1207
1208 static void removedouble_scrverts(void)
1209 {
1210         ScrVert *v1, *verg;
1211         ScrEdge *se;
1212         ScrArea *sa;
1213         
1214         verg= G.curscreen->vertbase.first;
1215         while(verg) {
1216                 if(verg->newv==0) {     /* !!! */
1217                         v1= verg->next;
1218                         while(v1) {
1219                                 if(v1->newv==0) {       /* !?! */
1220                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
1221                                                 /* printf("doublevert\n"); */
1222                                                 v1->newv= verg;
1223                                         }
1224                                 }
1225                                 v1= v1->next;
1226                         }
1227                 }
1228                 verg= verg->next;
1229         }
1230         
1231         /* replace pointers in edges and faces */
1232         se= G.curscreen->edgebase.first;
1233         while(se) {
1234                 if(se->v1->newv) se->v1= se->v1->newv;
1235                 if(se->v2->newv) se->v2= se->v2->newv;
1236                 /* edges changed: so.... */
1237                 sortscrvert(&(se->v1), &(se->v2));
1238                 se= se->next;
1239         }
1240         sa= G.curscreen->areabase.first;
1241         while(sa) {
1242                 if(sa->v1->newv) sa->v1= sa->v1->newv;
1243                 if(sa->v2->newv) sa->v2= sa->v2->newv;
1244                 if(sa->v3->newv) sa->v3= sa->v3->newv;
1245                 if(sa->v4->newv) sa->v4= sa->v4->newv;
1246                 sa= sa->next;
1247         }
1248         
1249         /* remove */
1250         verg= G.curscreen->vertbase.first;
1251         while(verg) {
1252                 v1= verg->next;
1253                 if(verg->newv) {
1254                         BLI_remlink(&G.curscreen->vertbase, verg);
1255                         MEM_freeN(verg);
1256                 }
1257                 verg= v1;
1258         }
1259         
1260 }
1261
1262 static void removenotused_scrverts(void)
1263 {
1264         ScrVert *sv, *svn;
1265         ScrEdge *se;
1266
1267         /* we assume edges are ok */
1268         
1269         se= G.curscreen->edgebase.first;
1270         while(se) {
1271                 se->v1->flag= 1;
1272                 se->v2->flag= 1;
1273                 se= se->next;
1274         }
1275         
1276         sv= G.curscreen->vertbase.first;
1277         while(sv) {
1278                 svn= sv->next;
1279                 if(sv->flag==0) {
1280                         BLI_remlink(&G.curscreen->vertbase, sv);
1281                         MEM_freeN(sv);
1282                 }
1283                 else sv->flag= 0;
1284                 sv= svn;
1285         }
1286 }
1287
1288 static void removedouble_scredges(void)
1289 {
1290         ScrEdge *verg, *se, *sn;
1291         
1292         /* compare */
1293         verg= G.curscreen->edgebase.first;
1294         while(verg) {
1295                 se= verg->next;
1296                 while(se) {
1297                         sn= se->next;
1298                         if(verg->v1==se->v1 && verg->v2==se->v2) {
1299                                 BLI_remlink(&G.curscreen->edgebase, se);
1300                                 MEM_freeN(se);
1301                         }
1302                         se= sn;
1303                 }
1304                 verg= verg->next;
1305         }
1306 }
1307
1308 static void removenotused_scredges(void)
1309 {
1310         ScrEdge *se, *sen;
1311         ScrArea *sa;
1312         int a=0;
1313         
1314         /* sets flags when edge is used in area */
1315         sa= G.curscreen->areabase.first;
1316         while(sa) {
1317                 se= screen_findedge(G.curscreen, sa->v1, sa->v2);
1318                 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
1319                 else se->flag= 1;
1320                 se= screen_findedge(G.curscreen, sa->v2, sa->v3);
1321                 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
1322                 else se->flag= 1;
1323                 se= screen_findedge(G.curscreen, sa->v3, sa->v4);
1324                 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
1325                 else se->flag= 1;
1326                 se= screen_findedge(G.curscreen, sa->v4, sa->v1);
1327                 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
1328                 else se->flag= 1;
1329                 sa= sa->next;
1330                 a++;
1331         }
1332         se= G.curscreen->edgebase.first;
1333         while(se) {
1334                 sen= se->next;
1335                 if(se->flag==0) {
1336                         BLI_remlink(&G.curscreen->edgebase, se);
1337                         MEM_freeN(se);
1338                 }
1339                 else se->flag= 0;
1340                 se= sen;
1341         }
1342 }
1343
1344 void calc_arearcts(ScrArea *sa)
1345 {
1346
1347         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+EDGEWIDTH2+1;
1348         else sa->totrct.xmin= sa->v1->vec.x;
1349         if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-EDGEWIDTH2-1;
1350         else sa->totrct.xmax= sa->v4->vec.x;
1351         
1352         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+EDGEWIDTH2+1;
1353         else sa->totrct.ymin= sa->v1->vec.y;
1354         if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-EDGEWIDTH2-1;
1355         else sa->totrct.ymax= sa->v2->vec.y;
1356         
1357         sa->winrct= sa->totrct;
1358         if(sa->headertype) {
1359                 sa->headrct= sa->totrct;
1360                 if(sa->headertype==HEADERDOWN) {
1361                         sa->headrct.ymax= sa->headrct.ymin+HEADERY-1;
1362                         sa->winrct.ymin= sa->headrct.ymax+1;
1363                 }
1364                 else if(sa->headertype==HEADERTOP) {
1365                         sa->headrct.ymin= sa->headrct.ymax-HEADERY+1;
1366                         sa->winrct.ymax= sa->headrct.ymin-1;
1367                 }
1368         }
1369         if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
1370         
1371         /* for speedup */
1372         sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
1373         sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
1374 }
1375
1376 static void openheadwin(ScrArea *sa)
1377 {
1378         sa->headwin= myswinopen(G.curscreen->mainwin,
1379                 sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1380
1381         glMatrixMode(GL_MODELVIEW);
1382         
1383         areawinar[sa->headwin]= sa;     /* oterwise addqueue does not work */
1384         addqueue(sa->headwin, CHANGED, 1);
1385 }
1386
1387 static void openareawin(ScrArea *sa)
1388 {
1389         sa->win= myswinopen(G.curscreen->mainwin, 
1390                 sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1391
1392         areawinar[sa->win]= sa; /* otherwise addqueue does not work */
1393         addqueue(sa->win, CHANGED, 1);
1394 }
1395
1396 static void closeheadwin(ScrArea *sa)
1397 {
1398         if(sa->headwin) mywinclose(sa->headwin);
1399         sa->headwin= 0;
1400 }
1401
1402 static void closeareawin(ScrArea *sa)
1403 {
1404         uiFreeBlocksWin(&sa->uiblocks, sa->win);
1405
1406         if(sa->win) mywinclose(sa->win);
1407         sa->win= 0;
1408 }
1409
1410 static void del_area(ScrArea *sa)
1411 {
1412         closeareawin(sa);
1413         closeheadwin(sa);
1414
1415         freespacelist(&sa->spacedata);
1416         
1417         uiFreeBlocks(&sa->uiblocks);
1418         
1419         if(sa==curarea) curarea= 0;
1420         if(sa==g_activearea) g_activearea= 0;
1421 }
1422
1423 static void copy_areadata(ScrArea *sa1, ScrArea *sa2)
1424 {
1425         sa1->headertype= sa2->headertype;
1426         sa1->spacetype= sa2->spacetype;
1427         Mat4CpyMat4(sa1->winmat, sa2->winmat);
1428         
1429         freespacelist(&sa1->spacedata);
1430         
1431         duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
1432 }
1433
1434 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
1435 {
1436         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
1437         sa->cursor= CURSOR_STD;
1438         sa->v1= v1;
1439         sa->v2= v2;
1440         sa->v3= v3;
1441         sa->v4= v4;
1442         sa->headertype= headertype;
1443         sa->spacetype= spacetype;
1444
1445         calc_arearcts(sa);
1446
1447         if (sa->headertype) openheadwin(sa);
1448         openareawin(sa);
1449
1450         BLI_addtail(&sc->areabase, sa);
1451         return sa;
1452 }
1453
1454 static int rcti_eq(rcti *a, rcti *b) {
1455         return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
1456                         (a->ymin==b->ymin && a->ymax==b->ymax));
1457 }
1458
1459 static void testareas(void)
1460 {
1461         ScrArea *sa;
1462
1463         /* test for header, if removed, or moved */
1464         /* testen for window, if removed, or moved */
1465
1466         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1467                 rcti oldhr= sa->headrct;
1468                 rcti oldwr= sa->winrct;
1469                 
1470                 calc_arearcts(sa);
1471
1472                         /* test header */
1473                 if (sa->headwin) {
1474                         if (!rcti_eq(&oldhr, &sa->headrct)) {
1475                                 mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1476                                 addqueue(sa->headwin, CHANGED, 1);
1477                         }
1478                                 
1479                         if(sa->headbutlen<sa->winx) {
1480                                 sa->headbutofs= 0;
1481                                 addqueue(sa->headwin, CHANGED, 1);
1482                         }
1483                         else if(sa->headbutofs+sa->winx > sa->headbutlen) {
1484                                 sa->headbutofs= sa->headbutlen-sa->winx;
1485                                 addqueue(sa->headwin, CHANGED, 1);
1486                         }
1487                 }
1488
1489                 if (!rcti_eq(&oldwr, &sa->winrct)) {
1490                         mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1491                         addqueue(sa->win, CHANGED, 1);
1492                 }
1493         }
1494         
1495                 /* remake global windowarray */
1496         memset(areawinar, 0, sizeof(void *)*MAXWIN);
1497         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1498                 areawinar[sa->headwin]= sa;
1499                 areawinar[sa->win]= sa;
1500         }
1501         
1502                 /* test if winakt is OK */      
1503         if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
1504 }
1505
1506 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
1507 {
1508         /* test if edge is in area, if not, 
1509            then find an area that has it */
1510   
1511         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
1512         
1513         if(sa) {
1514                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1515                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1516                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1517                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1518         }
1519         if(se1!=se && se2!=se && se3!=se && se4!=se) {
1520                 
1521                 sa= G.curscreen->areabase.first;
1522                 while(sa) {
1523                         /* a bit optimise? */
1524                         if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
1525                                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1526                                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1527                                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1528                                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1529                                 if(se1==se || se2==se || se3==se || se4==se) return sa;
1530                         }
1531                         sa= sa->next;
1532                 }
1533         }
1534
1535         return sa;      /* is null when not find */
1536 }
1537
1538 ScrArea *closest_bigger_area(void)
1539 {
1540         ScrArea *sa, *big=0;
1541         float cent[3], vec[3],len, len1, len2, len3, dist=1000;
1542         short mval[2];
1543         
1544         getmouseco_sc(mval);
1545         
1546         cent[0]= mval[0];
1547         cent[1]= mval[1];
1548         cent[2]= vec[2]= 0;
1549
1550         sa= G.curscreen->areabase.first;
1551         while(sa) {
1552                 if(sa!=curarea) {
1553                         if(sa->winy>=curarea->winy) {
1554                         
1555                                 /* mimimum of the 4 corners */
1556                                 vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
1557                                 len= VecLenf(vec, cent);
1558                                 vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
1559                                 len1= VecLenf(vec, cent);
1560                                 vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
1561                                 len2= VecLenf(vec, cent);
1562                                 vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
1563                                 len3= VecLenf(vec, cent);
1564                                 
1565                                 len= MIN4(len, len1, len2, len3);
1566                                 
1567                                 /* plus centre */
1568                                 vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
1569                                 vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
1570
1571                                 len+= 0.5*VecLenf(vec, cent);
1572                                 
1573                                 /* min size */
1574                                 len-= sa->winy+sa->winx;
1575                                 
1576                                 if(len<dist) {
1577                                         dist= len;
1578                                         big= sa;
1579                                 }
1580                         }
1581                 }
1582                 sa= sa->next;
1583         }
1584         
1585         if(big) return big;
1586         else return curarea;
1587 }
1588
1589 /* ************ SCREEN MANAGEMENT ************** */
1590
1591 static int statechanged= 0;
1592 void BIF_wait_for_statechange(void)
1593 {
1594         if (!statechanged) {
1595                         /* Safety, don't wait more than 0.1 seconds */
1596                 double stime= PIL_check_seconds_timer();
1597                 while (!statechanged) {
1598                         winlay_process_events(1);
1599                         if ((PIL_check_seconds_timer()-stime)>0.1) break;
1600                 }
1601                 statechanged= 0;
1602         }
1603 }
1604 void getmouse(short *mval)
1605 {
1606         winlay_process_events(0);
1607         window_get_mouse(mainwin, mval);
1608 }
1609 short get_qual(void)
1610 {
1611         winlay_process_events(0);
1612         return window_get_qual(mainwin);
1613 }
1614 short get_mbut(void)
1615 {
1616         winlay_process_events(0);
1617         return window_get_mbut(mainwin);
1618 }
1619
1620 static unsigned short convert_for_nonumpad(unsigned short event)
1621 {
1622         if (event>=ZEROKEY && event<=NINEKEY) {
1623                 return event - ZEROKEY + PAD0;
1624         } else if (event==MINUSKEY) {
1625                 return PADMINUS;
1626         } else if (event==EQUALKEY) {
1627                 return PADPLUSKEY;
1628         } else if (event==BACKSLASHKEY) {
1629                 return PADSLASHKEY;
1630         } else {
1631                 return event;
1632         }
1633 }
1634
1635 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
1636 {
1637         short qual= window_get_qual(win);
1638
1639         statechanged= 1;
1640
1641         if (U.flag&NONUMPAD) {
1642                 evt= convert_for_nonumpad(evt);
1643         }
1644         
1645                 /* enforce some guarentees about ascii values... these should
1646                  * be enforced in ghost probably - zr
1647                  */
1648
1649         if (!val || !isprint(ascii) || (qual&~LR_SHIFTKEY)) {
1650                 ascii= '\0';
1651         }
1652
1653         mainqenter_ext(evt, val, ascii);
1654 }
1655
1656 static bScreen *addscreen(char *name)           /* use setprefsize() if you want something else than a full windpw */
1657 {
1658         /* this function sets variabele G.curscreen,
1659          * that global is about used everywhere!
1660          */
1661         bScreen *sc;
1662         ScrVert *sv1, *sv2, *sv3, *sv4;
1663         short startx, starty, endx, endy;       
1664         
1665         sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
1666
1667         if (!prefsizx) {
1668                 prefstax= 0;
1669                 prefstay= 0;
1670                 
1671                 winlay_get_screensize(&prefsizx, &prefsizy);
1672         }
1673
1674         startx= prefstax;
1675         starty= prefstay;
1676         endx= prefstax+prefsizx-1;
1677         endy= prefstay+prefsizy-1;
1678
1679         sc->startx= startx;     sc->starty= starty;
1680         sc->endx= endx; sc->endy= endy;
1681         sc->sizex= sc->endx-sc->startx+1;
1682         sc->sizey= sc->endy-sc->starty+1;
1683         
1684         sc->scene= G.scene;
1685         
1686         if (!mainwin) {
1687 #ifdef _WIN32   // FULLSCREEN
1688                 if (G.windowstate == G_WINDOWSTATE_FULLSCREEN)
1689                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, G_WINDOWSTATE_FULLSCREEN);
1690                 else
1691                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
1692 #else
1693                 mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
1694 #endif
1695                 
1696                 if (!mainwin) {
1697                         printf("ERROR: Unable to open Blender window\n");
1698                         exit(1);
1699                 }
1700                 
1701                 window_set_handler(mainwin, add_to_mainqueue, NULL);
1702                 init_mainwin();
1703                 mywinset(1);
1704         
1705                 glMatrixMode(GL_PROJECTION);
1706                 glLoadIdentity();
1707                 myortho2(-0.5, sc->sizex-0.5, -0.5, sc->sizey-0.5);
1708                 glMatrixMode(GL_MODELVIEW);
1709                 glLoadIdentity();
1710
1711                 glDrawBuffer(GL_FRONT);
1712                 glClearColor(.45, .45, .45, 0.0);
1713                 glClear(GL_COLOR_BUFFER_BIT);
1714                 glDrawBuffer(GL_BACK);
1715                 
1716                 warp_pointer(sc->sizex/2,  sc->sizey/2);
1717                 
1718                 mainqenter(REDRAW, 1);
1719         }
1720
1721         sc->mainwin= 1;
1722         
1723         sv1= screen_addvert(sc, 0, 0);
1724         sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
1725         sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
1726         sv4= screen_addvert(sc, sc->sizex-1, 0);
1727         
1728         screen_addedge(sc, sv1, sv2);
1729         screen_addedge(sc, sv2, sv3);
1730         screen_addedge(sc, sv3, sv4);
1731         screen_addedge(sc, sv4, sv1);
1732
1733         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
1734         
1735         G.curscreen= sc;
1736
1737         return sc;
1738 }
1739
1740 void setscreen(bScreen *sc)
1741 {
1742         bScreen *sc1;
1743         ScrArea *sa;
1744         short mval[2];
1745         
1746         if(sc->full) {                          /* find associated full */
1747                 sc1= G.main->screen.first;
1748                 while(sc1) {
1749                         sa= sc1->areabase.first;
1750                         if(sa->full==sc) {
1751                                 sc= sc1;
1752                                 break;
1753                         }
1754                         sc1= sc1->id.next;
1755                 }
1756                 if(sc1==0) printf("setscreen error\n");
1757         }
1758
1759         /* de-activate G.curscreen */
1760         if (G.curscreen && G.curscreen != sc) {
1761                 sa= G.curscreen->areabase.first;
1762                 while(sa) {
1763                         if(sa->win) mywinclose(sa->win);
1764                         sa->win= 0;
1765                         if(sa->headwin) mywinclose(sa->headwin);
1766                         sa->headwin= 0;
1767                         
1768                         uiFreeBlocks(&sa->uiblocks);
1769                         
1770                         sa= sa->next;
1771                 }               
1772         }
1773
1774         if (G.curscreen != sc) {
1775                 mywinset(sc->mainwin);
1776         }
1777         
1778         G.curscreen= sc;
1779
1780         for (sa= sc->areabase.first; sa; sa= sa->next) {
1781                         /* XXX, fixme zr */
1782 /*              if (sa->win || sa->headwin) */
1783 /*                      printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
1784                 if (!sa->win)
1785                         openareawin(sa);
1786                 if (!sa->headwin && sa->headertype)
1787                         openheadwin(sa);
1788         }
1789
1790         /* recalculate winakt */
1791         getmouseco_sc(mval);
1792
1793         test_scale_screen(sc);
1794         testareas();
1795         
1796         for (sa= sc->areabase.first; sa; sa= sa->next) {
1797                 SpaceLink *sl;
1798
1799                 for (sl= sa->spacedata.first; sl; sl= sl->next) {
1800                         sl->area= sa;
1801
1802                         if (sl->spacetype==SPACE_OOPS) {
1803                                 SpaceOops *soops= (SpaceOops*) sl;
1804
1805                                 /* patch for old files */
1806                                 if (soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
1807                                         extern void init_v2d_oops(View2D*);
1808                                         init_v2d_oops(&soops->v2d);
1809                                 }
1810                         }
1811                 }
1812                 
1813                 sa->cursor= CURSOR_STD;
1814         }
1815
1816         G.scene= sc->scene;
1817         countall();
1818         
1819         G.curscreen->winakt= 0;
1820         curarea= sc->areabase.first;
1821         
1822         mainqenter(DRAWEDGES, 1);
1823         dodrawscreen= 1;                /* patch! even gets lost,,,? */
1824
1825         winqueue_break= 1;              /* means leave queue everywhere */
1826 }
1827
1828 static void splitarea(ScrArea *sa, char dir, float fac);
1829
1830 void area_fullscreen(void)      /* with curarea */
1831 {
1832         /* this function toggles: if area is full then the parent will be restored */
1833         bScreen *sc, *oldscreen;
1834         ScrArea *newa, *old;
1835         short headertype, fulltype;
1836         
1837         if(curarea->full) {
1838                 sc= curarea->full;      /* the old screen */
1839                 fulltype = sc->full;
1840
1841                 // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
1842                 // is set
1843
1844                 if (fulltype != SCREENAUTOPLAY || (G.flags & G_FLAGS_AUTOPLAY) == 0) {
1845                         sc->full= 0;
1846                 
1847                         /* find old area */
1848                         old= sc->areabase.first;
1849                         while(old) {
1850                                 if(old->full) break;
1851                                 old= old->next;
1852                         }
1853                         if(old==0) {error("something wrong in areafullscreen"); return;}
1854                 
1855                         if (fulltype == SCREENAUTOPLAY) {
1856                                 // in autoplay screens the headers are disabled by 
1857                                 // default. So use the old headertype instead
1858                                 headertype = old->headertype;
1859                         } else {
1860                                 // normal fullscreen. Use current headertype
1861                                 headertype = curarea->headertype;
1862                         }
1863
1864                         copy_areadata(old, curarea);
1865                         old->headertype = headertype;
1866
1867                         old->full= 0;
1868                 
1869                         unlink_screen(G.curscreen);
1870                         free_libblock(&G.main->screen, G.curscreen);
1871                         G.curscreen= NULL;
1872
1873                         setscreen(sc);
1874                 }
1875                 
1876         }
1877         else {
1878                 /* is there only 1 area? */
1879                 if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
1880                 if(curarea->spacetype==SPACE_INFO) return;
1881                 
1882                 G.curscreen->full = SCREENFULL;
1883                 
1884                 old= curarea;           
1885                 oldscreen= G.curscreen;
1886                 sc= addscreen("temp");          /* this sets G.curscreen */
1887
1888                 splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
1889                 newa= sc->areabase.first;
1890                 newspace(newa->next, SPACE_INFO);
1891                 
1892                 curarea= old;
1893                 G.curscreen= oldscreen; /* needed because of setscreen */
1894                 
1895                 /* vopy area */
1896                 copy_areadata(newa, curarea);
1897                 
1898                 curarea->full= oldscreen;
1899                 newa->full= oldscreen;
1900                 newa->next->full= oldscreen;
1901                 
1902                 setscreen(sc);
1903                 wich_cursor(newa);
1904         }
1905 }
1906
1907 static void area_autoplayscreen(void)
1908 {
1909         bScreen *sc, *oldscreen;
1910         ScrArea *newa, *old, *sa;
1911         
1912         if (curarea->full) {
1913                 area_fullscreen();
1914         }
1915
1916         if (curarea->full == NULL) { 
1917                 sa = G.curscreen->areabase.first;
1918                 while (sa) {
1919                         if (sa->spacetype == SPACE_VIEW3D) {
1920                                 break;
1921                         }
1922                         sa= sa->next;
1923                 }
1924
1925                 if (sa) {
1926                         areawinset(sa->win);
1927                         G.curscreen->full = SCREENAUTOPLAY;
1928                         
1929                         old= curarea;           
1930                         oldscreen= G.curscreen;
1931                         sc= addscreen("temp");          /* this sets G.curscreen */
1932         
1933                         newa= sc->areabase.first;
1934                         
1935                         curarea= old;
1936                         G.curscreen= oldscreen; /* because of setscreen */
1937                         
1938                         /* copy area settings */
1939                         copy_areadata(newa, curarea);
1940                         newa->headertype= 0;
1941                         
1942                         curarea->full= oldscreen;
1943                         newa->full= oldscreen;
1944         
1945                         setscreen(sc);
1946                         wich_cursor(newa);
1947                 }
1948         }
1949 }
1950
1951 static void copy_screen(bScreen *to, bScreen *from)
1952 {
1953         ScrVert *s1, *s2;
1954         ScrEdge *se;
1955         ScrArea *sa;
1956         ListBase lbase;
1957
1958         /* free 'to' */
1959         free_screen(to);
1960         winqueue_break= 1;      /* leave queues everywhere */
1961         
1962         duplicatelist(&to->vertbase, &from->vertbase);
1963         duplicatelist(&to->edgebase, &from->edgebase);
1964         duplicatelist(&to->areabase, &from->areabase);
1965         
1966         s1= from->vertbase.first;
1967         s2= to->vertbase.first;
1968         while(s1) {
1969                 s1->newv= s2;
1970                 s2= s2->next;
1971                 s1= s1->next;
1972         }
1973         se= to->edgebase.first;
1974         while(se) {
1975                 se->v1= se->v1->newv;
1976                 se->v2= se->v2->newv;
1977                 sortscrvert(&(se->v1), &(se->v2));
1978                 se= se->next;
1979         }
1980
1981         sa= to->areabase.first;
1982         while(sa) {
1983                 sa->v1= sa->v1->newv;
1984                 sa->v2= sa->v2->newv;
1985                 sa->v3= sa->v3->newv;
1986                 sa->v4= sa->v4->newv;
1987                 sa->win= 0;
1988                 sa->headwin= 0;
1989                 
1990                 sa->uiblocks.first= sa->uiblocks.last= NULL;
1991                 
1992                 duplicatespacelist(sa, &lbase, &sa->spacedata);
1993                 sa->spacedata= lbase;
1994                 
1995                 sa= sa->next;
1996         }
1997         
1998         /* put at zero (needed?) */
1999         s1= from->vertbase.first;
2000         while(s1) {
2001                 s1->newv= 0;
2002                 s1= s1->next;
2003         }
2004 }
2005
2006 void duplicate_screen(void)
2007 {
2008         bScreen *sc, *oldscreen;
2009         
2010         if(G.curscreen->full != SCREENNORMAL) return;
2011         
2012         /* make new screen: */
2013
2014         oldscreen= G.curscreen;
2015         sc= addscreen(oldscreen->id.name+2);    /* this sets G.curscreen */
2016         copy_screen(sc, oldscreen);
2017
2018         G.curscreen= oldscreen;
2019         setscreen(sc);
2020
2021 }
2022
2023
2024 /* ************ END SCREEN MANAGEMENT ************** */
2025 /* ************  JOIN/SPLIT/MOVE ************** */
2026
2027 static void joinarea(ScrArea *sa, ScrEdge *onedge)
2028 {
2029         ScrArea *sa2;
2030         ScrArea *up=0, *down=0, *right=0, *left=0;
2031         ScrEdge *setest;
2032         short val=0;
2033         
2034         sa= test_edge_area(sa, onedge);
2035         if (sa==0) return;
2036
2037         /* which edges? */
2038         /* find directions with same edge */
2039         sa2= G.curscreen->areabase.first;
2040         while(sa2) {
2041                 if(sa2 != sa) {
2042                         setest= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
2043                         if(onedge==setest) right= sa2;
2044                         setest= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
2045                         if(onedge==setest) down= sa2;
2046                         setest= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
2047                         if(onedge==setest) left= sa2;
2048                         setest= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
2049                         if(onedge==setest) up= sa2;
2050                 }
2051                 sa2= sa2->next;
2052         }
2053         
2054         sa2= 0;
2055         setest= 0;
2056         
2057         if(left) val++;
2058         if(up) val++;
2059         if(right) val++;
2060         if(down) val++;
2061         
2062         if(val==0) return;
2063         else if(val==1) {
2064                 if(left) sa2= left;
2065                 else if(up) sa2= up;
2066                 else if(right) sa2= right;
2067                 else if(down) sa2= down;
2068         }
2069         
2070         
2071         if(sa2) {
2072                 /* new area is old sa */
2073                 if(sa2==left) {
2074                         sa->v1= sa2->v1;
2075                         sa->v2= sa2->v2;
2076                         screen_addedge(G.curscreen, sa->v2, sa->v3);
2077                         screen_addedge(G.curscreen, sa->v1, sa->v4);
2078                 }
2079                 else if(sa2==up) {
2080                         sa->v2= sa2->v2;
2081                         sa->v3= sa2->v3;
2082                         screen_addedge(G.curscreen, sa->v1, sa->v2);
2083                         screen_addedge(G.curscreen, sa->v3, sa->v4);
2084                 }
2085                 else if(sa2==right) {
2086                         sa->v3= sa2->v3;
2087                         sa->v4= sa2->v4;
2088                         screen_addedge(G.curscreen, sa->v2, sa->v3);
2089                         screen_addedge(G.curscreen, sa->v1, sa->v4);
2090                 }
2091                 else if(sa2==down) {
2092                         sa->v1= sa2->v1;
2093                         sa->v4= sa2->v4;
2094                         screen_addedge(G.curscreen, sa->v1, sa->v2);
2095                         screen_addedge(G.curscreen, sa->v3, sa->v4);
2096                 }
2097         
2098                 /* remove edge and area */
2099                 /* remlink(&G.curscreen->edgebase, setest); */
2100                 /* freeN(setest); */
2101                 del_area(sa2);
2102                 BLI_remlink(&G.curscreen->areabase, sa2);
2103                 MEM_freeN(sa2);
2104                 
2105                 removedouble_scredges();
2106                 removenotused_scredges();
2107                 removenotused_scrverts();       /* as last */
2108                 
2109                 testareas();
2110                 mainqenter(DRAWEDGES, 1);
2111                         /* test cursor en inputwindow */
2112                 mainqenter(MOUSEY, -1);         
2113         }
2114 }
2115
2116 static short testsplitpoint(ScrArea *sa, char dir, float fac)
2117 /* return 0: no split possible */
2118 /* else return (integer) screencoordinate split point */
2119 {
2120         short x, y;
2121         
2122         /* area big enough? */
2123         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
2124         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
2125
2126         /* to be sure */
2127         if(fac<0.0) fac= 0.0;
2128         if(fac>1.0) fac= 1.0;
2129         
2130         if(dir=='h') {
2131                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
2132                 
2133                 if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY+EDGEWIDTH2) 
2134                         y= sa->v2->vec.y- HEADERY-EDGEWIDTH2;
2135
2136                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY+EDGEWIDTH2)
2137                         y= sa->v1->vec.y+ HEADERY+EDGEWIDTH2;
2138
2139                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
2140                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
2141                 else y-= (y % AREAGRID);
2142
2143                 return y;
2144         }
2145         else {
2146                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
2147                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
2148                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
2149                 else x-= (x % AREAGRID);
2150
2151                 return x;
2152         }
2153 }
2154
2155 static void splitarea(ScrArea *sa, char dir, float fac)
2156 {
2157         bScreen *sc;
2158         ScrArea *newa;
2159         ScrVert *sv1, *sv2;
2160         short split;
2161         
2162         if(sa==0) return;
2163         
2164         split= testsplitpoint(sa, dir, fac);
2165         if(split==0) return;
2166         
2167         sc= G.curscreen;
2168         
2169         areawinset(sa->win);
2170         
2171         if(dir=='h') {
2172                 /* new vertices */
2173                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
2174                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
2175                 
2176                 /* new edges */
2177                 screen_addedge(sc, sa->v1, sv1);
2178                 screen_addedge(sc, sv1, sa->v2);
2179                 screen_addedge(sc, sa->v3, sv2);
2180                 screen_addedge(sc, sv2, sa->v4);
2181                 screen_addedge(sc, sv1, sv2);
2182                 
2183                 /* new areas: top */
2184                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
2185                 copy_areadata(newa, sa);
2186
2187                 /* area below */
2188                 sa->v2= sv1;
2189                 sa->v3= sv2;
2190                 
2191         }
2192         else {
2193                 /* new vertices */
2194                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
2195                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
2196                 
2197                 /* new edges */
2198                 screen_addedge(sc, sa->v1, sv1);
2199                 screen_addedge(sc, sv1, sa->v4);
2200                 screen_addedge(sc, sa->v2, sv2);
2201                 screen_addedge(sc, sv2, sa->v3);
2202                 screen_addedge(sc, sv1, sv2);
2203                 
2204                 /* new areas: left */
2205                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
2206                 copy_areadata(newa, sa);
2207
2208                 /* area right */
2209                 sa->v1= sv1;            
2210                 sa->v2= sv2;
2211         }
2212         
2213         /* remove double vertices en edges */
2214         removedouble_scrverts();
2215         removedouble_scredges();
2216         removenotused_scredges();
2217         
2218         mainqenter(DRAWEDGES, 1);
2219         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2220         testareas();
2221 }
2222
2223 static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
2224 {
2225         int split= testsplitpoint(sa, dir, fac);
2226
2227         if (split) {
2228                 if(dir=='h') {
2229                         glutil_draw_front_xor_line(sa->totrct.xmin, split, sa->totrct.xmax, split);
2230                         glutil_draw_front_xor_line(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
2231                 } else {
2232                         glutil_draw_front_xor_line(split, sa->totrct.ymin, split, sa->totrct.ymax);
2233                         glutil_draw_front_xor_line(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
2234                 }
2235         }
2236 }
2237
2238 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
2239 {
2240         ScrArea *sa= area;
2241         float fac;
2242         unsigned short event;
2243         short ok= 0, val, split = 0, mval[2], mvalo[2], first= 1;
2244         char dir;
2245         
2246         if(sa->win==0) return;
2247         if(sa->full) return;
2248
2249         dir= scredge_is_horizontal(onedge)?'v':'h';
2250         
2251         mywinset(G.curscreen->mainwin);
2252         /* should already have a good matrix */
2253
2254         /* keep track of grid and minsize */
2255         while(ok==0) {
2256                 getmouseco_sc(mval);
2257                 
2258                 if (first || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2259                         if (!first) {
2260                                 scrarea_draw_splitpoint(sa, dir, fac);
2261                         }
2262
2263                         if(dir=='h') {
2264                                 fac= mval[1]- (sa->v1->vec.y);
2265                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2266                         } else {
2267                                 fac= mval[0]- sa->v1->vec.x;
2268                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2269                         }
2270
2271                         split= testsplitpoint(sa, dir, fac);
2272                         if (split) {
2273                                 scrarea_draw_splitpoint(sa, dir, fac);
2274                         } else {
2275                                 ok= -1;
2276                         }
2277
2278                         mvalo[0]= mval[0];
2279                         mvalo[1]= mval[1];
2280                         first= 0;                       
2281                 }
2282                 
2283                 event= extern_qread(&val);
2284                 if(val && event==LEFTMOUSE) {
2285                         if(dir=='h') {
2286                                 fac= split- (sa->v1->vec.y);
2287                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2288                         }
2289                         else {
2290                                 fac= split- sa->v1->vec.x;
2291                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2292                         }
2293                         ok= 1;
2294                 }
2295                 if(val && event==ESCKEY) {
2296                         ok= -1;
2297                 }
2298         }
2299
2300         if (!first) {
2301                 scrarea_draw_splitpoint(sa, dir, fac);
2302         }
2303
2304         if(ok==1) {
2305                 splitarea(sa, dir, fac);
2306                 mainqenter(DRAWEDGES, 1);
2307                 dodrawscreen= 1;                /* patch! event gets lost,,,? */
2308         }
2309 }
2310
2311 View3D *find_biggest_view3d(void)
2312 {
2313         ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
2314         
2315         if (sa) {
2316                 return (View3D*) sa->spacedata.first;
2317         } else {
2318                 return NULL;
2319         }
2320 }
2321
2322 ScrArea *find_biggest_area_of_type(int spacecode)
2323 {
2324         ScrArea *sa, *biggest= NULL;
2325         int bigsize;
2326         
2327         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2328                 if (spacecode==0 || sa->spacetype==spacecode) {
2329                         int x= sa->v3->vec.x - sa->v1->vec.x;
2330                         int y= sa->v3->vec.y - sa->v1->vec.y;
2331                         int size= x*x + y*y;
2332                 
2333                         if (!biggest || size>bigsize) {
2334                                 biggest= sa;
2335                                 bigsize= size;
2336                         }
2337                 }
2338         }
2339         
2340         return biggest;
2341 }
2342
2343 ScrArea *find_biggest_area(void)
2344 {
2345         return find_biggest_area_of_type(0);
2346 }
2347
2348 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
2349 {
2350         ScrEdge *se;
2351         ScrVert *sv;
2352         int oneselected;
2353         char dir;
2354         
2355         /* select connected, only in the right direction */
2356         /* 'dir' is the direction of EDGE */
2357
2358         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
2359         else dir= 'h';
2360
2361         sv= sc->vertbase.first;
2362         while(sv) {
2363                 sv->flag= 0;
2364                 sv= sv->next;
2365         }
2366
2367         edge->v1->flag= 1;
2368         edge->v2->flag= 1;
2369
2370         oneselected= 1;
2371         while(oneselected) {
2372                 se= sc->edgebase.first;
2373                 oneselected= 0;
2374                 while(se) {
2375                         if(se->v1->flag + se->v2->flag==1) {
2376                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
2377                                         se->v1->flag= se->v2->flag= 1;
2378                                         oneselected= 1;
2379                                 }
2380                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
2381                                         se->v1->flag= se->v2->flag= 1;
2382                                         oneselected= 1;
2383                                 }
2384                         }
2385                         se= se->next;
2386                 }
2387         }
2388 }
2389
2390 void test_scale_screen(bScreen *sc)
2391 /* test if screen vertices should be scaled */
2392 /* also check offset */
2393 {
2394         ScrVert *sv=0;
2395         ScrEdge *se;
2396         ScrArea *sa, *san;
2397         int yval;
2398         float facx, facy, tempf, min[2], max[2];
2399
2400         sc->startx= prefstax;
2401         sc->starty= prefstay;
2402         sc->endx= prefstax+prefsizx-1;
2403         sc->endy= prefstay+prefsizy-1;
2404
2405         /* calculate size */
2406         sv= sc->vertbase.first;
2407         min[0]= min[1]= 0.0;
2408         max[0]= sc->sizex;
2409         max[1]= sc->sizey;
2410         while(sv) {
2411                 min[0]= MIN2(min[0], sv->vec.x);
2412                 min[1]= MIN2(min[1], sv->vec.y);
2413                 max[0]= MAX2(max[0], sv->vec.x);
2414                 max[1]= MAX2(max[1], sv->vec.y);
2415                 sv= sv->next;
2416         }
2417
2418         /* always make 0.0 left under */
2419         sv= sc->vertbase.first;
2420         while(sv) {
2421                 sv->vec.x -= min[0];
2422                 sv->vec.y -= min[1];
2423                 sv= sv->next;
2424         }
2425         
2426
2427         sc->sizex= max[0]-min[0];
2428         sc->sizey= max[1]-min[1];
2429
2430         if(sc->sizex!= prefsizx || sc->sizey!= prefsizy) {
2431                 facx= prefsizx;
2432                 facx/= (float)sc->sizex;
2433                 facy= prefsizy;
2434                 facy/= (float)sc->sizey;
2435
2436                 /* make sure it fits! */
2437                 sv= sc->vertbase.first;
2438                 while(sv) {
2439                         tempf= ((float)sv->vec.x)*facx;
2440                         sv->vec.x= (short)(tempf+0.5);
2441                         sv->vec.x+= AREAGRID-1;
2442                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
2443                         
2444                         CLAMP(sv->vec.x, 0, prefsizx);
2445
2446                         tempf= ((float)sv->vec.y )*facy;
2447                         sv->vec.y= (short)(tempf+0.5);
2448                         sv->vec.y+= AREAGRID-1;
2449                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
2450                         
2451                         CLAMP(sv->vec.y, 0, prefsizy);
2452
2453                         sv= sv->next;
2454                 }
2455                 
2456                 sc->sizex= prefsizx;
2457                 sc->sizey= prefsizy;
2458         }
2459
2460         /* test for collapsed areas. This could happen in some blender version... */
2461         sa= sc->areabase.first;
2462         while(sa) {
2463                 san= sa->next;
2464                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
2465                         del_area(sa);
2466                         BLI_remlink(&sc->areabase, sa);
2467                         MEM_freeN(sa);
2468                 }
2469                 sa= san;
2470         }
2471
2472         /* make each window at least HEADERY high */
2473
2474         sa= sc->areabase.first;
2475         while(sa) {
2476
2477                 if(sa->v1->vec.y+HEADERY > sa->v2->vec.y) {
2478                         /* lower edge */
2479                         se= screen_findedge(sc, sa->v4, sa->v1);
2480                         if(se && sa->v1!=sa->v2 ) {
2481                                 select_connected_scredge(sc, se);
2482                                 
2483                                 /* all selected vertices get the right offset */
2484                                 yval= sa->v2->vec.y-HEADERY;
2485                                 sv= sc->vertbase.first;
2486                                 while(sv) {
2487                                         /* if is a collapsed area */
2488                                         if(sv!=sa->v2 && sv!=sa->v3) {
2489                                                 if(sv->flag) sv->vec.y= yval;
2490                                         }
2491                                         sv= sv->next;
2492                                 }
2493                         }
2494                 }
2495
2496                 sa= sa->next;
2497         }
2498
2499 }
2500
2501 static void draw_front_xor_dirdist_line(char dir, int dist, int start, int end)
2502 {
2503         if (dir=='h') {
2504                 glutil_draw_front_xor_line(start, dist, end, dist);
2505                 glutil_draw_front_xor_line(start, dist+1, end, dist+1);
2506         } else {
2507                 glutil_draw_front_xor_line(dist, start, dist, end);
2508                 glutil_draw_front_xor_line(dist+1, start, dist+1, end);
2509         }
2510 }
2511
2512 static void moveareas(ScrEdge *edge)
2513 {
2514         ScrVert *v1;
2515         ScrArea *sa;
2516         short mvalo[2];
2517         short edge_start, edge_end, edge_position;
2518         short bigger, smaller, headery, areaminy;
2519         int delta, doit;
2520         char dir;
2521         
2522         if(edge->border) return;
2523
2524         dir= scredge_is_horizontal(edge)?'h':'v';
2525         
2526         select_connected_scredge(G.curscreen, edge);
2527
2528         edge_position= (dir=='h')?edge->v1->vec.y:edge->v1->vec.x;
2529         edge_start= 10000;
2530         edge_end= -10000;
2531         for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
2532                 if (v1->flag) {
2533                         if (dir=='h') {
2534                                 edge_start= MIN2(edge_start, v1->vec.x);
2535                                 edge_end= MAX2(edge_end, v1->vec.x);
2536                         } else {
2537                                 edge_start= MIN2(edge_start, v1->vec.y);
2538                                 edge_end= MAX2(edge_end, v1->vec.y);
2539                         }
2540                 }
2541         }
2542
2543         /* now all verices with 'flag==1' are the ones that can be moved. */
2544         /* we check all areas and test for free space with MINSIZE */
2545         bigger= smaller= 10000;
2546         sa= G.curscreen->areabase.first;
2547         while(sa) {
2548                 if(dir=='h') {  /* if top or down edge selected, test height */
2549                         if(sa->headertype) {
2550                                 headery= HEADERY;
2551                                 areaminy= AREAMINY;
2552                         }
2553                         else {
2554                                 headery= 0;
2555                                 areaminy= EDGEWIDTH;
2556                         }
2557
2558                         if(sa->v1->flag && sa->v4->flag) {
2559                                 int y1;
2560                                 if(sa->v2->vec.y==G.curscreen->sizey-1) /* top 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                                 bigger= MIN2(bigger, y1);
2565                         }
2566                         else if(sa->v2->flag && sa->v3->flag) {
2567                                 int y1;
2568                                 if(sa->v1->vec.y==0)    /* bottom edge */
2569                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
2570                                 else
2571                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
2572                                 smaller= MIN2(smaller, y1);
2573                         }
2574                 }
2575                 else {  /* if left or right edge selected, test width */
2576                         if(sa->v1->flag && sa->v2->flag) {
2577                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
2578                                 bigger= MIN2(bigger, x1);
2579                         }
2580                         else if(sa->v3->flag && sa->v4->flag) {
2581                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
2582                                 smaller= MIN2(smaller, x1);
2583                         }
2584                 }
2585                 sa= sa->next;
2586         }
2587         
2588         mywinset(G.curscreen->mainwin);
2589
2590         doit= delta= 0;
2591         getmouseco_sc(mvalo);
2592         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2593         while (!doit) {
2594                 short val;
2595                 unsigned short event= extern_qread(&val);
2596                 
2597                 if (event==MOUSEY) {
2598                         short mval[2];
2599                         
2600                         getmouseco_sc(mval);
2601                         
2602                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2603
2604                         delta= (dir=='h')?(mval[1]-mvalo[1]):(mval[0]-mvalo[0]);
2605                         delta= CLAMPIS(delta, -smaller, bigger);
2606                         
2607                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2608                 } else if (event==LEFTMOUSE) {
2609                         doit= 1;
2610                 } else if (val) {
2611                         if (ELEM(event, ESCKEY, RIGHTMOUSE))
2612                                 doit= -1;
2613                         else if (ELEM(event, SPACEKEY, RETKEY))
2614                                 doit= 1;
2615                 }
2616         }
2617         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
2618
2619         if (doit==1) {
2620                 for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
2621                         if (v1->flag) {
2622                                         /* that way a nice AREAGRID  */
2623                                 if((dir=='v') && v1->vec.x>0 && v1->vec.x<G.curscreen->sizex-1) {
2624                                         v1->vec.x+= delta;
2625                                         if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
2626                                 }
2627                                 if((dir=='h') && v1->vec.y>0 && v1->vec.y<G.curscreen->sizey-1) {
2628                                         v1->vec.y+= delta;
2629                                         
2630                                         /* with these lines commented out you can pull the top bar exact to the screen border. */
2631                                         /* if(delta != bigger && delta != -smaller) { */
2632                                                 v1->vec.y+= AREAGRID-1;
2633                                                 v1->vec.y-= (v1->vec.y % AREAGRID);
2634                                         
2635                                         /* } */
2636                                 }
2637                         }
2638                         v1->flag= 0;
2639                 }
2640                 
2641                 removedouble_scrverts();
2642                 removedouble_scredges();
2643                 testareas();
2644         }
2645         
2646         glDrawBuffer(GL_BACK);
2647         mainqenter(DRAWEDGES, 1);
2648         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2649 }
2650
2651 static void scrollheader(ScrArea *area)
2652 {
2653         short mval[2], mvalo[2];
2654         
2655         if(area->headbutlen<area->winx) {
2656                 area->headbutofs= 0;
2657         }
2658         else if(area->headbutofs+area->winx > area->headbutlen) {
2659                 area->headbutofs= area->headbutlen-area->winx;
2660         }
2661
2662         getmouseco_sc(mvalo);
2663
2664         while(get_mbut() & M_MOUSE) {
2665                 getmouseco_sc(mval);
2666                 if(mval[0]!=mvalo[0]) {
2667                         area->headbutofs-= (mval[0]-mvalo[0]);
2668
2669                         if(area->headbutlen-area->winx < area->headbutofs) area->headbutofs= area->headbutlen-area->winx;
2670                         if(area->headbutofs<0) area->headbutofs= 0;
2671
2672                         scrarea_do_headchange(area);
2673                         scrarea_do_headdraw(area);
2674
2675                         screen_swapbuffers();
2676                         
2677                         mvalo[0]= mval[0];
2678                 } else {
2679                         BIF_wait_for_statechange();
2680                 }
2681         }
2682 }
2683
2684 int select_area(int spacetype)
2685 {
2686         /* call from edit routines, when there are more areas
2687          * of type 'spacetype', you can indicate an area manually
2688          */
2689         ScrArea *sa, *sact = NULL;
2690         int tot=0;
2691         unsigned short event = 0;
2692         short val, mval[2];
2693         
2694         sa= G.curscreen->areabase.first;
2695         while(sa) {
2696                 if(sa->spacetype==spacetype) {
2697                         sact= sa;
2698                         tot++;
2699                 }
2700                 sa= sa->next;
2701         } 
2702         
2703         if(tot==0) {
2704                 error("Can't do this! Open correct window");
2705                 return 0;
2706         }
2707         
2708         if(tot==1) {
2709                 if(curarea!=sact) areawinset(sact->win);
2710                 return 1;
2711         }
2712         else if(tot>1) {
2713                 set_cursor(CURSOR_HELP);
2714                 while(1) {
2715                         event= extern_qread(&val);
2716                         
2717                         if (val) {
2718                                 if(event==ESCKEY) break;
2719                                 if(event==LEFTMOUSE) break;
2720                                 if(event==SPACEKEY) break;
2721                         } else {
2722                                 BIF_wait_for_statechange();
2723                         }
2724                 }
2725                 screen_set_cursor(G.curscreen);
2726                 
2727                 /* recalculate winakt */
2728                 getmouseco_sc(mval);
2729                 
2730                 if(event==LEFTMOUSE) {
2731                         ScrArea *sa= screen_find_area_for_pt(G.curscreen, mval);
2732                         
2733                         if (sa &&sa->spacetype==spacetype) {
2734                                 G.curscreen->winakt= sa->win;
2735                                 areawinset(G.curscreen->winakt);
2736                         } else {
2737                                 error("wrong window");
2738                                 return 0;
2739                         }
2740                 }
2741         }
2742         
2743         if(event==LEFTMOUSE) return 1;
2744         else return 0;
2745 }
2746
2747 /* ************  END JOIN/SPLIT/MOVE ************** */
2748 /* **************** DRAW SCREENEDGES ***************** */
2749
2750 #define EDGE_EXTEND 3
2751
2752 void drawedge(short x1, short y1, short x2, short y2)
2753 {
2754         static unsigned int edcol[EDGEWIDTH]= {0x0, 0x505050, 0x909090, 0xF0F0F0, 0x0};
2755         int a;
2756         
2757         if(x1==x2) {            /* vertical */
2758                 if (y2<y1)
2759                         y1^= y2^= y1^= y2;
2760                 
2761                 if (y1==0) y1-= EDGE_EXTEND;
2762                 if (y2==G.curscreen->sizey) y2+= EDGE_EXTEND;
2763                 
2764                 x1+= EDGEWIDTH2;
2765                 x2+= EDGEWIDTH2;
2766
2767                 glBegin(GL_LINES);              
2768                 for(a=0; a<EDGEWIDTH; a++) {
2769                         int rounding= abs(a-EDGEWIDTH2);
2770                         
2771                         cpack(edcol[a]);
2772                         glVertex2i(x1-a, y1+rounding);
2773                         glVertex2i(x2-a, y2-rounding);
2774                 }
2775                 glEnd();
2776         }
2777         else {                          /* horizontal */
2778                 if (x2<x1)
2779                         x1^= x2^= x1^= x2;
2780                 
2781                 if (x1==0) x1-= EDGE_EXTEND;
2782                 if (x2==G.curscreen->sizex) x2+= EDGE_EXTEND;
2783
2784                 y1-= EDGEWIDTH2;
2785                 y2-= EDGEWIDTH2;
2786                 
2787                 glBegin(GL_LINES);
2788                 for(a=0; a<EDGEWIDTH; a++) {
2789                         int rounding= abs(a-EDGEWIDTH2);
2790                         
2791                         cpack(edcol[a]);
2792                         glVertex2i(x1+rounding, y1+a);
2793                         glVertex2i(x2-rounding, y2+a);
2794                 }
2795                 glEnd();
2796         }
2797 }
2798
2799 static void drawscredge(ScrEdge *se)
2800 {
2801         bScreen *sc;
2802         vec2s *v1, *v2;
2803         
2804         sc= G.curscreen;
2805         
2806         v1= &(se->v1->vec);
2807         v2= &(se->v2->vec);
2808         
2809         /* do not draw borders screen© */
2810         /* bcause of different framebuffer resoltions (PC/SGI etc files) 
2811          * a bit rounding here? should be looked at further...
2812          */
2813         se->border= 1;
2814         if(v1->x<=1 && v2->x<=1) return;
2815         if(v1->x>=sc->sizex-2 && v2->x>=sc->sizex-2) return;
2816         if(v1->y<=1 && v2->y<=1) return;
2817         if(v1->y>=sc->sizey-2 && v2->y>=sc->sizey-2) return;
2818         se->border= 0;
2819
2820         drawedge(v1->x, v1->y, v2->x, v2->y);
2821 }
2822
2823 void drawscreen(void)
2824 {
2825         ScrEdge *se;
2826         
2827         mywinset(G.curscreen->mainwin);
2828         myortho2(-0.5, (float)G.curscreen->sizex-0.5, -0.6, (float)G.curscreen->sizey-0.6);
2829
2830         /* two times, because there is no 'win_swap' for this  available */
2831         glDrawBuffer(GL_FRONT);
2832         se= G.curscreen->edgebase.first;
2833         while(se) {
2834                 drawscredge(se);
2835                 se= se->next;
2836         }
2837
2838         glDrawBuffer(GL_BACK);
2839         se= G.curscreen->edgebase.first;
2840         while(se) {
2841                 drawscredge(se);
2842                 se= se->next;
2843         }
2844 }
2845
2846 /* ********************************* */
2847
2848 bScreen *default_twosplit() 
2849 {
2850         bScreen *sc= addscreen("screen");
2851         ScrArea *sa;
2852
2853         splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
2854         sa= sc->areabase.first;
2855         newspace(sa, SPACE_VIEW3D);
2856         newspace(sa->next, SPACE_INFO);
2857         
2858         return sc;
2859 }
2860
2861 void initscreen(void)
2862 {
2863         default_twosplit();
2864 }
2865
2866 /***/
2867
2868 void screen_draw_info_text(bScreen *sc, char *text) {
2869         Window *oldactwin= winlay_get_active_window();
2870         ScrArea *sa;
2871         
2872                 /*
2873                  * Because this is called from within rendering
2874                  * internals it is possible our window is not
2875                  * active.
2876                  */
2877         window_make_active(mainwin);
2878         
2879         for (sa= sc->areabase.first; sa; sa= sa->next) {
2880                 if (sa->spacetype==SPACE_INFO) {
2881                         int x= sa->headbutlen - 28;
2882                         int y= 6;
2883                         
2884                         areawinset(sa->headwin);
2885                         glDrawBuffer(GL_FRONT);
2886
2887                         cpack(0xA08060);
2888                         glRecti(x-11,  y-6,  x+55,  y+13);
2889                         
2890                         cpack(0x909090);
2891                         glRecti(x+55,  y-6,  x+1280,  y+14);
2892                         
2893                         cpack(0x0);
2894                         glRasterPos2i(x,  y);
2895                         BMF_DrawString(G.fonts, text);
2896                         
2897                         glFinish();
2898                         glDrawBuffer(GL_BACK);
2899                         
2900                         sa->head_swap= WIN_FRONT_OK;
2901                 }
2902         }
2903         
2904         if (oldactwin && oldactwin!=mainwin) window_make_active(oldactwin);
2905 }
2906
2907 static int curcursor;
2908
2909 int get_cursor(void) {
2910         return curcursor;
2911 }
2912
2913 void set_cursor(int curs) {
2914         if (!(R.flag & R_RENDERING)) {
2915                 if (curs!=curcursor) {
2916                         curcursor= curs;
2917                         window_set_cursor(mainwin, curs);
2918                 }
2919         }
2920 }
2921
2922 void unlink_screen(bScreen *sc) {
2923         ScrArea *sa;
2924         
2925         for (sa= sc->areabase.first; sa; sa= sa->next)  
2926                 del_area(sa);
2927 }
2928
2929 void warp_pointer(int x, int y)
2930 {
2931         window_warp_pointer(mainwin, x, y);
2932 }
2933
2934 void set_timecursor(int nr)
2935 {
2936                 /* 10 8x8 digits */
2937         static char number_bitmaps[10][8]= {
2938                 {0,  56,  68,  68,  68,  68,  68,  56}, 
2939                 {0,  24,  16,  16,  16,  16,  16,  56}, 
2940                 {0,  60,  66,  32,  16,   8,   4, 126}, 
2941                 {0, 124,  32,  16,  56,  64,  66,  60}, 
2942                 {0,  32,  48,  40,  36, 126,  32,  32}, 
2943                 {0, 124,   4,  60,  64,  64,  68,  56}, 
2944                 {0,  56,   4,   4,  60,  68,  68,  56}, 
2945                 {0, 124,  64,  32,  16,   8,   8,   8}, 
2946                 {0,  60,  66,  66,  60,  66,  66,  60}, 
2947                 {0,  56,  68,  68, 120,  64,  68,  56} 
2948         };
2949         unsigned char mask[16][2];
2950         unsigned char bitmap[16][2];
2951         int i, idx;
2952
2953         memset(&bitmap, 0x00, sizeof(bitmap));
2954         memset(&mask, 0xFF, sizeof(mask));
2955         
2956                 /* print number bottom right justified */
2957         for (idx= 3; nr && idx>=0; idx--) {
2958                 char *digit= number_bitmaps[nr%10];
2959                 int x = idx%2;
2960                 int y = idx/2;
2961                 
2962                 for (i=0; i<8; i++)
2963                         bitmap[i + y*8][x]= digit[i];
2964                 nr/= 10;
2965         }
2966
2967         curcursor= CURSOR_NONE;
2968         window_set_custom_cursor(mainwin, mask, bitmap);
2969         BIF_renderwin_set_custom_cursor(mask, bitmap);
2970 }
2971