Blender  V2.59
wm_event_system.c
Go to the documentation of this file.
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(&note->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(&note->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 }