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