|
Blender
V2.59
|
00001 /* 00002 * $Id: wm_window.c 38908 2011-08-02 04:28:05Z merwin $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2007 Blender Foundation but based 00021 * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV 00022 * All rights reserved. 00023 * 00024 * Contributor(s): Blender Foundation, 2008 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <math.h> 00035 #include <stdlib.h> 00036 #include <stdio.h> 00037 #include <string.h> 00038 00039 #include "DNA_listBase.h" 00040 #include "DNA_screen_types.h" 00041 #include "DNA_windowmanager_types.h" 00042 #include "RNA_access.h" 00043 00044 #include "MEM_guardedalloc.h" 00045 00046 #include "GHOST_C-api.h" 00047 00048 #include "BLI_blenlib.h" 00049 #include "BLI_utildefines.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 /* the global to talk to ghost */ 00077 static GHOST_SystemHandle g_system= NULL; 00078 00079 /* set by commandline */ 00080 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, initialstate= GHOST_kWindowStateNormal; 00081 static unsigned short useprefsize= 0; 00082 00083 /* ******** win open & close ************ */ 00084 00085 /* XXX this one should correctly check for apple top header... 00086 done for Cocoa : returns window contents (and not frame) max size*/ 00087 void wm_get_screensize(int *width_r, int *height_r) 00088 { 00089 unsigned int uiwidth; 00090 unsigned int uiheight; 00091 00092 GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight); 00093 *width_r= uiwidth; 00094 *height_r= uiheight; 00095 } 00096 00097 /* keeps offset and size within monitor bounds */ 00098 /* XXX solve dual screen... */ 00099 static void wm_window_check_position(rcti *rect) 00100 { 00101 int width, height, d; 00102 00103 wm_get_screensize(&width, &height); 00104 00105 #if defined(__APPLE__) && !defined(GHOST_COCOA) 00106 height -= 70; 00107 #endif 00108 00109 if(rect->xmin < 0) { 00110 d= rect->xmin; 00111 rect->xmax -= d; 00112 rect->xmin -= d; 00113 } 00114 if(rect->ymin < 0) { 00115 d= rect->ymin; 00116 rect->ymax -= d; 00117 rect->ymin -= d; 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, "Blender Render"); 00508 else if(ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) 00509 GHOST_SetTitle(win->ghostwin, "Blender User Preferences"); 00510 else if(sa->spacetype==SPACE_FILE) 00511 GHOST_SetTitle(win->ghostwin, "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 if (win->eventstate->shift && !query_qual(SHIFT)) { 00653 kdata.key= GHOST_kKeyLeftShift; 00654 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); 00655 } 00656 if (win->eventstate->ctrl && !query_qual(CONTROL)) { 00657 kdata.key= GHOST_kKeyLeftControl; 00658 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); 00659 } 00660 if (win->eventstate->alt && !query_qual(ALT)) { 00661 kdata.key= GHOST_kKeyLeftAlt; 00662 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); 00663 } 00664 if (win->eventstate->oskey && !query_qual(OS)) { 00665 kdata.key= GHOST_kKeyOS; 00666 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); 00667 } 00668 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */ 00669 win->eventstate->keymodifier= 0; 00670 00671 /* entering window, update mouse pos. but no event */ 00672 GHOST_GetCursorPosition(g_system, &wx, &wy); 00673 00674 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy); 00675 win->eventstate->x= cx; 00676 win->eventstate->y= (win->sizey-1) - cy; 00677 00678 win->addmousemove= 1; /* enables highlighted buttons */ 00679 00680 wm_window_make_drawable(C, win); 00681 break; 00682 } 00683 case GHOST_kEventWindowClose: { 00684 wm_window_close(C, wm, win); 00685 break; 00686 } 00687 case GHOST_kEventWindowUpdate: { 00688 if(G.f & G_DEBUG) printf("ghost redraw\n"); 00689 00690 wm_window_make_drawable(C, win); 00691 WM_event_add_notifier(C, NC_WINDOW, NULL); 00692 00693 break; 00694 } 00695 case GHOST_kEventWindowSize: 00696 case GHOST_kEventWindowMove: { 00697 GHOST_TWindowState state; 00698 state = GHOST_GetWindowState(win->ghostwin); 00699 00700 /* win32: gives undefined window size when minimized */ 00701 if(state!=GHOST_kWindowStateMinimized) { 00702 GHOST_RectangleHandle client_rect; 00703 int l, t, r, b, scr_w, scr_h; 00704 int sizex, sizey, posx, posy; 00705 00706 client_rect= GHOST_GetClientBounds(win->ghostwin); 00707 GHOST_GetRectangle(client_rect, &l, &t, &r, &b); 00708 00709 GHOST_DisposeRectangle(client_rect); 00710 00711 wm_get_screensize(&scr_w, &scr_h); 00712 sizex= r-l; 00713 sizey= b-t; 00714 posx= l; 00715 posy= scr_h - t - win->sizey; 00716 00717 /* 00718 * Ghost sometimes send size or move events when the window hasn't changed. 00719 * One case of this is using compiz on linux. To alleviate the problem 00720 * we ignore all such event here. 00721 * 00722 * It might be good to eventually do that at Ghost level, but that is for 00723 * another time. 00724 */ 00725 if (win->sizex != sizex || 00726 win->sizey != sizey || 00727 win->posx != posx || 00728 win->posy != posy) 00729 { 00730 win->sizex= sizex; 00731 win->sizey= sizey; 00732 win->posx= posx; 00733 win->posy= posy; 00734 00735 /* debug prints */ 00736 if(0) { 00737 state = GHOST_GetWindowState(win->ghostwin); 00738 00739 if(state==GHOST_kWindowStateNormal) { 00740 if(G.f & G_DEBUG) printf("window state: normal\n"); 00741 } 00742 else if(state==GHOST_kWindowStateMinimized) { 00743 if(G.f & G_DEBUG) printf("window state: minimized\n"); 00744 } 00745 else if(state==GHOST_kWindowStateMaximized) { 00746 if(G.f & G_DEBUG) printf("window state: maximized\n"); 00747 } 00748 else if(state==GHOST_kWindowStateFullScreen) { 00749 if(G.f & G_DEBUG) printf("window state: fullscreen\n"); 00750 } 00751 00752 if(type!=GHOST_kEventWindowSize) { 00753 if(G.f & G_DEBUG) printf("win move event pos %d %d size %d %d\n", win->posx, win->posy, win->sizex, win->sizey); 00754 } 00755 00756 } 00757 00758 wm_window_make_drawable(C, win); 00759 wm_draw_window_clear(win); 00760 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); 00761 WM_event_add_notifier(C, NC_WINDOW|NA_EDITED, NULL); 00762 } 00763 } 00764 break; 00765 } 00766 00767 case GHOST_kEventOpenMainFile: 00768 { 00769 PointerRNA props_ptr; 00770 wmWindow *oldWindow; 00771 char *path = GHOST_GetEventData(evt); 00772 00773 if (path) { 00774 /* operator needs a valid window in context, ensures 00775 it is correctly set */ 00776 oldWindow = CTX_wm_window(C); 00777 CTX_wm_window_set(C, win); 00778 00779 WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile"); 00780 RNA_string_set(&props_ptr, "filepath", path); 00781 WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr); 00782 WM_operator_properties_free(&props_ptr); 00783 00784 CTX_wm_window_set(C, oldWindow); 00785 } 00786 break; 00787 } 00788 case GHOST_kEventDraggingDropDone: 00789 { 00790 wmEvent event; 00791 GHOST_TEventDragnDropData *ddd= GHOST_GetEventData(evt); 00792 int cx, cy, wx, wy; 00793 00794 /* entering window, update mouse pos */ 00795 GHOST_GetCursorPosition(g_system, &wx, &wy); 00796 00797 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy); 00798 win->eventstate->x= cx; 00799 win->eventstate->y= (win->sizey-1) - cy; 00800 00801 event= *(win->eventstate); /* copy last state, like mouse coords */ 00802 00803 // activate region 00804 event.type= MOUSEMOVE; 00805 event.prevx= event.x; 00806 event.prevy= event.y; 00807 00808 wm->winactive= win; /* no context change! c->wm->windrawable is drawable, or for area queues */ 00809 win->active= 1; 00810 00811 wm_event_add(win, &event); 00812 00813 00814 /* make blender drop event with custom data pointing to wm drags */ 00815 event.type= EVT_DROP; 00816 event.val= KM_RELEASE; 00817 event.custom= EVT_DATA_LISTBASE; 00818 event.customdata= &wm->drags; 00819 event.customdatafree= 1; 00820 00821 wm_event_add(win, &event); 00822 00823 /* printf("Drop detected\n"); */ 00824 00825 /* add drag data to wm for paths: */ 00826 00827 if(ddd->dataType == GHOST_kDragnDropTypeFilenames) { 00828 GHOST_TStringArray *stra= ddd->data; 00829 int a, icon; 00830 00831 for(a=0; a<stra->count; a++) { 00832 printf("drop file %s\n", stra->strings[a]); 00833 /* try to get icon type from extension */ 00834 icon= ED_file_extension_icon((char *)stra->strings[a]); 00835 00836 WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0); 00837 /* void poin should point to string, it makes a copy */ 00838 break; // only one drop element supported now 00839 } 00840 } 00841 00842 00843 00844 break; 00845 } 00846 00847 default: 00848 wm_event_add_ghostevent(wm, win, type, time, data); 00849 break; 00850 } 00851 00852 } 00853 return 1; 00854 } 00855 00856 00857 /* This timer system only gives maximum 1 timer event per redraw cycle, 00858 to prevent queues to get overloaded. 00859 Timer handlers should check for delta to decide if they just 00860 update, or follow real time. 00861 Timer handlers can also set duration to match frames passed 00862 */ 00863 static int wm_window_timer(const bContext *C) 00864 { 00865 wmWindowManager *wm= CTX_wm_manager(C); 00866 wmTimer *wt, *wtnext; 00867 wmWindow *win; 00868 double time= PIL_check_seconds_timer(); 00869 int retval= 0; 00870 00871 for(wt= wm->timers.first; wt; wt= wtnext) { 00872 wtnext= wt->next; /* in case timer gets removed */ 00873 win= wt->win; 00874 00875 if(wt->sleep==0) { 00876 if(time > wt->ntime) { 00877 wt->delta= time - wt->ltime; 00878 wt->duration += wt->delta; 00879 wt->ltime= time; 00880 wt->ntime= wt->stime + wt->timestep*ceil(wt->duration/wt->timestep); 00881 00882 if(wt->event_type == TIMERJOBS) 00883 wm_jobs_timer(C, wm, wt); 00884 else if(wt->event_type == TIMERAUTOSAVE) 00885 wm_autosave_timer(C, wm, wt); 00886 else if(win) { 00887 wmEvent event= *(win->eventstate); 00888 00889 event.type= wt->event_type; 00890 event.custom= EVT_DATA_TIMER; 00891 event.customdata= wt; 00892 wm_event_add(win, &event); 00893 00894 retval= 1; 00895 } 00896 } 00897 } 00898 } 00899 return retval; 00900 } 00901 00902 void wm_window_process_events(const bContext *C) 00903 { 00904 int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */ 00905 00906 if(hasevent) 00907 GHOST_DispatchEvents(g_system); 00908 00909 hasevent |= wm_window_timer(C); 00910 00911 /* no event, we sleep 5 milliseconds */ 00912 if(hasevent==0) 00913 PIL_sleep_ms(5); 00914 } 00915 00916 void wm_window_process_events_nosleep(void) 00917 { 00918 if(GHOST_ProcessEvents(g_system, 0)) 00919 GHOST_DispatchEvents(g_system); 00920 } 00921 00922 /* exported as handle callback to bke blender.c */ 00923 void wm_window_testbreak(void) 00924 { 00925 static double ltime= 0; 00926 double curtime= PIL_check_seconds_timer(); 00927 00928 /* only check for breaks every 50 milliseconds 00929 * if we get called more often. 00930 */ 00931 if ((curtime-ltime)>.05) { 00932 int hasevent= GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */ 00933 00934 if(hasevent) 00935 GHOST_DispatchEvents(g_system); 00936 00937 ltime= curtime; 00938 } 00939 } 00940 00941 /* **************** init ********************** */ 00942 00943 void wm_ghost_init(bContext *C) 00944 { 00945 if (!g_system) { 00946 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(ghost_event_proc, C); 00947 00948 g_system= GHOST_CreateSystem(); 00949 GHOST_AddEventConsumer(g_system, consumer); 00950 } 00951 } 00952 00953 void wm_ghost_exit(void) 00954 { 00955 if(g_system) 00956 GHOST_DisposeSystem(g_system); 00957 00958 g_system= NULL; 00959 } 00960 00961 /* **************** timer ********************** */ 00962 00963 /* to (de)activate running timers temporary */ 00964 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, int dosleep) 00965 { 00966 wmTimer *wt; 00967 00968 for(wt= wm->timers.first; wt; wt= wt->next) 00969 if(wt==timer) 00970 break; 00971 00972 if(wt) 00973 wt->sleep= dosleep; 00974 } 00975 00976 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep) 00977 { 00978 wmTimer *wt= MEM_callocN(sizeof(wmTimer), "window timer"); 00979 00980 wt->event_type= event_type; 00981 wt->ltime= PIL_check_seconds_timer(); 00982 wt->ntime= wt->ltime + timestep; 00983 wt->stime= wt->ltime; 00984 wt->timestep= timestep; 00985 wt->win= win; 00986 00987 BLI_addtail(&wm->timers, wt); 00988 00989 return wt; 00990 } 00991 00992 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer) 00993 { 00994 wmTimer *wt; 00995 00996 /* extra security check */ 00997 for(wt= wm->timers.first; wt; wt= wt->next) 00998 if(wt==timer) 00999 break; 01000 if(wt) { 01001 if(wm->reports.reporttimer == wt) 01002 wm->reports.reporttimer= NULL; 01003 01004 BLI_remlink(&wm->timers, wt); 01005 if(wt->customdata) 01006 MEM_freeN(wt->customdata); 01007 MEM_freeN(wt); 01008 } 01009 } 01010 01011 /* ******************* clipboard **************** */ 01012 01013 char *WM_clipboard_text_get(int selection) 01014 { 01015 char *p, *p2, *buf, *newbuf; 01016 01017 if(G.background) 01018 return NULL; 01019 01020 buf= (char*)GHOST_getClipboard(selection); 01021 if(!buf) 01022 return NULL; 01023 01024 /* always convert from \r\n to \n */ 01025 newbuf= MEM_callocN(strlen(buf)+1, "WM_clipboard_text_get"); 01026 01027 for(p= buf, p2= newbuf; *p; p++) { 01028 if(*p != '\r') 01029 *(p2++)= *p; 01030 } 01031 *p2= '\0'; 01032 01033 free(buf); /* ghost uses regular malloc */ 01034 01035 return newbuf; 01036 } 01037 01038 void WM_clipboard_text_set(char *buf, int selection) 01039 { 01040 if(!G.background) { 01041 #ifdef _WIN32 01042 /* do conversion from \n to \r\n on Windows */ 01043 char *p, *p2, *newbuf; 01044 int newlen= 0; 01045 01046 for(p= buf; *p; p++) { 01047 if(*p == '\n') 01048 newlen += 2; 01049 else 01050 newlen++; 01051 } 01052 01053 newbuf= MEM_callocN(newlen+1, "WM_clipboard_text_set"); 01054 01055 for(p= buf, p2= newbuf; *p; p++, p2++) { 01056 if(*p == '\n') { 01057 *(p2++)= '\r'; *p2= '\n'; 01058 } 01059 else *p2= *p; 01060 } 01061 *p2= '\0'; 01062 01063 GHOST_putClipboard((GHOST_TInt8*)newbuf, selection); 01064 MEM_freeN(newbuf); 01065 #else 01066 GHOST_putClipboard((GHOST_TInt8*)buf, selection); 01067 #endif 01068 } 01069 } 01070 01071 /* ******************* progress bar **************** */ 01072 01073 void WM_progress_set(wmWindow *win, float progress) 01074 { 01075 GHOST_SetProgressBar(win->ghostwin, progress); 01076 } 01077 01078 void WM_progress_clear(wmWindow *win) 01079 { 01080 GHOST_EndProgressBar(win->ghostwin); 01081 } 01082 01083 /* ************************************ */ 01084 01085 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) 01086 { 01087 *posx_r= win->posx; 01088 *posy_r= win->posy; 01089 } 01090 01091 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r) 01092 { 01093 *width_r= win->sizex; 01094 *height_r= win->sizey; 01095 } 01096 01097 /* exceptional case: - splash is called before events are processed 01098 * this means we dont actually know the window size so get this from GHOST */ 01099 void wm_window_get_size_ghost(wmWindow *win, int *width_r, int *height_r) 01100 { 01101 GHOST_RectangleHandle bounds= GHOST_GetClientBounds(win->ghostwin); 01102 *width_r= GHOST_GetWidthRectangle(bounds); 01103 *height_r= GHOST_GetHeightRectangle(bounds); 01104 01105 GHOST_DisposeRectangle(bounds); 01106 } 01107 01108 void wm_window_set_size(wmWindow *win, int width, int height) 01109 { 01110 GHOST_SetClientSize(win->ghostwin, width, height); 01111 } 01112 01113 void wm_window_lower(wmWindow *win) 01114 { 01115 GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom); 01116 } 01117 01118 void wm_window_raise(wmWindow *win) 01119 { 01120 GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop); 01121 } 01122 01123 void wm_window_swap_buffers(wmWindow *win) 01124 { 01125 01126 #ifdef WIN32 01127 glDisable(GL_SCISSOR_TEST); 01128 GHOST_SwapWindowBuffers(win->ghostwin); 01129 glEnable(GL_SCISSOR_TEST); 01130 #else 01131 GHOST_SwapWindowBuffers(win->ghostwin); 01132 #endif 01133 } 01134 01135 void wm_get_cursor_position(wmWindow *win, int *x, int *y) 01136 { 01137 GHOST_GetCursorPosition(g_system, x, y); 01138 GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y); 01139 *y = (win->sizey-1) - *y; 01140 } 01141 01142 /* ******************* exported api ***************** */ 01143 01144 01145 /* called whem no ghost system was initialized */ 01146 void WM_setprefsize(int stax, int stay, int sizx, int sizy) 01147 { 01148 prefstax= stax; 01149 prefstay= stay; 01150 prefsizx= sizx; 01151 prefsizy= sizy; 01152 useprefsize= 1; 01153 } 01154 01155 /* for borderless and border windows set from command-line */ 01156 void WM_setinitialstate_fullscreen(void) 01157 { 01158 initialstate= GHOST_kWindowStateFullScreen; 01159 } 01160 01161 void WM_setinitialstate_normal(void) 01162 { 01163 initialstate= GHOST_kWindowStateNormal; 01164 } 01165 01166 /* This function requires access to the GHOST_SystemHandle (g_system) */ 01167 void WM_cursor_warp(wmWindow *win, int x, int y) 01168 { 01169 if (win && win->ghostwin) { 01170 int oldx=x, oldy=y; 01171 01172 y= win->sizey -y - 1; 01173 01174 GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y); 01175 GHOST_SetCursorPosition(g_system, x, y); 01176 01177 win->eventstate->prevx= oldx; 01178 win->eventstate->prevy= oldy; 01179 } 01180 } 01181