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