Blender V2.61 - r43446

wm_event_system.c

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