* Added additional shift space to fullscreen/tile window spaces. So much
[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_interactive(ScrArea *area, 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_interactive(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 drawscreen(void)
1104 {
1105         ScrArea *sa;
1106         
1107         mywinset(G.curscreen->mainwin);
1108         myortho2(-0.375, (float)G.curscreen->sizex-0.375, -0.375, (float)G.curscreen->sizey-0.375);
1109         
1110         sa= G.curscreen->areabase.first;
1111         while(sa) {
1112                 drawscredge_area(sa);
1113                 sa= sa->next;
1114         }
1115         
1116         /* this double draw patch seems to be needed for certain sgi's (octane, indigo2) */
1117 #if defined(__sgi) || defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
1118         glDrawBuffer(GL_FRONT);
1119         
1120         sa= G.curscreen->areabase.first;
1121         while(sa) {
1122                 drawscredge_area(sa);
1123                 sa= sa->next;
1124         }
1125         
1126         glDrawBuffer(GL_BACK);
1127 #endif
1128 }
1129
1130 static void screen_dispatch_events(void) {
1131         int events_remaining= 1;
1132         ScrArea *sa;
1133
1134         window_make_active(mainwin); // added it here instead of screenmain (ton)
1135
1136         while (events_remaining) {
1137                 events_remaining= 0;
1138                                 
1139                 winqueue_break= 0;
1140                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1141                                 /* first check header, then rest. Header sometimes has initialization code */
1142                         if (sa->headwin && bwin_qtest(sa->headwin)) {
1143                                 scrarea_dispatch_header_events(sa);
1144                                 events_remaining= 1;
1145                         }
1146                         if (winqueue_break) break;
1147
1148                         if (bwin_qtest(sa->win)) {
1149                                 scrarea_dispatch_events(sa);
1150                                 events_remaining= 1;
1151                         }
1152                         if (winqueue_break) break;
1153                 }
1154
1155                 if (winqueue_break) break;
1156         }
1157
1158         if (dodrawscreen) {
1159                 drawscreen();
1160                 dodrawscreen= 0;
1161         }
1162         
1163         screen_swapbuffers();
1164         do_screenhandlers(G.curscreen);
1165 }
1166
1167 static ScrArea *screen_find_area_for_pt(bScreen *sc, short *mval) 
1168 {
1169         ScrArea *sa;
1170         
1171         /* hotspot area of 1 pixel extra */
1172         
1173         for (sa= sc->areabase.first; sa; sa= sa->next) {
1174                 if( sa->totrct.xmin + 1 < mval[0] )
1175                         if( sa->totrct.ymin + 1 < mval[1] )
1176                                 if( sa->totrct.xmax - 1 > mval[0] )
1177                                         if( sa->totrct.ymax - 1 > mval[1] )
1178                                                 return sa;
1179         }
1180         return NULL;
1181 }
1182
1183 /* ugly yah, will disappear on better event system */
1184 /* is called from interface.c after button events */
1185 static char delayed_undo_name[64];
1186 void screen_delayed_undo_push(char *name)
1187 {
1188         strncpy(delayed_undo_name, name, 63);
1189         mainqenter(UNDOPUSH, 1);
1190 }
1191
1192 void screenmain(void)
1193 {
1194         int has_input= 1;
1195         int firsttime = 1;
1196         int onload_script = 0;
1197
1198         window_make_active(mainwin);
1199         
1200         while (1) {
1201                 unsigned short event;
1202                 short val, towin;
1203                 char ascii;
1204
1205                 flush_extqd_events();
1206                 if (nafterqitems && !qtest()) {
1207                         append_afterqueue();
1208                         event= val= ascii= 0;
1209                 } else {
1210                         event= screen_qread(&val, &ascii);
1211                 }
1212                 
1213                 // window_make_active(mainwin); // (only for inputchange, removed, (ton))
1214
1215                 if (event==INPUTCHANGE) {
1216                         window_make_active(mainwin);
1217                         G.qual= get_qual();
1218                 }
1219                 
1220                         /* If the main window is active, find the current active ScrArea
1221                          * underneath the mouse cursor, updating the headers & cursor for
1222                          * the appropriate internal window if things have changed.
1223                          * 
1224                          * If the main window is not active, deactivate the internal 
1225                          * window.
1226                          */
1227                 if (has_input || g_activearea==NULL || G.curscreen->winakt) {
1228                         ScrArea *newactarea;
1229                         int newactwin;
1230                         short mval[2];
1231
1232                         getmouseco_sc(mval);
1233                         newactarea= screen_find_area_for_pt(G.curscreen, mval);                 
1234
1235                         if (newactarea) {
1236                                 if (BLI_in_rcti(&newactarea->headrct, mval[0], mval[1])) {
1237                                         newactwin= newactarea->headwin;
1238                                 } else {
1239                                         newactwin= newactarea->win;
1240                                 }
1241                         } else {
1242                                 newactwin= 0;
1243                         }
1244
1245                         if (newactarea && (newactarea != g_activearea)) {
1246                                 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1247                                 scrarea_queue_headredraw(newactarea);
1248                                 set_cursor(newactarea->cursor);
1249                                 g_activearea= newactarea;
1250                         }
1251                         /* when you move mouse from header to window, buttons can remain hilited otherwise */
1252                         if(newactwin != G.curscreen->winakt) {
1253                                 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1254                         }
1255                         G.curscreen->winakt= newactwin;
1256                         
1257                         if (G.curscreen->winakt) {
1258                                 areawinset(G.curscreen->winakt);
1259                                 set_cursor(choose_cursor(g_activearea));
1260                         }
1261                 } 
1262                 else {
1263                         if (g_activearea) {
1264                                 scrarea_queue_headredraw(g_activearea);
1265                         }
1266                         g_activearea= NULL;
1267                         G.curscreen->winakt= 0;
1268                 }
1269
1270                 towin= 0;
1271                 if (event==WINCLOSE) {
1272                         exit_usiblender();
1273                 } 
1274                 else if (event==DRAWEDGES) {
1275                         dodrawscreen= 1;
1276                 }
1277                 else if (event==RESHAPE) {
1278                         init_mainwin();
1279                         markdirty_all();
1280                         dodrawscreen= 1;
1281                 }
1282                 else if (event==REDRAW) {
1283                         markdirty_all();
1284                         dodrawscreen= 1;
1285                 }
1286                 else if( event==UNDOPUSH) {
1287                         BIF_undo_push(delayed_undo_name);
1288                 }
1289                 else if (event==AUTOSAVE_FILE) {
1290                         BIF_write_autosave();
1291                 }
1292                 else if (event==LOAD_FILE) {
1293                         BIF_read_file(ext_load_str);
1294                         sound_initialize_sounds();
1295                 }
1296                 else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) {
1297                         /* event queued in setup_app_data() in blender.c, where G.f is checked */
1298                         onload_script = 1;
1299                         firsttime = 1; /* see last 'if' in this function */
1300                 }
1301                 else {
1302                         towin= 1;
1303                 }
1304
1305                 if (!g_activearea) {
1306                         towin= 0;
1307                 }
1308                 else if (event==QKEY) {
1309                         if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
1310                         else {
1311                                 if(val) {
1312                                         if(okee("Quit Blender")) exit_usiblender();
1313                                 }
1314                                 towin= 0;
1315                         }
1316                 }
1317                 else if(ELEM(event, LEFTARROWKEY, RIGHTARROWKEY)) {
1318                         if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
1319                                 bScreen *sc= (event==LEFTARROWKEY)?G.curscreen->id.prev:G.curscreen->id.next;
1320                                 if(is_allowed_to_change_screen(sc)) setscreen(sc);
1321                                 g_activearea= NULL;
1322                                 towin= 0;
1323                         }
1324                 }
1325                 else if (!G.curscreen->winakt) {
1326                         ScrEdge *actedge;
1327                         short mval[2];
1328
1329                         getmouseco_sc(mval);
1330                         actedge= screen_find_active_scredge(G.curscreen, mval);
1331
1332                         if (actedge) {
1333                                 if (scredge_is_horizontal(actedge)) {
1334                                         set_cursor(CURSOR_Y_MOVE);
1335                                 } else {
1336                                         set_cursor(CURSOR_X_MOVE);
1337                                 }
1338                                 // this does global hotkeys too
1339                                 screen_edge_edit_event(g_activearea, actedge, event, val);
1340                         } else {
1341                                 set_cursor(CURSOR_STD);
1342                         }
1343                         
1344                         towin= 0;
1345                 }
1346                 else if (event==ZKEY) {
1347                         if(val && G.qual==(LR_ALTKEY|LR_SHIFTKEY|LR_CTRLKEY)) {
1348                                 extern void set_debug_swapbuffers_ovveride(bScreen *sc, int mode);
1349
1350                                 int which= pupmenu("Swapbuffers%t|Simple|Debug|DebugSwap|Redraw|Default|KillSwap");
1351                                         
1352                                 switch (which) {
1353                                 case 1: set_debug_swapbuffers_ovveride(G.curscreen, 's'); break;
1354                                 case 2: set_debug_swapbuffers_ovveride(G.curscreen, 'd'); break;
1355                                 case 3: set_debug_swapbuffers_ovveride(G.curscreen, 'f'); break;
1356                                 case 4: set_debug_swapbuffers_ovveride(G.curscreen, 'r'); break;
1357                                 case 5: set_debug_swapbuffers_ovveride(G.curscreen, 0); break;
1358                                 case 6: 
1359                                         if (g_activearea) {
1360                                                 g_activearea->head_swap= 0;
1361                                                 g_activearea->win_swap= 0;
1362                                         }
1363                                         break;
1364                                 }
1365                                 towin= 0;
1366                         }
1367                 }
1368                 else if (event==SPACEKEY) {
1369                         if(val && (G.qual & LR_SHIFTKEY)) {
1370                                 area_fullscreen();
1371                                 g_activearea= NULL;
1372                                 towin= 0;
1373                         }
1374                         else {
1375                                 if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
1376                                 else if(G.qual==0) {
1377                                         if(val) toolbox_n();
1378                                         towin= 0;
1379                                 }
1380                         }
1381                 }
1382                 else if(ELEM(event, UPARROWKEY, DOWNARROWKEY)) {
1383                         if(val && (G.qual & LR_CTRLKEY)) {
1384                                 area_fullscreen();
1385                                 g_activearea= NULL;
1386                                 towin= 0;
1387                         }
1388                 }
1389
1390                 if (towin && event) {
1391                         if (blenderqread(event, val))   // the global keys
1392                                 addqueue_ext(G.curscreen->winakt, event, val, ascii);
1393                 }
1394
1395                         /* only process subwindow queue's once the
1396                          * main queue has been emptyied.
1397                          */
1398                 event= qtest();
1399                 if (event==0 || event==EXECUTE) {
1400                         screen_dispatch_events();
1401                 }
1402                 
1403                 if(G.f & G_DEBUG) {
1404                         GLenum error = glGetError();
1405                         if (error)
1406                                 printf("GL error: %s\n", gluErrorString(error));
1407                 }
1408                 /* Bizar hack. The event queue has mutated... */
1409                 if ( (firsttime) && (event == 0) ) {
1410
1411                         if (onload_script) {
1412                                 /* OnLoad scriptlink */
1413                                 BPY_do_pyscript(&G.scene->id, SCRIPT_ONLOAD);
1414                                 onload_script = 0;
1415                         }
1416                         else if (G.fileflags & G_FILE_AUTOPLAY) {
1417                                 // SET AUTOPLAY in G.flags for
1418                                 // other fileloads
1419
1420                                 G.flags |= G_FILE_AUTOPLAY;
1421                                 area_autoplayscreen();
1422
1423                                 // Let The Games Begin
1424                                 // fake a 'p' keypress
1425
1426                                 mainqenter(PKEY, 1);
1427                         } else {
1428                                 extern char datatoc_splash_jpg[];
1429                                 extern int datatoc_splash_jpg_size;
1430
1431                                 //if (! ((G.main->versionfile >= G.version)
1432                                 //       || G.save_over)) {
1433                                         splash((void *)datatoc_splash_jpg,
1434                                                datatoc_splash_jpg_size, NULL);
1435                                 //}
1436                         }
1437                         firsttime = 0;
1438                 }
1439         }
1440 }
1441
1442 #if 0
1443 //#ifdef _WIN32 // FULLSCREEN
1444 void mainwindow_toggle_fullscreen(int fullscreen){
1445         if (fullscreen) U.uiflag |= USER_FLIPFULLSCREEN;
1446         else U.uiflag &= ~USER_FLIPFULLSCREEN;
1447
1448         window_toggle_fullscreen(mainwin, fullscreen);
1449 }
1450 #endif
1451
1452 void mainwindow_raise(void) {
1453         window_raise(mainwin);
1454 }
1455
1456 void mainwindow_make_active(void) {
1457         window_make_active(mainwin);
1458 }
1459
1460 void mainwindow_close(void) {
1461         window_destroy(mainwin);
1462         mainwin= NULL;
1463 }
1464
1465 void mainwindow_set_filename_to_title(char *filename) {
1466         char str[FILE_MAXDIR + FILE_MAXFILE];
1467         char dir[FILE_MAXDIR];
1468         char file[FILE_MAXFILE];
1469
1470         BLI_split_dirfile(filename, dir, file);
1471
1472         if(BLI_streq(file, ".B.blend") || filename[0] =='\0')
1473                 sprintf(str, "Blender");
1474         else
1475                 sprintf(str, "Blender [%s]", filename);
1476
1477         window_set_title(mainwin, str);
1478 }
1479
1480 /* *********  AREAS  ************* */
1481
1482 void setprefsize(int stax, int stay, int sizx, int sizy)
1483 {
1484         int scrwidth, scrheight;
1485         
1486         winlay_get_screensize(&scrwidth, &scrheight);
1487                 
1488         if(stax<0) stax= 0;
1489         if(stay<0) stay= 0;
1490         if(sizx<320) sizx= 320;
1491         if(sizy<256) sizy= 256;
1492
1493         if(stax+sizx>scrwidth) {
1494                 fprintf(stderr," width prob \n");
1495                 sizx= scrwidth-stax;
1496                 }
1497
1498         if(stay+sizy>scrheight) {
1499                 fprintf(stderr," height prob \n");
1500                 sizy= scrheight-stay;
1501                 }
1502
1503 /* #ifdef __APPLE__ */
1504 /*      if(stay+sizy>scrheight-22) sizy= scrheight-22-stay;     // 22 = topbar  */
1505 /* #endif*/
1506
1507         if(sizx<320 || sizy<256) {
1508                 printf("ERROR: illegal prefsize\n");
1509                 return;
1510         }
1511         
1512         prefstax= stax;
1513         prefstay= stay;
1514         prefsizx= sizx;
1515         prefsizy= sizy;
1516
1517         start_maximized= 0;
1518 }
1519
1520
1521 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
1522 {
1523         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
1524         sv->vec.x= x;
1525         sv->vec.y= y;
1526         
1527         BLI_addtail(&sc->vertbase, sv);
1528         return sv;
1529 }
1530
1531 static void sortscrvert(ScrVert **v1, ScrVert **v2)
1532 {
1533         ScrVert *tmp;
1534         
1535         if (*v1 > *v2) {
1536                 tmp= *v1;
1537                 *v1= *v2;
1538                 *v2= tmp;       
1539         }
1540 }
1541
1542 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1543 {
1544         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
1545
1546         sortscrvert(&v1, &v2);
1547         se->v1= v1;
1548         se->v2= v2;
1549         
1550         BLI_addtail(&sc->edgebase, se);
1551         return se;
1552 }
1553
1554 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1555 {
1556         ScrEdge *se;
1557
1558         sortscrvert(&v1, &v2);
1559         for (se= sc->edgebase.first; se; se= se->next)
1560                 if(se->v1==v1 && se->v2==v2)
1561                         return se;
1562
1563         return NULL;
1564 }
1565
1566 static void removedouble_scrverts(void)
1567 {
1568         ScrVert *v1, *verg;
1569         ScrEdge *se;
1570         ScrArea *sa;
1571         
1572         verg= G.curscreen->vertbase.first;
1573         while(verg) {
1574                 if(verg->newv==0) {     /* !!! */
1575                         v1= verg->next;
1576                         while(v1) {
1577                                 if(v1->newv==0) {       /* !?! */
1578                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
1579                                                 /* printf("doublevert\n"); */
1580                                                 v1->newv= verg;
1581                                         }
1582                                 }
1583                                 v1= v1->next;
1584                         }
1585                 }
1586                 verg= verg->next;
1587         }
1588         
1589         /* replace pointers in edges and faces */
1590         se= G.curscreen->edgebase.first;
1591         while(se) {
1592                 if(se->v1->newv) se->v1= se->v1->newv;
1593                 if(se->v2->newv) se->v2= se->v2->newv;
1594                 /* edges changed: so.... */
1595                 sortscrvert(&(se->v1), &(se->v2));
1596                 se= se->next;
1597         }
1598         sa= G.curscreen->areabase.first;
1599         while(sa) {
1600                 if(sa->v1->newv) sa->v1= sa->v1->newv;
1601                 if(sa->v2->newv) sa->v2= sa->v2->newv;
1602                 if(sa->v3->newv) sa->v3= sa->v3->newv;
1603                 if(sa->v4->newv) sa->v4= sa->v4->newv;
1604                 sa= sa->next;
1605         }
1606         
1607         /* remove */
1608         verg= G.curscreen->vertbase.first;
1609         while(verg) {
1610                 v1= verg->next;
1611                 if(verg->newv) {
1612                         BLI_remlink(&G.curscreen->vertbase, verg);
1613                         MEM_freeN(verg);
1614                 }
1615                 verg= v1;
1616         }
1617         
1618 }
1619
1620 static void removenotused_scrverts(void)
1621 {
1622         ScrVert *sv, *svn;
1623         ScrEdge *se;
1624
1625         /* we assume edges are ok */
1626         
1627         se= G.curscreen->edgebase.first;
1628         while(se) {
1629                 se->v1->flag= 1;
1630                 se->v2->flag= 1;
1631                 se= se->next;
1632         }
1633         
1634         sv= G.curscreen->vertbase.first;
1635         while(sv) {
1636                 svn= sv->next;
1637                 if(sv->flag==0) {
1638                         BLI_remlink(&G.curscreen->vertbase, sv);
1639                         MEM_freeN(sv);
1640                 }
1641                 else sv->flag= 0;
1642                 sv= svn;
1643         }
1644 }
1645
1646 static void removedouble_scredges(void)
1647 {
1648         ScrEdge *verg, *se, *sn;
1649         
1650         /* compare */
1651         verg= G.curscreen->edgebase.first;
1652         while(verg) {
1653                 se= verg->next;
1654                 while(se) {
1655                         sn= se->next;
1656                         if(verg->v1==se->v1 && verg->v2==se->v2) {
1657                                 BLI_remlink(&G.curscreen->edgebase, se);
1658                                 MEM_freeN(se);
1659                         }
1660                         se= sn;
1661                 }
1662                 verg= verg->next;
1663         }
1664 }
1665
1666 static void removenotused_scredges(void)
1667 {
1668         ScrEdge *se, *sen;
1669         ScrArea *sa;
1670         int a=0;
1671         
1672         /* sets flags when edge is used in area */
1673         sa= G.curscreen->areabase.first;
1674         while(sa) {
1675                 se= screen_findedge(G.curscreen, sa->v1, sa->v2);
1676                 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
1677                 else se->flag= 1;
1678                 se= screen_findedge(G.curscreen, sa->v2, sa->v3);
1679                 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
1680                 else se->flag= 1;
1681                 se= screen_findedge(G.curscreen, sa->v3, sa->v4);
1682                 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
1683                 else se->flag= 1;
1684                 se= screen_findedge(G.curscreen, sa->v4, sa->v1);
1685                 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
1686                 else se->flag= 1;
1687                 sa= sa->next;
1688                 a++;
1689         }
1690         se= G.curscreen->edgebase.first;
1691         while(se) {
1692                 sen= se->next;
1693                 if(se->flag==0) {
1694                         BLI_remlink(&G.curscreen->edgebase, se);
1695                         MEM_freeN(se);
1696                 }
1697                 else se->flag= 0;
1698                 se= sen;
1699         }
1700 }
1701
1702 void calc_arearcts(ScrArea *sa)
1703 {
1704
1705         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
1706         else sa->totrct.xmin= sa->v1->vec.x;
1707         if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
1708         else sa->totrct.xmax= sa->v4->vec.x;
1709         
1710         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
1711         else sa->totrct.ymin= sa->v1->vec.y;
1712         if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
1713         else sa->totrct.ymax= sa->v2->vec.y;
1714         
1715         sa->winrct= sa->totrct;
1716         sa->headrct= sa->totrct;
1717         if(sa->headertype) {
1718                 if(sa->headertype==HEADERDOWN) {
1719                         sa->headrct.ymax= sa->headrct.ymin+HEADERY;
1720                         sa->winrct.ymin= sa->headrct.ymax+1;
1721                 }
1722                 else if(sa->headertype==HEADERTOP) {
1723                         sa->headrct.ymin= sa->headrct.ymax-HEADERY;
1724                         sa->winrct.ymax= sa->headrct.ymin-1;
1725                 }
1726         }
1727         else {
1728                 sa->headrct.ymax= sa->headrct.ymin;
1729         }
1730         if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
1731         
1732         /* for speedup */
1733         sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
1734         sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
1735 }
1736
1737 static void openheadwin(ScrArea *sa)
1738 {
1739         sa->headwin= myswinopen(G.curscreen->mainwin,
1740                 sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1741
1742         glMatrixMode(GL_MODELVIEW);
1743         
1744         areawinar[sa->headwin]= sa;     /* oterwise addqueue does not work */
1745         addqueue(sa->headwin, CHANGED, 1);
1746 }
1747
1748 static void openareawin(ScrArea *sa)
1749 {
1750         sa->win= myswinopen(G.curscreen->mainwin, 
1751                 sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1752
1753         areawinar[sa->win]= sa; /* otherwise addqueue does not work */
1754         addqueue(sa->win, CHANGED, 1);
1755 }
1756
1757 static void closeheadwin(ScrArea *sa)
1758 {
1759         if(sa->headwin) mywinclose(sa->headwin);
1760         sa->headwin= 0;
1761 }
1762
1763 static void closeareawin(ScrArea *sa)
1764 {
1765         uiFreeBlocksWin(&sa->uiblocks, sa->win);
1766         
1767         if(sa->win) mywinclose(sa->win);
1768         sa->win= 0;
1769 }
1770
1771 static void del_area(ScrArea *sa)
1772 {
1773         closeareawin(sa);
1774         closeheadwin(sa);
1775
1776         freespacelist(&sa->spacedata);
1777         
1778         uiFreeBlocks(&sa->uiblocks);
1779         uiFreePanels(&sa->panels);
1780         
1781         if(sa==curarea) curarea= 0;
1782         if(sa==g_activearea) g_activearea= 0;
1783 }
1784
1785 /* sa2 to sa1 */
1786 static void copy_areadata(ScrArea *sa1, ScrArea *sa2)
1787 {
1788         Panel *pa1, *pa2, *patab;
1789         ScriptLink *slink1 = &sa1->scriptlink, *slink2 = &sa2->scriptlink;
1790
1791         sa1->headertype= sa2->headertype;
1792         sa1->spacetype= sa2->spacetype;
1793         Mat4CpyMat4(sa1->winmat, sa2->winmat);
1794
1795         freespacelist(&sa1->spacedata);
1796         duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
1797
1798         BLI_freelistN(&sa1->panels);
1799         duplicatelist(&sa1->panels, &sa2->panels);
1800
1801         /* space handler script links */
1802         if (slink1->totscript) {
1803                 MEM_freeN(slink1->scripts);
1804                 MEM_freeN(slink1->flag);
1805                 slink1->totscript = 0;
1806         }
1807         if (slink2->totscript) {
1808                 slink1->scripts = MEM_dupallocN(slink2->scripts);
1809                 slink1->flag = MEM_dupallocN(slink2->flag);
1810                 slink1->totscript = slink2->totscript;
1811         }
1812
1813         /* copy pointers */
1814         pa1= sa1->panels.first;
1815         while(pa1) {
1816                 
1817                 patab= sa1->panels.first;
1818                 pa2= sa2->panels.first;
1819                 while(patab) {
1820                         if( pa1->paneltab == pa2) {
1821                                 pa1->paneltab = patab;
1822                                 break;
1823                         }
1824                         patab= patab->next;
1825                         pa2= pa2->next;
1826                 }
1827                 pa1= pa1->next;
1828         }
1829 }
1830
1831 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
1832 {
1833         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
1834         sa->cursor= CURSOR_STD;
1835         sa->v1= v1;
1836         sa->v2= v2;
1837         sa->v3= v3;
1838         sa->v4= v4;
1839         sa->headertype= headertype;
1840         sa->spacetype= spacetype;
1841
1842         calc_arearcts(sa);
1843
1844         if (sa->headertype) openheadwin(sa);
1845         openareawin(sa);
1846
1847         BLI_addtail(&sc->areabase, sa);
1848         return sa;
1849 }
1850
1851 static int rcti_eq(rcti *a, rcti *b) {
1852         return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
1853                         (a->ymin==b->ymin && a->ymax==b->ymax));
1854 }
1855
1856 static void testareas(void)
1857 {
1858         ScrArea *sa, *next;
1859
1860         /* test for header, if removed, or moved */
1861         /* test for window, if removed, or moved */
1862         
1863         sa= G.curscreen->areabase.first;
1864         while(sa) {
1865                 rcti oldhr= sa->headrct;
1866                 rcti oldwr= sa->winrct;
1867                 
1868                 next= sa->next;
1869                 
1870                 calc_arearcts(sa);
1871                 
1872                 /* ilegally scaled down area.... */
1873                 if(sa->totrct.xmin>=sa->totrct.xmax || sa->totrct.ymin>=sa->totrct.ymax) {
1874                         del_area(sa);
1875                         BLI_remlink(&G.curscreen->areabase, sa);
1876                         MEM_freeN(sa);
1877                         printf("Warning, removed zero sized window from screen %s\n", G.curscreen->id.name+2);
1878                 }
1879                 else {
1880                                 /* test header */
1881                         if (sa->headwin) {
1882                                 if (!rcti_eq(&oldhr, &sa->headrct)) {
1883                                         mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1884                                         addqueue(sa->headwin, CHANGED, 1);
1885                                 }
1886                                         
1887                                 if(sa->headbutlen<sa->winx) {
1888                                         sa->headbutofs= 0;
1889                                         addqueue(sa->headwin, CHANGED, 1);
1890                                 }
1891                                 else if(sa->headbutofs+sa->winx > sa->headbutlen) {
1892                                         sa->headbutofs= sa->headbutlen-sa->winx;
1893                                         addqueue(sa->headwin, CHANGED, 1);
1894                                 }
1895                         }
1896
1897                         if (!rcti_eq(&oldwr, &sa->winrct)) {
1898                                 mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1899                                 addqueue(sa->win, CHANGED, 1);
1900                         }
1901                 }
1902                 sa= next;
1903         }
1904         
1905                 /* remake global windowarray */
1906         memset(areawinar, 0, sizeof(void *)*MAXWIN);
1907         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1908                 areawinar[sa->headwin]= sa;
1909                 areawinar[sa->win]= sa;
1910         }
1911         
1912                 /* test if winakt is OK */      
1913         if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
1914 }
1915
1916 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
1917 {
1918         /* test if edge is in area, if not, 
1919            then find an area that has it */
1920   
1921         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
1922         
1923         if(sa) {
1924                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1925                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1926                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1927                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1928         }
1929         if(se1!=se && se2!=se && se3!=se && se4!=se) {
1930                 
1931                 sa= G.curscreen->areabase.first;
1932                 while(sa) {
1933                         /* a bit optimise? */
1934                         if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
1935                                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1936                                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1937                                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1938                                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1939                                 if(se1==se || se2==se || se3==se || se4==se) return sa;
1940                         }
1941                         sa= sa->next;
1942                 }
1943         }
1944
1945         return sa;      /* is null when not find */
1946 }
1947
1948 ScrArea *closest_bigger_area(void)
1949 {
1950         ScrArea *sa, *big=0;
1951         float cent[3], vec[3],len, len1, len2, len3, dist=1000;
1952         short mval[2];
1953         
1954         getmouseco_sc(mval);
1955         
1956         cent[0]= mval[0];
1957         cent[1]= mval[1];
1958         cent[2]= vec[2]= 0;
1959
1960         sa= G.curscreen->areabase.first;
1961         while(sa) {
1962                 if(sa!=curarea) {
1963                         if(sa->winy>=curarea->winy) {
1964                         
1965                                 /* mimimum of the 4 corners */
1966                                 vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
1967                                 len= VecLenf(vec, cent);
1968                                 vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
1969                                 len1= VecLenf(vec, cent);
1970                                 vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
1971                                 len2= VecLenf(vec, cent);
1972                                 vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
1973                                 len3= VecLenf(vec, cent);
1974                                 
1975                                 len= MIN4(len, len1, len2, len3);
1976                                 
1977                                 /* plus centre */
1978                                 vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
1979                                 vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
1980
1981                                 len+= 0.5*VecLenf(vec, cent);
1982                                 
1983                                 /* min size */
1984                                 len-= sa->winy+sa->winx;
1985                                 
1986                                 if(len<dist) {
1987                                         dist= len;
1988                                         big= sa;
1989                                 }
1990                         }
1991                 }
1992                 sa= sa->next;
1993         }
1994         
1995         if(big) return big;
1996         else return curarea;
1997 }
1998
1999 /* ************ SCREEN MANAGEMENT ************** */
2000
2001 static int statechanged= 0;
2002 void BIF_wait_for_statechange(void)
2003 {
2004         if (!statechanged) {
2005                         /* Safety, don't wait more than 0.1 seconds */
2006                 double stime= PIL_check_seconds_timer();
2007                 while (!statechanged) {
2008                         winlay_process_events(1);
2009                         if ((PIL_check_seconds_timer()-stime)>0.1) break;
2010                 }
2011                 statechanged= 0;
2012         }
2013         else PIL_sleep_ms(3);   /* statechanged can be set '1' while holding mousebutton, causing locks */
2014
2015 }
2016 void getmouse(short *mval)
2017 {
2018         winlay_process_events(0);
2019         window_get_mouse(mainwin, mval);
2020 }
2021 short get_qual(void)
2022 {
2023         winlay_process_events(0);
2024         return window_get_qual(mainwin);
2025 }
2026 short get_mbut(void)
2027 {
2028         winlay_process_events(0);
2029         return window_get_mbut(mainwin);
2030 }
2031
2032 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
2033 {
2034
2035         statechanged= 1;
2036
2037         /*  accept the extended ascii set (ton) */
2038         if( !val || ascii<32 ) {
2039                 ascii= '\0';
2040         }
2041
2042         mainqenter_ext(evt, val, ascii);
2043 }
2044
2045 /* ScrVert ordering in a ScrArea:
2046
2047 2---------3
2048 |         |
2049 |         |
2050 1---------4
2051   
2052 */
2053
2054 static bScreen *addscreen(char *name)           /* use setprefsize() if you want something else than a full windpw */
2055 {
2056         /* this function sets variabele G.curscreen,
2057          * that global is about used everywhere!
2058          */
2059         bScreen *sc;
2060         ScrVert *sv1, *sv2, *sv3, *sv4;
2061         short startx, starty, endx, endy;       
2062         
2063         sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
2064
2065         if (!prefsizx) {
2066                 prefstax= 0;
2067                 prefstay= 0;
2068                 
2069                 winlay_get_screensize(&prefsizx, &prefsizy);
2070         }
2071
2072         startx= prefstax;
2073         starty= prefstay;
2074         endx= prefstax+prefsizx-1;
2075         endy= prefstay+prefsizy-1;
2076
2077         sc->startx= startx;     sc->starty= starty;
2078         sc->endx= endx; sc->endy= endy;
2079         sc->sizex= sc->endx-sc->startx+1;
2080         sc->sizey= sc->endy-sc->starty+1;
2081         
2082         sc->scene= G.scene;
2083         
2084         if (!mainwin) {
2085 #if 0
2086 //#ifdef _WIN32 // FULLSCREEN
2087                 if (G.windowstate == G_WINDOWSTATE_FULLSCREEN)
2088                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, G_WINDOWSTATE_FULLSCREEN);
2089                 else
2090                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
2091 #else
2092                 mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
2093 #endif
2094                 
2095                 if (!mainwin) {
2096                         printf("ERROR: Unable to open Blender window\n");
2097                         exit(1);
2098                 }
2099                 
2100                 window_set_handler(mainwin, add_to_mainqueue, NULL);
2101                 init_mainwin();
2102                 mywinset(1);
2103         
2104                 /* for visual speed, but still needed? */
2105                 glClearColor(.55, .55, .55, 0.0);
2106                 glClear(GL_COLOR_BUFFER_BIT);
2107                 window_swap_buffers(mainwin);
2108                 
2109                 warp_pointer(sc->sizex/2,  sc->sizey/2);
2110                 
2111                 mainqenter(REDRAW, 1);
2112         }
2113
2114         sc->mainwin= 1;
2115         
2116         sv1= screen_addvert(sc, 0, 0);
2117         sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
2118         sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
2119         sv4= screen_addvert(sc, sc->sizex-1, 0);
2120         
2121         screen_addedge(sc, sv1, sv2);
2122         screen_addedge(sc, sv2, sv3);
2123         screen_addedge(sc, sv3, sv4);
2124         screen_addedge(sc, sv4, sv1);
2125
2126         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
2127         
2128         G.curscreen= sc;
2129
2130         return sc;
2131 }
2132
2133 void setscreen(bScreen *sc)
2134 {
2135         bScreen *sc1;
2136         ScrArea *sa;
2137         short mval[2];
2138         
2139         if(sc->full) {                          /* find associated full */
2140                 sc1= G.main->screen.first;
2141                 while(sc1) {
2142                         sa= sc1->areabase.first;
2143                         if(sa->full==sc) {
2144                                 sc= sc1;
2145                                 break;
2146                         }
2147                         sc1= sc1->id.next;
2148                 }
2149                 if(sc1==0) printf("setscreen error\n");
2150         }
2151
2152         /* de-activate G.curscreen */
2153         if (G.curscreen && G.curscreen != sc) {
2154                 sa= G.curscreen->areabase.first;
2155                 while(sa) {
2156                         if(sa->win) mywinclose(sa->win);
2157                         sa->win= 0;
2158                         if(sa->headwin) mywinclose(sa->headwin);
2159                         sa->headwin= 0;
2160                         
2161                         uiFreeBlocks(&sa->uiblocks);
2162                         
2163                         sa= sa->next;
2164                 }               
2165         }
2166         else if(G.curscreen) markdirty_all();   /* at least redraw */
2167
2168         if (G.curscreen != sc) {
2169                 mywinset(sc->mainwin);
2170         }
2171         
2172         G.curscreen= sc;
2173
2174         for (sa= sc->areabase.first; sa; sa= sa->next) {
2175                         /* XXX, fixme zr */
2176 /*              if (sa->win || sa->headwin) */
2177 /*                      printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
2178                 if (!sa->win)
2179                         openareawin(sa);
2180                 if (!sa->headwin && sa->headertype)
2181                         openheadwin(sa);
2182         }
2183
2184         /* recalculate winakt */
2185         getmouseco_sc(mval);
2186
2187         test_scale_screen(sc);
2188         testareas();
2189         
2190         for(sa= sc->areabase.first; sa; sa= sa->next) {
2191                 SpaceLink *sl;
2192
2193                 for(sl= sa->spacedata.first; sl; sl= sl->next) {
2194                         sl->area= sa;
2195
2196                         if(sl->spacetype==SPACE_OOPS) {
2197                                 SpaceOops *soops= (SpaceOops *) sl;
2198
2199                                 /* patch for old files */
2200                                 if(soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
2201                                         init_v2d_oops(sa, soops);
2202                                 }
2203                         }
2204                         else if(sl->spacetype==SPACE_BUTS) {
2205                                 SpaceButs *sbuts= (SpaceButs *)sl;
2206                                 sbuts->re_align= 1;             // force an align call, maybe new panels were added, also for after file reading
2207                         }
2208                 }
2209                 
2210                 sa->cursor= CURSOR_STD;
2211         }
2212         
2213         G.scene= sc->scene;
2214         countall();
2215         
2216         G.curscreen->winakt= 0;
2217         curarea= sc->areabase.first;
2218         
2219         mainqenter(DRAWEDGES, 1);
2220         dodrawscreen= 1;                /* patch! even gets lost,,,? */
2221
2222         winqueue_break= 1;              /* means leave queue everywhere */
2223 }
2224
2225 static void splitarea(ScrArea *sa, char dir, float fac);
2226
2227 void area_fullscreen(void)      /* with curarea */
2228 {
2229         /* this function toggles: if area is full then the parent will be restored */
2230         bScreen *sc, *oldscreen;
2231         ScrArea *newa, *old;
2232         short headertype, fulltype;
2233         
2234         if(curarea->full) {
2235                 sc= curarea->full;      /* the old screen */
2236                 fulltype = sc->full;
2237
2238                 // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
2239                 // is set
2240
2241                 if (fulltype != SCREENAUTOPLAY || (G.flags & G_FILE_AUTOPLAY) == 0) {
2242                         sc->full= 0;
2243                 
2244                         /* find old area */
2245                         old= sc->areabase.first;
2246                         while(old) {
2247                                 if(old->full) break;
2248                                 old= old->next;
2249                         }
2250                         if(old==0) {error("something wrong in areafullscreen"); return;}
2251                 
2252                         if (fulltype == SCREENAUTOPLAY) {
2253                                 // in autoplay screens the headers are disabled by 
2254                                 // default. So use the old headertype instead
2255                                 headertype = old->headertype;
2256                         } else {
2257                                 // normal fullscreen. Use current headertype
2258                                 headertype = curarea->headertype;
2259                         }
2260
2261                         copy_areadata(old, curarea);
2262                         old->headertype = headertype;
2263
2264                         old->full= 0;
2265                 
2266                         unlink_screen(G.curscreen);
2267                         free_libblock(&G.main->screen, G.curscreen);
2268                         G.curscreen= NULL;
2269
2270                         setscreen(sc);
2271                 }
2272                 
2273         }
2274         else {
2275                 /* is there only 1 area? */
2276                 if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
2277                 if(curarea->spacetype==SPACE_INFO) return;
2278                 
2279                 G.curscreen->full = SCREENFULL;
2280                 
2281                 old= curarea;           
2282                 oldscreen= G.curscreen;
2283                 sc= addscreen("temp");          /* this sets G.curscreen */
2284
2285                 splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
2286                 newa= sc->areabase.first;
2287                 newspace(newa->next, SPACE_INFO);
2288                 
2289                 curarea= old;
2290                 G.curscreen= oldscreen; /* needed because of setscreen */
2291                 
2292                 /* copy area */
2293                 copy_areadata(newa, curarea);
2294                 
2295                 curarea->full= oldscreen;
2296                 newa->full= oldscreen;
2297                 newa->next->full= oldscreen;
2298                 
2299                 setscreen(sc);
2300                 wich_cursor(newa);
2301         }
2302 }
2303
2304 static void area_autoplayscreen(void)
2305 {
2306         bScreen *sc, *oldscreen;
2307         ScrArea *newa, *old, *sa;
2308         
2309         if (curarea->full) {
2310                 area_fullscreen();
2311         }
2312
2313         if (curarea->full == NULL) { 
2314                 sa = G.curscreen->areabase.first;
2315                 while (sa) {
2316                         if (sa->spacetype == SPACE_VIEW3D) {
2317                                 break;
2318                         }
2319                         sa= sa->next;
2320                 }
2321
2322                 if (sa) {
2323                         areawinset(sa->win);
2324                         G.curscreen->full = SCREENAUTOPLAY;
2325                         
2326                         old= curarea;           
2327                         oldscreen= G.curscreen;
2328                         sc= addscreen("temp");          /* this sets G.curscreen */
2329         
2330                         newa= sc->areabase.first;
2331                         
2332                         curarea= old;
2333                         G.curscreen= oldscreen; /* because of setscreen */
2334                         
2335                         /* copy area settings */
2336                         copy_areadata(newa, curarea);
2337                         newa->headertype= 0;
2338                         
2339                         curarea->full= oldscreen;
2340                         newa->full= oldscreen;
2341         
2342                         setscreen(sc);
2343                         wich_cursor(newa);
2344                 }
2345         }
2346 }
2347
2348 static void copy_screen(bScreen *to, bScreen *from)
2349 {
2350         ScrVert *s1, *s2;
2351         ScrEdge *se;
2352         ScrArea *sa, *saf;
2353
2354         /* free 'to' */
2355         free_screen(to);
2356         winqueue_break= 1;      /* leave queues everywhere */
2357         
2358         duplicatelist(&to->vertbase, &from->vertbase);
2359         duplicatelist(&to->edgebase, &from->edgebase);
2360         duplicatelist(&to->areabase, &from->areabase);
2361         
2362         s1= from->vertbase.first;
2363         s2= to->vertbase.first;
2364         while(s1) {
2365                 s1->newv= s2;
2366                 s2= s2->next;
2367                 s1= s1->next;
2368         }
2369         se= to->edgebase.first;
2370         while(se) {
2371                 se->v1= se->v1->newv;
2372                 se->v2= se->v2->newv;
2373                 sortscrvert(&(se->v1), &(se->v2));
2374                 se= se->next;
2375         }
2376
2377         sa= to->areabase.first;
2378         saf= from->areabase.first;
2379         while(sa) {
2380                 sa->v1= sa->v1->newv;
2381                 sa->v2= sa->v2->newv;
2382                 sa->v3= sa->v3->newv;
2383                 sa->v4= sa->v4->newv;
2384                 sa->win= 0;
2385                 sa->headwin= 0;
2386                 
2387                 sa->spacedata.first= sa->spacedata.last= NULL;
2388                 sa->uiblocks.first= sa->uiblocks.last= NULL;
2389                 sa->panels.first= sa->panels.last= NULL;
2390                 copy_areadata(sa, saf);
2391                 
2392                 sa= sa->next;
2393                 saf= saf->next;
2394         }
2395         
2396         /* put at zero (needed?) */
2397         s1= from->vertbase.first;
2398         while(s1) {
2399                 s1->newv= 0;
2400                 s1= s1->next;
2401         }
2402 }
2403
2404 void duplicate_screen(void)
2405 {
2406         bScreen *sc, *oldscreen;
2407         
2408         if(G.curscreen->full != SCREENNORMAL) return;
2409         
2410         /* make new screen: */
2411
2412         oldscreen= G.curscreen;
2413         sc= addscreen(oldscreen->id.name+2);    /* this sets G.curscreen */
2414         copy_screen(sc, oldscreen);
2415
2416         G.curscreen= oldscreen;
2417         setscreen(sc);
2418
2419 }
2420
2421
2422 /* ************ END SCREEN MANAGEMENT ************** */
2423 /* ************  JOIN/SPLIT/MOVE ************** */
2424
2425 typedef struct point{
2426         float x,y;
2427 }_point;
2428
2429 /* draw vertical shape visualising future joining (left as well
2430  * right direction of future joining) */
2431 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
2432 {
2433         _point points[10];
2434         short i;
2435         float w, h;
2436         float width = sa->v3->vec.x - sa->v1->vec.x;
2437         float height = sa->v3->vec.y - sa->v1->vec.y;
2438
2439         if(height<width) {
2440                 h = height/8;
2441                 w = height/4;
2442         }
2443         else {
2444                 h = width/8;
2445                 w = width/4;
2446         }
2447
2448         points[0].x = sa->v1->vec.x;
2449         points[0].y = sa->v1->vec.y + height/2;
2450
2451         points[1].x = sa->v1->vec.x;
2452         points[1].y = sa->v1->vec.y;
2453
2454         points[2].x = sa->v4->vec.x - w;
2455         points[2].y = sa->v4->vec.y;
2456
2457         points[3].x = sa->v4->vec.x - w;
2458         points[3].y = sa->v4->vec.y + height/2 - 2*h;
2459
2460         points[4].x = sa->v4->vec.x - 2*w;
2461         points[4].y = sa->v4->vec.y + height/2;
2462
2463         points[5].x = sa->v4->vec.x - w;
2464         points[5].y = sa->v4->vec.y + height/2 + 2*h;
2465
2466         points[6].x = sa->v3->vec.x - w;
2467         points[6].y = sa->v3->vec.y;
2468
2469         points[7].x = sa->v2->vec.x;
2470         points[7].y = sa->v2->vec.y;
2471
2472         points[8].x = sa->v4->vec.x;
2473         points[8].y = sa->v4->vec.y + height/2 - h;
2474
2475         points[9].x = sa->v4->vec.x;
2476         points[9].y = sa->v4->vec.y + height/2 + h;
2477
2478         if(dir=='l') {
2479                 /* when direction is left, then we flip direction of arrow */
2480                 float cx = sa->v1->vec.x + width;
2481                 for(i=0;i<10;i++) {
2482                         points[i].x -= cx;
2483                         points[i].x = -points[i].x;
2484                         points[i].x += sa->v1->vec.x;
2485                 }
2486         }
2487
2488         glBegin(GL_POLYGON);
2489         for(i=0;i<8;i++)
2490                 glVertex2f(points[i].x, points[i].y);
2491         glEnd();
2492
2493         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2494         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2495 }
2496
2497 /* draw vertical shape visualising future joining (up/down direction) */
2498 static void draw_vertical_join_shape(ScrArea *sa, char dir)
2499 {
2500         _point points[10];
2501         short i;
2502         float w, h;
2503         float width = sa->v3->vec.x - sa->v1->vec.x;
2504         float height = sa->v3->vec.y - sa->v1->vec.y;
2505
2506         if(height<width) {
2507                 h = height/4;
2508                 w = height/8;
2509         }
2510         else {
2511                 h = width/4;
2512                 w = width/8;
2513         }
2514
2515         points[0].x = sa->v1->vec.x + width/2;
2516         points[0].y = sa->v3->vec.y;
2517
2518         points[1].x = sa->v2->vec.x;
2519         points[1].y = sa->v2->vec.y;
2520
2521         points[2].x = sa->v1->vec.x;
2522         points[2].y = sa->v1->vec.y + h;
2523
2524         points[3].x = sa->v1->vec.x + width/2 - 2*w;
2525         points[3].y = sa->v1->vec.y + h;
2526
2527         points[4].x = sa->v1->vec.x + width/2;
2528         points[4].y = sa->v1->vec.y + 2*h;
2529
2530         points[5].x = sa->v1->vec.x + width/2 + 2*w;
2531         points[5].y = sa->v1->vec.y + h;
2532
2533         points[6].x = sa->v4->vec.x;
2534         points[6].y = sa->v4->vec.y + h;
2535         
2536         points[7].x = sa->v3->vec.x;
2537         points[7].y = sa->v3->vec.y;
2538
2539         points[8].x = sa->v1->vec.x + width/2 - w;
2540         points[8].y = sa->v1->vec.y;
2541
2542         points[9].x = sa->v1->vec.x + width/2 + w;
2543         points[9].y = sa->v1->vec.y;
2544
2545         if(dir=='u') {
2546                 /* when direction is up, then we flip direction of arrow */
2547                 float cy = sa->v1->vec.y + height;
2548                 for(i=0;i<10;i++) {
2549                         points[i].y -= cy;
2550                         points[i].y = -points[i].y;
2551                         points[i].y += sa->v1->vec.y;
2552                 }
2553         }
2554
2555         glBegin(GL_POLYGON);
2556         for(i=0;i<8;i++)
2557                 glVertex2f(points[i].x, points[i].y);
2558         glEnd();
2559
2560         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2561         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2562 }
2563
2564 /* draw join shape due to direction of joining */
2565 static void draw_join_shape(ScrArea *sa, char dir)
2566 {
2567         if(dir=='u' || dir=='d')
2568                 draw_vertical_join_shape(sa, dir);
2569         else
2570                 draw_horizontal_join_shape(sa, dir);
2571 }
2572
2573 /* draw screen area darker with arrow (visualisation of future joining) */
2574 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
2575 {
2576         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2577         glEnable(GL_BLEND);
2578         glColor4ub(0, 0, 0, 105);
2579         draw_join_shape(sa, dir);
2580         glDisable(GL_BLEND);
2581 }
2582
2583 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
2584 static void scrarea_draw_shape_light(ScrArea *sa, char dir)
2585 {
2586         glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
2587         glEnable(GL_BLEND);
2588         /* value 181 was hardly computed: 181~105 */
2589         glColor4ub(255, 255, 255, 181);         
2590         draw_join_shape(sa, dir);
2591         glDisable(GL_BLEND);
2592 }
2593
2594 static void joinarea_interactive(ScrArea *area, ScrEdge *onedge)
2595 {
2596         struct ScrArea *sa1 = area, *sa2, *scr;
2597         struct ScrArea *up=0, *down=0, *right=0, *left=0;
2598         struct ScrEdge *se;
2599         unsigned short event;
2600         short ok=0, val=0, mval[2];
2601         char dir;
2602
2603         sa1 = test_edge_area(sa1, onedge);
2604         if(sa1==0) return;
2605
2606         /* find directions with same edge */
2607         sa2= G.curscreen->areabase.first;
2608         while(sa2) {
2609                 if(sa2 != sa1) {
2610                         se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
2611                         if(onedge==se) right= sa2;
2612                         se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
2613                         if(onedge==se) down= sa2;
2614                         se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
2615                         if(onedge==se) left= sa2;
2616                         se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
2617                         if(onedge==se) up= sa2;
2618                 }
2619                 sa2= sa2->next;
2620         }
2621         
2622         if(left) val++;
2623         if(up) val++;
2624         if(right) val++;
2625         if(down) val++;
2626         
2627         if(val==0) return;
2628         else if(val==1) {
2629                 if(left) {
2630                         right = sa1;
2631                         sa2 = left;
2632                         dir = 'h';
2633                 }
2634                 else if(right) {
2635                         left = sa1;
2636                         sa2 = right;
2637                         dir = 'h';
2638                 }
2639                 else if(up) {
2640                         down = sa1;
2641                         sa2= up;
2642                         dir = 'v';
2643                 }
2644                 else if(down) {
2645                         up = sa1;
2646                         sa2 = down;
2647                         dir = 'v';
2648                 }
2649         }
2650
2651         mywinset(G.curscreen->mainwin);
2652
2653         /* initial set up screen area asigned for destroying */
2654         scr = sa2;
2655
2656         /* set up standard cursor */
2657         set_cursor(CURSOR_STD);
2658
2659         /* should already have a good matrix */
2660         glReadBuffer(GL_FRONT);
2661         glDrawBuffer(GL_FRONT);
2662
2663         /* to prevent flickering after clicking at "Join Areas " */
2664         getmouseco_sc(mval);
2665         if(dir=='h') {
2666                 if(scr==left && mval[0]<=onedge->v1->vec.x) scr = right;
2667                 else if(scr==right && mval[0]>onedge->v1->vec.x) scr = left;
2668         }
2669         else if(dir=='v') {
2670                 if(scr==down && mval[1]<=onedge->v1->vec.y) scr = up;
2671                 else if(scr==up && mval[1]>onedge->v1->vec.y) scr = down;
2672         }
2673
2674         /* draw scr screen area with dark shape */
2675         if(scr==left)
2676                 scrarea_draw_shape_dark(scr,'r');
2677         else if(scr==right)
2678                 scrarea_draw_shape_dark(scr,'l');
2679         else if(scr==up)
2680                 scrarea_draw_shape_dark(scr,'d');
2681         else if(scr==down)
2682                 scrarea_draw_shape_dark(scr,'u');
2683         glFlush();
2684
2685         /* "never ending loop" of interactive selection */
2686         while(!ok) {
2687                 getmouseco_sc(mval);
2688
2689                 /* test if position of mouse is on the "different side" of
2690                  * "joining edge" */
2691                 if(dir=='h') {
2692                         if(scr==left && mval[0]<=onedge->v1->vec.x) {
2693                                 scrarea_draw_shape_light(scr,'r');
2694                                 scr = right;
2695                                 scrarea_draw_shape_dark(scr,'l');
2696                         }
2697                         else if(scr==right && mval[0]>onedge->v1->vec.x) {
2698                                 scrarea_draw_shape_light(scr,'l');
2699                                 scr = left;
2700                                 scrarea_draw_shape_dark(scr,'r');
2701                         }
2702                 }
2703                 else if(dir=='v') {
2704                         if(scr==down && mval[1]<=onedge->v1->vec.y) {
2705                                 scrarea_draw_shape_light(scr,'u');
2706                                 scr = up;
2707                                 scrarea_draw_shape_dark(scr,'d');
2708                         }
2709                         else if(scr==up && mval[1]>onedge->v1->vec.y){
2710                                 scrarea_draw_shape_light(scr,'d');
2711                                 scr = down;
2712                                 scrarea_draw_shape_dark(scr,'u');
2713                         }
2714                 }
2715
2716
2717                 /* get pressed keys and mouse buttons */
2718                 event = extern_qread(&val);
2719
2720                 /* confirm joining of two screen areas */
2721                 if(val && event==LEFTMOUSE) ok= 1;
2722
2723                 /* cancel joining of joining */
2724                 if(val && (event==ESCKEY || event==RIGHTMOUSE)) ok= -1;
2725
2726                 glFlush();
2727         }
2728
2729         glReadBuffer(GL_BACK);
2730         glDrawBuffer(GL_BACK);
2731
2732         /* joining af screen areas was confirmed ... proceed joining */
2733         if(ok==1) {
2734                 if(sa2!=scr) {
2735                         sa1 = sa2;
2736                         sa2 = scr;
2737                 }
2738
2739                 if(sa2==left) {
2740                         sa1->v1= sa2->v1;
2741                         sa1->v2= sa2->v2;
2742                         screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2743                         screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2744                 }
2745                 else if(sa2==up) {
2746                         sa1->v2= sa2->v2;
2747                         sa1->v3= sa2->v3;
2748                         screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2749                         screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2750                 }
2751                 else if(sa2==right) {
2752                         sa1->v3= sa2->v3;
2753                         sa1->v4= sa2->v4;
2754                         screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2755                         screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2756                 }
2757                 else if(sa2==down) {
2758                         sa1->v1= sa2->v1;
2759                         sa1->v4= sa2->v4;
2760                         screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2761                         screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2762                 }
2763         
2764                 del_area(sa2);
2765                 BLI_remlink(&G.curscreen->areabase, sa2);
2766                 MEM_freeN(sa2);
2767                 
2768                 removedouble_scredges();
2769                 removenotused_scredges();
2770                 removenotused_scrverts();
2771                 
2772                 testareas();
2773                 mainqenter(DRAWEDGES, 1);
2774
2775                 /* test cursor en inputwindow */
2776                 mainqenter(MOUSEY, -1);
2777         }
2778 }
2779
2780 static short testsplitpoint(ScrArea *sa, char dir, float fac)
2781 /* return 0: no split possible */
2782 /* else return (integer) screencoordinate split point */
2783 {
2784         short x, y;
2785         
2786         /* area big enough? */
2787         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
2788         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
2789
2790         /* to be sure */
2791         if(fac<0.0) fac= 0.0;
2792         if(fac>1.0) fac= 1.0;
2793         
2794         if(dir=='h') {
2795                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
2796                 
2797                 if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY) 
2798                         y= sa->v2->vec.y- HEADERY;
2799
2800                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
2801                         y= sa->v1->vec.y+ HEADERY;
2802
2803                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
2804                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
2805                 else y-= (y % AREAGRID);
2806
2807                 return y;
2808         }
2809         else {
2810                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
2811                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
2812                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
2813                 else x-= (x % AREAGRID);
2814
2815                 return x;
2816         }
2817 }
2818
2819 static void splitarea(ScrArea *sa, char dir, float fac)
2820 {
2821         bScreen *sc;
2822         ScrArea *newa=NULL;
2823         ScrVert *sv1, *sv2;
2824         short split;
2825         
2826         if(sa==0) return;
2827         
2828         split= testsplitpoint(sa, dir, fac);
2829         if(split==0) return;
2830         
2831         sc= G.curscreen;
2832         
2833         areawinset(sa->win);
2834         
2835         if(dir=='h') {
2836                 /* new vertices */
2837                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
2838                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
2839                 
2840                 /* new edges */
2841                 screen_addedge(sc, sa->v1, sv1);
2842                 screen_addedge(sc, sv1, sa->v2);
2843                 screen_addedge(sc, sa->v3, sv2);
2844                 screen_addedge(sc, sv2, sa->v4);
2845                 screen_addedge(sc, sv1, sv2);
2846                 
2847                 /* new areas: top */
2848                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
2849                 copy_areadata(newa, sa);
2850
2851                 /* area below */
2852                 sa->v2= sv1;
2853                 sa->v3= sv2;
2854                 
2855         }
2856         else {
2857                 /* new vertices */
2858                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
2859                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
2860                 
2861                 /* new edges */
2862                 screen_addedge(sc, sa->v1, sv1);
2863                 screen_addedge(sc, sv1, sa->v4);
2864                 screen_addedge(sc, sa->v2, sv2);
2865                 screen_addedge(sc, sv2, sa->v3);
2866                 screen_addedge(sc, sv1, sv2);
2867                 
2868                 /* new areas: left */
2869                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
2870                 copy_areadata(newa, sa);
2871
2872                 /* area right */
2873                 sa->v1= sv1;            
2874                 sa->v2= sv2;
2875         }
2876         
2877         if(sa->spacetype==SPACE_BUTS) {
2878                 addqueue(sa->win, UI_BUT_EVENT, B_BUTSHOME);
2879                 addqueue(newa->win, UI_BUT_EVENT, B_BUTSHOME);
2880         }
2881         
2882         /* remove double vertices en edges */
2883         removedouble_scrverts();
2884         removedouble_scredges();
2885         removenotused_scredges();
2886         
2887         mainqenter(DRAWEDGES, 1);
2888         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2889         testareas();
2890 }
2891
2892 static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
2893 {
2894         int split= testsplitpoint(sa, dir, fac);
2895
2896         if (split) {
2897                 if(dir=='h') {
2898                         sdrawXORline(sa->totrct.xmin, split, sa->totrct.xmax, split);
2899                         sdrawXORline(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
2900                 } else {
2901                         sdrawXORline(split, sa->totrct.ymin, split, sa->totrct.ymax);
2902                         sdrawXORline(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
2903                 }
2904         }
2905 }
2906
2907 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
2908 {
2909         ScrArea *scr, *sa= area;
2910         float fac= 0.0;
2911         unsigned short event;
2912         short ok= 0, val, split = 0, mval[2], mvalo[2], first= 1;
2913         char dir;
2914         
2915         if(sa->win==0) return;
2916         if(sa->full) return;
2917
2918         dir= scredge_is_horizontal(onedge)?'v':'h';
2919         
2920         mywinset(G.curscreen->mainwin);
2921         /* should already have a good matrix */
2922         glReadBuffer(GL_FRONT);
2923         glDrawBuffer(GL_FRONT);
2924
2925         /* keep track of grid and minsize */
2926         while(ok==0) {
2927                 getmouseco_sc(mval);
2928
2929                 /* this part of code allows to choose, what window will be splited */
2930                 /* cursor is out of the current ScreenArea */
2931                 if((mval[0] < sa->v1->vec.x) || (mval[0] > sa->v3->vec.x) ||
2932                 (mval[1] < sa->v1->vec.y) || (mval[1] > sa->v3->vec.y)){
2933                         scr= (ScrArea*)G.curscreen->areabase.first;
2934                         while(scr){
2935                                 if((mval[0] > scr->v1->vec.x) && (mval[0] < scr->v4->vec.x) &&
2936                                 (mval[1] < scr->v2->vec.y) && (mval[1] > scr->v1->vec.y)){
2937                                         /* test: is ScreenArea enough big for splitting */
2938                                         split= testsplitpoint(scr, dir, fac);
2939                                         if(split){
2940                                                 /* delete old line from previous ScreenArea */
2941                                                 if(!first) scrarea_draw_splitpoint(sa, dir, fac);
2942                                                 sa= scr;
2943                                                 first= 1;
2944                                                 break;
2945                                         }
2946                                 }
2947                                 scr= scr->next;
2948                         }
2949                 }
2950                 
2951                 if (first || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2952                         if (!first) {
2953                                 scrarea_draw_splitpoint(sa, dir, fac);
2954                         }
2955
2956                         if(dir=='h') {
2957                                 fac= mval[1]- (sa->v1->vec.y);
2958                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2959                         } else {
2960                                 fac= mval[0]- sa->v1->vec.x;
2961                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2962                         }
2963
2964                         split= testsplitpoint(sa, dir, fac);
2965                         if (split) {
2966                                 scrarea_draw_splitpoint(sa, dir, fac);
2967                         } else {
2968                                 ok= -1;
2969                         }
2970
2971                         mvalo[0]= mval[0];
2972                         mvalo[1]= mval[1];
2973                         first= 0;                       
2974                 }
2975                 
2976                 event= extern_qread(&val);
2977
2978                 /* change direction of splitting between horizontal and vertical
2979                  * patch was offered by Guillaume */
2980                 if(val && (event==TABKEY || event==MIDDLEMOUSE)) {
2981                         scrarea_draw_splitpoint(sa, dir, fac);
2982                         if(dir=='h') {
2983                                 dir='v';
2984                                 set_cursor(CURSOR_Y_MOVE);
2985                         } else {
2986                                 dir='h';
2987                                 set_cursor(CURSOR_X_MOVE);
2988                         }
2989                         first= 1;
2990                 }
2991
2992                 if(val && event==LEFTMOUSE) {
2993                         if(dir=='h') {
2994                                 fac= split- (sa->v1->vec.y);
2995                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2996                         }
2997                         else {
2998                                 fac= split- sa->v1->vec.x;
2999                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
3000                         }
3001                         ok= 1;
3002                 }
3003                 if(val && (event==ESCKEY || event==RIGHTMOUSE)) {
3004                         ok= -1;
3005                 }
3006                 glFlush();
3007         }
3008
3009         if (!first) {
3010                 scrarea_draw_splitpoint(sa, dir, fac);
3011                 glFlush();
3012         }
3013         glReadBuffer(GL_BACK);
3014         glDrawBuffer(GL_BACK);
3015
3016         if(ok==1) {
3017                 splitarea(sa, dir, fac);
3018                 mainqenter(DRAWEDGES, 1);
3019                 dodrawscreen= 1;                /* patch! event gets lost,,,? */
3020         }
3021 }
3022
3023 View3D *find_biggest_view3d(void)
3024 {
3025         ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
3026         
3027         if (sa) {
3028                 return (View3D*) sa->spacedata.first;
3029         } else {
3030                 return NULL;
3031         }
3032 }
3033
3034 ScrArea *find_biggest_area_of_type(int spacecode)
3035 {
3036         ScrArea *sa, *biggest= NULL;
3037         int bigsize= 0;
3038         
3039         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
3040                 if (spacecode==0 || sa->spacetype==spacecode) {
3041                         int x= sa->v3->vec.x - sa->v1->vec.x;
3042                         int y= sa->v3->vec.y - sa->v1->vec.y;
3043                         int size= x*x + y*y;
3044                 
3045                         if (!biggest || size>bigsize) {
3046                                 biggest= sa;
3047                                 bigsize= size;
3048                         }
3049                 }
3050         }
3051         
3052         return biggest;
3053 }
3054
3055 ScrArea *find_biggest_area(void)
3056 {
3057         return find_biggest_area_of_type(0);
3058 }
3059
3060 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
3061 {
3062         ScrEdge *se;
3063         ScrVert *sv;
3064         int oneselected;
3065         char dir;
3066         
3067         /* select connected, only in the right direction */
3068         /* 'dir' is the direction of EDGE */
3069
3070         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
3071         else dir= 'h';
3072
3073         sv= sc->vertbase.first;
3074         while(sv) {
3075                 sv->flag= 0;
3076                 sv= sv->next;
3077         }
3078
3079         edge->v1->flag= 1;
3080         edge->v2->flag= 1;
3081
3082         oneselected= 1;
3083         while(oneselected) {
3084                 se= sc->edgebase.first;
3085                 oneselected= 0;
3086                 while(se) {
3087                         if(se->v1->flag + se->v2->flag==1) {
3088                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
3089                                         se->v1->flag= se->v2->flag= 1;
3090                                         oneselected= 1;
3091                                 }
3092                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
3093                                         se->v1->flag= se->v2->flag= 1;
3094                                         oneselected= 1;
3095                                 }
3096                         }
3097                         se= se->next;
3098                 }
3099         }
3100 }
3101
3102 void test_scale_screen(bScreen *sc)
3103 /* test if screen vertices should be scaled */
3104 /* also check offset */
3105 {
3106         ScrVert *sv=0;
3107         ScrEdge *se;
3108         ScrArea *sa, *san;
3109         int yval;
3110         float facx, facy, tempf, min[2], max[2];
3111
3112         sc->startx= prefstax;
3113         sc->starty= prefstay;
3114         sc->endx= prefstax+prefsizx-1;
3115         sc->endy= prefstay+prefsizy-1;
3116
3117         /* calculate size */
3118         sv= sc->vertbase.first;
3119         min[0]= min[1]= 0.0;
3120         max[0]= sc->sizex;
3121         max[1]= sc->sizey;
3122         while(sv) {
3123                 min[0]= MIN2(min[0], sv->vec.x);
3124                 min[1]= MIN2(min[1], sv->vec.y);
3125                 max[0]= MAX2(max[0], sv->vec.x);
3126                 max[1]= MAX2(max[1], sv->vec.y);
3127                 sv= sv->next;
3128         }
3129
3130         /* always make 0.0 left under */
3131         sv= sc->vertbase.first;
3132         while(sv) {
3133                 sv->vec.x -= min[0];
3134                 sv->vec.y -= min[1];
3135                 sv= sv->next;
3136         }
3137         
3138
3139         sc->sizex= max[0]-min[0];
3140         sc->sizey= max[1]-min[1];
3141
3142         if(sc->sizex!= prefsizx || sc->sizey!= prefsizy) {
3143                 facx= prefsizx;
3144                 facx/= (float)sc->sizex;
3145                 facy= prefsizy;
3146                 facy/= (float)sc->sizey;
3147
3148                 /* make sure it fits! */
3149                 sv= sc->vertbase.first;
3150                 while(sv) {
3151                         tempf= ((float)sv->vec.x)*facx;
3152                         sv->vec.x= (short)(tempf+0.5);
3153                         sv->vec.x+= AREAGRID-1;
3154                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
3155                         
3156                         CLAMP(sv->vec.x, 0, prefsizx);
3157
3158                         tempf= ((float)sv->vec.y )*facy;
3159                         sv->vec.y= (short)(tempf+0.5);
3160                         sv->vec.y+= AREAGRID-1;
3161                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
3162                         
3163                         CLAMP(sv->vec.y, 0, prefsizy);
3164
3165                         sv= sv->next;
3166                 }
3167                 
3168                 sc->sizex= prefsizx;
3169                 sc->sizey= prefsizy;
3170         }
3171
3172         /* test for collapsed areas. This could happen in some blender version... */
3173         sa= sc->areabase.first;
3174         while(sa) {
3175                 san= sa->next;
3176                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
3177                         del_area(sa);
3178                         BLI_remlink(&sc->areabase, sa);
3179                         MEM_freeN(sa);
3180                 }
3181                 sa= san;
3182         }
3183
3184         /* make each window at least HEADERY high */
3185         sa= sc->areabase.first;
3186         while(sa) {
3187
3188                 if(sa->v1->vec.y+HEADERY > sa->v2->vec.y) {
3189                         /* lower edge */
3190                         se= screen_findedge(sc, sa->v4, sa->v1);
3191                         if(se && sa->v1!=sa->v2 ) {
3192                                 select_connected_scredge(sc, se);
3193                                 
3194                                 /* all selected vertices get the right offset */
3195                                 yval= sa->v2->vec.y-HEADERY;
3196                                 sv= sc->vertbase.first;
3197                                 while(sv) {
3198                                         /* if is a collapsed area */
3199                                         if(sv!=sa->v2 && sv!=sa->v3) {
3200                                                 if(sv->flag) sv->vec.y= yval;
3201                                         }
3202                                         sv= sv->next;
3203                                 }
3204                         }
3205                 }
3206
3207                 sa= sa->next;
3208         }
3209
3210 }
3211
3212 static void draw_front_xor_dirdist_line(char dir, int dist, int start, int end)
3213 {
3214         if (dir=='h') {
3215                 sdrawXORline(start, dist, end, dist);
3216                 sdrawXORline(start, dist+1, end, dist+1);
3217         } else {
3218                 sdrawXORline(dist, start, dist, end);
3219                 sdrawXORline(dist+1, start, dist+1, end);
3220         }
3221 }
3222
3223 static void moveareas(ScrEdge *edge)
3224 {
3225         ScrVert *v1;
3226         ScrArea *sa;
3227         short mvalo[2];
3228         short edge_start, edge_end, edge_position;
3229         short bigger, smaller, headery, areaminy;
3230         int delta, doit;
3231         char dir;
3232         
3233         if(edge->border) return;
3234
3235         dir= scredge_is_horizontal(edge)?'h':'v';
3236         
3237         select_connected_scredge(G.curscreen, edge);
3238
3239         edge_position= (dir=='h')?edge->v1->vec.y:edge->v1->vec.x;
3240         edge_start= 10000;
3241         edge_end= -10000;
3242         for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
3243                 if (v1->flag) {
3244                         if (dir=='h') {
3245                                 edge_start= MIN2(edge_start, v1->vec.x);
3246                                 edge_end= MAX2(edge_end, v1->vec.x);
3247                         } else {
3248                                 edge_start= MIN2(edge_start, v1->vec.y);
3249                                 edge_end= MAX2(edge_end, v1->vec.y);
3250                         }
3251                 }
3252         }
3253
3254         /* now all verices with 'flag==1' are the ones that can be moved. */
3255         /* we check all areas and test for free space with MINSIZE */
3256         bigger= smaller= 10000;
3257         sa= G.curscreen->areabase.first;
3258         while(sa) {
3259                 if(dir=='h') {  /* if top or down edge selected, test height */
3260                         if(sa->headertype) {
3261                                 headery= HEADERY;
3262                                 areaminy= AREAMINY;
3263                         }
3264                         else {
3265                                 headery= 0;
3266                                 areaminy= AREAMINY; /*areaminy= EDGEWIDTH;*/
3267                         }
3268
3269                         if(sa->v1->flag && sa->v4->flag) {
3270                                 int y1;
3271                                 if(sa->v2->vec.y==G.curscreen->sizey-1) /* top edge */
3272                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
3273                                 else 
3274                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
3275                                 bigger= MIN2(bigger, y1);
3276                         }
3277                         else if(sa->v2->flag && sa->v3->flag) {
3278                                 int y1;
3279                                 if(sa->v1->vec.y==0)    /* bottom edge */
3280                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
3281                                 else
3282                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
3283                                 smaller= MIN2(smaller, y1);
3284                         }
3285                 }
3286                 else {  /* if left or right edge selected, test width */
3287                         if(sa->v1->flag && sa->v2->flag) {
3288                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
3289                                 bigger= MIN2(bigger, x1);
3290                         }
3291                         else if(sa->v3->flag && sa->v4->flag) {
3292                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
3293                                 smaller= MIN2(smaller, x1);
3294                         }
3295                 }
3296                 sa= sa->next;
3297         }
3298         
3299         mywinset(G.curscreen->mainwin);
3300
3301         glReadBuffer(GL_FRONT);
3302         glDrawBuffer(GL_FRONT);
3303
3304         doit= delta= 0;
3305         getmouseco_sc(mvalo);
3306         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3307
3308         while (!doit) {
3309                 short val;
3310                 unsigned short event= extern_qread(&val);
3311                 
3312                 if (event==MOUSEY) {
3313                         short mval[2];
3314                         
3315                         getmouseco_sc(mval);
3316                         
3317                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3318
3319                         delta= (dir=='h')?(mval[1]-mvalo[1]):(mval[0]-mvalo[0]);
3320                         delta= CLAMPIS(delta, -smaller, bigger);
3321                         
3322                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3323                         glFlush();
3324                 } 
3325                 else if (event==LEFTMOUSE) {
3326                         doit= 1;
3327                 } 
3328                 else if (val) {
3329                         if (ELEM(event, ESCKEY, RIGHTMOUSE))
3330                                 doit= -1;
3331                         else if (ELEM(event, SPACEKEY, RETKEY))
3332                                 doit= 1;
3333                 }
3334                 else BIF_wait_for_statechange();
3335                 
3336         }
3337         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3338         glFlush();
3339         glReadBuffer(GL_BACK);
3340         glDrawBuffer(GL_BACK);
3341
3342         if (doit==1) {
3343                 for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
3344                         if (v1->flag) {
3345                                         /* that way a nice AREAGRID  */
3346                                 if((dir=='v') && v1->vec.x>0 && v1->vec.x<G.curscreen->sizex-1) {
3347                                         v1->vec.x+= delta;
3348