|
Blender
V2.59
|
00001 /* 00002 * $Id: wm_event_system.c 39161 2011-08-07 18:00:47Z 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. 00021 * All rights reserved. 00022 * 00023 * 00024 * Contributor(s): Blender Foundation 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <math.h> 00037 00038 #include "DNA_listBase.h" 00039 #include "DNA_screen_types.h" 00040 #include "DNA_scene_types.h" 00041 #include "DNA_windowmanager_types.h" 00042 #include "DNA_userdef_types.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_idprop.h" 00054 #include "BKE_global.h" 00055 #include "BKE_main.h" 00056 #include "BKE_report.h" 00057 #include "BKE_scene.h" 00058 #include "BKE_screen.h" 00059 00060 #include "BKE_sound.h" 00061 00062 #include "ED_fileselect.h" 00063 #include "ED_info.h" 00064 #include "ED_screen.h" 00065 #include "ED_view3d.h" 00066 #include "ED_util.h" 00067 00068 #include "RNA_access.h" 00069 00070 #include "UI_interface.h" 00071 00072 #include "PIL_time.h" 00073 00074 #include "WM_api.h" 00075 #include "WM_types.h" 00076 #include "wm.h" 00077 #include "wm_window.h" 00078 #include "wm_event_system.h" 00079 #include "wm_event_types.h" 00080 #include "wm_draw.h" 00081 00082 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only); 00083 00084 /* ************ event management ************** */ 00085 00086 void wm_event_add(wmWindow *win, wmEvent *event_to_add) 00087 { 00088 wmEvent *event= MEM_callocN(sizeof(wmEvent), "event"); 00089 00090 *event= *event_to_add; 00091 BLI_addtail(&win->queue, event); 00092 } 00093 00094 void wm_event_free(wmEvent *event) 00095 { 00096 if(event->customdata) { 00097 if(event->customdatafree) { 00098 /* note: pointer to listbase struct elsewhere */ 00099 if(event->custom==EVT_DATA_LISTBASE) 00100 BLI_freelistN(event->customdata); 00101 else 00102 MEM_freeN(event->customdata); 00103 } 00104 } 00105 MEM_freeN(event); 00106 } 00107 00108 void wm_event_free_all(wmWindow *win) 00109 { 00110 wmEvent *event; 00111 00112 while((event= win->queue.first)) { 00113 BLI_remlink(&win->queue, event); 00114 wm_event_free(event); 00115 } 00116 } 00117 00118 /* ********************* notifiers, listeners *************** */ 00119 00120 static int wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference) 00121 { 00122 wmNotifier *note; 00123 00124 for(note=wm->queue.first; note; note=note->next) 00125 if((note->category|note->data|note->subtype|note->action) == type && note->reference == reference) 00126 return 1; 00127 00128 return 0; 00129 } 00130 00131 /* XXX: in future, which notifiers to send to other windows? */ 00132 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference) 00133 { 00134 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier"); 00135 00136 note->wm= CTX_wm_manager(C); 00137 BLI_addtail(¬e->wm->queue, note); 00138 00139 note->window= CTX_wm_window(C); 00140 00141 if(CTX_wm_region(C)) 00142 note->swinid= CTX_wm_region(C)->swinid; 00143 00144 note->category= type & NOTE_CATEGORY; 00145 note->data= type & NOTE_DATA; 00146 note->subtype= type & NOTE_SUBTYPE; 00147 note->action= type & NOTE_ACTION; 00148 00149 note->reference= reference; 00150 } 00151 00152 void WM_main_add_notifier(unsigned int type, void *reference) 00153 { 00154 Main *bmain= G.main; 00155 wmWindowManager *wm= bmain->wm.first; 00156 00157 if(wm && !wm_test_duplicate_notifier(wm, type, reference)) { 00158 wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier"); 00159 00160 note->wm= wm; 00161 BLI_addtail(¬e->wm->queue, note); 00162 00163 note->category= type & NOTE_CATEGORY; 00164 note->data= type & NOTE_DATA; 00165 note->subtype= type & NOTE_SUBTYPE; 00166 note->action= type & NOTE_ACTION; 00167 00168 note->reference= reference; 00169 } 00170 } 00171 00172 static wmNotifier *wm_notifier_next(wmWindowManager *wm) 00173 { 00174 wmNotifier *note= wm->queue.first; 00175 00176 if(note) BLI_remlink(&wm->queue, note); 00177 return note; 00178 } 00179 00180 /* called in mainloop */ 00181 void wm_event_do_notifiers(bContext *C) 00182 { 00183 wmWindowManager *wm= CTX_wm_manager(C); 00184 wmNotifier *note, *next; 00185 wmWindow *win; 00186 unsigned int win_combine_v3d_datamask= 0; 00187 00188 if(wm==NULL) 00189 return; 00190 00191 /* cache & catch WM level notifiers, such as frame change, scene/screen set */ 00192 for(win= wm->windows.first; win; win= win->next) { 00193 int do_anim= 0; 00194 00195 CTX_wm_window_set(C, win); 00196 00197 for(note= wm->queue.first; note; note= next) { 00198 next= note->next; 00199 00200 if(note->category==NC_WM) { 00201 if( ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) { 00202 wm->file_saved= 1; 00203 wm_window_title(wm, win); 00204 } 00205 else if(note->data==ND_DATACHANGED) 00206 wm_window_title(wm, win); 00207 } 00208 if(note->window==win) { 00209 if(note->category==NC_SCREEN) { 00210 if(note->data==ND_SCREENBROWSE) { 00211 ED_screen_set(C, note->reference); // XXX hrms, think this over! 00212 if(G.f & G_DEBUG) 00213 printf("screen set %p\n", note->reference); 00214 } 00215 else if(note->data==ND_SCREENDELETE) { 00216 ED_screen_delete(C, note->reference); // XXX hrms, think this over! 00217 if(G.f & G_DEBUG) 00218 printf("screen delete %p\n", note->reference); 00219 } 00220 } 00221 } 00222 00223 if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) { 00224 if(note->category==NC_SCENE) { 00225 if(note->data==ND_SCENEBROWSE) { 00226 ED_screen_set_scene(C, note->reference); // XXX hrms, think this over! 00227 if(G.f & G_DEBUG) 00228 printf("scene set %p\n", note->reference); 00229 } 00230 else if(note->data==ND_FRAME) 00231 do_anim= 1; 00232 00233 if(note->action == NA_REMOVED) { 00234 ED_screen_delete_scene(C, note->reference); // XXX hrms, think this over! 00235 if(G.f & G_DEBUG) 00236 printf("scene delete %p\n", note->reference); 00237 } 00238 00239 } 00240 } 00241 if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { 00242 ED_info_stats_clear(CTX_data_scene(C)); 00243 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL); 00244 } 00245 } 00246 if(do_anim) { 00247 00248 /* XXX, quick frame changes can cause a crash if framechange and rendering 00249 * collide (happens on slow scenes), scene_update_for_newframe can be called 00250 * twice which can depgraph update the same object at once */ 00251 if(!G.rendering) { 00252 00253 /* depsgraph gets called, might send more notifiers */ 00254 ED_update_for_newframe(CTX_data_main(C), win->screen->scene, win->screen, 1); 00255 } 00256 } 00257 } 00258 00259 /* the notifiers are sent without context, to keep it clean */ 00260 while( (note=wm_notifier_next(wm)) ) { 00261 for(win= wm->windows.first; win; win= win->next) { 00262 00263 /* filter out notifiers */ 00264 if(note->category==NC_SCREEN && note->reference && note->reference!=win->screen); 00265 else if(note->category==NC_SCENE && note->reference && note->reference!=win->screen->scene); 00266 else { 00267 ScrArea *sa; 00268 ARegion *ar; 00269 00270 /* XXX context in notifiers? */ 00271 CTX_wm_window_set(C, win); 00272 00273 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name+2, note->category); */ 00274 ED_screen_do_listen(C, note); 00275 00276 for(ar=win->screen->regionbase.first; ar; ar= ar->next) { 00277 ED_region_do_listen(ar, note); 00278 } 00279 00280 for(sa= win->screen->areabase.first; sa; sa= sa->next) { 00281 ED_area_do_listen(sa, note); 00282 for(ar=sa->regionbase.first; ar; ar= ar->next) { 00283 ED_region_do_listen(ar, note); 00284 } 00285 } 00286 } 00287 } 00288 00289 MEM_freeN(note); 00290 } 00291 00292 /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */ 00293 for(win= wm->windows.first; win; win= win->next) { 00294 win_combine_v3d_datamask |= ED_viewedit_datamask(win->screen); 00295 } 00296 00297 /* cached: editor refresh callbacks now, they get context */ 00298 for(win= wm->windows.first; win; win= win->next) { 00299 ScrArea *sa; 00300 00301 CTX_wm_window_set(C, win); 00302 for(sa= win->screen->areabase.first; sa; sa= sa->next) { 00303 if(sa->do_refresh) { 00304 CTX_wm_area_set(C, sa); 00305 ED_area_do_refresh(C, sa); 00306 } 00307 } 00308 00309 /* XXX make lock in future, or separated derivedmesh users in scene */ 00310 if(!G.rendering) { 00311 /* depsgraph & animation: update tagged datablocks */ 00312 00313 /* copied to set's in scene_update_tagged_recursive() */ 00314 win->screen->scene->customdata_mask= win_combine_v3d_datamask; 00315 00316 /* XXX, hack so operators can enforce datamasks [#26482], gl render */ 00317 win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal; 00318 00319 scene_update_tagged(CTX_data_main(C), win->screen->scene); 00320 } 00321 } 00322 00323 CTX_wm_window_set(C, NULL); 00324 } 00325 00326 static int wm_event_always_pass(wmEvent *event) 00327 { 00328 /* some events we always pass on, to ensure proper communication */ 00329 return ISTIMER(event->type) || (event->type == WINDEACTIVATE); 00330 } 00331 00332 /* ********************* ui handler ******************* */ 00333 00334 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass) 00335 { 00336 ScrArea *area= CTX_wm_area(C); 00337 ARegion *region= CTX_wm_region(C); 00338 ARegion *menu= CTX_wm_menu(C); 00339 static int do_wheel_ui= 1; 00340 int is_wheel= ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE); 00341 int retval; 00342 00343 /* UI is quite aggressive with swallowing events, like scrollwheel */ 00344 /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */ 00345 if(do_wheel_ui==0) { 00346 if(is_wheel) 00347 return WM_HANDLER_CONTINUE; 00348 else if(wm_event_always_pass(event)==0) 00349 do_wheel_ui= 1; 00350 } 00351 00352 /* we set context to where ui handler came from */ 00353 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area); 00354 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region); 00355 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu); 00356 00357 retval= handler->ui_handle(C, event, handler->ui_userdata); 00358 00359 /* putting back screen context */ 00360 if((retval != WM_UI_HANDLER_BREAK) || always_pass) { 00361 CTX_wm_area_set(C, area); 00362 CTX_wm_region_set(C, region); 00363 CTX_wm_menu_set(C, menu); 00364 } 00365 else { 00366 /* this special cases is for areas and regions that get removed */ 00367 CTX_wm_area_set(C, NULL); 00368 CTX_wm_region_set(C, NULL); 00369 CTX_wm_menu_set(C, NULL); 00370 } 00371 00372 if(retval == WM_UI_HANDLER_BREAK) 00373 return WM_HANDLER_BREAK; 00374 00375 /* event not handled in UI, if wheel then we temporarily disable it */ 00376 if(is_wheel) 00377 do_wheel_ui= 0; 00378 00379 return WM_HANDLER_CONTINUE; 00380 } 00381 00382 static void wm_handler_ui_cancel(bContext *C) 00383 { 00384 wmWindow *win= CTX_wm_window(C); 00385 ARegion *ar= CTX_wm_region(C); 00386 wmEventHandler *handler, *nexthandler; 00387 00388 if(!ar) 00389 return; 00390 00391 for(handler= ar->handlers.first; handler; handler= nexthandler) { 00392 nexthandler= handler->next; 00393 00394 if(handler->ui_handle) { 00395 wmEvent event= *(win->eventstate); 00396 event.type= EVT_BUT_CANCEL; 00397 handler->ui_handle(C, &event, handler->ui_userdata); 00398 } 00399 } 00400 } 00401 00402 /* ********************* operators ******************* */ 00403 00404 int WM_operator_poll(bContext *C, wmOperatorType *ot) 00405 { 00406 wmOperatorTypeMacro *otmacro; 00407 00408 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) { 00409 wmOperatorType *ot_macro= WM_operatortype_find(otmacro->idname, 0); 00410 00411 if(0==WM_operator_poll(C, ot_macro)) 00412 return 0; 00413 } 00414 00415 /* python needs operator type, so we added exception for it */ 00416 if(ot->pyop_poll) 00417 return ot->pyop_poll(C, ot); 00418 else if(ot->poll) 00419 return ot->poll(C); 00420 00421 return 1; 00422 } 00423 00424 /* sets up the new context and calls 'wm_operator_invoke()' with poll_only */ 00425 int WM_operator_poll_context(bContext *C, wmOperatorType *ot, int context) 00426 { 00427 return wm_operator_call_internal(C, ot, NULL, NULL, context, TRUE); 00428 } 00429 00430 static void wm_operator_print(bContext *C, wmOperator *op) 00431 { 00432 /* context is needed for enum function */ 00433 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); 00434 printf("%s\n", buf); 00435 MEM_freeN(buf); 00436 } 00437 00438 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup) 00439 { 00440 if(popup) 00441 if(op->reports->list.first) 00442 uiPupMenuReports(C, op->reports); 00443 00444 if(retval & OPERATOR_FINISHED) { 00445 if(G.f & G_DEBUG) 00446 wm_operator_print(C, op); /* todo - this print may double up, might want to check more flags then the FINISHED */ 00447 00448 BKE_reports_print(op->reports, RPT_DEBUG); /* print out reports to console. */ 00449 if (op->type->flag & OPTYPE_REGISTER) { 00450 if(G.background == 0) { /* ends up printing these in the terminal, gets annoying */ 00451 /* Report the python string representation of the operator */ 00452 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); 00453 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf); 00454 MEM_freeN(buf); 00455 } 00456 } 00457 } 00458 00459 /* if the caller owns them them handle this */ 00460 if (op->reports->list.first && (op->reports->flag & RPT_OP_HOLD) == 0) { 00461 00462 wmWindowManager *wm = CTX_wm_manager(C); 00463 ReportList *wm_reports= CTX_wm_reports(C); 00464 ReportTimerInfo *rti; 00465 00466 /* add reports to the global list, otherwise they are not seen */ 00467 BLI_movelisttolist(&wm_reports->list, &op->reports->list); 00468 00469 /* After adding reports to the global list, reset the report timer. */ 00470 WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); 00471 00472 /* Records time since last report was added */ 00473 wm_reports->reporttimer= WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05); 00474 00475 rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); 00476 wm_reports->reporttimer->customdata = rti; 00477 } 00478 } 00479 00480 /* this function is mainly to check that the rules for freeing 00481 * an operator are kept in sync. 00482 */ 00483 static int wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot) 00484 { 00485 return wm && (wm->op_undo_depth == 0) && (ot->flag & OPTYPE_REGISTER); 00486 } 00487 00488 static void wm_operator_finished(bContext *C, wmOperator *op, int repeat) 00489 { 00490 wmWindowManager *wm= CTX_wm_manager(C); 00491 00492 op->customdata= NULL; 00493 00494 /* we don't want to do undo pushes for operators that are being 00495 called from operators that already do an undo push. usually 00496 this will happen for python operators that call C operators */ 00497 if(wm->op_undo_depth == 0) 00498 if(op->type->flag & OPTYPE_UNDO) 00499 ED_undo_push_op(C, op); 00500 00501 if(repeat==0) { 00502 if(G.f & G_DEBUG) { 00503 char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); 00504 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf); 00505 MEM_freeN(buf); 00506 } 00507 00508 if(wm_operator_register_check(wm, op->type)) 00509 wm_operator_register(C, op); 00510 else 00511 WM_operator_free(op); 00512 } 00513 } 00514 00515 /* if repeat is true, it doesn't register again, nor does it free */ 00516 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat) 00517 { 00518 wmWindowManager *wm= CTX_wm_manager(C); 00519 int retval= OPERATOR_CANCELLED; 00520 00521 CTX_wm_operator_poll_msg_set(C, NULL); 00522 00523 if(op==NULL || op->type==NULL) 00524 return retval; 00525 00526 if(0==WM_operator_poll(C, op->type)) 00527 return retval; 00528 00529 if(op->type->exec) { 00530 if(op->type->flag & OPTYPE_UNDO) 00531 wm->op_undo_depth++; 00532 00533 retval= op->type->exec(C, op); 00534 00535 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 00536 wm->op_undo_depth--; 00537 } 00538 00539 if (retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED) && repeat == 0) 00540 wm_operator_reports(C, op, retval, 0); 00541 00542 if(retval & OPERATOR_FINISHED) 00543 wm_operator_finished(C, op, repeat); 00544 else if(repeat==0) 00545 WM_operator_free(op); 00546 00547 return retval | OPERATOR_HANDLED; 00548 00549 } 00550 00551 /* for running operators with frozen context (modal handlers, menus) */ 00552 int WM_operator_call(bContext *C, wmOperator *op) 00553 { 00554 return wm_operator_exec(C, op, 0); 00555 } 00556 00557 /* do this operator again, put here so it can share above code */ 00558 int WM_operator_repeat(bContext *C, wmOperator *op) 00559 { 00560 return wm_operator_exec(C, op, 1); 00561 } 00562 /* TRUE if WM_operator_repeat can run 00563 * simple check for now but may become more involved. 00564 * To be sure the operator can run call WM_operator_poll(C, op->type) also, since this call 00565 * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. */ 00566 int WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) 00567 { 00568 return op->type->exec != NULL; 00569 } 00570 00571 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports) 00572 { 00573 wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */ 00574 00575 /* XXX adding new operator could be function, only happens here now */ 00576 op->type= ot; 00577 BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME); 00578 00579 /* initialize properties, either copy or create */ 00580 op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA"); 00581 if(properties && properties->data) { 00582 op->properties= IDP_CopyProperty(properties->data); 00583 } 00584 else { 00585 IDPropertyTemplate val = {0}; 00586 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties"); 00587 } 00588 RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr); 00589 00590 /* initialize error reports */ 00591 if (reports) { 00592 op->reports= reports; /* must be initialized already */ 00593 } 00594 else { 00595 op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); 00596 BKE_reports_init(op->reports, RPT_STORE|RPT_FREE); 00597 } 00598 00599 /* recursive filling of operator macro list */ 00600 if(ot->macro.first) { 00601 static wmOperator *motherop= NULL; 00602 wmOperatorTypeMacro *otmacro; 00603 int root = 0; 00604 00605 /* ensure all ops are in execution order in 1 list */ 00606 if(motherop==NULL) { 00607 motherop = op; 00608 root = 1; 00609 } 00610 00611 00612 /* if properties exist, it will contain everything needed */ 00613 if (properties) { 00614 otmacro= ot->macro.first; 00615 00616 RNA_STRUCT_BEGIN(properties, prop) { 00617 00618 if (otmacro == NULL) 00619 break; 00620 00621 /* skip invalid properties */ 00622 if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0) 00623 { 00624 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0); 00625 PointerRNA someptr = RNA_property_pointer_get(properties, prop); 00626 wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL); 00627 00628 IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties); 00629 00630 BLI_addtail(&motherop->macro, opm); 00631 opm->opm= motherop; /* pointer to mom, for modal() */ 00632 00633 otmacro= otmacro->next; 00634 } 00635 } 00636 RNA_STRUCT_END; 00637 } else { 00638 for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { 00639 wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0); 00640 wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL); 00641 00642 BLI_addtail(&motherop->macro, opm); 00643 opm->opm= motherop; /* pointer to mom, for modal() */ 00644 } 00645 } 00646 00647 if (root) 00648 motherop= NULL; 00649 } 00650 00651 WM_operator_properties_sanitize(op->ptr, 0); 00652 00653 return op; 00654 } 00655 00656 static void wm_region_mouse_co(bContext *C, wmEvent *event) 00657 { 00658 ARegion *ar= CTX_wm_region(C); 00659 if(ar) { 00660 /* compatibility convention */ 00661 event->mval[0]= event->x - ar->winrct.xmin; 00662 event->mval[1]= event->y - ar->winrct.ymin; 00663 } 00664 else { 00665 /* these values are invalid (avoid odd behavior by relying on old mval values) */ 00666 event->mval[0]= -1; 00667 event->mval[1]= -1; 00668 } 00669 } 00670 00671 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only) 00672 { 00673 wmWindowManager *wm= CTX_wm_manager(C); 00674 int retval= OPERATOR_PASS_THROUGH; 00675 00676 /* this is done because complicated setup is done to call this function that is better not duplicated */ 00677 if(poll_only) 00678 return WM_operator_poll(C, ot); 00679 00680 if(WM_operator_poll(C, ot)) { 00681 wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */ 00682 00683 if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE) 00684 printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 00685 00686 if(op->type->invoke && event) { 00687 wm_region_mouse_co(C, event); 00688 00689 if(op->type->flag & OPTYPE_UNDO) 00690 wm->op_undo_depth++; 00691 00692 retval= op->type->invoke(C, op, event); 00693 00694 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 00695 wm->op_undo_depth--; 00696 } 00697 else if(op->type->exec) { 00698 if(op->type->flag & OPTYPE_UNDO) 00699 wm->op_undo_depth++; 00700 00701 retval= op->type->exec(C, op); 00702 00703 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 00704 wm->op_undo_depth--; 00705 } 00706 else 00707 printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */ 00708 00709 /* Note, if the report is given as an argument then assume the caller will deal with displaying them 00710 * currently python only uses this */ 00711 if (!(retval & OPERATOR_HANDLED) && retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) 00712 /* only show the report if the report list was not given in the function */ 00713 wm_operator_reports(C, op, retval, (reports==NULL)); 00714 00715 if(retval & OPERATOR_HANDLED) 00716 ; /* do nothing, wm_operator_exec() has been called somewhere */ 00717 else if(retval & OPERATOR_FINISHED) { 00718 wm_operator_finished(C, op, 0); 00719 } 00720 else if(retval & OPERATOR_RUNNING_MODAL) { 00721 /* grab cursor during blocking modal ops (X11) 00722 * Also check for macro 00723 * */ 00724 if(ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) { 00725 int bounds[4] = {-1,-1,-1,-1}; 00726 int wrap; 00727 00728 if (op->opm) { 00729 wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER)); 00730 } else { 00731 wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER)); 00732 } 00733 00734 /* exception, cont. grab in header is annoying */ 00735 if(wrap) { 00736 ARegion *ar= CTX_wm_region(C); 00737 if(ar && ar->regiontype == RGN_TYPE_HEADER) { 00738 wrap= FALSE; 00739 } 00740 } 00741 00742 if(wrap) { 00743 rcti *winrect= NULL; 00744 ARegion *ar= CTX_wm_region(C); 00745 ScrArea *sa= CTX_wm_area(C); 00746 00747 if(ar && ar->regiontype == RGN_TYPE_WINDOW && event && BLI_in_rcti(&ar->winrct, event->x, event->y)) { 00748 winrect= &ar->winrct; 00749 } 00750 else if(sa) { 00751 winrect= &sa->totrct; 00752 } 00753 00754 if(winrect) { 00755 bounds[0]= winrect->xmin; 00756 bounds[1]= winrect->ymax; 00757 bounds[2]= winrect->xmax; 00758 bounds[3]= winrect->ymin; 00759 } 00760 } 00761 00762 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds); 00763 } 00764 00765 /* cancel UI handlers, typically tooltips that can hang around 00766 while dragging the view or worse, that stay there permanently 00767 after the modal operator has swallowed all events and passed 00768 none to the UI handler */ 00769 wm_handler_ui_cancel(C); 00770 } 00771 else 00772 WM_operator_free(op); 00773 } 00774 00775 return retval; 00776 } 00777 00778 /* WM_operator_name_call is the main accessor function 00779 * this is for python to access since its done the operator lookup 00780 * 00781 * invokes operator in context */ 00782 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only) 00783 { 00784 wmWindow *window= CTX_wm_window(C); 00785 wmEvent *event; 00786 00787 int retval; 00788 00789 CTX_wm_operator_poll_msg_set(C, NULL); 00790 00791 /* dummie test */ 00792 if(ot && C) { 00793 switch(context) { 00794 case WM_OP_INVOKE_DEFAULT: 00795 case WM_OP_INVOKE_REGION_WIN: 00796 case WM_OP_INVOKE_AREA: 00797 case WM_OP_INVOKE_SCREEN: 00798 /* window is needed for invoke, cancel operator */ 00799 if (window == NULL) 00800 return 0; 00801 else 00802 event= window->eventstate; 00803 break; 00804 default: 00805 event = NULL; 00806 } 00807 00808 switch(context) { 00809 00810 case WM_OP_EXEC_REGION_WIN: 00811 case WM_OP_INVOKE_REGION_WIN: 00812 case WM_OP_EXEC_REGION_CHANNELS: 00813 case WM_OP_INVOKE_REGION_CHANNELS: 00814 case WM_OP_EXEC_REGION_PREVIEW: 00815 case WM_OP_INVOKE_REGION_PREVIEW: 00816 { 00817 /* forces operator to go to the region window/channels/preview, for header menus 00818 * but we stay in the same region if we are already in one 00819 */ 00820 ARegion *ar= CTX_wm_region(C); 00821 ScrArea *area= CTX_wm_area(C); 00822 int type = RGN_TYPE_WINDOW; 00823 00824 switch (context) { 00825 case WM_OP_EXEC_REGION_CHANNELS: 00826 case WM_OP_INVOKE_REGION_CHANNELS: 00827 type = RGN_TYPE_CHANNELS; 00828 break; 00829 00830 case WM_OP_EXEC_REGION_PREVIEW: 00831 case WM_OP_INVOKE_REGION_PREVIEW: 00832 type = RGN_TYPE_PREVIEW; 00833 break; 00834 00835 case WM_OP_EXEC_REGION_WIN: 00836 case WM_OP_INVOKE_REGION_WIN: 00837 default: 00838 type = RGN_TYPE_WINDOW; 00839 break; 00840 } 00841 00842 if(!(ar && ar->regiontype == type) && area) { 00843 ARegion *ar1= BKE_area_find_region_type(area, type); 00844 if(ar1) 00845 CTX_wm_region_set(C, ar1); 00846 } 00847 00848 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); 00849 00850 /* set region back */ 00851 CTX_wm_region_set(C, ar); 00852 00853 return retval; 00854 } 00855 case WM_OP_EXEC_AREA: 00856 case WM_OP_INVOKE_AREA: 00857 { 00858 /* remove region from context */ 00859 ARegion *ar= CTX_wm_region(C); 00860 00861 CTX_wm_region_set(C, NULL); 00862 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); 00863 CTX_wm_region_set(C, ar); 00864 00865 return retval; 00866 } 00867 case WM_OP_EXEC_SCREEN: 00868 case WM_OP_INVOKE_SCREEN: 00869 { 00870 /* remove region + area from context */ 00871 ARegion *ar= CTX_wm_region(C); 00872 ScrArea *area= CTX_wm_area(C); 00873 00874 CTX_wm_region_set(C, NULL); 00875 CTX_wm_area_set(C, NULL); 00876 retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); 00877 CTX_wm_region_set(C, ar); 00878 CTX_wm_area_set(C, area); 00879 00880 return retval; 00881 } 00882 case WM_OP_EXEC_DEFAULT: 00883 case WM_OP_INVOKE_DEFAULT: 00884 return wm_operator_invoke(C, ot, event, properties, reports, poll_only); 00885 } 00886 } 00887 00888 return 0; 00889 } 00890 00891 00892 /* invokes operator in context */ 00893 int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties) 00894 { 00895 wmOperatorType *ot= WM_operatortype_find(opstring, 0); 00896 if(ot) 00897 return wm_operator_call_internal(C, ot, properties, NULL, context, FALSE); 00898 00899 return 0; 00900 } 00901 00902 /* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context. 00903 - wmOperatorType is used instead of operator name since python already has the operator type 00904 - poll() must be called by python before this runs. 00905 - reports can be passed to this function (so python can report them as exceptions) 00906 */ 00907 int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports) 00908 { 00909 int retval= OPERATOR_CANCELLED; 00910 00911 #if 0 00912 wmOperator *op; 00913 op= wm_operator_create(wm, ot, properties, reports); 00914 00915 if (op->type->exec) { 00916 if(op->type->flag & OPTYPE_UNDO) 00917 wm->op_undo_depth++; 00918 00919 retval= op->type->exec(C, op); 00920 00921 if(op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 00922 wm->op_undo_depth--; 00923 } 00924 else 00925 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name); 00926 #endif 00927 00928 retval= wm_operator_call_internal(C, ot, properties, reports, context, FALSE); 00929 00930 /* keep the reports around if needed later */ 00931 if ( (retval & OPERATOR_RUNNING_MODAL) || 00932 ((retval & OPERATOR_FINISHED) && wm_operator_register_check(CTX_wm_manager(C), ot)) 00933 ) { 00934 reports->flag |= RPT_FREE; /* let blender manage freeing */ 00935 } 00936 00937 return retval; 00938 } 00939 00940 00941 /* ********************* handlers *************** */ 00942 00943 /* future extra customadata free? */ 00944 void wm_event_free_handler(wmEventHandler *handler) 00945 { 00946 MEM_freeN(handler); 00947 } 00948 00949 /* only set context when area/region is part of screen */ 00950 static void wm_handler_op_context(bContext *C, wmEventHandler *handler) 00951 { 00952 bScreen *screen= CTX_wm_screen(C); 00953 00954 if(screen && handler->op) { 00955 if(handler->op_area==NULL) 00956 CTX_wm_area_set(C, NULL); 00957 else { 00958 ScrArea *sa; 00959 00960 for(sa= screen->areabase.first; sa; sa= sa->next) 00961 if(sa==handler->op_area) 00962 break; 00963 if(sa==NULL) { 00964 /* when changing screen layouts with running modal handlers (like render display), this 00965 is not an error to print */ 00966 if(handler->op==NULL) 00967 printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname); 00968 } 00969 else { 00970 ARegion *ar; 00971 CTX_wm_area_set(C, sa); 00972 for(ar= sa->regionbase.first; ar; ar= ar->next) 00973 if(ar==handler->op_region) 00974 break; 00975 /* XXX no warning print here, after full-area and back regions are remade */ 00976 if(ar) 00977 CTX_wm_region_set(C, ar); 00978 } 00979 } 00980 } 00981 } 00982 00983 /* called on exit or remove area, only here call cancel callback */ 00984 void WM_event_remove_handlers(bContext *C, ListBase *handlers) 00985 { 00986 wmEventHandler *handler; 00987 wmWindowManager *wm= CTX_wm_manager(C); 00988 00989 /* C is zero on freeing database, modal handlers then already were freed */ 00990 while((handler=handlers->first)) { 00991 BLI_remlink(handlers, handler); 00992 00993 if(handler->op) { 00994 if(handler->op->type->cancel) { 00995 ScrArea *area= CTX_wm_area(C); 00996 ARegion *region= CTX_wm_region(C); 00997 00998 wm_handler_op_context(C, handler); 00999 01000 if(handler->op->type->flag & OPTYPE_UNDO) 01001 wm->op_undo_depth++; 01002 01003 handler->op->type->cancel(C, handler->op); 01004 01005 if(handler->op->type->flag & OPTYPE_UNDO) 01006 wm->op_undo_depth--; 01007 01008 CTX_wm_area_set(C, area); 01009 CTX_wm_region_set(C, region); 01010 } 01011 01012 WM_cursor_ungrab(CTX_wm_window(C)); 01013 WM_operator_free(handler->op); 01014 } 01015 else if(handler->ui_remove) { 01016 ScrArea *area= CTX_wm_area(C); 01017 ARegion *region= CTX_wm_region(C); 01018 ARegion *menu= CTX_wm_menu(C); 01019 01020 if(handler->ui_area) CTX_wm_area_set(C, handler->ui_area); 01021 if(handler->ui_region) CTX_wm_region_set(C, handler->ui_region); 01022 if(handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu); 01023 01024 handler->ui_remove(C, handler->ui_userdata); 01025 01026 CTX_wm_area_set(C, area); 01027 CTX_wm_region_set(C, region); 01028 CTX_wm_menu_set(C, menu); 01029 } 01030 01031 wm_event_free_handler(handler); 01032 } 01033 } 01034 01035 /* do userdef mappings */ 01036 int WM_userdef_event_map(int kmitype) 01037 { 01038 switch(kmitype) { 01039 case SELECTMOUSE: 01040 if(U.flag & USER_LMOUSESELECT) 01041 return LEFTMOUSE; 01042 else 01043 return RIGHTMOUSE; 01044 01045 case ACTIONMOUSE: 01046 if(U.flag & USER_LMOUSESELECT) 01047 return RIGHTMOUSE; 01048 else 01049 return LEFTMOUSE; 01050 01051 case WHEELOUTMOUSE: 01052 if(U.uiflag & USER_WHEELZOOMDIR) 01053 return WHEELUPMOUSE; 01054 else 01055 return WHEELDOWNMOUSE; 01056 01057 case WHEELINMOUSE: 01058 if(U.uiflag & USER_WHEELZOOMDIR) 01059 return WHEELDOWNMOUSE; 01060 else 01061 return WHEELUPMOUSE; 01062 01063 case EVT_TWEAK_A: 01064 if(U.flag & USER_LMOUSESELECT) 01065 return EVT_TWEAK_R; 01066 else 01067 return EVT_TWEAK_L; 01068 01069 case EVT_TWEAK_S: 01070 if(U.flag & USER_LMOUSESELECT) 01071 return EVT_TWEAK_L; 01072 else 01073 return EVT_TWEAK_R; 01074 } 01075 01076 return kmitype; 01077 } 01078 01079 static void wm_eventemulation(wmEvent *event) 01080 { 01081 static int mmb_emulated = 0; /* this should be in a data structure somwhere */ 01082 01083 /* middlemouse emulation */ 01084 if(U.flag & USER_TWOBUTTONMOUSE) { 01085 if(event->type == LEFTMOUSE && (event->alt || mmb_emulated == KM_PRESS)) { 01086 event->type = MIDDLEMOUSE; 01087 event->alt = 0; 01088 mmb_emulated = event->val; 01089 } 01090 } 01091 01092 #ifdef __APPLE__ 01093 /* rightmouse emulation */ 01094 if(U.flag & USER_TWOBUTTONMOUSE) { 01095 if(event->type == LEFTMOUSE && (event->oskey || mmb_emulated == KM_PRESS)) { 01096 event->type = RIGHTMOUSE; 01097 event->oskey = 0; 01098 mmb_emulated = event->val; 01099 } 01100 } 01101 #endif 01102 01103 /* numpad emulation */ 01104 if(U.flag & USER_NONUMPAD) { 01105 switch(event->type) { 01106 case ZEROKEY: event->type = PAD0; break; 01107 case ONEKEY: event->type = PAD1; break; 01108 case TWOKEY: event->type = PAD2; break; 01109 case THREEKEY: event->type = PAD3; break; 01110 case FOURKEY: event->type = PAD4; break; 01111 case FIVEKEY: event->type = PAD5; break; 01112 case SIXKEY: event->type = PAD6; break; 01113 case SEVENKEY: event->type = PAD7; break; 01114 case EIGHTKEY: event->type = PAD8; break; 01115 case NINEKEY: event->type = PAD9; break; 01116 case MINUSKEY: event->type = PADMINUS; break; 01117 case EQUALKEY: event->type = PADPLUSKEY; break; 01118 case BACKSLASHKEY: event->type = PADSLASHKEY; break; 01119 } 01120 } 01121 } 01122 01123 static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi) 01124 { 01125 int kmitype= WM_userdef_event_map(kmi->type); 01126 01127 if(kmi->flag & KMI_INACTIVE) return 0; 01128 01129 /* the matching rules */ 01130 if(kmitype==KM_TEXTINPUT) 01131 if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1; 01132 if(kmitype!=KM_ANY) 01133 if(winevent->type!=kmitype) return 0; 01134 01135 if(kmi->val!=KM_ANY) 01136 if(winevent->val!=kmi->val) return 0; 01137 01138 /* modifiers also check bits, so it allows modifier order */ 01139 if(kmi->shift!=KM_ANY) 01140 if(winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0; 01141 if(kmi->ctrl!=KM_ANY) 01142 if(winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0; 01143 if(kmi->alt!=KM_ANY) 01144 if(winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0; 01145 if(kmi->oskey!=KM_ANY) 01146 if(winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0; 01147 01148 if(kmi->keymodifier) 01149 if(winevent->keymodifier!=kmi->keymodifier) return 0; 01150 01151 /* key modifiers always check when event has it */ 01152 /* otherwise regular keypresses with keymodifier still work */ 01153 if(winevent->keymodifier) 01154 if(ISTEXTINPUT(winevent->type)) 01155 if(winevent->keymodifier!=kmi->keymodifier) return 0; 01156 01157 return 1; 01158 } 01159 01160 01161 /* operator exists */ 01162 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event) 01163 { 01164 /* support for modal keymap in macros */ 01165 if (op->opm) 01166 op = op->opm; 01167 01168 if(op->type->modalkeymap) { 01169 wmKeyMap *keymap= WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); 01170 wmKeyMapItem *kmi; 01171 01172 for(kmi= keymap->items.first; kmi; kmi= kmi->next) { 01173 if(wm_eventmatch(event, kmi)) { 01174 01175 event->type= EVT_MODAL_MAP; 01176 event->val= kmi->propvalue; 01177 } 01178 } 01179 } 01180 } 01181 01182 /* Warning: this function removes a modal handler, when finished */ 01183 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties) 01184 { 01185 int retval= OPERATOR_PASS_THROUGH; 01186 01187 /* derived, modal or blocking operator */ 01188 if(handler->op) { 01189 wmOperator *op= handler->op; 01190 wmOperatorType *ot= op->type; 01191 01192 if(ot->modal) { 01193 /* we set context to where modal handler came from */ 01194 wmWindowManager *wm= CTX_wm_manager(C); 01195 ScrArea *area= CTX_wm_area(C); 01196 ARegion *region= CTX_wm_region(C); 01197 01198 wm_handler_op_context(C, handler); 01199 wm_region_mouse_co(C, event); 01200 wm_event_modalkeymap(C, op, event); 01201 01202 if(ot->flag & OPTYPE_UNDO) 01203 wm->op_undo_depth++; 01204 01205 retval= ot->modal(C, op, event); 01206 01207 if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 01208 wm->op_undo_depth--; 01209 01210 /* putting back screen context, reval can pass trough after modal failures! */ 01211 if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) { 01212 CTX_wm_area_set(C, area); 01213 CTX_wm_region_set(C, region); 01214 } 01215 else { 01216 /* this special cases is for areas and regions that get removed */ 01217 CTX_wm_area_set(C, NULL); 01218 CTX_wm_region_set(C, NULL); 01219 } 01220 01221 if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) 01222 wm_operator_reports(C, op, retval, 0); 01223 01224 if(retval & OPERATOR_FINISHED) { 01225 wm_operator_finished(C, op, 0); 01226 handler->op= NULL; 01227 } 01228 else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { 01229 WM_operator_free(op); 01230 handler->op= NULL; 01231 } 01232 01233 /* remove modal handler, operator itself should have been cancelled and freed */ 01234 if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { 01235 WM_cursor_ungrab(CTX_wm_window(C)); 01236 01237 BLI_remlink(handlers, handler); 01238 wm_event_free_handler(handler); 01239 01240 /* prevent silly errors from operator users */ 01241 //retval &= ~OPERATOR_PASS_THROUGH; 01242 } 01243 01244 } 01245 else 01246 printf("wm_handler_operator_call error\n"); 01247 } 01248 else { 01249 wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0); 01250 01251 if(ot) 01252 retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE); 01253 } 01254 01255 /* Finished and pass through flag as handled */ 01256 if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH)) 01257 return WM_HANDLER_HANDLED; 01258 01259 /* Modal unhandled, break */ 01260 if(retval == (OPERATOR_PASS_THROUGH|OPERATOR_RUNNING_MODAL)) 01261 return (WM_HANDLER_BREAK|WM_HANDLER_MODAL); 01262 01263 if(retval & OPERATOR_PASS_THROUGH) 01264 return WM_HANDLER_CONTINUE; 01265 01266 return WM_HANDLER_BREAK; 01267 } 01268 01269 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */ 01270 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event) 01271 { 01272 wmWindowManager *wm= CTX_wm_manager(C); 01273 SpaceFile *sfile; 01274 int action= WM_HANDLER_CONTINUE; 01275 01276 if(event->type != EVT_FILESELECT) 01277 return action; 01278 if(handler->op != (wmOperator *)event->customdata) 01279 return action; 01280 01281 switch(event->val) { 01282 case EVT_FILESELECT_OPEN: 01283 case EVT_FILESELECT_FULL_OPEN: 01284 { 01285 ScrArea *sa; 01286 01287 /* sa can be null when window A is active, but mouse is over window B */ 01288 /* in this case, open file select in original window A */ 01289 if (handler->op_area == NULL) { 01290 bScreen *screen = CTX_wm_screen(C); 01291 sa = (ScrArea *)screen->areabase.first; 01292 } 01293 else { 01294 sa = handler->op_area; 01295 } 01296 01297 if(event->val==EVT_FILESELECT_OPEN) { 01298 ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */ 01299 } 01300 else { 01301 sa= ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */ 01302 } 01303 01304 /* note, getting the 'sa' back from the context causes a nasty bug where the newly created 01305 * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */ 01306 /* sa = CTX_wm_area(C); */ 01307 01308 /* settings for filebrowser, sfile is not operator owner but sends events */ 01309 sfile= (SpaceFile*)sa->spacedata.first; 01310 sfile->op= handler->op; 01311 01312 ED_fileselect_set_params(sfile); 01313 01314 action= WM_HANDLER_BREAK; 01315 } 01316 break; 01317 01318 case EVT_FILESELECT_EXEC: 01319 case EVT_FILESELECT_CANCEL: 01320 case EVT_FILESELECT_EXTERNAL_CANCEL: 01321 { 01322 /* XXX validate area and region? */ 01323 bScreen *screen= CTX_wm_screen(C); 01324 01325 /* remlink now, for load file case before removing*/ 01326 BLI_remlink(handlers, handler); 01327 01328 if(event->val!=EVT_FILESELECT_EXTERNAL_CANCEL) { 01329 if(screen != handler->filescreen) { 01330 ED_screen_full_prevspace(C, CTX_wm_area(C)); 01331 } 01332 else { 01333 ED_area_prevspace(C, CTX_wm_area(C)); 01334 } 01335 } 01336 01337 wm_handler_op_context(C, handler); 01338 01339 /* needed for uiPupMenuReports */ 01340 01341 if(event->val==EVT_FILESELECT_EXEC) { 01342 #if 0 // use REDALERT now 01343 01344 /* a bit weak, might become arg for WM_event_fileselect? */ 01345 /* XXX also extension code in image-save doesnt work for this yet */ 01346 if (RNA_struct_find_property(handler->op->ptr, "check_existing") && 01347 RNA_boolean_get(handler->op->ptr, "check_existing")) { 01348 char *path= RNA_string_get_alloc(handler->op->ptr, "filepath", NULL, 0); 01349 /* this gives ownership to pupmenu */ 01350 uiPupMenuSaveOver(C, handler->op, (path)? path: ""); 01351 if(path) 01352 MEM_freeN(path); 01353 } 01354 else 01355 #endif 01356 { 01357 int retval; 01358 01359 if(handler->op->type->flag & OPTYPE_UNDO) 01360 wm->op_undo_depth++; 01361 01362 retval= handler->op->type->exec(C, handler->op); 01363 01364 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */ 01365 if(handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) 01366 wm->op_undo_depth--; 01367 01368 if (retval & OPERATOR_FINISHED) 01369 if(G.f & G_DEBUG) 01370 wm_operator_print(C, handler->op); 01371 01372 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */ 01373 if(CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) 01374 if(handler->op->type->flag & OPTYPE_UNDO) 01375 ED_undo_push_op(C, handler->op); 01376 01377 if(handler->op->reports->list.first) { 01378 01379 /* FIXME, temp setting window, this is really bad! 01380 * only have because lib linking errors need to be seen by users :( 01381 * it can be removed without breaking anything but then no linking errors - campbell */ 01382 wmWindow *win_prev= CTX_wm_window(C); 01383 if(win_prev==NULL) 01384 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); 01385 01386 handler->op->reports->printlevel = RPT_WARNING; 01387 uiPupMenuReports(C, handler->op->reports); 01388 01389 /* XXX - copied from 'wm_operator_finished()' */ 01390 /* add reports to the global list, otherwise they are not seen */ 01391 BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list); 01392 01393 CTX_wm_window_set(C, win_prev); 01394 } 01395 01396 WM_operator_free(handler->op); 01397 } 01398 } 01399 else { 01400 if(handler->op->type->cancel) { 01401 if(handler->op->type->flag & OPTYPE_UNDO) 01402 wm->op_undo_depth++; 01403 01404 handler->op->type->cancel(C, handler->op); 01405 01406 if(handler->op->type->flag & OPTYPE_UNDO) 01407 wm->op_undo_depth--; 01408 } 01409 01410 WM_operator_free(handler->op); 01411 } 01412 01413 CTX_wm_area_set(C, NULL); 01414 01415 wm_event_free_handler(handler); 01416 01417 action= WM_HANDLER_BREAK; 01418 } 01419 break; 01420 } 01421 01422 return action; 01423 } 01424 01425 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event) 01426 { 01427 if(handler->bbwin) { 01428 if(handler->bblocal) { 01429 rcti rect= *handler->bblocal; 01430 BLI_translate_rcti(&rect, handler->bbwin->xmin, handler->bbwin->ymin); 01431 01432 if(BLI_in_rcti(&rect, event->x, event->y)) 01433 return 1; 01434 else if(event->type==MOUSEMOVE && BLI_in_rcti(&rect, event->prevx, event->prevy)) 01435 return 1; 01436 else 01437 return 0; 01438 } 01439 else { 01440 if(BLI_in_rcti(handler->bbwin, event->x, event->y)) 01441 return 1; 01442 else if(event->type==MOUSEMOVE && BLI_in_rcti(handler->bbwin, event->prevx, event->prevy)) 01443 return 1; 01444 else 01445 return 0; 01446 } 01447 } 01448 return 1; 01449 } 01450 01451 static int wm_action_not_handled(int action) 01452 { 01453 return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL); 01454 } 01455 01456 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) 01457 { 01458 wmWindowManager *wm= CTX_wm_manager(C); 01459 wmEventHandler *handler, *nexthandler; 01460 int action= WM_HANDLER_CONTINUE; 01461 int always_pass; 01462 01463 if(handlers==NULL) return action; 01464 01465 /* modal handlers can get removed in this loop, we keep the loop this way */ 01466 for(handler= handlers->first; handler; handler= nexthandler) { 01467 01468 nexthandler= handler->next; 01469 01470 /* during this loop, ui handlers for nested menus can tag multiple handlers free */ 01471 if(handler->flag & WM_HANDLER_DO_FREE); 01472 /* optional boundbox */ 01473 else if(handler_boundbox_test(handler, event)) { 01474 /* in advance to avoid access to freed event on window close */ 01475 always_pass= wm_event_always_pass(event); 01476 01477 /* modal+blocking handler */ 01478 if(handler->flag & WM_HANDLER_BLOCKING) 01479 action |= WM_HANDLER_BREAK; 01480 01481 if(handler->keymap) { 01482 wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap); 01483 wmKeyMapItem *kmi; 01484 01485 if(!keymap->poll || keymap->poll(C)) { 01486 for(kmi= keymap->items.first; kmi; kmi= kmi->next) { 01487 if(wm_eventmatch(event, kmi)) { 01488 01489 event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ 01490 01491 action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); 01492 if(action & WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */ 01493 break; 01494 } 01495 } 01496 } 01497 } 01498 else if(handler->ui_handle) { 01499 action |= wm_handler_ui_call(C, handler, event, always_pass); 01500 } 01501 else if(handler->type==WM_HANDLER_FILESELECT) { 01502 /* screen context changes here */ 01503 action |= wm_handler_fileselect_call(C, handlers, handler, event); 01504 } 01505 else if(handler->dropboxes) { 01506 if(event->type==EVT_DROP) { 01507 wmDropBox *drop= handler->dropboxes->first; 01508 for(; drop; drop= drop->next) { 01509 /* other drop custom types allowed */ 01510 if(event->custom==EVT_DATA_LISTBASE) { 01511 ListBase *lb= (ListBase *)event->customdata; 01512 wmDrag *drag; 01513 01514 for(drag= lb->first; drag; drag= drag->next) { 01515 if(drop->poll(C, drag, event)) { 01516 01517 drop->copy(drag, drop); 01518 01519 /* free the drags before calling operator */ 01520 BLI_freelistN(event->customdata); 01521 event->customdata= NULL; 01522 event->custom= 0; 01523 01524 WM_operator_name_call(C, drop->ot->idname, drop->opcontext, drop->ptr); 01525 action |= WM_HANDLER_BREAK; 01526 01527 /* XXX fileread case */ 01528 if(CTX_wm_window(C)==NULL) 01529 return action; 01530 01531 /* escape from drag loop, got freed */ 01532 break; 01533 } 01534 } 01535 } 01536 } 01537 } 01538 } 01539 else { 01540 /* modal, swallows all */ 01541 action |= wm_handler_operator_call(C, handlers, handler, event, NULL); 01542 } 01543 01544 if(action & WM_HANDLER_BREAK) { 01545 if(always_pass) 01546 action &= ~WM_HANDLER_BREAK; 01547 else 01548 break; 01549 } 01550 } 01551 01552 /* XXX fileread case, if the wm is freed then the handler's 01553 * will have been too so the code below need not run. */ 01554 if(CTX_wm_window(C)==NULL) { 01555 return action; 01556 } 01557 01558 /* XXX code this for all modal ops, and ensure free only happens here */ 01559 01560 /* modal ui handler can be tagged to be freed */ 01561 if(BLI_findindex(handlers, handler) != -1) { /* could be free'd already by regular modal ops */ 01562 if(handler->flag & WM_HANDLER_DO_FREE) { 01563 BLI_remlink(handlers, handler); 01564 wm_event_free_handler(handler); 01565 } 01566 } 01567 } 01568 01569 /* test for CLICK event */ 01570 if (wm_action_not_handled(action) && event->val == KM_RELEASE) { 01571 wmWindow *win = CTX_wm_window(C); 01572 01573 if (win && win->eventstate->prevtype == event->type && win->eventstate->prevval == KM_PRESS) { 01574 /* test for double click first, 01575 * note1: this can be problematic because single click operators can get the 01576 * double click event but then with old mouse coords which is highly confusing, 01577 * so check for mouse moves too. 01578 * note2: the first click event will be handled but still used to create a 01579 * double click event if clicking again quickly. 01580 * If no double click events are found it will fallback to a single click. 01581 * So a double click event can result in 2 successive single click calls 01582 * if its not handled by the keymap - campbell */ 01583 if ( (ABS(event->x - win->eventstate->prevclickx)) <= 2 && 01584 (ABS(event->y - win->eventstate->prevclicky)) <= 2 && 01585 ((PIL_check_seconds_timer() - win->eventstate->prevclicktime) * 1000 < U.dbl_click_time) 01586 ) { 01587 event->val = KM_DBL_CLICK; 01588 /* removed this because in cases where we're this is used as a single click 01589 * event, this will give old coords, since the distance is checked above, using new coords should be ok. */ 01590 // event->x = win->eventstate->prevclickx; 01591 // event->y = win->eventstate->prevclicky; 01592 action |= wm_handlers_do(C, event, handlers); 01593 } 01594 01595 if (wm_action_not_handled(action)) { 01596 event->val = KM_CLICK; 01597 action |= wm_handlers_do(C, event, handlers); 01598 } 01599 01600 01601 /* revert value if not handled */ 01602 if (wm_action_not_handled(action)) { 01603 event->val = KM_RELEASE; 01604 } 01605 } 01606 } 01607 01608 if(action == (WM_HANDLER_BREAK|WM_HANDLER_MODAL)) 01609 wm_cursor_arrow_move(CTX_wm_window(C), event); 01610 01611 return action; 01612 } 01613 01614 static int wm_event_inside_i(wmEvent *event, rcti *rect) 01615 { 01616 if(wm_event_always_pass(event)) 01617 return 1; 01618 if(BLI_in_rcti(rect, event->x, event->y)) 01619 return 1; 01620 if(event->type==MOUSEMOVE) { 01621 if( BLI_in_rcti(rect, event->prevx, event->prevy)) { 01622 return 1; 01623 } 01624 return 0; 01625 } 01626 return 0; 01627 } 01628 01629 static ScrArea *area_event_inside(bContext *C, int x, int y) 01630 { 01631 bScreen *screen= CTX_wm_screen(C); 01632 ScrArea *sa; 01633 01634 if(screen) 01635 for(sa= screen->areabase.first; sa; sa= sa->next) 01636 if(BLI_in_rcti(&sa->totrct, x, y)) 01637 return sa; 01638 return NULL; 01639 } 01640 01641 static ARegion *region_event_inside(bContext *C, int x, int y) 01642 { 01643 bScreen *screen= CTX_wm_screen(C); 01644 ScrArea *area= CTX_wm_area(C); 01645 ARegion *ar; 01646 01647 if(screen && area) 01648 for(ar= area->regionbase.first; ar; ar= ar->next) 01649 if(BLI_in_rcti(&ar->winrct, x, y)) 01650 return ar; 01651 return NULL; 01652 } 01653 01654 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar) 01655 { 01656 if(ar) { 01657 for(; pc; pc= pc->next) { 01658 if(pc->poll == NULL || pc->poll(C)) { 01659 wmWindow *win= CTX_wm_window(C); 01660 win->screen->do_draw_paintcursor= 1; 01661 wm_tag_redraw_overlay(win, ar); 01662 } 01663 } 01664 } 01665 } 01666 01667 /* called on mousemove, check updates for paintcursors */ 01668 /* context was set on active area and region */ 01669 static void wm_paintcursor_test(bContext *C, wmEvent *event) 01670 { 01671 wmWindowManager *wm= CTX_wm_manager(C); 01672 01673 if(wm->paintcursors.first) { 01674 ARegion *ar= CTX_wm_region(C); 01675 01676 if(ar) 01677 wm_paintcursor_tag(C, wm->paintcursors.first, ar); 01678 01679 /* if previous position was not in current region, we have to set a temp new context */ 01680 if(ar==NULL || !BLI_in_rcti(&ar->winrct, event->prevx, event->prevy)) { 01681 ScrArea *sa= CTX_wm_area(C); 01682 01683 CTX_wm_area_set(C, area_event_inside(C, event->prevx, event->prevy)); 01684 CTX_wm_region_set(C, region_event_inside(C, event->prevx, event->prevy)); 01685 01686 wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C)); 01687 01688 CTX_wm_area_set(C, sa); 01689 CTX_wm_region_set(C, ar); 01690 } 01691 } 01692 } 01693 01694 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event) 01695 { 01696 if(wm->drags.first==NULL) return; 01697 01698 if(event->type==MOUSEMOVE) 01699 win->screen->do_draw_drag= 1; 01700 else if(event->type==ESCKEY) { 01701 BLI_freelistN(&wm->drags); 01702 win->screen->do_draw_drag= 1; 01703 } 01704 else if(event->type==LEFTMOUSE && event->val==KM_RELEASE) { 01705 event->type= EVT_DROP; 01706 01707 /* create customdata, first free existing */ 01708 if(event->customdata) { 01709 if(event->customdatafree) 01710 MEM_freeN(event->customdata); 01711 } 01712 01713 event->custom= EVT_DATA_LISTBASE; 01714 event->customdata= &wm->drags; 01715 event->customdatafree= 1; 01716 01717 /* clear drop icon */ 01718 win->screen->do_draw_drag= 1; 01719 01720 /* restore cursor (disabled, see wm_dragdrop.c) */ 01721 // WM_cursor_restore(win); 01722 } 01723 01724 /* overlap fails otherwise */ 01725 if(win->screen->do_draw_drag) 01726 if(win->drawmethod == USER_DRAW_OVERLAP) 01727 win->screen->do_draw= 1; 01728 01729 } 01730 01731 /* called in main loop */ 01732 /* goes over entire hierarchy: events -> window -> screen -> area -> region */ 01733 void wm_event_do_handlers(bContext *C) 01734 { 01735 wmWindowManager *wm= CTX_wm_manager(C); 01736 wmWindow *win; 01737 01738 /* update key configuration before handling events */ 01739 WM_keyconfig_update(wm); 01740 01741 for(win= wm->windows.first; win; win= win->next) { 01742 wmEvent *event; 01743 01744 if( win->screen==NULL ) 01745 wm_event_free_all(win); 01746 else { 01747 Scene* scene = win->screen->scene; 01748 01749 if(scene) { 01750 int playing = sound_scene_playing(win->screen->scene); 01751 01752 if(playing != -1) { 01753 CTX_wm_window_set(C, win); 01754 CTX_wm_screen_set(C, win->screen); 01755 CTX_data_scene_set(C, scene); 01756 01757 if(((playing == 1) && (!win->screen->animtimer)) || ((playing == 0) && (win->screen->animtimer))){ 01758 ED_screen_animation_play(C, -1, 1); 01759 } 01760 01761 if(playing == 0) { 01762 int ncfra = sound_sync_scene(scene) * (float)FPS + 0.5f; 01763 if(ncfra != scene->r.cfra) { 01764 scene->r.cfra = ncfra; 01765 ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1); 01766 WM_event_add_notifier(C, NC_WINDOW, NULL); 01767 } 01768 } 01769 01770 CTX_data_scene_set(C, NULL); 01771 CTX_wm_screen_set(C, NULL); 01772 CTX_wm_window_set(C, NULL); 01773 } 01774 } 01775 } 01776 01777 while( (event= win->queue.first) ) { 01778 int action = WM_HANDLER_CONTINUE; 01779 01780 if((G.f & G_DEBUG) && event && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) 01781 printf("pass on evt %d val %d\n", event->type, event->val); 01782 01783 wm_eventemulation(event); 01784 01785 CTX_wm_window_set(C, win); 01786 01787 /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ 01788 CTX_wm_area_set(C, area_event_inside(C, event->x, event->y)); 01789 CTX_wm_region_set(C, region_event_inside(C, event->x, event->y)); 01790 01791 /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */ 01792 wm_window_make_drawable(C, win); 01793 01794 wm_region_mouse_co(C, event); 01795 01796 /* first we do priority handlers, modal + some limited keymaps */ 01797 action |= wm_handlers_do(C, event, &win->modalhandlers); 01798 01799 /* fileread case */ 01800 if(CTX_wm_window(C)==NULL) 01801 return; 01802 01803 /* check dragging, creates new event or frees, adds draw tag */ 01804 wm_event_drag_test(wm, win, event); 01805 01806 /* builtin tweak, if action is break it removes tweak */ 01807 wm_tweakevent_test(C, event, action); 01808 01809 if((action & WM_HANDLER_BREAK) == 0) { 01810 ScrArea *sa; 01811 ARegion *ar; 01812 int doit= 0; 01813 01814 /* Note: setting subwin active should be done here, after modal handlers have been done */ 01815 if(event->type==MOUSEMOVE) { 01816 /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */ 01817 ED_screen_set_subwinactive(C, event); 01818 /* for regions having custom cursors */ 01819 wm_paintcursor_test(C, event); 01820 } 01821 else if (event->type==NDOF_MOTION) { 01822 win->addmousemove = TRUE; 01823 } 01824 01825 for(sa= win->screen->areabase.first; sa; sa= sa->next) { 01826 if(wm_event_inside_i(event, &sa->totrct)) { 01827 CTX_wm_area_set(C, sa); 01828 01829 if((action & WM_HANDLER_BREAK) == 0) { 01830 for(ar=sa->regionbase.first; ar; ar= ar->next) { 01831 if(wm_event_inside_i(event, &ar->winrct)) { 01832 CTX_wm_region_set(C, ar); 01833 01834 /* call even on non mouse events, since the */ 01835 wm_region_mouse_co(C, event); 01836 01837 /* does polls for drop regions and checks uibuts */ 01838 /* need to be here to make sure region context is true */ 01839 if(ELEM(event->type, MOUSEMOVE, EVT_DROP)) { 01840 wm_drags_check_ops(C, event); 01841 } 01842 01843 action |= wm_handlers_do(C, event, &ar->handlers); 01844 01845 /* fileread case (python), [#29489] */ 01846 if(CTX_wm_window(C)==NULL) 01847 return; 01848 01849 doit |= (BLI_in_rcti(&ar->winrct, event->x, event->y)); 01850 01851 if(action & WM_HANDLER_BREAK) 01852 break; 01853 } 01854 } 01855 } 01856 01857 CTX_wm_region_set(C, NULL); 01858 01859 if((action & WM_HANDLER_BREAK) == 0) { 01860 wm_region_mouse_co(C, event); /* only invalidates event->mval in this case */ 01861 action |= wm_handlers_do(C, event, &sa->handlers); 01862 } 01863 CTX_wm_area_set(C, NULL); 01864 01865 /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */ 01866 } 01867 } 01868 01869 if((action & WM_HANDLER_BREAK) == 0) { 01870 /* also some non-modal handlers need active area/region */ 01871 CTX_wm_area_set(C, area_event_inside(C, event->x, event->y)); 01872 CTX_wm_region_set(C, region_event_inside(C, event->x, event->y)); 01873 01874 wm_region_mouse_co(C, event); 01875 01876 action |= wm_handlers_do(C, event, &win->handlers); 01877 01878 /* fileread case */ 01879 if(CTX_wm_window(C)==NULL) 01880 return; 01881 } 01882 01883 /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? 01884 doing it on ghost queue gives errors when mousemoves go over area borders */ 01885 if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) { 01886 win->eventstate->prevx= event->x; 01887 win->eventstate->prevy= event->y; 01888 //printf("win->eventstate->prev = %d %d\n", event->x, event->y); 01889 } 01890 else 01891 ;//printf("not setting prev to %d %d\n", event->x, event->y); 01892 } 01893 01894 /* store last event for this window */ 01895 /* mousemove and timer events don't overwrite last type */ 01896 if (event->type != MOUSEMOVE && !ISTIMER(event->type)) { 01897 if (wm_action_not_handled(action)) { 01898 if (win->eventstate->prevtype == event->type) { 01899 /* set click time on first click (press -> release) */ 01900 if (win->eventstate->prevval == KM_PRESS && event->val == KM_RELEASE) { 01901 win->eventstate->prevclicktime = PIL_check_seconds_timer(); 01902 win->eventstate->prevclickx = event->x; 01903 win->eventstate->prevclicky = event->y; 01904 } 01905 } else { 01906 /* reset click time if event type not the same */ 01907 win->eventstate->prevclicktime = 0; 01908 } 01909 01910 win->eventstate->prevval = event->val; 01911 win->eventstate->prevtype = event->type; 01912 } else if (event->val == KM_CLICK) { /* keep click for double click later */ 01913 win->eventstate->prevtype = event->type; 01914 win->eventstate->prevval = event->val; 01915 win->eventstate->prevclicktime = PIL_check_seconds_timer(); 01916 win->eventstate->prevclickx = event->x; 01917 win->eventstate->prevclicky = event->y; 01918 } else { /* reset if not */ 01919 win->eventstate->prevtype = -1; 01920 win->eventstate->prevval = 0; 01921 win->eventstate->prevclicktime = 0; 01922 } 01923 } 01924 01925 /* unlink and free here, blender-quit then frees all */ 01926 BLI_remlink(&win->queue, event); 01927 wm_event_free(event); 01928 01929 } 01930 01931 /* only add mousemove when queue was read entirely */ 01932 if(win->addmousemove && win->eventstate) { 01933 wmEvent tevent= *(win->eventstate); 01934 //printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y); 01935 tevent.type= MOUSEMOVE; 01936 tevent.prevx= tevent.x; 01937 tevent.prevy= tevent.y; 01938 wm_event_add(win, &tevent); 01939 win->addmousemove= 0; 01940 } 01941 01942 CTX_wm_window_set(C, NULL); 01943 } 01944 01945 /* update key configuration after handling events */ 01946 WM_keyconfig_update(wm); 01947 } 01948 01949 /* ********** filesector handling ************ */ 01950 01951 void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval) 01952 { 01953 /* add to all windows! */ 01954 wmWindow *win; 01955 01956 for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) { 01957 wmEvent event= *win->eventstate; 01958 01959 event.type= EVT_FILESELECT; 01960 event.val= eventval; 01961 event.customdata= ophandle; // only as void pointer type check 01962 01963 wm_event_add(win, &event); 01964 } 01965 } 01966 01967 /* operator is supposed to have a filled "path" property */ 01968 /* optional property: filetype (XXX enum?) */ 01969 01970 /* Idea is to keep a handler alive on window queue, owning the operator. 01971 The filewindow can send event to make it execute, thus ensuring 01972 executing happens outside of lower level queues, with UI refreshed. 01973 Should also allow multiwin solutions */ 01974 01975 void WM_event_add_fileselect(bContext *C, wmOperator *op) 01976 { 01977 wmEventHandler *handler, *handlernext; 01978 wmWindow *win= CTX_wm_window(C); 01979 int full= 1; // XXX preset? 01980 01981 /* only allow 1 file selector open per window */ 01982 for(handler= win->modalhandlers.first; handler; handler=handlernext) { 01983 handlernext= handler->next; 01984 01985 if(handler->type == WM_HANDLER_FILESELECT) { 01986 if(handler->op) 01987 WM_operator_free(handler->op); 01988 BLI_remlink(&win->modalhandlers, handler); 01989 wm_event_free_handler(handler); 01990 } 01991 } 01992 01993 handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler"); 01994 01995 handler->type= WM_HANDLER_FILESELECT; 01996 handler->op= op; 01997 handler->op_area= CTX_wm_area(C); 01998 handler->op_region= CTX_wm_region(C); 01999 handler->filescreen= CTX_wm_screen(C); 02000 02001 BLI_addhead(&win->modalhandlers, handler); 02002 02003 /* check props once before invoking if check is available 02004 * ensures initial properties are valid */ 02005 if(op->type->check) { 02006 op->type->check(C, op); /* ignore return value */ 02007 } 02008 02009 WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN); 02010 } 02011 02012 #if 0 02013 /* lets not expose struct outside wm? */ 02014 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag) 02015 { 02016 handler->flag= flag; 02017 } 02018 #endif 02019 02020 wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) 02021 { 02022 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler"); 02023 wmWindow *win= CTX_wm_window(C); 02024 02025 /* operator was part of macro */ 02026 if(op->opm) { 02027 /* give the mother macro to the handler */ 02028 handler->op= op->opm; 02029 /* mother macro opm becomes the macro element */ 02030 handler->op->opm= op; 02031 } 02032 else 02033 handler->op= op; 02034 02035 handler->op_area= CTX_wm_area(C); /* means frozen screen context for modal handlers! */ 02036 handler->op_region= CTX_wm_region(C); 02037 02038 BLI_addhead(&win->modalhandlers, handler); 02039 02040 return handler; 02041 } 02042 02043 wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap) 02044 { 02045 wmEventHandler *handler; 02046 02047 if(!keymap) { 02048 printf("WM_event_add_keymap_handler called with NULL keymap\n"); 02049 return NULL; 02050 } 02051 02052 /* only allow same keymap once */ 02053 for(handler= handlers->first; handler; handler= handler->next) 02054 if(handler->keymap==keymap) 02055 return handler; 02056 02057 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler"); 02058 BLI_addtail(handlers, handler); 02059 handler->keymap= keymap; 02060 02061 return handler; 02062 } 02063 02064 /* priorities not implemented yet, for time being just insert in begin of list */ 02065 wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority)) 02066 { 02067 wmEventHandler *handler; 02068 02069 WM_event_remove_keymap_handler(handlers, keymap); 02070 02071 handler= MEM_callocN(sizeof(wmEventHandler), "event keymap handler"); 02072 BLI_addhead(handlers, handler); 02073 handler->keymap= keymap; 02074 02075 return handler; 02076 } 02077 02078 wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, rcti *bblocal, rcti *bbwin) 02079 { 02080 wmEventHandler *handler= WM_event_add_keymap_handler(handlers, keymap); 02081 02082 if(handler) { 02083 handler->bblocal= bblocal; 02084 handler->bbwin= bbwin; 02085 } 02086 return handler; 02087 } 02088 02089 void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) 02090 { 02091 wmEventHandler *handler; 02092 02093 for(handler= handlers->first; handler; handler= handler->next) { 02094 if(handler->keymap==keymap) { 02095 BLI_remlink(handlers, handler); 02096 wm_event_free_handler(handler); 02097 break; 02098 } 02099 } 02100 } 02101 02102 wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata) 02103 { 02104 wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event ui handler"); 02105 handler->ui_handle= func; 02106 handler->ui_remove= remove; 02107 handler->ui_userdata= userdata; 02108 handler->ui_area= (C)? CTX_wm_area(C): NULL; 02109 handler->ui_region= (C)? CTX_wm_region(C): NULL; 02110 handler->ui_menu= (C)? CTX_wm_menu(C): NULL; 02111 02112 BLI_addhead(handlers, handler); 02113 02114 return handler; 02115 } 02116 02117 /* set "postpone" for win->modalhandlers, this is in a running for() loop in wm_handlers_do() */ 02118 void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, int postpone) 02119 { 02120 wmEventHandler *handler; 02121 02122 for(handler= handlers->first; handler; handler= handler->next) { 02123 if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) { 02124 /* handlers will be freed in wm_handlers_do() */ 02125 if(postpone) { 02126 handler->flag |= WM_HANDLER_DO_FREE; 02127 } 02128 else { 02129 BLI_remlink(handlers, handler); 02130 wm_event_free_handler(handler); 02131 } 02132 break; 02133 } 02134 } 02135 } 02136 02137 wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes) 02138 { 02139 wmEventHandler *handler; 02140 02141 /* only allow same dropbox once */ 02142 for(handler= handlers->first; handler; handler= handler->next) 02143 if(handler->dropboxes==dropboxes) 02144 return handler; 02145 02146 handler= MEM_callocN(sizeof(wmEventHandler), "dropbox handler"); 02147 02148 /* dropbox stored static, no free or copy */ 02149 handler->dropboxes= dropboxes; 02150 BLI_addhead(handlers, handler); 02151 02152 return handler; 02153 } 02154 02155 /* XXX solution works, still better check the real cause (ton) */ 02156 void WM_event_remove_area_handler(ListBase *handlers, void *area) 02157 { 02158 wmEventHandler *handler, *nexthandler; 02159 02160 for(handler = handlers->first; handler; handler= nexthandler) { 02161 nexthandler = handler->next; 02162 if (handler->type != WM_HANDLER_FILESELECT) { 02163 if (handler->ui_area == area) { 02164 BLI_remlink(handlers, handler); 02165 wm_event_free_handler(handler); 02166 } 02167 } 02168 } 02169 } 02170 02171 #if 0 02172 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler) 02173 { 02174 BLI_remlink(handlers, handler); 02175 wm_event_free_handler(handler); 02176 } 02177 #endif 02178 02179 void WM_event_add_mousemove(bContext *C) 02180 { 02181 wmWindow *window= CTX_wm_window(C); 02182 02183 window->addmousemove= 1; 02184 } 02185 02186 /* for modal callbacks, check configuration for how to interpret exit with tweaks */ 02187 int WM_modal_tweak_exit(wmEvent *evt, int tweak_event) 02188 { 02189 /* if the release-confirm userpref setting is enabled, 02190 * tweak events can be cancelled when mouse is released 02191 */ 02192 if (U.flag & USER_RELEASECONFIRM) { 02193 /* option on, so can exit with km-release */ 02194 if (evt->val == KM_RELEASE) { 02195 switch (tweak_event) { 02196 case EVT_TWEAK_L: 02197 case EVT_TWEAK_M: 02198 case EVT_TWEAK_R: 02199 return 1; 02200 } 02201 } 02202 else { 02203 /* if the initial event wasn't a tweak event then 02204 * ignore USER_RELEASECONFIRM setting: see [#26756] */ 02205 if(ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { 02206 return 1; 02207 } 02208 } 02209 } 02210 else { 02211 /* this is fine as long as not doing km-release, otherwise 02212 * some items (i.e. markers) being tweaked may end up getting 02213 * dropped all over 02214 */ 02215 if (evt->val != KM_RELEASE) 02216 return 1; 02217 } 02218 02219 return 0; 02220 } 02221 02222 /* ********************* ghost stuff *************** */ 02223 02224 static int convert_key(GHOST_TKey key) 02225 { 02226 if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) { 02227 return (AKEY + ((int) key - GHOST_kKeyA)); 02228 } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) { 02229 return (ZEROKEY + ((int) key - GHOST_kKey0)); 02230 } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) { 02231 return (PAD0 + ((int) key - GHOST_kKeyNumpad0)); 02232 } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF19) { 02233 return (F1KEY + ((int) key - GHOST_kKeyF1)); 02234 } else { 02235 switch (key) { 02236 case GHOST_kKeyBackSpace: return BACKSPACEKEY; 02237 case GHOST_kKeyTab: return TABKEY; 02238 case GHOST_kKeyLinefeed: return LINEFEEDKEY; 02239 case GHOST_kKeyClear: return 0; 02240 case GHOST_kKeyEnter: return RETKEY; 02241 02242 case GHOST_kKeyEsc: return ESCKEY; 02243 case GHOST_kKeySpace: return SPACEKEY; 02244 case GHOST_kKeyQuote: return QUOTEKEY; 02245 case GHOST_kKeyComma: return COMMAKEY; 02246 case GHOST_kKeyMinus: return MINUSKEY; 02247 case GHOST_kKeyPeriod: return PERIODKEY; 02248 case GHOST_kKeySlash: return SLASHKEY; 02249 02250 case GHOST_kKeySemicolon: return SEMICOLONKEY; 02251 case GHOST_kKeyEqual: return EQUALKEY; 02252 02253 case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY; 02254 case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY; 02255 case GHOST_kKeyBackslash: return BACKSLASHKEY; 02256 case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY; 02257 02258 case GHOST_kKeyLeftShift: return LEFTSHIFTKEY; 02259 case GHOST_kKeyRightShift: return RIGHTSHIFTKEY; 02260 case GHOST_kKeyLeftControl: return LEFTCTRLKEY; 02261 case GHOST_kKeyRightControl: return RIGHTCTRLKEY; 02262 case GHOST_kKeyOS: return OSKEY; 02263 case GHOST_kKeyLeftAlt: return LEFTALTKEY; 02264 case GHOST_kKeyRightAlt: return RIGHTALTKEY; 02265 02266 case GHOST_kKeyCapsLock: return CAPSLOCKKEY; 02267 case GHOST_kKeyNumLock: return 0; 02268 case GHOST_kKeyScrollLock: return 0; 02269 02270 case GHOST_kKeyLeftArrow: return LEFTARROWKEY; 02271 case GHOST_kKeyRightArrow: return RIGHTARROWKEY; 02272 case GHOST_kKeyUpArrow: return UPARROWKEY; 02273 case GHOST_kKeyDownArrow: return DOWNARROWKEY; 02274 02275 case GHOST_kKeyPrintScreen: return 0; 02276 case GHOST_kKeyPause: return PAUSEKEY; 02277 02278 case GHOST_kKeyInsert: return INSERTKEY; 02279 case GHOST_kKeyDelete: return DELKEY; 02280 case GHOST_kKeyHome: return HOMEKEY; 02281 case GHOST_kKeyEnd: return ENDKEY; 02282 case GHOST_kKeyUpPage: return PAGEUPKEY; 02283 case GHOST_kKeyDownPage: return PAGEDOWNKEY; 02284 02285 case GHOST_kKeyNumpadPeriod: return PADPERIOD; 02286 case GHOST_kKeyNumpadEnter: return PADENTER; 02287 case GHOST_kKeyNumpadPlus: return PADPLUSKEY; 02288 case GHOST_kKeyNumpadMinus: return PADMINUS; 02289 case GHOST_kKeyNumpadAsterisk: return PADASTERKEY; 02290 case GHOST_kKeyNumpadSlash: return PADSLASHKEY; 02291 02292 case GHOST_kKeyGrLess: return GRLESSKEY; 02293 02294 case GHOST_kKeyMediaPlay: return MEDIAPLAY; 02295 case GHOST_kKeyMediaStop: return MEDIASTOP; 02296 case GHOST_kKeyMediaFirst: return MEDIAFIRST; 02297 case GHOST_kKeyMediaLast: return MEDIALAST; 02298 02299 default: 02300 return UNKNOWNKEY; /* GHOST_kKeyUnknown */ 02301 } 02302 } 02303 } 02304 02305 /* adds customdata to event */ 02306 static void update_tablet_data(wmWindow *win, wmEvent *event) 02307 { 02308 const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin); 02309 02310 /* if there's tablet data from an active tablet device then add it */ 02311 if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { 02312 struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet"); 02313 02314 wmtab->Active = (int)td->Active; 02315 wmtab->Pressure = td->Pressure; 02316 wmtab->Xtilt = td->Xtilt; 02317 wmtab->Ytilt = td->Ytilt; 02318 02319 event->custom= EVT_DATA_TABLET; 02320 event->customdata= wmtab; 02321 event->customdatafree= 1; 02322 } 02323 } 02324 02325 /* adds customdata to event */ 02326 static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost) 02327 { 02328 wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF"); 02329 02330 const float s = U.ndof_sensitivity; 02331 02332 data->tx = s * ghost->tx; 02333 02334 data->rx = s * ghost->rx; 02335 data->ry = s * ghost->ry; 02336 data->rz = s * ghost->rz; 02337 02338 if (U.ndof_flag & NDOF_ZOOM_UPDOWN) 02339 { 02340 /* rotate so Y is where Z was */ 02341 data->ty = s * ghost->tz; 02342 data->tz = s * ghost->ty; 02343 /* maintain handed-ness? or just do what feels right? */ 02344 02345 /* should this affect rotation also? 02346 * initial guess is 'yes', but get user feedback immediately! 02347 */ 02348 #if 0 02349 /* after turning this on, my guess becomes 'no' */ 02350 data->ry = s * ghost->rz; 02351 data->rz = s * ghost->ry; 02352 #endif 02353 } 02354 else 02355 { 02356 data->ty = s * ghost->ty; 02357 data->tz = s * ghost->tz; 02358 } 02359 02360 data->dt = ghost->dt; 02361 02362 data->progress = (wmProgress) ghost->progress; 02363 02364 event->custom = EVT_DATA_NDOF_MOTION; 02365 event->customdata = data; 02366 event->customdatafree = 1; 02367 } 02368 02369 /* imperfect but probably usable... draw/enable drags to other windows */ 02370 static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt) 02371 { 02372 int mx= evt->x, my= evt->y; 02373 02374 if(wm->windows.first== wm->windows.last) 02375 return NULL; 02376 02377 /* top window bar... */ 02378 if(mx<0 || my<0 || mx>win->sizex || my>win->sizey+30) { 02379 wmWindow *owin; 02380 wmEventHandler *handler; 02381 02382 /* let's skip windows having modal handlers now */ 02383 /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */ 02384 for(handler= win->modalhandlers.first; handler; handler= handler->next) 02385 if(handler->ui_handle || handler->op) 02386 return NULL; 02387 02388 /* to desktop space */ 02389 mx += (int)win->posx; 02390 my += (int)win->posy; 02391 02392 /* check other windows to see if it has mouse inside */ 02393 for(owin= wm->windows.first; owin; owin= owin->next) { 02394 02395 if(owin!=win) { 02396 if(mx-owin->posx >= 0 && my-owin->posy >= 0 && 02397 mx-owin->posx <= owin->sizex && my-owin->posy <= owin->sizey) { 02398 evt->x= mx - (int)owin->posx; 02399 evt->y= my - (int)owin->posy; 02400 02401 return owin; 02402 } 02403 } 02404 } 02405 } 02406 return NULL; 02407 } 02408 02409 /* windows store own event queues, no bContext here */ 02410 /* time is in 1000s of seconds, from ghost */ 02411 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata) 02412 { 02413 wmWindow *owin; 02414 wmEvent event, *evt= win->eventstate; 02415 02416 /* initialize and copy state (only mouse x y and modifiers) */ 02417 event= *evt; 02418 02419 switch (type) { 02420 /* mouse move */ 02421 case GHOST_kEventCursorMove: { 02422 if(win->active) { 02423 GHOST_TEventCursorData *cd= customdata; 02424 wmEvent *lastevent= win->queue.last; 02425 int cx, cy; 02426 02427 GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy); 02428 evt->x= cx; 02429 evt->y= (win->sizey-1) - cy; 02430 02431 event.x= evt->x; 02432 event.y= evt->y; 02433 02434 event.type= MOUSEMOVE; 02435 02436 /* some painting operators want accurate mouse events, they can 02437 handle in between mouse move moves, others can happily ignore 02438 them for better performance */ 02439 if(lastevent && lastevent->type == MOUSEMOVE) 02440 lastevent->type = INBETWEEN_MOUSEMOVE; 02441 02442 update_tablet_data(win, &event); 02443 wm_event_add(win, &event); 02444 02445 //printf("sending MOUSEMOVE %d %d\n", event.x, event.y); 02446 02447 /* also add to other window if event is there, this makes overdraws disappear nicely */ 02448 /* it remaps mousecoord to other window in event */ 02449 owin= wm_event_cursor_other_windows(wm, win, &event); 02450 if(owin) { 02451 wmEvent oevent= *(owin->eventstate); 02452 02453 oevent.x=owin->eventstate->x= event.x; 02454 oevent.y=owin->eventstate->y= event.y; 02455 oevent.type= MOUSEMOVE; 02456 02457 update_tablet_data(owin, &oevent); 02458 wm_event_add(owin, &oevent); 02459 } 02460 02461 } 02462 break; 02463 } 02464 case GHOST_kEventTrackpad: { 02465 GHOST_TEventTrackpadData * pd = customdata; 02466 switch (pd->subtype) { 02467 case GHOST_kTrackpadEventMagnify: 02468 event.type = MOUSEZOOM; 02469 break; 02470 case GHOST_kTrackpadEventRotate: 02471 event.type = MOUSEROTATE; 02472 break; 02473 case GHOST_kTrackpadEventScroll: 02474 default: 02475 event.type= MOUSEPAN; 02476 break; 02477 } 02478 02479 { 02480 int cx, cy; 02481 GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy); 02482 event.x= evt->x= cx; 02483 event.y= evt->y= (win->sizey-1) - cy; 02484 } 02485 02486 // Use prevx/prevy so we can calculate the delta later 02487 event.prevx= event.x - pd->deltaX; 02488 event.prevy= event.y - (-pd->deltaY); 02489 02490 update_tablet_data(win, &event); 02491 wm_event_add(win, &event); 02492 break; 02493 } 02494 /* mouse button */ 02495 case GHOST_kEventButtonDown: 02496 case GHOST_kEventButtonUp: { 02497 GHOST_TEventButtonData *bd= customdata; 02498 event.val= (type==GHOST_kEventButtonDown) ? KM_PRESS:KM_RELEASE; /* Note!, this starts as 0/1 but later is converted to KM_PRESS/KM_RELEASE by tweak */ 02499 02500 if (bd->button == GHOST_kButtonMaskLeft) 02501 event.type= LEFTMOUSE; 02502 else if (bd->button == GHOST_kButtonMaskRight) 02503 event.type= RIGHTMOUSE; 02504 else if (bd->button == GHOST_kButtonMaskButton4) 02505 event.type= BUTTON4MOUSE; 02506 else if (bd->button == GHOST_kButtonMaskButton5) 02507 event.type= BUTTON5MOUSE; 02508 else 02509 event.type= MIDDLEMOUSE; 02510 02511 if(win->active==0) { 02512 int cx, cy; 02513 02514 /* entering window, update mouse pos. (ghost sends win-activate *after* the mouseclick in window!) */ 02515 wm_get_cursor_position(win, &cx, &cy); 02516 02517 event.x= evt->x= cx; 02518 event.y= evt->y= cy; 02519 } 02520 02521 /* add to other window if event is there (not to both!) */ 02522 owin= wm_event_cursor_other_windows(wm, win, &event); 02523 if(owin) { 02524 wmEvent oevent= *(owin->eventstate); 02525 02526 oevent.x= event.x; 02527 oevent.y= event.y; 02528 oevent.type= event.type; 02529 oevent.val= event.val; 02530 02531 update_tablet_data(owin, &oevent); 02532 wm_event_add(owin, &oevent); 02533 } 02534 else { 02535 update_tablet_data(win, &event); 02536 wm_event_add(win, &event); 02537 } 02538 02539 break; 02540 } 02541 /* keyboard */ 02542 case GHOST_kEventKeyDown: 02543 case GHOST_kEventKeyUp: { 02544 GHOST_TEventKeyData *kd= customdata; 02545 event.type= convert_key(kd->key); 02546 event.ascii= kd->ascii; 02547 event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE; 02548 02549 /* exclude arrow keys, esc, etc from text input */ 02550 if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0)) 02551 event.ascii= '\0'; 02552 02553 /* modifiers */ 02554 if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) { 02555 event.shift= evt->shift= (event.val==KM_PRESS); 02556 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey)) 02557 event.shift= evt->shift = 3; // define? 02558 } 02559 else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) { 02560 event.ctrl= evt->ctrl= (event.val==KM_PRESS); 02561 if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey)) 02562 event.ctrl= evt->ctrl = 3; // define? 02563 } 02564 else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) { 02565 event.alt= evt->alt= (event.val==KM_PRESS); 02566 if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey)) 02567 event.alt= evt->alt = 3; // define? 02568 } 02569 else if (event.type==OSKEY) { 02570 event.oskey= evt->oskey= (event.val==KM_PRESS); 02571 if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift)) 02572 event.oskey= evt->oskey = 3; // define? 02573 } 02574 else { 02575 if(event.val==KM_PRESS && event.keymodifier==0) 02576 evt->keymodifier= event.type; /* only set in eventstate, for next event */ 02577 else if(event.val==KM_RELEASE && event.keymodifier==event.type) 02578 event.keymodifier= evt->keymodifier= 0; 02579 } 02580 02581 /* this case happens on some systems that on holding a key pressed, 02582 generate press events without release, we still want to keep the 02583 modifier in win->eventstate, but for the press event of the same 02584 key we don't want the key modifier */ 02585 if(event.keymodifier == event.type) 02586 event.keymodifier= 0; 02587 02588 /* if test_break set, it catches this. XXX Keep global for now? */ 02589 if(event.type==ESCKEY) 02590 G.afbreek= 1; 02591 02592 wm_event_add(win, &event); 02593 02594 break; 02595 } 02596 02597 case GHOST_kEventWheel: { 02598 GHOST_TEventWheelData* wheelData = customdata; 02599 02600 if (wheelData->z > 0) 02601 event.type= WHEELUPMOUSE; 02602 else 02603 event.type= WHEELDOWNMOUSE; 02604 02605 event.val= KM_PRESS; 02606 wm_event_add(win, &event); 02607 02608 break; 02609 } 02610 case GHOST_kEventTimer: { 02611 event.type= TIMER; 02612 event.custom= EVT_DATA_TIMER; 02613 event.customdata= customdata; 02614 wm_event_add(win, &event); 02615 02616 break; 02617 } 02618 02619 case GHOST_kEventNDOFMotion: { 02620 event.type = NDOF_MOTION; 02621 attach_ndof_data(&event, customdata); 02622 wm_event_add(win, &event); 02623 02624 //printf("sending NDOF_MOTION, prev = %d %d\n", event.x, event.y); 02625 02626 break; 02627 } 02628 02629 case GHOST_kEventNDOFButton: { 02630 GHOST_TEventNDOFButtonData* e = customdata; 02631 02632 event.type = NDOF_BUTTON_NONE + e->button; 02633 02634 switch (e->action) { 02635 case GHOST_kPress: 02636 event.val = KM_PRESS; 02637 break; 02638 case GHOST_kRelease: 02639 event.val = KM_RELEASE; 02640 break; 02641 } 02642 02643 event.custom = 0; 02644 event.customdata = NULL; 02645 02646 wm_event_add(win, &event); 02647 02648 break; 02649 } 02650 02651 case GHOST_kEventUnknown: 02652 case GHOST_kNumEventTypes: 02653 break; 02654 02655 case GHOST_kEventWindowDeactivate: { 02656 event.type= WINDEACTIVATE; 02657 wm_event_add(win, &event); 02658 02659 break; 02660 02661 } 02662 02663 } 02664 }