Blender V2.61 - r43446

wm_window.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2007 Blender Foundation but based 
00019  * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV
00020  * All rights reserved.
00021  *
00022  * Contributor(s): Blender Foundation, 2008
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <math.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 
00037 #include "DNA_listBase.h"   
00038 #include "DNA_screen_types.h"
00039 #include "DNA_windowmanager_types.h"
00040 #include "RNA_access.h"
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "GHOST_C-api.h"
00045 
00046 #include "BLI_blenlib.h"
00047 #include "BLI_utildefines.h"
00048 
00049 #include "BLF_translation.h"
00050 
00051 #include "BKE_blender.h"
00052 #include "BKE_context.h"
00053 #include "BKE_library.h"
00054 #include "BKE_global.h"
00055 #include "BKE_main.h"
00056 
00057 
00058 #include "BIF_gl.h"
00059 
00060 #include "WM_api.h"
00061 #include "WM_types.h"
00062 #include "wm.h"
00063 #include "wm_draw.h"
00064 #include "wm_window.h"
00065 #include "wm_subwindow.h"
00066 #include "wm_event_system.h"
00067 
00068 #include "ED_screen.h"
00069 #include "ED_fileselect.h"
00070 
00071 #include "PIL_time.h"
00072 
00073 #include "GPU_draw.h"
00074 #include "GPU_extensions.h"
00075 
00076 #include "UI_interface.h"
00077 
00078 /* the global to talk to ghost */
00079 static GHOST_SystemHandle g_system= NULL;
00080 
00081 /* set by commandline */
00082 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, initialstate= GHOST_kWindowStateNormal;
00083 static unsigned short useprefsize= 0;
00084 
00085 /* ******** win open & close ************ */
00086 
00087 /* XXX this one should correctly check for apple top header...
00088  done for Cocoa : returns window contents (and not frame) max size*/
00089 void wm_get_screensize(int *width_r, int *height_r)
00090 {
00091     unsigned int uiwidth;
00092     unsigned int uiheight;
00093     
00094     GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
00095     *width_r= uiwidth;
00096     *height_r= uiheight;
00097 }
00098 
00099 /* keeps offset and size within monitor bounds */
00100 /* XXX solve dual screen... */
00101 static void wm_window_check_position(rcti *rect)
00102 {
00103     int width, height, d;
00104     
00105     wm_get_screensize(&width, &height);
00106     
00107 #if defined(__APPLE__) && !defined(GHOST_COCOA)
00108     height -= 70;
00109 #endif
00110     
00111     if(rect->xmin < 0) {
00112         rect->xmax -= rect->xmin;
00113         rect->xmin  = 0;
00114     }
00115     if(rect->ymin < 0) {
00116         rect->ymax -= rect->ymin;
00117         rect->ymin  = 0;
00118     }
00119     if(rect->xmax > width) {
00120         d= rect->xmax - width;
00121         rect->xmax -= d;
00122         rect->xmin -= d;
00123     }
00124     if(rect->ymax > height) {
00125         d= rect->ymax - height;
00126         rect->ymax -= d;
00127         rect->ymin -= d;
00128     }
00129     
00130     if(rect->xmin < 0) rect->xmin= 0;
00131     if(rect->ymin < 0) rect->ymin= 0;
00132 }
00133 
00134 
00135 static void wm_ghostwindow_destroy(wmWindow *win) 
00136 {
00137     if(win->ghostwin) {
00138         GHOST_DisposeWindow(g_system, win->ghostwin);
00139         win->ghostwin= NULL;
00140     }
00141 }
00142 
00143 /* including window itself, C can be NULL. 
00144    ED_screen_exit should have been called */
00145 void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
00146 {
00147     wmTimer *wt, *wtnext;
00148     
00149     /* update context */
00150     if(C) {
00151         WM_event_remove_handlers(C, &win->handlers);
00152         WM_event_remove_handlers(C, &win->modalhandlers);
00153 
00154         if(CTX_wm_window(C)==win)
00155             CTX_wm_window_set(C, NULL);
00156     }   
00157 
00158     /* always set drawable and active to NULL, prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
00159     wm->windrawable= NULL;
00160     wm->winactive= NULL;
00161 
00162     /* end running jobs, a job end also removes its timer */
00163     for(wt= wm->timers.first; wt; wt= wtnext) {
00164         wtnext= wt->next;
00165         if(wt->win==win && wt->event_type==TIMERJOBS)
00166             wm_jobs_timer_ended(wm, wt);
00167     }
00168     
00169     /* timer removing, need to call this api function */
00170     for(wt= wm->timers.first; wt; wt=wtnext) {
00171         wtnext= wt->next;
00172         if(wt->win==win)
00173             WM_event_remove_timer(wm, win, wt);
00174     }
00175 
00176     if(win->eventstate) MEM_freeN(win->eventstate);
00177     
00178     wm_event_free_all(win);
00179     wm_subwindows_free(win);
00180     
00181     if(win->drawdata)
00182         MEM_freeN(win->drawdata);
00183     
00184     wm_ghostwindow_destroy(win);
00185     
00186     MEM_freeN(win);
00187 }
00188 
00189 static int find_free_winid(wmWindowManager *wm)
00190 {
00191     wmWindow *win;
00192     int id= 1;
00193     
00194     for(win= wm->windows.first; win; win= win->next)
00195         if(id <= win->winid)
00196             id= win->winid+1;
00197     
00198     return id;
00199 }
00200 
00201 /* dont change context itself */
00202 wmWindow *wm_window_new(bContext *C)
00203 {
00204     wmWindowManager *wm= CTX_wm_manager(C);
00205     wmWindow *win= MEM_callocN(sizeof(wmWindow), "window");
00206     
00207     BLI_addtail(&wm->windows, win);
00208     win->winid= find_free_winid(wm);
00209 
00210     return win;
00211 }
00212 
00213 
00214 /* part of wm_window.c api */
00215 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
00216 {
00217     wmWindow *win= wm_window_new(C);
00218     
00219     win->posx= winorig->posx+10;
00220     win->posy= winorig->posy;
00221     win->sizex= winorig->sizex;
00222     win->sizey= winorig->sizey;
00223     
00224     /* duplicate assigns to window */
00225     win->screen= ED_screen_duplicate(win, winorig->screen);
00226     BLI_strncpy(win->screenname, win->screen->id.name+2, sizeof(win->screenname));
00227     win->screen->winid= win->winid;
00228 
00229     win->screen->do_refresh= 1;
00230     win->screen->do_draw= 1;
00231 
00232     win->drawmethod= -1;
00233     win->drawdata= NULL;
00234     
00235     return win;
00236 }
00237 
00238 /* this is event from ghost, or exit-blender op */
00239 void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
00240 {
00241     bScreen *screen= win->screen;
00242     
00243     BLI_remlink(&wm->windows, win);
00244     
00245     wm_draw_window_clear(win);
00246     CTX_wm_window_set(C, win);  /* needed by handlers */
00247     WM_event_remove_handlers(C, &win->handlers);
00248     WM_event_remove_handlers(C, &win->modalhandlers);
00249     ED_screen_exit(C, win, win->screen); 
00250     
00251     wm_window_free(C, wm, win);
00252     
00253     /* if temp screen, delete it after window free (it stops jobs that can access it) */
00254     if(screen->temp) {
00255         Main *bmain= CTX_data_main(C);
00256         free_libblock(&bmain->screen, screen);
00257     }
00258     
00259     /* check remaining windows */
00260     if(wm->windows.first) {
00261         for(win= wm->windows.first; win; win= win->next)
00262             if(win->screen->temp == 0)
00263                 break;
00264         /* in this case we close all */
00265         if(win==NULL)
00266             WM_exit(C);
00267     }
00268     else
00269         WM_exit(C);
00270 }
00271 
00272 void wm_window_title(wmWindowManager *wm, wmWindow *win)
00273 {
00274     /* handle the 'temp' window, only set title when not set before */
00275     if(win->screen && win->screen->temp) {
00276         char *title= GHOST_GetTitle(win->ghostwin);
00277         if(title==NULL || title[0]==0)
00278             GHOST_SetTitle(win->ghostwin, "Blender");
00279     }
00280     else {
00281         
00282         /* this is set to 1 if you don't have startup.blend open */
00283         if(G.save_over && G.main->name[0]) {
00284             char str[sizeof(G.main->name) + 12];
00285             BLI_snprintf(str, sizeof(str), "Blender%s [%s]", wm->file_saved ? "":"*", G.main->name);
00286             GHOST_SetTitle(win->ghostwin, str);
00287         }
00288         else
00289             GHOST_SetTitle(win->ghostwin, "Blender");
00290 
00291         /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
00292          and to give hint of unsaved changes for a user warning mechanism
00293          in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
00294         GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8)!wm->file_saved);
00295         
00296 #if defined(__APPLE__) && !defined(GHOST_COCOA)
00297         if(wm->file_saved)
00298             GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateUnModified);
00299         else
00300             GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateModified);
00301 #endif
00302     }
00303 }
00304 
00305 /* belongs to below */
00306 static void wm_window_add_ghostwindow(bContext *C, const char *title, wmWindow *win)
00307 {
00308     GHOST_WindowHandle ghostwin;
00309     int scr_w, scr_h, posy;
00310     GHOST_TWindowState initial_state;
00311 
00312     /* when there is no window open uses the initial state */
00313     if(!CTX_wm_window(C))
00314         initial_state= initialstate;
00315     else
00316         initial_state= GHOST_kWindowStateNormal;
00317     
00318     wm_get_screensize(&scr_w, &scr_h);
00319     posy= (scr_h - win->posy - win->sizey);
00320     
00321 #if defined(__APPLE__) && !defined(GHOST_COCOA)
00322     {
00323         extern int macPrefState; /* creator.c */
00324         initial_state += macPrefState;
00325     }
00326 #endif
00327     /* Disable AA for now, as GL_SELECT (used for border, lasso, ... select)
00328      doesn't work well when AA is initialized, even if not used. */
00329     ghostwin= GHOST_CreateWindow(g_system, title, 
00330                                  win->posx, posy, win->sizex, win->sizey, 
00331                                  initial_state, 
00332                                  GHOST_kDrawingContextTypeOpenGL,
00333                                  0 /* no stereo */,
00334                                  0 /* no AA */);
00335     
00336     if (ghostwin) {
00337         /* needed so we can detect the graphics card below */
00338         GPU_extensions_init();
00339         
00340         /* set the state*/
00341         GHOST_SetWindowState(ghostwin, initial_state);
00342 
00343         win->ghostwin= ghostwin;
00344         GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
00345         
00346         if(win->eventstate==NULL)
00347             win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
00348         
00349         /* until screens get drawn, make it nice grey */
00350         glClearColor(.55, .55, .55, 0.0);
00351         /* Crash on OSS ATI: bugs.launchpad.net/ubuntu/+source/mesa/+bug/656100 */
00352         if(!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
00353             glClear(GL_COLOR_BUFFER_BIT);
00354         }
00355 
00356         wm_window_swap_buffers(win);
00357         
00358         //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
00359         
00360         /* standard state vars for window */
00361         glEnable(GL_SCISSOR_TEST);
00362         
00363         GPU_state_init();
00364     }
00365 }
00366 
00367 /* for wmWindows without ghostwin, open these and clear */
00368 /* window size is read from window, if 0 it uses prefsize */
00369 /* called in WM_check, also inits stuff after file read */
00370 void wm_window_add_ghostwindows(bContext* C, wmWindowManager *wm)
00371 {
00372     wmKeyMap *keymap;
00373     wmWindow *win;
00374     
00375     /* no commandline prefsize? then we set this.
00376      * Note that these values will be used only
00377      * when there is no startup.blend yet.
00378      */
00379     if (!prefsizx) {
00380         wm_get_screensize(&prefsizx, &prefsizy);
00381         
00382 #if defined(__APPLE__) && !defined(GHOST_COCOA)
00383 //Cocoa provides functions to get correct max window size
00384         {
00385             extern void wm_set_apple_prefsize(int, int);    /* wm_apple.c */
00386             
00387             wm_set_apple_prefsize(prefsizx, prefsizy);
00388         }
00389 #else
00390         prefstax= 0;
00391         prefstay= 0;
00392         
00393 #endif
00394     }
00395     
00396     for(win= wm->windows.first; win; win= win->next) {
00397         if(win->ghostwin==NULL) {
00398             if(win->sizex==0 || useprefsize) {
00399                 win->posx= prefstax;
00400                 win->posy= prefstay;
00401                 win->sizex= prefsizx;
00402                 win->sizey= prefsizy;
00403                 win->windowstate= initialstate;
00404                 useprefsize= 0;
00405             }
00406             wm_window_add_ghostwindow(C, "Blender", win);
00407         }
00408         /* happens after fileread */
00409         if(win->eventstate==NULL)
00410             win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state");
00411 
00412         /* add keymap handlers (1 handler for all keys in map!) */
00413         keymap= WM_keymap_find(wm->defaultconf, "Window", 0, 0);
00414         WM_event_add_keymap_handler(&win->handlers, keymap);
00415         
00416         keymap= WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
00417         WM_event_add_keymap_handler(&win->handlers, keymap);
00418 
00419         keymap= WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
00420         WM_event_add_keymap_handler(&win->modalhandlers, keymap);
00421         
00422         /* add drop boxes */
00423         {
00424             ListBase *lb= WM_dropboxmap_find("Window", 0, 0);
00425             WM_event_add_dropbox_handler(&win->handlers, lb);
00426         }
00427         wm_window_title(wm, win);
00428     }
00429 }
00430 
00431 /* new window, no screen yet, but we open ghostwindow for it */
00432 /* also gets the window level handlers */
00433 /* area-rip calls this */
00434 wmWindow *WM_window_open(bContext *C, rcti *rect)
00435 {
00436     wmWindow *win= wm_window_new(C);
00437     
00438     win->posx= rect->xmin;
00439     win->posy= rect->ymin;
00440     win->sizex= rect->xmax - rect->xmin;
00441     win->sizey= rect->ymax - rect->ymin;
00442 
00443     win->drawmethod= -1;
00444     win->drawdata= NULL;
00445     
00446     WM_check(C);
00447     
00448     return win;
00449 }
00450 
00451 /* uses screen->temp tag to define what to do, currently it limits
00452    to only one "temp" window for render out, preferences, filewindow, etc */
00453 /* type is #define in WM_api.h */
00454 
00455 void WM_window_open_temp(bContext *C, rcti *position, int type)
00456 {
00457     wmWindow *win;
00458     ScrArea *sa;
00459     
00460     /* changes rect to fit within desktop */
00461     wm_window_check_position(position);
00462     
00463     /* test if we have a temp screen already */
00464     for(win= CTX_wm_manager(C)->windows.first; win; win= win->next)
00465         if(win->screen->temp)
00466             break;
00467     
00468     /* add new window? */
00469     if(win==NULL) {
00470         win= wm_window_new(C);
00471         
00472         win->posx= position->xmin;
00473         win->posy= position->ymin;
00474     }
00475     
00476     win->sizex= position->xmax - position->xmin;
00477     win->sizey= position->ymax - position->ymin;
00478     
00479     if(win->ghostwin) {
00480         wm_window_set_size(win, win->sizex, win->sizey) ;
00481         wm_window_raise(win);
00482     }
00483     
00484     /* add new screen? */
00485     if(win->screen==NULL)
00486         win->screen= ED_screen_add(win, CTX_data_scene(C), "temp");
00487     win->screen->temp = 1; 
00488     
00489     /* make window active, and validate/resize */
00490     CTX_wm_window_set(C, win);
00491     WM_check(C);
00492     
00493     /* ensure it shows the right spacetype editor */
00494     sa= win->screen->areabase.first;
00495     CTX_wm_area_set(C, sa);
00496     
00497     if(type==WM_WINDOW_RENDER) {
00498         ED_area_newspace(C, sa, SPACE_IMAGE);
00499     }
00500     else {
00501         ED_area_newspace(C, sa, SPACE_USERPREF);
00502     }
00503     
00504     ED_screen_set(C, win->screen);
00505     
00506     if(sa->spacetype==SPACE_IMAGE)
00507         GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
00508     else if(ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
00509         GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences"));
00510     else if(sa->spacetype==SPACE_FILE)
00511         GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View"));
00512     else
00513         GHOST_SetTitle(win->ghostwin, "Blender");
00514 }
00515 
00516 
00517 /* ****************** Operators ****************** */
00518 
00519 /* operator callback */
00520 int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
00521 {
00522     wm_window_copy(C, CTX_wm_window(C));
00523     WM_check(C);
00524     
00525     WM_event_add_notifier(C, NC_WINDOW|NA_ADDED, NULL);
00526     
00527     return OPERATOR_FINISHED;
00528 }
00529 
00530 
00531 /* fullscreen operator callback */
00532 int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
00533 {
00534     wmWindow *window= CTX_wm_window(C);
00535     GHOST_TWindowState state;
00536 
00537     if(G.background)
00538         return OPERATOR_CANCELLED;
00539 
00540     state= GHOST_GetWindowState(window->ghostwin);
00541     if(state!=GHOST_kWindowStateFullScreen)
00542         GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen);
00543     else
00544         GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
00545 
00546     return OPERATOR_FINISHED;
00547     
00548 }
00549 
00550 
00551 /* ************ events *************** */
00552 
00553 typedef enum
00554 {
00555     SHIFT = 's',
00556     CONTROL = 'c',
00557     ALT = 'a',
00558     OS = 'C'
00559 } modifierKeyType;
00560 
00561 /* check if specified modifier key type is pressed */
00562 static int query_qual(modifierKeyType qual) 
00563 {
00564     GHOST_TModifierKeyMask left, right;
00565     int val= 0;
00566     
00567     switch(qual) {
00568         case SHIFT:
00569             left= GHOST_kModifierKeyLeftShift;
00570             right= GHOST_kModifierKeyRightShift;
00571             break;
00572         case CONTROL:
00573             left= GHOST_kModifierKeyLeftControl;
00574             right= GHOST_kModifierKeyRightControl;
00575             break;
00576         case OS:
00577             left= right= GHOST_kModifierKeyOS;
00578             break;
00579         case ALT:
00580         default:
00581             left= GHOST_kModifierKeyLeftAlt;
00582             right= GHOST_kModifierKeyRightAlt;
00583             break;
00584     }
00585     
00586     GHOST_GetModifierKeyState(g_system, left, &val);
00587     if (!val)
00588         GHOST_GetModifierKeyState(g_system, right, &val);
00589     
00590     return val;
00591 }
00592 
00593 void wm_window_make_drawable(bContext *C, wmWindow *win) 
00594 {
00595     wmWindowManager *wm= CTX_wm_manager(C);
00596 
00597     if (win != wm->windrawable && win->ghostwin) {
00598 //      win->lmbut= 0;  /* keeps hanging when mousepressed while other window opened */
00599         
00600         wm->windrawable= win;
00601         if(G.f & G_DEBUG) printf("set drawable %d\n", win->winid);
00602         GHOST_ActivateWindowDrawingContext(win->ghostwin);
00603     }
00604 }
00605 
00606 /* called by ghost, here we handle events for windows themselves or send to event system */
00607 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) 
00608 {
00609     bContext *C= private;
00610     wmWindowManager *wm= CTX_wm_manager(C);
00611     GHOST_TEventType type= GHOST_GetEventType(evt);
00612     int time= GHOST_GetEventTime(evt);
00613     
00614     if (type == GHOST_kEventQuit) {
00615         WM_exit(C);
00616     } else {
00617         GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
00618         GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
00619         wmWindow *win;
00620         
00621         if (!ghostwin) {
00622             // XXX - should be checked, why are we getting an event here, and
00623             //  what is it?
00624             puts("<!> event has no window");
00625             return 1;
00626         } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
00627             // XXX - should be checked, why are we getting an event here, and
00628             //  what is it?
00629             puts("<!> event has invalid window");           
00630             return 1;
00631         } else {
00632             win= GHOST_GetWindowUserData(ghostwin);
00633         }
00634         
00635         switch(type) {
00636             case GHOST_kEventWindowDeactivate:
00637                 wm_event_add_ghostevent(wm, win, type, time, data);
00638                 win->active= 0; /* XXX */
00639                 break;
00640             case GHOST_kEventWindowActivate: 
00641             {
00642                 GHOST_TEventKeyData kdata;
00643                 int cx, cy, wx, wy;
00644                 
00645                 wm->winactive= win; /* no context change! c->wm->windrawable is drawable, or for area queues */
00646                 
00647                 win->active= 1;
00648 //              window_handle(win, INPUTCHANGE, win->active);
00649                 
00650                 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
00651                 kdata.ascii= '\0';
00652                 kdata.utf8_buf[0]= '\0';
00653                 if (win->eventstate->shift && !query_qual(SHIFT)) {
00654                     kdata.key= GHOST_kKeyLeftShift;
00655                     wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
00656                 }
00657                 if (win->eventstate->ctrl && !query_qual(CONTROL)) {
00658                     kdata.key= GHOST_kKeyLeftControl;
00659                     wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
00660                 }
00661                 if (win->eventstate->alt && !query_qual(ALT)) {
00662                     kdata.key= GHOST_kKeyLeftAlt;
00663                     wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
00664                 }
00665                 if (win->eventstate->oskey && !query_qual(OS)) {
00666                     kdata.key= GHOST_kKeyOS;
00667                     wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
00668                 }
00669                 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */
00670                 win->eventstate->keymodifier= 0;
00671                 
00672                 /* entering window, update mouse pos. but no event */
00673                 GHOST_GetCursorPosition(g_system, &wx, &wy);
00674                 
00675                 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
00676                 win->eventstate->x= cx;
00677                 win->eventstate->y= (win->sizey-1) - cy;
00678                 
00679                 win->addmousemove= 1;   /* enables highlighted buttons */
00680                 
00681                 wm_window_make_drawable(C, win);
00682                 break;
00683             }
00684             case GHOST_kEventWindowClose: {
00685                 wm_window_close(C, wm, win);
00686                 break;
00687             }
00688             case GHOST_kEventWindowUpdate: {
00689                 if(G.f & G_DEBUG) printf("ghost redraw\n");
00690                 
00691                 wm_window_make_drawable(C, win);
00692                 WM_event_add_notifier(C, NC_WINDOW, NULL);
00693 
00694                 break;
00695             }
00696             case GHOST_kEventWindowSize:
00697             case GHOST_kEventWindowMove: {
00698                 GHOST_TWindowState state;
00699                 state = GHOST_GetWindowState(win->ghostwin);
00700 
00701                  /* win32: gives undefined window size when minimized */
00702                 if(state!=GHOST_kWindowStateMinimized) {
00703                     GHOST_RectangleHandle client_rect;
00704                     int l, t, r, b, scr_w, scr_h;
00705                     int sizex, sizey, posx, posy;
00706                     
00707                     client_rect= GHOST_GetClientBounds(win->ghostwin);
00708                     GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
00709                     
00710                     GHOST_DisposeRectangle(client_rect);
00711                     
00712                     wm_get_screensize(&scr_w, &scr_h);
00713                     sizex= r-l;
00714                     sizey= b-t;
00715                     posx= l;
00716                     posy= scr_h - t - win->sizey;
00717 
00718                     /*
00719                      * Ghost sometimes send size or move events when the window hasn't changed.
00720                      * One case of this is using compiz on linux. To alleviate the problem
00721                      * we ignore all such event here.
00722                      * 
00723                      * It might be good to eventually do that at Ghost level, but that is for 
00724                      * another time.
00725                      */
00726                     if (win->sizex != sizex ||
00727                             win->sizey != sizey ||
00728                             win->posx != posx ||
00729                             win->posy != posy)
00730                     {
00731                         win->sizex= sizex;
00732                         win->sizey= sizey;
00733                         win->posx= posx;
00734                         win->posy= posy;
00735 
00736                         /* debug prints */
00737                         if(0) {
00738                             state = GHOST_GetWindowState(win->ghostwin);
00739     
00740                             if(state==GHOST_kWindowStateNormal) {
00741                                 if(G.f & G_DEBUG) printf("window state: normal\n");
00742                             }
00743                             else if(state==GHOST_kWindowStateMinimized) {
00744                                 if(G.f & G_DEBUG) printf("window state: minimized\n");
00745                             }
00746                             else if(state==GHOST_kWindowStateMaximized) {
00747                                 if(G.f & G_DEBUG) printf("window state: maximized\n");
00748                             }
00749                             else if(state==GHOST_kWindowStateFullScreen) {
00750                                 if(G.f & G_DEBUG) printf("window state: fullscreen\n");
00751                             }
00752                             
00753                             if(type!=GHOST_kEventWindowSize) {
00754                                 if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey);
00755                             }
00756                             
00757                         }
00758                     
00759                         wm_window_make_drawable(C, win);
00760                         wm_draw_window_clear(win);
00761                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
00762                         WM_event_add_notifier(C, NC_WINDOW|NA_EDITED, NULL);
00763                     }
00764                 }
00765                 break;
00766             }
00767                 
00768             case GHOST_kEventOpenMainFile:
00769             {
00770                 PointerRNA props_ptr;
00771                 wmWindow *oldWindow;
00772                 char *path = GHOST_GetEventData(evt);
00773                 
00774                 if (path) {
00775                     /* operator needs a valid window in context, ensures
00776                      it is correctly set */
00777                     oldWindow = CTX_wm_window(C);
00778                     CTX_wm_window_set(C, win);
00779                     
00780                     WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile");
00781                     RNA_string_set(&props_ptr, "filepath", path);
00782                     WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr);
00783                     WM_operator_properties_free(&props_ptr);
00784                     
00785                     CTX_wm_window_set(C, oldWindow);
00786                 }
00787                 break;
00788             }
00789             case GHOST_kEventDraggingDropDone:
00790             {
00791                 wmEvent event;
00792                 GHOST_TEventDragnDropData *ddd= GHOST_GetEventData(evt);
00793                 int cx, cy, wx, wy;
00794                 
00795                 /* entering window, update mouse pos */
00796                 GHOST_GetCursorPosition(g_system, &wx, &wy);
00797                 
00798                 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
00799                 win->eventstate->x= cx;
00800                 win->eventstate->y= (win->sizey-1) - cy;
00801                 
00802                 event= *(win->eventstate);  /* copy last state, like mouse coords */
00803                 
00804                 // activate region
00805                 event.type= MOUSEMOVE;
00806                 event.prevx= event.x;
00807                 event.prevy= event.y;
00808                 
00809                 wm->winactive= win; /* no context change! c->wm->windrawable is drawable, or for area queues */
00810                 win->active= 1;
00811                 
00812                 wm_event_add(win, &event);
00813                 
00814                 
00815                 /* make blender drop event with custom data pointing to wm drags */
00816                 event.type= EVT_DROP;
00817                 event.val= KM_RELEASE;
00818                 event.custom= EVT_DATA_LISTBASE;
00819                 event.customdata= &wm->drags;
00820                 event.customdatafree= 1;
00821                 
00822                 wm_event_add(win, &event);
00823                 
00824                 /* printf("Drop detected\n"); */
00825                 
00826                 /* add drag data to wm for paths: */
00827                 
00828                 if(ddd->dataType == GHOST_kDragnDropTypeFilenames) {
00829                     GHOST_TStringArray *stra= ddd->data;
00830                     int a, icon;
00831                     
00832                     for(a=0; a<stra->count; a++) {
00833                         printf("drop file %s\n", stra->strings[a]);
00834                         /* try to get icon type from extension */
00835                         icon= ED_file_extension_icon((char *)stra->strings[a]);
00836                         
00837                         WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0);
00838                         /* void poin should point to string, it makes a copy */
00839                         break; // only one drop element supported now 
00840                     }
00841                 }
00842                 
00843                 
00844                 
00845                 break;
00846             }
00847             
00848             default:
00849                 wm_event_add_ghostevent(wm, win, type, time, data);
00850                 break;
00851         }
00852 
00853     }
00854     return 1;
00855 }
00856 
00857 
00858 /* This timer system only gives maximum 1 timer event per redraw cycle,
00859    to prevent queues to get overloaded. 
00860    Timer handlers should check for delta to decide if they just
00861    update, or follow real time.
00862    Timer handlers can also set duration to match frames passed
00863 */
00864 static int wm_window_timer(const bContext *C)
00865 {
00866     wmWindowManager *wm= CTX_wm_manager(C);
00867     wmTimer *wt, *wtnext;
00868     wmWindow *win;
00869     double time= PIL_check_seconds_timer();
00870     int retval= 0;
00871     
00872     for(wt= wm->timers.first; wt; wt= wtnext) {
00873         wtnext= wt->next; /* in case timer gets removed */
00874         win= wt->win;
00875 
00876         if(wt->sleep==0) {
00877             if(time > wt->ntime) {
00878                 wt->delta= time - wt->ltime;
00879                 wt->duration += wt->delta;
00880                 wt->ltime= time;
00881                 wt->ntime= wt->stime + wt->timestep*ceil(wt->duration/wt->timestep);
00882 
00883                 if(wt->event_type == TIMERJOBS)
00884                     wm_jobs_timer(C, wm, wt);
00885                 else if(wt->event_type == TIMERAUTOSAVE)
00886                     wm_autosave_timer(C, wm, wt);
00887                 else if(win) {
00888                     wmEvent event= *(win->eventstate);
00889                     
00890                     event.type= wt->event_type;
00891                     event.custom= EVT_DATA_TIMER;
00892                     event.customdata= wt;
00893                     wm_event_add(win, &event);
00894 
00895                     retval= 1;
00896                 }
00897             }
00898         }
00899     }
00900     return retval;
00901 }
00902 
00903 void wm_window_process_events(const bContext *C) 
00904 {
00905     int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
00906     
00907     if(hasevent)
00908         GHOST_DispatchEvents(g_system);
00909     
00910     hasevent |= wm_window_timer(C);
00911 
00912     /* no event, we sleep 5 milliseconds */
00913     if(hasevent==0)
00914         PIL_sleep_ms(5);
00915 }
00916 
00917 void wm_window_process_events_nosleep(void) 
00918 {
00919     if(GHOST_ProcessEvents(g_system, 0))
00920         GHOST_DispatchEvents(g_system);
00921 }
00922 
00923 /* exported as handle callback to bke blender.c */
00924 void wm_window_testbreak(void)
00925 {
00926     static double ltime= 0;
00927     double curtime= PIL_check_seconds_timer();
00928     
00929     /* only check for breaks every 50 milliseconds
00930         * if we get called more often.
00931         */
00932     if ((curtime-ltime)>.05) {
00933         int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
00934         
00935         if(hasevent)
00936             GHOST_DispatchEvents(g_system);
00937         
00938         ltime= curtime;
00939     }
00940 }
00941 
00942 /* **************** init ********************** */
00943 
00944 void wm_ghost_init(bContext *C)
00945 {
00946     if (!g_system) {
00947         GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(ghost_event_proc, C);
00948         
00949         g_system= GHOST_CreateSystem();
00950         GHOST_AddEventConsumer(g_system, consumer);
00951     }   
00952 }
00953 
00954 void wm_ghost_exit(void)
00955 {
00956     if(g_system)
00957         GHOST_DisposeSystem(g_system);
00958 
00959     g_system= NULL;
00960 }
00961 
00962 /* **************** timer ********************** */
00963 
00964 /* to (de)activate running timers temporary */
00965 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, int dosleep)
00966 {
00967     wmTimer *wt;
00968     
00969     for(wt= wm->timers.first; wt; wt= wt->next)
00970         if(wt==timer)
00971             break;
00972 
00973     if(wt)
00974         wt->sleep= dosleep;
00975 }
00976 
00977 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
00978 {
00979     wmTimer *wt= MEM_callocN(sizeof(wmTimer), "window timer");
00980     
00981     wt->event_type= event_type;
00982     wt->ltime= PIL_check_seconds_timer();
00983     wt->ntime= wt->ltime + timestep;
00984     wt->stime= wt->ltime;
00985     wt->timestep= timestep;
00986     wt->win= win;
00987     
00988     BLI_addtail(&wm->timers, wt);
00989     
00990     return wt;
00991 }
00992 
00993 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
00994 {
00995     wmTimer *wt;
00996     
00997     /* extra security check */
00998     for(wt= wm->timers.first; wt; wt= wt->next)
00999         if(wt==timer)
01000             break;
01001     if(wt) {
01002         if(wm->reports.reporttimer == wt)
01003             wm->reports.reporttimer= NULL;
01004         
01005         BLI_remlink(&wm->timers, wt);
01006         if(wt->customdata)
01007             MEM_freeN(wt->customdata);
01008         MEM_freeN(wt);
01009     }
01010 }
01011 
01012 /* ******************* clipboard **************** */
01013 
01014 char *WM_clipboard_text_get(int selection)
01015 {
01016     char *p, *p2, *buf, *newbuf;
01017 
01018     if(G.background)
01019         return NULL;
01020 
01021     buf= (char*)GHOST_getClipboard(selection);
01022     if(!buf)
01023         return NULL;
01024     
01025     /* always convert from \r\n to \n */
01026     newbuf= MEM_callocN(strlen(buf)+1, "WM_clipboard_text_get");
01027 
01028     for(p= buf, p2= newbuf; *p; p++) {
01029         if(*p != '\r')
01030             *(p2++)= *p;
01031     }
01032     *p2= '\0';
01033 
01034     free(buf); /* ghost uses regular malloc */
01035     
01036     return newbuf;
01037 }
01038 
01039 void WM_clipboard_text_set(char *buf, int selection)
01040 {
01041     if(!G.background) {
01042 #ifdef _WIN32
01043         /* do conversion from \n to \r\n on Windows */
01044         char *p, *p2, *newbuf;
01045         int newlen= 0;
01046         
01047         for(p= buf; *p; p++) {
01048             if(*p == '\n')
01049                 newlen += 2;
01050             else
01051                 newlen++;
01052         }
01053         
01054         newbuf= MEM_callocN(newlen+1, "WM_clipboard_text_set");
01055     
01056         for(p= buf, p2= newbuf; *p; p++, p2++) {
01057             if(*p == '\n') { 
01058                 *(p2++)= '\r'; *p2= '\n';
01059             }
01060             else *p2= *p;
01061         }
01062         *p2= '\0';
01063     
01064         GHOST_putClipboard((GHOST_TInt8*)newbuf, selection);
01065         MEM_freeN(newbuf);
01066 #else
01067         GHOST_putClipboard((GHOST_TInt8*)buf, selection);
01068 #endif
01069     }
01070 }
01071 
01072 /* ******************* progress bar **************** */
01073 
01074 void WM_progress_set(wmWindow *win, float progress)
01075 {
01076     GHOST_SetProgressBar(win->ghostwin, progress);
01077 }
01078 
01079 void WM_progress_clear(wmWindow *win)
01080 {
01081     GHOST_EndProgressBar(win->ghostwin);
01082 }
01083 
01084 /* ************************************ */
01085 
01086 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) 
01087 {
01088     *posx_r= win->posx;
01089     *posy_r= win->posy;
01090 }
01091 
01092 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r) 
01093 {
01094     *width_r= win->sizex;
01095     *height_r= win->sizey;
01096 }
01097 
01098 /* exceptional case: - splash is called before events are processed
01099  * this means we dont actually know the window size so get this from GHOST */
01100 void wm_window_get_size_ghost(wmWindow *win, int *width_r, int *height_r)
01101 {
01102     GHOST_RectangleHandle bounds= GHOST_GetClientBounds(win->ghostwin);
01103     *width_r= GHOST_GetWidthRectangle(bounds);
01104     *height_r= GHOST_GetHeightRectangle(bounds);
01105     
01106     GHOST_DisposeRectangle(bounds);
01107 }
01108 
01109 void wm_window_set_size(wmWindow *win, int width, int height) 
01110 {
01111     GHOST_SetClientSize(win->ghostwin, width, height);
01112 }
01113 
01114 void wm_window_lower(wmWindow *win) 
01115 {
01116     GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
01117 }
01118 
01119 void wm_window_raise(wmWindow *win) 
01120 {
01121     GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
01122 }
01123 
01124 void wm_window_swap_buffers(wmWindow *win)
01125 {
01126     
01127 #ifdef WIN32
01128     glDisable(GL_SCISSOR_TEST);
01129     GHOST_SwapWindowBuffers(win->ghostwin);
01130     glEnable(GL_SCISSOR_TEST);
01131 #else
01132     GHOST_SwapWindowBuffers(win->ghostwin);
01133 #endif
01134 }
01135 
01136 void wm_get_cursor_position(wmWindow *win, int *x, int *y)
01137 {
01138     GHOST_GetCursorPosition(g_system, x, y);
01139     GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
01140     *y = (win->sizey-1) - *y;
01141 }
01142 
01143 /* ******************* exported api ***************** */
01144 
01145 
01146 /* called whem no ghost system was initialized */
01147 void WM_setprefsize(int stax, int stay, int sizx, int sizy)
01148 {
01149     prefstax= stax;
01150     prefstay= stay;
01151     prefsizx= sizx;
01152     prefsizy= sizy;
01153     useprefsize= 1;
01154 }
01155 
01156 /* for borderless and border windows set from command-line */
01157 void WM_setinitialstate_fullscreen(void)
01158 {
01159     initialstate= GHOST_kWindowStateFullScreen;
01160 }
01161 
01162 void WM_setinitialstate_normal(void)
01163 {
01164     initialstate= GHOST_kWindowStateNormal;
01165 }
01166 
01167 /* This function requires access to the GHOST_SystemHandle (g_system) */
01168 void WM_cursor_warp(wmWindow *win, int x, int y)
01169 {
01170     if (win && win->ghostwin) {
01171         int oldx=x, oldy=y;
01172 
01173         y= win->sizey -y - 1;
01174 
01175         GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
01176         GHOST_SetCursorPosition(g_system, x, y);
01177 
01178         win->eventstate->prevx= oldx;
01179         win->eventstate->prevy= oldy;
01180     }
01181 }
01182