Blender V2.61 - r43446
|
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