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