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