Merge branch 'master' into blender2.8
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/windowmanager/intern/wm_event_system.c
28  *  \ingroup wm
29  *
30  * Handle events and notifiers from GHOST input (mouse, keyboard, tablet, ndof).
31  *
32  * Also some operator reports utility functions.
33  */
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "DNA_listBase.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_windowmanager_types.h"
42 #include "DNA_userdef_types.h"
43
44 #include "MEM_guardedalloc.h"
45
46 #include "GHOST_C-api.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_dynstr.h"
50 #include "BLI_utildefines.h"
51 #include "BLI_math.h"
52
53 #include "BKE_context.h"
54 #include "BKE_idprop.h"
55 #include "BKE_global.h"
56 #include "BKE_layer.h"
57 #include "BKE_main.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_workspace.h"
62
63 #include "BKE_sound.h"
64
65 #include "ED_fileselect.h"
66 #include "ED_info.h"
67 #include "ED_screen.h"
68 #include "ED_view3d.h"
69 #include "ED_util.h"
70
71 #include "RNA_access.h"
72
73 #include "UI_interface.h"
74
75 #include "PIL_time.h"
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79 #include "WM_message.h"
80 #include "wm.h"
81 #include "wm_window.h"
82 #include "wm_event_system.h"
83 #include "wm_event_types.h"
84
85 #include "RNA_enum_types.h"
86
87 #include "DEG_depsgraph.h"
88
89 /* Motion in pixels allowed before we don't consider single/double click. */
90 #define WM_EVENT_CLICK_WIGGLE_ROOM 2
91
92 static void wm_notifier_clear(wmNotifier *note);
93 static void update_tablet_data(wmWindow *win, wmEvent *event);
94
95 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
96                                      const short context, const bool poll_only);
97
98 /* ************ event management ************** */
99
100 wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
101 {
102         wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
103         
104         *event = *event_to_add;
105
106         update_tablet_data(win, event);
107
108         if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
109                 /* We could have a preference to support relative tablet motion (we can't detect that). */
110                 event->is_motion_absolute = (
111                         (event->tablet_data != NULL) &&
112                         (event->tablet_data->Active != GHOST_kTabletModeNone));
113         }
114
115         if (event_to_add_after == NULL) {
116                 BLI_addtail(&win->queue, event);
117         }
118         else {
119                 /* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */
120                 BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event);
121         }
122         return event;
123 }
124
125 wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
126 {
127         return wm_event_add_ex(win, event_to_add, NULL);
128 }
129
130 void wm_event_free(wmEvent *event)
131 {
132         if (event->customdata) {
133                 if (event->customdatafree) {
134                         /* note: pointer to listbase struct elsewhere */
135                         if (event->custom == EVT_DATA_DRAGDROP) {
136                                 ListBase *lb = event->customdata;
137                                 WM_drag_free_list(lb);
138                         }
139                         else {
140                                 MEM_freeN(event->customdata);
141                         }
142                 }
143         }
144
145         if (event->tablet_data) {
146                 MEM_freeN((void *)event->tablet_data);
147         }
148
149         MEM_freeN(event);
150 }
151
152 void wm_event_free_all(wmWindow *win)
153 {
154         wmEvent *event;
155         
156         while ((event = BLI_pophead(&win->queue))) {
157                 wm_event_free(event);
158         }
159 }
160
161 void wm_event_init_from_window(wmWindow *win, wmEvent *event)
162 {
163         /* make sure we don't copy any owned pointers */
164         BLI_assert(win->eventstate->tablet_data == NULL);
165
166         *event = *(win->eventstate);
167 }
168
169 /* ********************* notifiers, listeners *************** */
170
171 static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, void *reference)
172 {
173         wmNotifier *note;
174
175         for (note = wm->queue.first; note; note = note->next)
176                 if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference)
177                         return 1;
178         
179         return 0;
180 }
181
182 /* XXX: in future, which notifiers to send to other windows? */
183 void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
184 {
185         ARegion *ar;
186         wmWindowManager *wm = CTX_wm_manager(C);
187         wmNotifier *note;
188
189         if (wm_test_duplicate_notifier(wm, type, reference))
190                 return;
191
192         note = MEM_callocN(sizeof(wmNotifier), "notifier");
193         
194         note->wm = wm;
195         BLI_addtail(&note->wm->queue, note);
196         
197         note->window = CTX_wm_window(C);
198         
199         ar = CTX_wm_region(C);
200         if (ar)
201                 note->swinid = ar->swinid;
202         
203         note->category = type & NOTE_CATEGORY;
204         note->data = type & NOTE_DATA;
205         note->subtype = type & NOTE_SUBTYPE;
206         note->action = type & NOTE_ACTION;
207         
208         note->reference = reference;
209 }
210
211 void WM_main_add_notifier(unsigned int type, void *reference)
212 {
213         Main *bmain = G.main;
214         wmWindowManager *wm = bmain->wm.first;
215         wmNotifier *note;
216
217         if (!wm || wm_test_duplicate_notifier(wm, type, reference))
218                 return;
219
220         note = MEM_callocN(sizeof(wmNotifier), "notifier");
221         
222         note->wm = wm;
223         BLI_addtail(&note->wm->queue, note);
224         
225         note->category = type & NOTE_CATEGORY;
226         note->data = type & NOTE_DATA;
227         note->subtype = type & NOTE_SUBTYPE;
228         note->action = type & NOTE_ACTION;
229         
230         note->reference = reference;
231 }
232
233 /**
234  * Clear notifiers by reference, Used so listeners don't act on freed data.
235  */
236 void WM_main_remove_notifier_reference(const void *reference)
237 {
238         Main *bmain = G.main;
239         wmWindowManager *wm = bmain->wm.first;
240
241         if (wm) {
242                 wmNotifier *note, *note_next;
243
244                 for (note = wm->queue.first; note; note = note_next) {
245                         note_next = note->next;
246
247                         if (note->reference == reference) {
248                                 /* don't remove because this causes problems for #wm_event_do_notifiers
249                                  * which may be looping on the data (deleting screens) */
250                                 wm_notifier_clear(note);
251                         }
252                 }
253
254                 /* Remap instead. */
255 #if 0
256                 if (wm->message_bus) {
257                         WM_msg_id_remove(wm->message_bus, reference);
258                 }
259 #endif
260
261         }
262 }
263
264 void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
265 {
266         Main *bmain = G.main;
267         bScreen *sc;
268
269         for (sc = bmain->screen.first; sc; sc = sc->id.next) {
270                 ScrArea *sa;
271
272                 for (sa = sc->areabase.first; sa; sa = sa->next) {
273                         SpaceLink *sl;
274
275                         for (sl = sa->spacedata.first; sl; sl = sl->next) {
276                                 ED_spacedata_id_remap(sa, sl, old_id, new_id);
277                         }
278                 }
279         }
280
281         wmWindowManager *wm = bmain->wm.first;
282         if (wm && wm->message_bus) {
283                 struct wmMsgBus *mbus = wm->message_bus;
284                 if (new_id != NULL) {
285                         WM_msg_id_update(mbus, old_id, new_id);
286                 }
287                 else {
288                         WM_msg_id_remove(mbus, old_id);
289                 }
290         }
291 }
292
293 static void wm_notifier_clear(wmNotifier *note)
294 {
295         /* NULL the entire notifier, only leaving (next, prev) members intact */
296         memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
297 }
298
299 /**
300  * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
301  * This ensures operators don't run before the UI and depsgraph are initialized.
302  */
303 void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
304 {
305         wmWindowManager *wm = CTX_wm_manager(C);
306         uint64_t win_combine_v3d_datamask = 0;
307
308         /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
309         for (wmWindow *win = wm->windows.first; win; win = win->next) {
310                 const Scene *scene = WM_window_get_active_scene(win);
311                 const bScreen *screen = WM_window_get_active_screen(win);
312
313                 win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
314         }
315
316         /* cached: editor refresh callbacks now, they get context */
317         for (wmWindow *win = wm->windows.first; win; win = win->next) {
318                 const bScreen *screen = WM_window_get_active_screen(win);
319                 Scene *scene = WM_window_get_active_scene(win);
320                 ScrArea *sa;
321
322                 CTX_wm_window_set(C, win);
323                 for (sa = screen->areabase.first; sa; sa = sa->next) {
324                         if (sa->do_refresh) {
325                                 CTX_wm_area_set(C, sa);
326                                 ED_area_do_refresh(C, sa);
327                         }
328                 }
329
330                 /* XXX make lock in future, or separated derivedmesh users in scene */
331                 if (G.is_rendering == false) {
332                         /* depsgraph & animation: update tagged datablocks */
333                         Main *bmain = CTX_data_main(C);
334
335                         /* copied to set's in scene_update_tagged_recursive() */
336                         scene->customdata_mask = win_combine_v3d_datamask;
337
338                         /* XXX, hack so operators can enforce datamasks [#26482], gl render */
339                         scene->customdata_mask |= scene->customdata_mask_modal;
340
341                         WorkSpace *workspace = WM_window_get_active_workspace(win);
342
343                         BKE_workspace_update_object_mode(bmain->eval_ctx, workspace);
344
345                         BKE_workspace_update_tagged(bmain->eval_ctx, bmain, workspace, scene);
346                 }
347         }
348
349         CTX_wm_window_set(C, NULL);
350 }
351
352 /* called in mainloop */
353 void wm_event_do_notifiers(bContext *C)
354 {
355         wmWindowManager *wm = CTX_wm_manager(C);
356         wmNotifier *note, *next;
357         wmWindow *win;
358         
359         if (wm == NULL)
360                 return;
361
362         /* disable? - keep for now since its used for window level notifiers. */
363 #if 1
364         /* cache & catch WM level notifiers, such as frame change, scene/screen set */
365         for (win = wm->windows.first; win; win = win->next) {
366                 Scene *scene = WM_window_get_active_scene(win);
367                 bool do_anim = false;
368                 
369                 CTX_wm_window_set(C, win);
370                 
371                 for (note = wm->queue.first; note; note = next) {
372                         next = note->next;
373
374                         if (note->category == NC_WM) {
375                                 if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
376                                         wm->file_saved = 1;
377                                         wm_window_title(wm, win);
378                                 }
379                                 else if (note->data == ND_DATACHANGED)
380                                         wm_window_title(wm, win);
381                         }
382                         if (note->window == win) {
383                                 if (note->category == NC_SCREEN) {
384                                         if (note->data == ND_WORKSPACE_SET) {
385                                                 WorkSpace *ref_ws = note->reference;
386
387                                                 UI_popup_handlers_remove_all(C, &win->modalhandlers);
388
389                                                 ED_workspace_change(ref_ws, C, win);
390                                                 if (G.debug & G_DEBUG_EVENTS)
391                                                         printf("%s: Workspace set %p\n", __func__, note->reference);
392                                         }
393                                         else if (note->data == ND_LAYOUTBROWSE) {
394                                                 bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
395
396                                                 /* free popup handlers only [#35434] */
397                                                 UI_popup_handlers_remove_all(C, &win->modalhandlers);
398
399
400                                                 ED_screen_change(C, ref_screen);  /* XXX hrms, think this over! */
401                                                 if (G.debug & G_DEBUG_EVENTS)
402                                                         printf("%s: screen set %p\n", __func__, note->reference);
403                                         }
404                                         else if (note->data == ND_LAYOUTDELETE) {
405                                                 WorkSpace *workspace = WM_window_get_active_workspace(win);
406                                                 WorkSpaceLayout *layout = note->reference;
407
408                                                 ED_workspace_layout_delete(workspace, layout, C);   // XXX hrms, think this over!
409                                                 if (G.debug & G_DEBUG_EVENTS)
410                                                         printf("%s: screen delete %p\n", __func__, note->reference);
411                                         }
412                                 }
413                         }
414
415                         if (note->window == win ||
416                             (note->window == NULL && (note->reference == NULL || note->reference == scene)))
417                         {
418                                 if (note->category == NC_SCENE) {
419                                         if (note->data == ND_FRAME)
420                                                 do_anim = true;
421                                 }
422                         }
423                         if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
424                                 ViewLayer *view_layer = CTX_data_view_layer(C);
425                                 ED_info_stats_clear(view_layer);
426                                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
427                         }
428                 }
429                 if (do_anim) {
430
431                         /* XXX, quick frame changes can cause a crash if framechange and rendering
432                          * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
433                          * twice which can depgraph update the same object at once */
434                         if (G.is_rendering == false) {
435                                 /* depsgraph gets called, might send more notifiers */
436                                 ViewLayer *view_layer = CTX_data_view_layer(C);
437                                 Depsgraph *depsgraph = CTX_data_depsgraph(C);
438                                 ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph);
439                         }
440                 }
441         }
442         
443         /* the notifiers are sent without context, to keep it clean */
444         while ((note = BLI_pophead(&wm->queue))) {
445                 for (win = wm->windows.first; win; win = win->next) {
446                         Scene *scene = WM_window_get_active_scene(win);
447                         bScreen *screen = WM_window_get_active_screen(win);
448                         WorkSpace *workspace = WM_window_get_active_workspace(win);
449
450                         /* filter out notifiers */
451                         if (note->category == NC_SCREEN &&
452                             note->reference &&
453                             note->reference != screen &&
454                             note->reference != workspace &&
455                             note->reference != WM_window_get_active_layout(win))
456                         {
457                                 /* pass */
458                         }
459                         else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
460                                 /* pass */
461                         }
462                         else {
463                                 ScrArea *sa;
464                                 ARegion *ar;
465
466                                 /* XXX context in notifiers? */
467                                 CTX_wm_window_set(C, win);
468
469                                 /* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */
470                                 ED_screen_do_listen(C, note);
471
472                                 for (ar = screen->regionbase.first; ar; ar = ar->next) {
473                                         ED_region_do_listen(screen, NULL, ar, note, scene);
474                                 }
475                                 
476                                 for (sa = screen->areabase.first; sa; sa = sa->next) {
477                                         ED_area_do_listen(screen, sa, note, scene, workspace);
478                                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
479                                                 ED_region_do_listen(screen, sa, ar, note, scene);
480                                         }
481                                 }
482                         }
483                 }
484                 
485                 MEM_freeN(note);
486         }
487 #endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
488
489         /* Handle message bus. */
490         {
491                 for (win = wm->windows.first; win; win = win->next) {
492                         CTX_wm_window_set(C, win);
493                         WM_msgbus_handle(wm->message_bus, C);
494                 }
495                 CTX_wm_window_set(C, NULL);
496         }
497
498         wm_event_do_refresh_wm_and_depsgraph(C);
499 }
500
501 static int wm_event_always_pass(const wmEvent *event)
502 {
503         /* some events we always pass on, to ensure proper communication */
504         return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
505 }
506
507 /* ********************* ui handler ******************* */
508
509 static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEvent *event, int always_pass)
510 {
511         ScrArea *area = CTX_wm_area(C);
512         ARegion *region = CTX_wm_region(C);
513         ARegion *menu = CTX_wm_menu(C);
514         static bool do_wheel_ui = true;
515         const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
516         int retval;
517         
518         /* UI code doesn't handle return values - it just always returns break. 
519          * to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */
520         if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) &&
521             (event->type != LEFTMOUSE) &&
522             (event->val == KM_DBL_CLICK))
523         {
524                 return WM_HANDLER_CONTINUE;
525         }
526         
527         /* UI is quite aggressive with swallowing events, like scrollwheel */
528         /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
529         if (do_wheel_ui == false) {
530                 if (is_wheel)
531                         return WM_HANDLER_CONTINUE;
532                 else if (wm_event_always_pass(event) == 0)
533                         do_wheel_ui = true;
534         }
535         
536         /* we set context to where ui handler came from */
537         if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
538         if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
539         if (handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
540
541         retval = handler->ui_handle(C, event, handler->ui_userdata);
542
543         /* putting back screen context */
544         if ((retval != WM_UI_HANDLER_BREAK) || always_pass) {
545                 CTX_wm_area_set(C, area);
546                 CTX_wm_region_set(C, region);
547                 CTX_wm_menu_set(C, menu);
548         }
549         else {
550                 /* this special cases is for areas and regions that get removed */
551                 CTX_wm_area_set(C, NULL);
552                 CTX_wm_region_set(C, NULL);
553                 CTX_wm_menu_set(C, NULL);
554         }
555         
556         if (retval == WM_UI_HANDLER_BREAK)
557                 return WM_HANDLER_BREAK;
558         
559         /* event not handled in UI, if wheel then we temporarily disable it */
560         if (is_wheel)
561                 do_wheel_ui = false;
562         
563         return WM_HANDLER_CONTINUE;
564 }
565
566 static void wm_handler_ui_cancel(bContext *C)
567 {
568         wmWindow *win = CTX_wm_window(C);
569         ARegion *ar = CTX_wm_region(C);
570         wmEventHandler *handler, *nexthandler;
571
572         if (!ar)
573                 return;
574
575         for (handler = ar->handlers.first; handler; handler = nexthandler) {
576                 nexthandler = handler->next;
577
578                 if (handler->ui_handle) {
579                         wmEvent event;
580
581                         wm_event_init_from_window(win, &event);
582                         event.type = EVT_BUT_CANCEL;
583                         handler->ui_handle(C, &event, handler->ui_userdata);
584                 }
585         }
586 }
587
588 /* ********************* operators ******************* */
589
590 int WM_operator_poll(bContext *C, wmOperatorType *ot)
591 {
592         wmOperatorTypeMacro *otmacro;
593         
594         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
595                 wmOperatorType *ot_macro = WM_operatortype_find(otmacro->idname, 0);
596                 
597                 if (0 == WM_operator_poll(C, ot_macro))
598                         return 0;
599         }
600         
601         /* python needs operator type, so we added exception for it */
602         if (ot->pyop_poll)
603                 return ot->pyop_poll(C, ot);
604         else if (ot->poll)
605                 return ot->poll(C);
606
607         return 1;
608 }
609
610 /* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
611 int WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
612 {
613         return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
614 }
615
616 static void wm_operator_print(bContext *C, wmOperator *op)
617 {
618         /* context is needed for enum function */
619         char *buf = WM_operator_pystring(C, op, false, true);
620         puts(buf);
621         MEM_freeN(buf);
622 }
623
624 /**
625  * Sets the active region for this space from the context.
626  *
627  * \see #BKE_area_find_region_active_win
628  */
629 void WM_operator_region_active_win_set(bContext *C)
630 {
631         ScrArea *sa = CTX_wm_area(C);
632         if (sa) {
633                 ARegion *ar = CTX_wm_region(C);
634                 if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
635                         sa->region_active_win = BLI_findindex(&sa->regionbase, ar);
636                 }
637         }
638 }
639
640 /* for debugging only, getting inspecting events manually is tedious */
641 void WM_event_print(const wmEvent *event)
642 {
643         if (event) {
644                 const char *unknown = "UNKNOWN";
645                 const char *type_id = unknown;
646                 const char *val_id = unknown;
647
648                 RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
649                 RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
650
651                 printf("wmEvent  type:%d / %s, val:%d / %s,\n"
652                        "         shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
653                        "         mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n",
654                        event->type, type_id, event->val, val_id,
655                        event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
656                        event->x, event->y, event->ascii,
657                        BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
658                        event->keymap_idname, (const void *)event);
659
660 #ifdef WITH_INPUT_NDOF
661                 if (ISNDOF(event->type)) {
662                         const wmNDOFMotionData *ndof = event->customdata;
663                         if (event->type == NDOF_MOTION) {
664                                 printf("   ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
665                                        UNPACK3(ndof->rvec), UNPACK3(ndof->tvec), ndof->dt, ndof->progress);
666                         }
667                         else {
668                                 /* ndof buttons printed already */
669                         }
670                 }
671 #endif /* WITH_INPUT_NDOF */
672
673                 if (event->tablet_data) {
674                         const wmTabletData *wmtab = event->tablet_data;
675                         printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
676                                wmtab->Active, wmtab->Pressure, wmtab->Xtilt, wmtab->Ytilt);
677                 }
678         }
679         else {
680                 printf("wmEvent - NULL\n");
681         }
682 }
683
684 /**
685  * Show the report in the info header.
686  */
687 void WM_report_banner_show(void)
688 {
689         wmWindowManager *wm = G.main->wm.first;
690         ReportList *wm_reports = &wm->reports;
691         ReportTimerInfo *rti;
692
693         /* After adding reports to the global list, reset the report timer. */
694         WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
695
696         /* Records time since last report was added */
697         wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
698
699         rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
700         wm_reports->reporttimer->customdata = rti;
701 }
702
703 bool WM_event_is_last_mousemove(const wmEvent *event)
704 {
705         while ((event = event->next)) {
706                 if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
707                         return false;
708                 }
709         }
710         return true;
711 }
712
713 #ifdef WITH_INPUT_NDOF
714 void WM_ndof_deadzone_set(float deadzone)
715 {
716         GHOST_setNDOFDeadZone(deadzone);
717 }
718 #endif
719
720 static void wm_add_reports(ReportList *reports)
721 {
722         /* if the caller owns them, handle this */
723         if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
724                 wmWindowManager *wm = G.main->wm.first;
725
726                 /* add reports to the global list, otherwise they are not seen */
727                 BLI_movelisttolist(&wm->reports.list, &reports->list);
728
729                 WM_report_banner_show();
730         }
731 }
732
733 void WM_report(ReportType type, const char *message)
734 {
735         ReportList reports;
736
737         BKE_reports_init(&reports, RPT_STORE);
738         BKE_report(&reports, type, message);
739
740         wm_add_reports(&reports);
741
742         BKE_reports_clear(&reports);
743 }
744
745 void WM_reportf(ReportType type, const char *format, ...)
746 {
747         DynStr *ds;
748         va_list args;
749
750         ds = BLI_dynstr_new();
751         va_start(args, format);
752         BLI_dynstr_vappendf(ds, format, args);
753         va_end(args);
754
755         char *str = BLI_dynstr_get_cstring(ds);
756         WM_report(type, str);
757         MEM_freeN(str);
758
759         BLI_dynstr_free(ds);
760 }
761
762 /* (caller_owns_reports == true) when called from python */
763 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
764 {
765         if (caller_owns_reports == false) { /* popup */
766                 if (op->reports->list.first) {
767                         /* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */
768                         wmWindow *win_prev = CTX_wm_window(C);
769                         ScrArea *area_prev = CTX_wm_area(C);
770                         ARegion *ar_prev = CTX_wm_region(C);
771
772                         if (win_prev == NULL)
773                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
774
775                         UI_popup_menu_reports(C, op->reports);
776
777                         CTX_wm_window_set(C, win_prev);
778                         CTX_wm_area_set(C, area_prev);
779                         CTX_wm_region_set(C, ar_prev);
780                 }
781         }
782         
783         if (retval & OPERATOR_FINISHED) {
784                 if (G.debug & G_DEBUG_WM) {
785                         /* todo - this print may double up, might want to check more flags then the FINISHED */
786                         wm_operator_print(C, op);
787                 }
788
789                 if (caller_owns_reports == false) {
790                         BKE_reports_print(op->reports, RPT_DEBUG); /* print out reports to console. */
791                 }
792
793                 if (op->type->flag & OPTYPE_REGISTER) {
794                         if (G.background == 0) { /* ends up printing these in the terminal, gets annoying */
795                                 /* Report the python string representation of the operator */
796                                 char *buf = WM_operator_pystring(C, op, false, true);
797                                 BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
798                                 MEM_freeN(buf);
799                         }
800                 }
801         }
802
803         /* if the caller owns them, handle this */
804         wm_add_reports(op->reports);
805 }
806
807 /**
808  * This function is mainly to check that the rules for freeing
809  * an operator are kept in sync.
810  */
811 static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
812 {
813         /* Check undo flag here since undo operators are also added to the list,
814          * to support checking if the same operator is run twice. */
815         return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
816 }
817
818 static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
819 {
820         wmWindowManager *wm = CTX_wm_manager(C);
821
822         op->customdata = NULL;
823
824         if (store) {
825                 WM_operator_last_properties_store(op);
826         }
827
828         /* we don't want to do undo pushes for operators that are being
829          * called from operators that already do an undo push. usually
830          * this will happen for python operators that call C operators */
831         if (wm->op_undo_depth == 0) {
832                 if (op->type->flag & OPTYPE_UNDO)
833                         ED_undo_push_op(C, op);
834                 else if (op->type->flag & OPTYPE_UNDO_GROUPED)
835                         ED_undo_grouped_push_op(C, op);
836         }
837
838         if (repeat == 0) {
839                 if (G.debug & G_DEBUG_WM) {
840                         char *buf = WM_operator_pystring(C, op, false, true);
841                         BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
842                         MEM_freeN(buf);
843                 }
844
845                 if (wm_operator_register_check(wm, op->type)) {
846                         /* take ownership of reports (in case python provided own) */
847                         op->reports->flag |= RPT_FREE;
848
849                         wm_operator_register(C, op);
850                         WM_operator_region_active_win_set(C);
851                 }
852                 else {
853                         WM_operator_free(op);
854                 }
855         }
856 }
857
858 /* if repeat is true, it doesn't register again, nor does it free */
859 static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, const bool store)
860 {
861         wmWindowManager *wm = CTX_wm_manager(C);
862         int retval = OPERATOR_CANCELLED;
863         
864         CTX_wm_operator_poll_msg_set(C, NULL);
865         
866         if (op == NULL || op->type == NULL)
867                 return retval;
868         
869         if (0 == WM_operator_poll(C, op->type))
870                 return retval;
871         
872         if (op->type->exec) {
873                 if (op->type->flag & OPTYPE_UNDO) {
874                         wm->op_undo_depth++;
875                 }
876
877                 if (repeat) {
878                         op->flag |= OP_IS_REPEAT;
879                 }
880                 retval = op->type->exec(C, op);
881                 OPERATOR_RETVAL_CHECK(retval);
882                 if (repeat) {
883                         op->flag &= ~OP_IS_REPEAT;
884                 }
885
886                 if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
887                         wm->op_undo_depth--;
888                 }
889         }
890         
891         /* XXX Disabled the repeat check to address part 2 of #31840.
892          *     Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason
893          *     why this was needed, but worth to note it in case something turns bad. (mont29) */
894         if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */)
895                 wm_operator_reports(C, op, retval, false);
896         
897         if (retval & OPERATOR_FINISHED) {
898                 wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0);
899         }
900         else if (repeat == 0) {
901                 /* warning: modal from exec is bad practice, but avoid crashing. */
902                 if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
903                         WM_operator_free(op);
904                 }
905         }
906         
907         return retval | OPERATOR_HANDLED;
908         
909 }
910
911 /* simply calls exec with basic checks */
912 static int wm_operator_exec_notest(bContext *C, wmOperator *op)
913 {
914         int retval = OPERATOR_CANCELLED;
915
916         if (op == NULL || op->type == NULL || op->type->exec == NULL)
917                 return retval;
918
919         retval = op->type->exec(C, op);
920         OPERATOR_RETVAL_CHECK(retval);
921
922         return retval;
923 }
924
925 /**
926  * for running operators with frozen context (modal handlers, menus)
927  *
928  * \param store Store settings for re-use.
929  *
930  * warning: do not use this within an operator to call its self! [#29537] */
931 int WM_operator_call_ex(bContext *C, wmOperator *op,
932                         const bool store)
933 {
934         return wm_operator_exec(C, op, false, store);
935 }
936
937 int WM_operator_call(bContext *C, wmOperator *op)
938 {
939         return WM_operator_call_ex(C, op, false);
940 }
941
942 /**
943  * This is intended to be used when an invoke operator wants to call exec on its self
944  * and is basically like running op->type->exec() directly, no poll checks no freeing,
945  * since we assume whoever called invoke will take care of that
946  */
947 int WM_operator_call_notest(bContext *C, wmOperator *op)
948 {
949         return wm_operator_exec_notest(C, op);
950 }
951
952 /**
953  * Execute this operator again, put here so it can share above code
954  */
955 int WM_operator_repeat(bContext *C, wmOperator *op)
956 {
957         return wm_operator_exec(C, op, true, true);
958 }
959 /**
960  * \return true if #WM_operator_repeat can run
961  * simple check for now but may become more involved.
962  * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
963  * checks if WM_operator_repeat() can run at all, not that it WILL run at any time.
964  */
965 bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
966 {
967         if (op->type->exec != NULL) {
968                 return true;
969         }
970         else if (op->opm) {
971                 /* for macros, check all have exec() we can call */
972                 wmOperatorTypeMacro *otmacro;
973                 for (otmacro = op->opm->type->macro.first; otmacro; otmacro = otmacro->next) {
974                         wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
975                         if (otm && otm->exec == NULL) {
976                                 return false;
977                         }
978                 }
979                 return true;
980         }
981
982         return false;
983 }
984
985 bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
986 {
987         /* may be in the operators list or not */
988         wmOperator *op_prev;
989         if (op->prev == NULL && op->next == NULL) {
990                 wmWindowManager *wm = CTX_wm_manager(C);
991                 op_prev = wm->operators.last;
992         }
993         else {
994                 op_prev = op->prev;
995         }
996         return (op_prev && (op->type == op_prev->type));
997 }
998
999 static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
1000                                       PointerRNA *properties, ReportList *reports)
1001 {
1002         /* XXX operatortype names are static still. for debug */
1003         wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
1004         
1005         /* XXX adding new operator could be function, only happens here now */
1006         op->type = ot;
1007         BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
1008         
1009         /* initialize properties, either copy or create */
1010         op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
1011         if (properties && properties->data) {
1012                 op->properties = IDP_CopyProperty(properties->data);
1013         }
1014         else {
1015                 IDPropertyTemplate val = {0};
1016                 op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1017         }
1018         RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
1019
1020         /* initialize error reports */
1021         if (reports) {
1022                 op->reports = reports; /* must be initialized already */
1023         }
1024         else {
1025                 op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
1026                 BKE_reports_init(op->reports, RPT_STORE | RPT_FREE);
1027         }
1028         
1029         /* recursive filling of operator macro list */
1030         if (ot->macro.first) {
1031                 static wmOperator *motherop = NULL;
1032                 wmOperatorTypeMacro *otmacro;
1033                 int root = 0;
1034                 
1035                 /* ensure all ops are in execution order in 1 list */
1036                 if (motherop == NULL) {
1037                         motherop = op;
1038                         root = 1;
1039                 }
1040
1041                 
1042                 /* if properties exist, it will contain everything needed */
1043                 if (properties) {
1044                         otmacro = ot->macro.first;
1045
1046                         RNA_STRUCT_BEGIN (properties, prop)
1047                         {
1048
1049                                 if (otmacro == NULL)
1050                                         break;
1051
1052                                 /* skip invalid properties */
1053                                 if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
1054                                         wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
1055                                         PointerRNA someptr = RNA_property_pointer_get(properties, prop);
1056                                         wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
1057
1058                                         IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
1059
1060                                         BLI_addtail(&motherop->macro, opm);
1061                                         opm->opm = motherop; /* pointer to mom, for modal() */
1062
1063                                         otmacro = otmacro->next;
1064                                 }
1065                         }
1066                         RNA_STRUCT_END;
1067                 }
1068                 else {
1069                         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
1070                                 wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
1071                                 wmOperator *opm = wm_operator_create(wm, otm, otmacro->ptr, NULL);
1072
1073                                 BLI_addtail(&motherop->macro, opm);
1074                                 opm->opm = motherop; /* pointer to mom, for modal() */
1075                         }
1076                 }
1077                 
1078                 if (root)
1079                         motherop = NULL;
1080         }
1081         
1082         WM_operator_properties_sanitize(op->ptr, 0);
1083
1084         return op;
1085 }
1086
1087 static void wm_region_mouse_co(bContext *C, wmEvent *event)
1088 {
1089         ARegion *ar = CTX_wm_region(C);
1090         if (ar) {
1091                 /* compatibility convention */
1092                 event->mval[0] = event->x - ar->winrct.xmin;
1093                 event->mval[1] = event->y - ar->winrct.ymin;
1094         }
1095         else {
1096                 /* these values are invalid (avoid odd behavior by relying on old mval values) */
1097                 event->mval[0] = -1;
1098                 event->mval[1] = -1;
1099         }
1100 }
1101
1102 #if 1 /* may want to disable operator remembering previous state for testing */
1103 bool WM_operator_last_properties_init(wmOperator *op)
1104 {
1105         bool changed = false;
1106
1107         if (op->type->last_properties) {
1108                 IDPropertyTemplate val = {0};
1109                 IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1110                 PropertyRNA *iterprop;
1111
1112                 if (G.debug & G_DEBUG_WM) {
1113                         printf("%s: loading previous properties for '%s'\n", __func__, op->type->idname);
1114                 }
1115
1116                 iterprop = RNA_struct_iterator_property(op->type->srna);
1117
1118                 RNA_PROP_BEGIN (op->ptr, itemptr, iterprop)
1119                 {
1120                         PropertyRNA *prop = itemptr.data;
1121                         if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
1122                                 if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
1123                                         const char *identifier = RNA_property_identifier(prop);
1124                                         IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, identifier);
1125                                         if (idp_src) {
1126                                                 IDProperty *idp_dst = IDP_CopyProperty(idp_src);
1127
1128                                                 /* note - in the future this may need to be done recursively,
1129                                                  * but for now RNA doesn't access nested operators */
1130                                                 idp_dst->flag |= IDP_FLAG_GHOST;
1131
1132                                                 /* add to temporary group instead of immediate replace,
1133                                                  * because we are iterating over this group */
1134                                                 IDP_AddToGroup(replaceprops, idp_dst);
1135                                                 changed = true;
1136                                         }
1137                                 }
1138                         }
1139                 }
1140                 RNA_PROP_END;
1141
1142                 IDP_MergeGroup(op->properties, replaceprops, true);
1143                 IDP_FreeProperty(replaceprops);
1144                 MEM_freeN(replaceprops);
1145         }
1146
1147         return changed;
1148 }
1149
1150 bool WM_operator_last_properties_store(wmOperator *op)
1151 {
1152         if (op->type->last_properties) {
1153                 IDP_FreeProperty(op->type->last_properties);
1154                 MEM_freeN(op->type->last_properties);
1155                 op->type->last_properties = NULL;
1156         }
1157
1158         if (op->properties) {
1159                 if (G.debug & G_DEBUG_WM) {
1160                         printf("%s: storing properties for '%s'\n", __func__, op->type->idname);
1161                 }
1162                 op->type->last_properties = IDP_CopyProperty(op->properties);
1163                 return true;
1164         }
1165         else {
1166                 return false;
1167         }
1168 }
1169
1170 #else
1171
1172 bool WM_operator_last_properties_init(wmOperator *UNUSED(op))
1173 {
1174         return false;
1175 }
1176
1177 bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
1178 {
1179         return false;
1180 }
1181
1182 #endif
1183
1184 /**
1185  * Also used for exec when 'event' is NULL.
1186  */
1187 static int wm_operator_invoke(
1188         bContext *C, wmOperatorType *ot, wmEvent *event,
1189         PointerRNA *properties, ReportList *reports, const bool poll_only)
1190 {
1191         int retval = OPERATOR_PASS_THROUGH;
1192
1193         /* this is done because complicated setup is done to call this function that is better not duplicated */
1194         if (poll_only)
1195                 return WM_operator_poll(C, ot);
1196
1197         if (WM_operator_poll(C, ot)) {
1198                 wmWindowManager *wm = CTX_wm_manager(C);
1199                 wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
1200                 const bool is_nested_call = (wm->op_undo_depth != 0);
1201                 
1202                 if (event != NULL) {
1203                         op->flag |= OP_IS_INVOKE;
1204                 }
1205
1206                 /* initialize setting from previous run */
1207                 if (!is_nested_call) { /* not called by py script */
1208                         WM_operator_last_properties_init(op);
1209                 }
1210
1211                 if ((G.debug & G_DEBUG_HANDLERS) && ((event == NULL) || (event->type != MOUSEMOVE))) {
1212                         printf("%s: handle evt %d win %d op %s\n",
1213                                __func__, event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
1214                 }
1215                 
1216                 if (op->type->invoke && event) {
1217                         wm_region_mouse_co(C, event);
1218
1219                         if (op->type->flag & OPTYPE_UNDO)
1220                                 wm->op_undo_depth++;
1221
1222                         retval = op->type->invoke(C, op, event);
1223                         OPERATOR_RETVAL_CHECK(retval);
1224
1225                         if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1226                                 wm->op_undo_depth--;
1227                 }
1228                 else if (op->type->exec) {
1229                         if (op->type->flag & OPTYPE_UNDO)
1230                                 wm->op_undo_depth++;
1231
1232                         retval = op->type->exec(C, op);
1233                         OPERATOR_RETVAL_CHECK(retval);
1234
1235                         if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1236                                 wm->op_undo_depth--;
1237                 }
1238                 else {
1239                         /* debug, important to leave a while, should never happen */
1240                         printf("%s: invalid operator call '%s'\n", __func__, ot->idname);
1241                 }
1242                 
1243                 /* Note, if the report is given as an argument then assume the caller will deal with displaying them
1244                  * currently python only uses this */
1245                 if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
1246                         /* only show the report if the report list was not given in the function */
1247                         wm_operator_reports(C, op, retval, (reports != NULL));
1248                 }
1249
1250                 if (retval & OPERATOR_HANDLED) {
1251                         /* do nothing, wm_operator_exec() has been called somewhere */
1252                 }
1253                 else if (retval & OPERATOR_FINISHED) {
1254                         const bool store = !is_nested_call;
1255                         wm_operator_finished(C, op, false, store);
1256                 }
1257                 else if (retval & OPERATOR_RUNNING_MODAL) {
1258                         /* take ownership of reports (in case python provided own) */
1259                         op->reports->flag |= RPT_FREE;
1260
1261                         /* grab cursor during blocking modal ops (X11)
1262                          * Also check for macro
1263                          */
1264                         if (ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
1265                                 int bounds[4] = {-1, -1, -1, -1};
1266                                 bool wrap;
1267
1268                                 if (event == NULL) {
1269                                         wrap = false;
1270                                 }
1271                                 else if (op->opm) {
1272                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
1273                                                ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR));
1274                                 }
1275                                 else {
1276                                         wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
1277                                                ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR));
1278                                 }
1279
1280                                 /* exception, cont. grab in header is annoying */
1281                                 if (wrap) {
1282                                         ARegion *ar = CTX_wm_region(C);
1283                                         if (ar && ar->regiontype == RGN_TYPE_HEADER) {
1284                                                 wrap = false;
1285                                         }
1286                                 }
1287
1288                                 if (wrap) {
1289                                         const rcti *winrect = NULL;
1290                                         ARegion *ar = CTX_wm_region(C);
1291                                         ScrArea *sa = CTX_wm_area(C);
1292
1293                                         if (ar && ar->regiontype == RGN_TYPE_WINDOW &&
1294                                             BLI_rcti_isect_pt_v(&ar->winrct, &event->x))
1295                                         {
1296                                                 winrect = &ar->winrct;
1297                                         }
1298                                         else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) {
1299                                                 winrect = &sa->totrct;
1300                                         }
1301
1302                                         if (winrect) {
1303                                                 bounds[0] = winrect->xmin;
1304                                                 bounds[1] = winrect->ymax;
1305                                                 bounds[2] = winrect->xmax;
1306                                                 bounds[3] = winrect->ymin;
1307                                         }
1308                                 }
1309
1310                                 WM_cursor_grab_enable(CTX_wm_window(C), wrap, false, bounds);
1311                         }
1312
1313                         /* cancel UI handlers, typically tooltips that can hang around
1314                          * while dragging the view or worse, that stay there permanently
1315                          * after the modal operator has swallowed all events and passed
1316                          * none to the UI handler */
1317                         wm_handler_ui_cancel(C);
1318                 }
1319                 else {
1320                         WM_operator_free(op);
1321                 }
1322         }
1323
1324         return retval;
1325 }
1326
1327 /**
1328  * #WM_operator_name_call is the main accessor function
1329  * this is for python to access since its done the operator lookup
1330  * 
1331  * invokes operator in context
1332  */
1333 static int wm_operator_call_internal(
1334         bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
1335         const short context, const bool poll_only)
1336 {
1337         wmEvent *event;
1338         
1339         int retval;
1340
1341         CTX_wm_operator_poll_msg_set(C, NULL);
1342
1343         /* dummie test */
1344         if (ot) {
1345                 wmWindow *window = CTX_wm_window(C);
1346
1347                 switch (context) {
1348                         case WM_OP_INVOKE_DEFAULT:
1349                         case WM_OP_INVOKE_REGION_WIN:
1350                         case WM_OP_INVOKE_REGION_PREVIEW:
1351                         case WM_OP_INVOKE_REGION_CHANNELS:
1352                         case WM_OP_INVOKE_AREA:
1353                         case WM_OP_INVOKE_SCREEN:
1354                                 /* window is needed for invoke, cancel operator */
1355                                 if (window == NULL) {
1356                                         if (poll_only) {
1357                                                 CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
1358                                         }
1359                                         return 0;
1360                                 }
1361                                 else {
1362                                         event = window->eventstate;
1363                                 }
1364                                 break;
1365                         default:
1366                                 event = NULL;
1367                                 break;
1368                 }
1369
1370                 switch (context) {
1371                         
1372                         case WM_OP_EXEC_REGION_WIN:
1373                         case WM_OP_INVOKE_REGION_WIN: 
1374                         case WM_OP_EXEC_REGION_CHANNELS:
1375                         case WM_OP_INVOKE_REGION_CHANNELS:
1376                         case WM_OP_EXEC_REGION_PREVIEW:
1377                         case WM_OP_INVOKE_REGION_PREVIEW:
1378                         {
1379                                 /* forces operator to go to the region window/channels/preview, for header menus
1380                                  * but we stay in the same region if we are already in one 
1381                                  */
1382                                 ARegion *ar = CTX_wm_region(C);
1383                                 ScrArea *area = CTX_wm_area(C);
1384                                 int type = RGN_TYPE_WINDOW;
1385                                 
1386                                 switch (context) {
1387                                         case WM_OP_EXEC_REGION_CHANNELS:
1388                                         case WM_OP_INVOKE_REGION_CHANNELS:
1389                                                 type = RGN_TYPE_CHANNELS;
1390                                                 break;
1391                                         
1392                                         case WM_OP_EXEC_REGION_PREVIEW:
1393                                         case WM_OP_INVOKE_REGION_PREVIEW:
1394                                                 type = RGN_TYPE_PREVIEW;
1395                                                 break;
1396                                         
1397                                         case WM_OP_EXEC_REGION_WIN:
1398                                         case WM_OP_INVOKE_REGION_WIN: 
1399                                         default:
1400                                                 type = RGN_TYPE_WINDOW;
1401                                                 break;
1402                                 }
1403                                 
1404                                 if (!(ar && ar->regiontype == type) && area) {
1405                                         ARegion *ar1;
1406                                         if (type == RGN_TYPE_WINDOW) {
1407                                                 ar1 = BKE_area_find_region_active_win(area);
1408                                         }
1409                                         else {
1410                                                 ar1 = BKE_area_find_region_type(area, type);
1411                                         }
1412
1413                                         if (ar1)
1414                                                 CTX_wm_region_set(C, ar1);
1415                                 }
1416                                 
1417                                 retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
1418                                 
1419                                 /* set region back */
1420                                 CTX_wm_region_set(C, ar);
1421                                 
1422                                 return retval;
1423                         }
1424                         case WM_OP_EXEC_AREA:
1425                         case WM_OP_INVOKE_AREA:
1426                         {
1427                                 /* remove region from context */
1428                                 ARegion *ar = CTX_wm_region(C);
1429
1430                                 CTX_wm_region_set(C, NULL);
1431                                 retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
1432                                 CTX_wm_region_set(C, ar);
1433
1434                                 return retval;
1435                         }
1436                         case WM_OP_EXEC_SCREEN:
1437                         case WM_OP_INVOKE_SCREEN:
1438                         {
1439                                 /* remove region + area from context */
1440                                 ARegion *ar = CTX_wm_region(C);
1441                                 ScrArea *area = CTX_wm_area(C);
1442
1443                                 CTX_wm_region_set(C, NULL);
1444                                 CTX_wm_area_set(C, NULL);
1445                                 retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
1446                                 CTX_wm_area_set(C, area);
1447                                 CTX_wm_region_set(C, ar);
1448
1449                                 return retval;
1450                         }
1451                         case WM_OP_EXEC_DEFAULT:
1452                         case WM_OP_INVOKE_DEFAULT:
1453                                 return wm_operator_invoke(C, ot, event, properties, reports, poll_only);
1454                 }
1455         }
1456         
1457         return 0;
1458 }
1459
1460
1461 /* invokes operator in context */
1462 int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
1463 {
1464         BLI_assert(ot == WM_operatortype_find(ot->idname, true));
1465         return wm_operator_call_internal(C, ot, properties, NULL, context, false);
1466 }
1467 int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
1468 {
1469         wmOperatorType *ot = WM_operatortype_find(opstring, 0);
1470         if (ot) {
1471                 return WM_operator_name_call_ptr(C, ot, context, properties);
1472         }
1473
1474         return 0;
1475 }
1476
1477 /**
1478  * Call an existent menu. The menu can be created in C or Python.
1479  */
1480 void WM_menu_name_call(bContext *C, const char *menu_name, short context)
1481 {
1482         wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
1483         PointerRNA ptr;
1484         WM_operator_properties_create_ptr(&ptr, ot);
1485         RNA_string_set(&ptr, "name", menu_name);
1486         WM_operator_name_call_ptr(C, ot, context, &ptr);
1487         WM_operator_properties_free(&ptr);
1488 }
1489
1490 /**
1491  * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
1492  *
1493  * - #wmOperatorType is used instead of operator name since python already has the operator type.
1494  * - `poll()` must be called by python before this runs.
1495  * - reports can be passed to this function (so python can report them as exceptions).
1496  */
1497 int WM_operator_call_py(
1498         bContext *C, wmOperatorType *ot, short context,
1499         PointerRNA *properties, ReportList *reports, const bool is_undo)
1500 {
1501         int retval = OPERATOR_CANCELLED;
1502
1503 #if 0
1504         wmOperator *op;
1505         op = wm_operator_create(wm, ot, properties, reports);
1506
1507         if (op->type->exec) {
1508                 if (is_undo && op->type->flag & OPTYPE_UNDO)
1509                         wm->op_undo_depth++;
1510
1511                 retval = op->type->exec(C, op);
1512                 OPERATOR_RETVAL_CHECK(retval);
1513
1514                 if (is_undo && op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
1515                         wm->op_undo_depth--;
1516         }
1517         else
1518                 printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
1519 #endif
1520
1521         /* not especially nice using undo depth here, its used so py never
1522          * triggers undo or stores operators last used state.
1523          *
1524          * we could have some more obvious way of doing this like passing a flag.
1525          */
1526         wmWindowManager *wm = CTX_wm_manager(C);
1527         if (!is_undo && wm) wm->op_undo_depth++;
1528
1529         retval = wm_operator_call_internal(C, ot, properties, reports, context, false);
1530         
1531         if (!is_undo && wm && (wm == CTX_wm_manager(C))) wm->op_undo_depth--;
1532
1533         return retval;
1534 }
1535
1536
1537 /* ********************* handlers *************** */
1538
1539 /* future extra customadata free? */
1540 void wm_event_free_handler(wmEventHandler *handler)
1541 {
1542         MEM_freeN(handler);
1543 }
1544
1545 /* only set context when area/region is part of screen */
1546 static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
1547 {
1548         bScreen *screen = CTX_wm_screen(C);
1549         
1550         if (screen && handler->op) {
1551                 if (handler->op_area == NULL)
1552                         CTX_wm_area_set(C, NULL);
1553                 else {
1554                         ScrArea *sa;
1555                         
1556                         for (sa = screen->areabase.first; sa; sa = sa->next)
1557                                 if (sa == handler->op_area)
1558                                         break;
1559                         if (sa == NULL) {
1560                                 /* when changing screen layouts with running modal handlers (like render display), this
1561                                  * is not an error to print */
1562                                 if (handler->op == NULL)
1563                                         printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
1564                         }
1565                         else {
1566                                 ARegion *ar;
1567                                 wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
1568                                 CTX_wm_area_set(C, sa);
1569
1570                                 if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
1571                                         ar = BKE_area_find_region_xy(sa, handler->op_region_type, event->x, event->y);
1572                                         if (ar) {
1573                                                 handler->op_region = ar;
1574                                         }
1575                                 }
1576                                 else {
1577                                         ar = NULL;
1578                                 }
1579
1580                                 if (ar == NULL) {
1581                                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1582                                                 if (ar == handler->op_region) {
1583                                                         break;
1584                                                 }
1585                                         }
1586                                 }
1587
1588                                 /* XXX no warning print here, after full-area and back regions are remade */
1589                                 if (ar)
1590                                         CTX_wm_region_set(C, ar);
1591                         }
1592                 }
1593         }
1594 }
1595
1596 /* called on exit or remove area, only here call cancel callback */
1597 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
1598 {
1599         wmEventHandler *handler;
1600         wmWindowManager *wm = CTX_wm_manager(C);
1601         
1602         /* C is zero on freeing database, modal handlers then already were freed */
1603         while ((handler = BLI_pophead(handlers))) {
1604                 if (handler->op) {
1605                         wmWindow *win = CTX_wm_window(C);
1606                         if (handler->op->type->cancel) {
1607                                 ScrArea *area = CTX_wm_area(C);
1608                                 ARegion *region = CTX_wm_region(C);
1609                                 
1610                                 wm_handler_op_context(C, handler, win->eventstate);
1611
1612                                 if (handler->op->type->flag & OPTYPE_UNDO)
1613                                         wm->op_undo_depth++;
1614
1615                                 handler->op->type->cancel(C, handler->op);
1616
1617                                 if (handler->op->type->flag & OPTYPE_UNDO)
1618                                         wm->op_undo_depth--;
1619
1620                                 CTX_wm_area_set(C, area);
1621                                 CTX_wm_region_set(C, region);
1622                         }
1623
1624                         WM_cursor_grab_disable(win, NULL);
1625                         WM_operator_free(handler->op);
1626                 }
1627                 else if (handler->ui_remove) {
1628                         ScrArea *area = CTX_wm_area(C);
1629                         ARegion *region = CTX_wm_region(C);
1630                         ARegion *menu = CTX_wm_menu(C);
1631                         
1632                         if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
1633                         if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
1634                         if (handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
1635
1636                         handler->ui_remove(C, handler->ui_userdata);
1637
1638                         CTX_wm_area_set(C, area);
1639                         CTX_wm_region_set(C, region);
1640                         CTX_wm_menu_set(C, menu);
1641                 }
1642
1643                 wm_event_free_handler(handler);
1644         }
1645 }
1646
1647 /* do userdef mappings */
1648 int WM_userdef_event_map(int kmitype)
1649 {
1650         switch (kmitype) {
1651                 case SELECTMOUSE:
1652                         return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
1653                 case ACTIONMOUSE:
1654                         return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
1655                 case EVT_TWEAK_A:
1656                         return (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_R : EVT_TWEAK_L;
1657                 case EVT_TWEAK_S:
1658                         return (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_L : EVT_TWEAK_R;
1659                 case WHEELOUTMOUSE:
1660                         return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
1661                 case WHEELINMOUSE:
1662                         return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
1663         }
1664         
1665         return kmitype;
1666 }
1667
1668 /**
1669  * Use so we can check if 'wmEvent.type' is released in modal operators.
1670  *
1671  * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
1672  */
1673 int WM_userdef_event_type_from_keymap_type(int kmitype)
1674 {
1675         switch (kmitype) {
1676                 case SELECTMOUSE:
1677                         return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
1678                 case ACTIONMOUSE:
1679                         return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
1680                 case EVT_TWEAK_S:
1681                         return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
1682                 case EVT_TWEAK_A:
1683                         return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
1684                 case EVT_TWEAK_L:
1685                         return LEFTMOUSE;
1686                 case EVT_TWEAK_M:
1687                         return MIDDLEMOUSE;
1688                 case EVT_TWEAK_R:
1689                         return RIGHTMOUSE;
1690                 case WHEELOUTMOUSE:
1691                         return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
1692                 case WHEELINMOUSE:
1693                         return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
1694         }
1695
1696         return kmitype;
1697 }
1698
1699 static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
1700 {
1701         int kmitype = WM_userdef_event_map(kmi->type);
1702
1703         if (kmi->flag & KMI_INACTIVE) return 0;
1704
1705         /* the matching rules */
1706         if (kmitype == KM_TEXTINPUT)
1707                 if (winevent->val == KM_PRESS) {  /* prevent double clicks */
1708                         /* NOT using ISTEXTINPUT anymore because (at least on Windows) some key codes above 255
1709                          * could have printable ascii keys - BUG [#30479] */
1710                         if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1; 
1711                 }
1712
1713         if (kmitype != KM_ANY) {
1714                 if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
1715                         const wmTabletData *wmtab = winevent->tablet_data;
1716                         
1717                         if (wmtab == NULL)
1718                                 return 0;
1719                         else if (winevent->type != LEFTMOUSE) /* tablet events can occur on hover + keypress */
1720                                 return 0;
1721                         else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS))
1722                                 return 0;
1723                         else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER))
1724                                 return 0;
1725                 }
1726                 else {
1727                         if (winevent->type != kmitype)
1728                                 return 0;
1729                 }
1730         }
1731         
1732         if (kmi->val != KM_ANY)
1733                 if (winevent->val != kmi->val) return 0;
1734         
1735         /* modifiers also check bits, so it allows modifier order */
1736         if (kmi->shift != KM_ANY)
1737                 if (winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
1738         if (kmi->ctrl != KM_ANY)
1739                 if (winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl)) return 0;
1740         if (kmi->alt != KM_ANY)
1741                 if (winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
1742         if (kmi->oskey != KM_ANY)
1743                 if (winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
1744         
1745         /* only keymap entry with keymodifier is checked, means all keys without modifier get handled too. */
1746         /* that is currently needed to make overlapping events work (when you press A - G fast or so). */
1747         if (kmi->keymodifier)
1748                 if (winevent->keymodifier != kmi->keymodifier) return 0;
1749         
1750         return 1;
1751 }
1752
1753
1754 /* operator exists */
1755 static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *event, bool *dbl_click_disabled)
1756 {
1757         /* support for modal keymap in macros */
1758         if (op->opm)
1759                 op = op->opm;
1760
1761         if (op->type->modalkeymap) {
1762                 wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1763                 wmKeyMapItem *kmi;
1764
1765                 for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
1766                         if (wm_eventmatch(event, kmi)) {
1767                                         
1768                                 event->prevtype = event->type;
1769                                 event->prevval = event->val;
1770                                 event->type = EVT_MODAL_MAP;
1771                                 event->val = kmi->propvalue;
1772                                 
1773                                 break;
1774                         }
1775                 }
1776         }
1777         else {
1778                 /* modal keymap checking returns handled events fine, but all hardcoded modal
1779                  * handling typically swallows all events (OPERATOR_RUNNING_MODAL).
1780                  * This bypass just disables support for double clicks in hardcoded modal handlers */
1781                 if (event->val == KM_DBL_CLICK) {
1782                         event->val = KM_PRESS;
1783                         *dbl_click_disabled = true;
1784                 }
1785         }
1786 }
1787
1788 /**
1789  * Check whether operator is allowed to run in case interface is locked,
1790  * If interface is unlocked, will always return truth.
1791  */
1792 static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
1793 {
1794         wmWindowManager *wm = CTX_wm_manager(C);
1795
1796         if (wm->is_interface_locked) {
1797                 if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
1798                         return false;
1799                 }
1800         }
1801
1802         return true;
1803 }
1804
1805 /* bad hacking event system... better restore event type for checking of KM_CLICK for example */
1806 /* XXX modal maps could use different method (ton) */
1807 static void wm_event_modalmap_end(wmEvent *event, bool dbl_click_disabled)
1808 {
1809         if (event->type == EVT_MODAL_MAP) {
1810                 event->type = event->prevtype;
1811                 event->prevtype = 0;
1812                 event->val = event->prevval;
1813                 event->prevval = 0;
1814         }
1815         else if (dbl_click_disabled)
1816                 event->val = KM_DBL_CLICK;
1817
1818 }
1819
1820 /* Warning: this function removes a modal handler, when finished */
1821 static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler,
1822                                     wmEvent *event, PointerRNA *properties)
1823 {
1824         int retval = OPERATOR_PASS_THROUGH;
1825         
1826         /* derived, modal or blocking operator */
1827         if (handler->op) {
1828                 wmOperator *op = handler->op;
1829                 wmOperatorType *ot = op->type;
1830
1831                 if (!wm_operator_check_locked_interface(C, ot)) {
1832                         /* Interface is locked and operator is not allowed to run,
1833                          * nothing to do in this case.
1834                          */
1835                 }
1836                 else if (ot->modal) {
1837                         /* we set context to where modal handler came from */
1838                         wmWindowManager *wm = CTX_wm_manager(C);
1839                         ScrArea *area = CTX_wm_area(C);
1840                         ARegion *region = CTX_wm_region(C);
1841                         bool dbl_click_disabled = false;
1842
1843                         wm_handler_op_context(C, handler, event);
1844                         wm_region_mouse_co(C, event);
1845                         wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
1846
1847                         if (ot->flag & OPTYPE_UNDO)
1848                                 wm->op_undo_depth++;
1849
1850                         /* warning, after this call all context data and 'event' may be freed. see check below */
1851                         retval = ot->modal(C, op, event);
1852                         OPERATOR_RETVAL_CHECK(retval);
1853                         
1854                         /* when this is _not_ the case the modal modifier may have loaded
1855                          * a new blend file (demo mode does this), so we have to assume
1856                          * the event, operator etc have all been freed. - campbell */
1857                         if (CTX_wm_manager(C) == wm) {
1858
1859                                 wm_event_modalmap_end(event, dbl_click_disabled);
1860
1861                                 if (ot->flag & OPTYPE_UNDO)
1862                                         wm->op_undo_depth--;
1863
1864                                 if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
1865                                         wm_operator_reports(C, op, retval, false);
1866                                 }
1867                                 else {
1868                                         /* not very common, but modal operators may report before finishing */
1869                                         if (!BLI_listbase_is_empty(&op->reports->list)) {
1870                                                 wm_add_reports(op->reports);
1871                                         }
1872                                 }
1873
1874                                 /* important to run 'wm_operator_finished' before NULLing the context members */
1875                                 if (retval & OPERATOR_FINISHED) {
1876                                         wm_operator_finished(C, op, false, true);
1877                                         handler->op = NULL;
1878                                 }
1879                                 else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
1880                                         WM_operator_free(op);
1881                                         handler->op = NULL;
1882                                 }
1883
1884                                 /* putting back screen context, reval can pass trough after modal failures! */
1885                                 if ((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
1886                                         CTX_wm_area_set(C, area);
1887                                         CTX_wm_region_set(C, region);
1888                                 }
1889                                 else {
1890                                         /* this special cases is for areas and regions that get removed */
1891                                         CTX_wm_area_set(C, NULL);
1892                                         CTX_wm_region_set(C, NULL);
1893                                 }
1894
1895                                 /* update manipulators during modal handlers */
1896                                 wm_manipulatormaps_handled_modal_update(C, event, handler);
1897
1898                                 /* remove modal handler, operator itself should have been canceled and freed */
1899                                 if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
1900                                         WM_cursor_grab_disable(CTX_wm_window(C), NULL);
1901
1902                                         BLI_remlink(handlers, handler);
1903                                         wm_event_free_handler(handler);
1904
1905                                         /* prevent silly errors from operator users */
1906                                         //retval &= ~OPERATOR_PASS_THROUGH;
1907                                 }
1908                         }
1909                         
1910                 }
1911                 else {
1912                         printf("%s: error '%s' missing modal\n", __func__, op->idname);
1913                 }
1914         }
1915         else {
1916                 wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
1917
1918                 if (ot) {
1919                         if (wm_operator_check_locked_interface(C, ot)) {
1920                                 retval = wm_operator_invoke(C, ot, event, properties, NULL, false);
1921                         }
1922                 }
1923         }
1924         /* Finished and pass through flag as handled */
1925
1926         /* Finished and pass through flag as handled */
1927         if (retval == (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH))
1928                 return WM_HANDLER_HANDLED;
1929
1930         /* Modal unhandled, break */
1931         if (retval == (OPERATOR_PASS_THROUGH | OPERATOR_RUNNING_MODAL))
1932                 return (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
1933
1934         if (retval & OPERATOR_PASS_THROUGH)
1935                 return WM_HANDLER_CONTINUE;
1936
1937         return WM_HANDLER_BREAK;
1938 }
1939
1940 /* fileselect handlers are only in the window queue, so it's safe to switch screens or area types */
1941 static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHandler *handler, int val)
1942 {
1943         wmWindowManager *wm = CTX_wm_manager(C);
1944         SpaceFile *sfile;
1945         int action = WM_HANDLER_CONTINUE;
1946
1947         switch (val) {
1948                 case EVT_FILESELECT_FULL_OPEN: 
1949                 {
1950                         ScrArea *sa;
1951                                 
1952                         /* sa can be null when window A is active, but mouse is over window B */
1953                         /* in this case, open file select in original window A */
1954                         if (handler->op_area == NULL) {
1955                                 bScreen *screen = CTX_wm_screen(C);
1956                                 sa = (ScrArea *)screen->areabase.first;
1957                         }
1958                         else {
1959                                 sa = handler->op_area;
1960                         }
1961
1962                         if (sa->full) {
1963                                 /* ensure the first area becomes the file browser, because the second one is the small
1964                                  * top (info-)area which might be too small (in fullscreens we have max two areas) */
1965                                 if (sa->prev) {
1966                                         sa = sa->prev;
1967                                 }
1968                                 ED_area_newspace(C, sa, SPACE_FILE, true);     /* 'sa' is modified in-place */
1969                                 /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
1970                                 sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
1971                         }
1972                         else if (sa->spacetype == SPACE_FILE) {
1973                                 sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
1974                         }
1975                         else {
1976                                 sa = ED_screen_full_newspace(C, sa, SPACE_FILE);    /* sets context */
1977                         }
1978
1979                         /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
1980                          * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
1981                         /* sa = CTX_wm_area(C); */
1982
1983                         /* settings for filebrowser, sfile is not operator owner but sends events */
1984                         sfile = (SpaceFile *)sa->spacedata.first;
1985                         sfile->op = handler->op;
1986
1987                         ED_fileselect_set_params(sfile);
1988                                 
1989                         action = WM_HANDLER_BREAK;
1990                         break;
1991                 }
1992                         
1993                 case EVT_FILESELECT_EXEC:
1994                 case EVT_FILESELECT_CANCEL:
1995                 case EVT_FILESELECT_EXTERNAL_CANCEL:
1996                 {
1997                         /* remlink now, for load file case before removing*/
1998                         BLI_remlink(handlers, handler);
1999
2000                         if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
2001                                 ScrArea *sa = CTX_wm_area(C);
2002
2003                                 if (sa->full) {
2004                                         ED_screen_full_prevspace(C, sa);
2005                                 }
2006                                 /* user may have left fullscreen */
2007                                 else {
2008                                         ED_area_prevspace(C, sa);
2009                                 }
2010                         }
2011
2012                         wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
2013
2014                         /* needed for UI_popup_menu_reports */
2015
2016                         if (val == EVT_FILESELECT_EXEC) {
2017                                 int retval;
2018
2019                                 if (handler->op->type->flag & OPTYPE_UNDO)
2020                                         wm->op_undo_depth++;
2021
2022                                 retval = handler->op->type->exec(C, handler->op);
2023
2024                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
2025                                 if (handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
2026                                         wm->op_undo_depth--;
2027
2028                                 /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
2029                                 if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
2030                                         if (handler->op->type->flag & OPTYPE_UNDO)
2031                                                 ED_undo_push_op(C, handler->op);
2032                                         else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED)
2033                                                 ED_undo_grouped_push_op(C, handler->op);
2034                                 }
2035
2036                                 if (handler->op->reports->list.first) {
2037
2038                                         /* FIXME, temp setting window, this is really bad!
2039                                          * only have because lib linking errors need to be seen by users :(
2040                                          * it can be removed without breaking anything but then no linking errors - campbell */
2041                                         wmWindow *win_prev = CTX_wm_window(C);
2042                                         ScrArea *area_prev = CTX_wm_area(C);
2043                                         ARegion *ar_prev = CTX_wm_region(C);
2044
2045                                         if (win_prev == NULL)
2046                                                 CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
2047
2048                                         BKE_report_print_level_set(handler->op->reports, RPT_WARNING);
2049                                         UI_popup_menu_reports(C, handler->op->reports);
2050
2051                                         /* XXX - copied from 'wm_operator_finished()' */
2052                                         /* add reports to the global list, otherwise they are not seen */
2053                                         BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
2054
2055                                         /* more hacks, since we meddle with reports, banner display doesn't happen automatic */
2056                                         WM_report_banner_show();
2057
2058                                         CTX_wm_window_set(C, win_prev);
2059                                         CTX_wm_area_set(C, area_prev);
2060                                         CTX_wm_region_set(C, ar_prev);
2061                                 }
2062
2063                                 /* for WM_operator_pystring only, custom report handling is done above */
2064                                 wm_operator_reports(C, handler->op, retval, true);
2065
2066                                 if (retval & OPERATOR_FINISHED) {
2067                                         WM_operator_last_properties_store(handler->op);
2068                                 }
2069
2070                                 if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2071                                         WM_operator_free(handler->op);
2072                                 }
2073                         }
2074                         else {
2075                                 if (handler->op->type->cancel) {
2076                                         if (handler->op->type->flag & OPTYPE_UNDO)
2077                                                 wm->op_undo_depth++;
2078
2079                                         handler->op->type->cancel(C, handler->op);
2080                                 
2081                                         if (handler->op->type->flag & OPTYPE_UNDO)
2082                                                 wm->op_undo_depth--;
2083                                 }
2084                                 
2085                                 WM_operator_free(handler->op);
2086                         }
2087
2088                         CTX_wm_area_set(C, NULL);
2089
2090                         wm_event_free_handler(handler);
2091
2092                         action = WM_HANDLER_BREAK;
2093                         break;
2094                 }
2095         }
2096         
2097         return action;
2098 }
2099
2100 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, const wmEvent *event)
2101 {
2102         int action = WM_HANDLER_CONTINUE;
2103         
2104         if (event->type != EVT_FILESELECT)
2105                 return action;
2106         if (handler->op != (wmOperator *)event->customdata)
2107                 return action;
2108         
2109         return wm_handler_fileselect_do(C, handlers, handler, event->val);
2110 }
2111
2112 static bool handler_boundbox_test(wmEventHandler *handler, const wmEvent *event)
2113 {
2114         if (handler->bbwin) {
2115                 if (handler->bblocal) {
2116                         rcti rect = *handler->bblocal;
2117                         BLI_rcti_translate(&rect, handler->bbwin->xmin, handler->bbwin->ymin);
2118
2119                         if (BLI_rcti_isect_pt_v(&rect, &event->x))
2120                                 return 1;
2121                         else if (event->type == MOUSEMOVE && BLI_rcti_isect_pt_v(&rect, &event->prevx))
2122                                 return 1;
2123                         else
2124                                 return 0;
2125                 }
2126                 else {
2127                         if (BLI_rcti_isect_pt_v(handler->bbwin, &event->x))
2128                                 return 1;
2129                         else if (event->type == MOUSEMOVE && BLI_rcti_isect_pt_v(handler->bbwin, &event->prevx))
2130                                 return 1;
2131                         else
2132                                 return 0;
2133                 }
2134         }
2135         return 1;
2136 }
2137
2138 static int wm_action_not_handled(int action)
2139 {
2140         return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
2141 }
2142
2143 static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
2144 {
2145         const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
2146                 /* comment this out to flood the console! (if you really want to test) */
2147                 !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
2148                 ;
2149 # define PRINT if (do_debug_handler) printf
2150
2151         wmWindowManager *wm = CTX_wm_manager(C);
2152         wmEventHandler *handler, *nexthandler;
2153         int action = WM_HANDLER_CONTINUE;
2154         int always_pass;
2155
2156         if (handlers == NULL) {
2157                 return action;
2158         }
2159
2160         /* modal handlers can get removed in this loop, we keep the loop this way
2161          *
2162          * note: check 'handlers->first' because in rare cases the handlers can be cleared
2163          * by the event thats called, for eg:
2164          *
2165          * Calling a python script which changes the area.type, see [#32232] */
2166         for (handler = handlers->first; handler && handlers->first; handler = nexthandler) {
2167
2168                 nexthandler = handler->next;
2169                 
2170                 /* during this loop, ui handlers for nested menus can tag multiple handlers free */
2171                 if (handler->flag & WM_HANDLER_DO_FREE) {
2172                         /* pass */
2173                 }
2174                 else if (handler_boundbox_test(handler, event)) { /* optional boundbox */
2175                         /* in advance to avoid access to freed event on window close */
2176                         always_pass = wm_event_always_pass(event);
2177                 
2178                         /* modal+blocking handler */
2179                         if (handler->flag & WM_HANDLER_BLOCKING)
2180                                 action |= WM_HANDLER_BREAK;
2181
2182                         if (handler->keymap) {
2183                                 wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
2184                                 wmKeyMapItem *kmi;
2185
2186                                 PRINT("%s:   checking '%s' ...", __func__, keymap->idname);
2187
2188                                 if (!keymap->poll || keymap->poll(C)) {
2189
2190                                         PRINT("pass\n");
2191
2192                                         for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
2193                                                 if (wm_eventmatch(event, kmi)) {
2194
2195                                                         PRINT("%s:     item matched '%s'\n", __func__, kmi->idname);
2196
2197                                                         /* weak, but allows interactive callback to not use rawkey */
2198                                                         event->keymap_idname = kmi->idname;
2199
2200                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
2201                                                         if (action & WM_HANDLER_BREAK) {
2202                                                                 /* not always_pass here, it denotes removed handler */
2203                                                                 
2204                                                                 if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
2205                                                                         printf("%s:       handled! '%s'\n", __func__, kmi->idname);
2206
2207                                                                 break;
2208                                                         }
2209                                                         else {
2210                                                                 if (action & WM_HANDLER_HANDLED) {
2211                                                                         if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
2212                                                                                 printf("%s:       handled - and pass on! '%s'\n", __func__, kmi->idname);
2213                                                                 }
2214                                                                 else {
2215                                                                         PRINT("%s:       un-handled '%s'\n", __func__, kmi->idname);
2216                                                                 }
2217                                                         }
2218                                                 }
2219                                         }
2220                                 }
2221                                 else {
2222                                         PRINT("fail\n");
2223                                 }
2224                         }
2225                         else if (handler->ui_handle) {
2226                                 if (!wm->is_interface_locked) {
2227                                         action |= wm_handler_ui_call(C, handler, event, always_pass);
2228                                 }
2229                         }
2230                         else if (handler->type == WM_HANDLER_FILESELECT) {
2231                                 if (!wm->is_interface_locked) {
2232                                         /* screen context changes here */
2233                                         action |= wm_handler_fileselect_call(C, handlers, handler, event);
2234                                 }
2235                         }
2236                         else if (handler->dropboxes) {
2237                                 if (!wm->is_interface_locked && event->type == EVT_DROP) {
2238                                         wmDropBox *drop = handler->dropboxes->first;
2239                                         for (; drop; drop = drop->next) {
2240                                                 /* other drop custom types allowed */
2241                                                 if (event->custom == EVT_DATA_DRAGDROP) {
2242                                                         ListBase *lb = (ListBase *)event->customdata;
2243                                                         wmDrag *drag;
2244                                                         
2245                                                         for (drag = lb->first; drag; drag = drag->next) {
2246                                                                 if (drop->poll(C, drag, event)) {
2247                                                                         drop->copy(drag, drop);
2248                                                                         
2249                                                                         /* free the drags before calling operator */
2250                                                                         WM_drag_free_list(lb);
2251
2252                                                                         event->customdata = NULL;
2253                                                                         event->custom = 0;
2254                                                                         
2255                                                                         WM_operator_name_call_ptr(C, drop->ot, drop->opcontext, drop->ptr);
2256                                                                         action |= WM_HANDLER_BREAK;
2257                                                                         
2258                                                                         /* XXX fileread case */
2259                                                                         if (CTX_wm_window(C) == NULL)
2260                                                                                 return action;
2261                                                                         
2262                                                                         /* escape from drag loop, got freed */
2263                                                                         break;
2264                                                                 }
2265                                                         }
2266                                                 }
2267                                         }
2268                                 }
2269                         }
2270                         else if (handler->manipulator_map) {
2271                                 ScrArea *area = CTX_wm_area(C);
2272                                 ARegion *region = CTX_wm_region(C);
2273                                 wmManipulatorMap *mmap = handler->manipulator_map;
2274                                 wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap);
2275
2276                                 if (region->manipulator_map != handler->manipulator_map) {
2277                                         WM_manipulatormap_tag_refresh(handler->manipulator_map);
2278                                 }
2279
2280                                 wm_manipulatormap_handler_context(C, handler);
2281                                 wm_region_mouse_co(C, event);
2282
2283                                 /* handle manipulator highlighting */
2284                                 if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) {
2285                                         int part;
2286                                         mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
2287                                         wm_manipulatormap_highlight_set(mmap, C, mpr, part);
2288                                         if (mpr != NULL) {
2289                                                 WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init);
2290                                         }
2291                                 }
2292                                 else {
2293                                         /* Either we operate on a single highlighted item
2294                                          * or groups attached to the selected manipulators.
2295                                          * To simplify things both cases loop over an array of items. */
2296                                         wmManipulatorGroup *mgroup_first;
2297                                         bool is_mgroup_single;
2298
2299                                         if (ISMOUSE(event->type)) {
2300                                                 /* Keep mpr set as-is, just fake single selection. */
2301                                                 if (mpr) {
2302                                                         mgroup_first = mpr->parent_mgroup;
2303                                                 }
2304                                                 else {
2305                                                         mgroup_first = NULL;
2306                                                 }
2307                                                 is_mgroup_single = true;
2308                                         }
2309                                         else {
2310                                                 if (WM_manipulatormap_is_any_selected(mmap)) {
2311                                                         const ListBase *groups = WM_manipulatormap_group_list(mmap);
2312                                                         mgroup_first = groups->first;
2313                                                 }
2314                                                 else {
2315                                                         mgroup_first = NULL;
2316                                                 }
2317                                                 is_mgroup_single = false;
2318                                         }
2319
2320                                         /* Don't use from now on. */
2321                                         mpr = NULL;
2322
2323                                         for (wmManipulatorGroup *mgroup = mgroup_first; mgroup; mgroup = mgroup->next) {
2324                                                 /* get user customized keymap from default one */
2325
2326                                                 if ((is_mgroup_single == false) &&
2327                                                     /* We might want to change the logic here and use some kind of manipulator edit-mode.
2328                                                      * For now just use keymap when a selection exists. */
2329                                                     wm_manipulatorgroup_is_any_selected(mgroup) == false)
2330                                                 {
2331                                                         continue;
2332                                                 }
2333
2334                                                 const wmKeyMap *keymap = WM_keymap_active(wm, mgroup->type->keymap);
2335                                                 wmKeyMapItem *kmi;
2336
2337                                                 PRINT("%s:   checking '%s' ...", __func__, keymap->idname);
2338
2339                                                 if (!keymap->poll || keymap->poll(C)) {
2340                                                         PRINT("pass\n");
2341                                                         for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
2342                                                                 if (wm_eventmatch(event, kmi)) {
2343                                                                         wmOperator *op = handler->op;
2344
2345                                                                         PRINT("%s:     item matched '%s'\n", __func__, kmi->idname);
2346
2347                                                                         /* weak, but allows interactive callback to not use rawkey */
2348                                                                         event->keymap_idname = kmi->idname;
2349
2350                                                                         CTX_wm_manipulator_group_set(C, mgroup);
2351
2352                                                                         /* handler->op is called later, we want keymap op to be triggered here */
2353                                                                         handler->op = NULL;
2354                                                                         action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
2355                                                                         handler->op = op;
2356
2357                                                                         CTX_wm_manipulator_group_set(C, NULL);
2358
2359                                                                         if (action & WM_HANDLER_BREAK) {
2360                                                                                 if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2361                                                                                         printf("%s:       handled - and pass on! '%s'\n",
2362                                                                                                __func__, kmi->idname);
2363                                                                                 }
2364                                                                                 break;
2365                                                                         }
2366                                                                         else {
2367                                                                                 if (action & WM_HANDLER_HANDLED) {
2368                                                                                         if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2369                                                                                                 printf("%s:       handled - and pass on! '%s'\n",
2370                                                                                                        __func__, kmi->idname);
2371                                                                                         }
2372                                                                                 }
2373                                                                                 else {
2374                                                                                         PRINT("%s:       un-handled '%s'\n",
2375                                                                                               __func__, kmi->idname);
2376                                                                                 }
2377                                                                         }
2378                                                                 }
2379                                                         }
2380                                                 }
2381                                                 else {
2382                                                         PRINT("fail\n");
2383                                                 }
2384
2385                                                 if (action & WM_HANDLER_BREAK) {
2386                                                         break;
2387                                                 }
2388
2389                                                 if (is_mgroup_single) {
2390                                                         break;
2391                                                 }
2392                                         }
2393                                 }
2394
2395                                 /* restore the area */
2396                                 CTX_wm_area_set(C, area);
2397                                 CTX_wm_region_set(C, region);
2398
2399                                 if (handler->op) {
2400                                         action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
2401                                 }
2402                         }
2403                         else {
2404                                 /* modal, swallows all */
2405                                 action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
2406                         }
2407
2408                         if (action & WM_HANDLER_BREAK) {
2409                                 if (always_pass)
2410                                         action &= ~WM_HANDLER_BREAK;
2411                                 else
2412                                         break;
2413                         }
2414                 }
2415                 
2416                 /* XXX fileread case, if the wm is freed then the handler's
2417                  * will have been too so the code below need not run. */
2418                 if (CTX_wm_window(C) == NULL) {
2419                         return action;
2420                 }
2421
2422                 /* XXX code this for all modal ops, and ensure free only happens here */
2423                 
2424                 /* modal ui handler can be tagged to be freed */ 
2425                 if (BLI_findindex(handlers, handler) != -1) { /* could be freed already by regular modal ops */
2426                         if (handler->flag & WM_HANDLER_DO_FREE) {
2427                                 BLI_remlink(handlers, handler);
2428                                 wm_event_free_handler(handler);
2429                         }
2430                 }
2431         }
2432
2433         if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL))
2434                 wm_cursor_arrow_move(CTX_wm_window(C), event);
2435
2436 #undef PRINT
2437
2438         return action;
2439 }
2440
2441 /* this calls handlers twice - to solve (double-)click events */
2442 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
2443 {
2444         int action = wm_handlers_do_intern(C, event, handlers);
2445                 
2446         /* fileread case */
2447         if (CTX_wm_window(C) == NULL)
2448                 return action;
2449
2450         if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) {
2451
2452                 /* test for CLICK events */
2453                 if (wm_action_not_handled(action)) {
2454                         wmWindow *win = CTX_wm_window(C);
2455                         
2456                         /* eventstate stores if previous event was a KM_PRESS, in case that 
2457                          * wasn't handled, the KM_RELEASE will become a KM_CLICK */
2458                         
2459                         if (win && event->val == KM_PRESS) {
2460                                 win->eventstate->check_click = true;
2461                         }
2462                         
2463                         if (win && win->eventstate->prevtype == event->type) {
2464                                 
2465                                 if ((event->val == KM_RELEASE) &&
2466                                     (win->eventstate->prevval == KM_PRESS) &&
2467                                     (win->eventstate->check_click == true))
2468                                 {
2469                                         if ((abs(event->x - win->eventstate->prevclickx)) <= WM_EVENT_CLICK_WIGGLE_ROOM &&
2470                                             (abs(event->y - win->eventstate->prevclicky)) <= WM_EVENT_CLICK_WIGGLE_ROOM)
2471                                         {
2472                                                 event->val = KM_CLICK;
2473
2474                                                 if (G.debug & (G_DEBUG_HANDLERS)) {
2475                                                         printf("%s: handling CLICK\n", __func__);
2476                                                 }
2477
2478                                                 action |= wm_handlers_do_intern(C, event, handlers);
2479
2480                                                 event->val = KM_RELEASE;
2481                                         }
2482                                         else {
2483                                                 win->eventstate->check_click = 0;
2484                                         }
2485                                 }
2486                                 else if (event->val == KM_DBL_CLICK) {
2487                                         event->val = KM_PRESS;
2488                                         action |= wm_handlers_do_intern(C, event, handlers);
2489                                         
2490                                         /* revert value if not handled */
2491                                         if (wm_action_not_handled(action)) {
2492                                                 event->val = KM_DBL_CLICK;
2493                                         }
2494                                 }
2495                         }
2496                 }
2497                 else {
2498                         wmWindow *win = CTX_wm_window(C);
2499
2500                         if (win)
2501                                 win->eventstate->check_click = 0;
2502                 }
2503         }
2504         
2505         return action;
2506 }
2507
2508 static int wm_event_inside_i(wmEvent *event, rcti *rect)
2509 {
2510         if (wm_event_always_pass(event))
2511                 return 1;
2512         if (BLI_rcti_isect_pt_v(rect, &event->x))
2513                 return 1;
2514         return 0;
2515 }
2516
2517 static ScrArea *area_event_inside(bContext *C, const int xy[2])
2518 {
2519         bScreen *screen = CTX_wm_screen(C);
2520         ScrArea *sa;
2521         
2522         if (screen)
2523                 for (sa = screen->areabase.first; sa; sa = sa->next)
2524                         if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
2525                                 return sa;
2526         return NULL;
2527 }
2528
2529 static ARegion *region_event_inside(bContext *C, const int xy[2])
2530 {
2531         bScreen *screen = CTX_wm_screen(C);
2532         ScrArea *area = CTX_wm_area(C);
2533         ARegion *ar;
2534         
2535         if (screen && area)
2536                 for (ar = area->regionbase.first; ar; ar = ar->next)
2537                         if (BLI_rcti_isect_pt_v(&ar->winrct, xy))
2538                                 return ar;
2539         return NULL;
2540 }
2541
2542 static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
2543 {
2544         if (ar) {
2545                 for (; pc; pc = pc->next) {
2546                         if (pc->poll == NULL || pc->poll(C)) {
2547                                 wmWindow *win = CTX_wm_window(C);
2548                                 WM_paint_cursor_tag_redraw(win, ar);
2549                         }
2550                 }
2551         }
2552 }
2553
2554 /* called on mousemove, check updates for paintcursors */
2555 /* context was set on active area and region */
2556 static void wm_paintcursor_test(bContext *C, const wmEvent *event)
2557 {
2558         wmWindowManager *wm = CTX_wm_manager(C);
2559         
2560         if (wm->paintcursors.first) {
2561                 ARegion *ar = CTX_wm_region(C);
2562                 
2563                 if (ar)
2564                         wm_paintcursor_tag(C, wm->paintcursors.first, ar);
2565                 
2566                 /* if previous position was not in current region, we have to set a temp new context */
2567                 if (ar == NULL || !BLI_rcti_isect_pt_v(&ar->winrct, &event->prevx)) {
2568                         ScrArea *sa = CTX_wm_area(C);
2569                         
2570                         CTX_wm_area_set(C, area_event_inside(C, &event->prevx));
2571                         CTX_wm_region_set(C, region_event_inside(C, &event->prevx));
2572
2573                         wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
2574                         
2575                         CTX_wm_area_set(C, sa);
2576                         CTX_wm_region_set(C, ar);
2577                 }
2578         }
2579 }
2580
2581 static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
2582 {
2583         bScreen *screen = WM_window_get_active_screen(win);
2584
2585         if (BLI_listbase_is_empty(&wm->drags)) {
2586                 return;
2587         }
2588         
2589         if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
2590                 screen->do_draw_drag = true;
2591         }
2592         else if (event->type == ESCKEY) {
2593                 WM_drag_free_list(&wm->drags);
2594
2595                 screen->do_draw_drag = true;
2596         }
2597         else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
2598                 event->type = EVT_DROP;
2599                 
2600                 /* create customdata, first free existing */
2601                 if (event->customdata) {
2602                         if (event->customdatafree)
2603                                 MEM_freeN(event->customdata);
2604                 }
2605                 
2606                 event->custom = EVT_DATA_DRAGDROP;
2607                 event->customdata = &wm->drags;
2608                 event->customdatafree = 1;
2609                 
2610                 /* clear drop icon */
2611                 screen->do_draw_drag = true;
2612                 
2613                 /* restore cursor (disabled, see wm_dragdrop.c) */
2614                 // WM_cursor_modal_restore(win);
2615         }
2616         
2617         /* overlap fails otherwise */
2618         if (screen->do_draw_drag)
2619                 if (win->drawmethod == USER_DRAW_OVERLAP)
2620                         screen->do_draw = true;
2621         
2622 }
2623
2624 /* filter out all events of the pie that spawned the last pie unless it's a release event */
2625 static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
2626 {
2627         if (win->lock_pie_event && win->lock_pie_event == event->type) {
2628                 if (event->val == KM_RELEASE) {
2629                         win->lock_pie_event = EVENT_NONE;
2630                         return false;
2631                 }
2632                 else {
2633                         return true;
2634                 }
2635         }
2636         else {
2637                 return false;
2638         }
2639 }
2640
2641 /* called in main loop */
2642 /* goes over entire hierarchy:  events -> window -> screen -> area -> region */
2643 void wm_event_do_handlers(bContext *C)
2644 {
2645         wmWindowManager *wm = CTX_wm_manager(C);
2646         wmWindow *win;
2647
2648         /* update key configuration before handling events */
2649         WM_keyconfig_update(wm);
2650         WM_manipulatorconfig_update(CTX_data_main(C));
2651
2652         for (win = wm->windows.first; win; win = win->next) {
2653                 bScreen *screen = WM_window_get_active_screen(win);
2654                 wmEvent *event;
2655
2656                 /* some safty checks - these should always be set! */
2657                 BLI_assert(WM_window_get_active_scene(win));
2658                 BLI_assert(WM_window_get_active_screen(win));
2659                 BLI_assert(WM_window_get_active_workspace(win));
2660
2661                 if (screen == NULL)
2662                         wm_event_free_all(win);
2663                 else {
2664                         Scene *scene = WM_window_get_active_scene(win);
2665
2666                         if (scene) {
2667                                 int is_playing_sound = BKE_sound_scene_playing(scene);
2668                                 
2669                                 if (is_playing_sound != -1) {
2670                                         bool is_playing_screen;
2671                                         CTX_wm_window_set(C, win);
2672                                         CTX_data_scene_set(C, scene);
2673                                         
2674                                         is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
2675
2676                                         if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
2677                                             ((is_playing_sound == 0) && (is_playing_screen == 1)))
2678                                         {
2679                                                 ED_screen_animation_play(C, -1, 1);
2680                                         }
2681                                         
2682                                         if (is_playing_sound == 0) {
2683                                                 const float time = BKE_sound_sync_scene(scene);
2684                                                 if (isfinite(time)) {
2685                                                         int ncfra = time * (float)FPS + 0.5f;
2686                                                         if (ncfra != scene->r.cfra) {
2687                                                                 scene->r.cfra = ncfra;
2688                                                                 ViewLayer *view_layer = CTX_data_view_layer(C);
2689                                                                 Depsgraph *depsgraph = CTX_data_depsgraph(C);
2690                                                                 ED_update_for_newframe(CTX_data_main(C), scene, view_layer, depsgraph);
2691                                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
2692                                                         }
2693                                                 }
2694                                         }
2695                                         
2696                                         CTX_data_scene_set(C, NULL);
2697                                         CTX_wm_screen_set(C, NULL);
2698                                         CTX_wm_window_set(C, NULL);
2699                                 }
2700                         }
2701                 }
2702                 
2703                 while ( (event = win->queue.first) ) {
2704                         int action = WM_HANDLER_CONTINUE;
2705
2706                         /* active screen might change during handlers, update pointer */
2707                         screen = WM_window_get_active_screen(win);
2708
2709                         if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
2710                                 printf("\n%s: Handling event\n", __func__);
2711                                 WM_event_print(event);
2712                         }
2713
2714                         /* take care of pie event filter */
2715                         if (wm_event_pie_filter(win, event)) {
2716                                 if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
2717                                         printf("\n%s: event filtered due to pie button pressed\n", __func__);
2718                                 }
2719                                 BLI_remlink(&win->queue, event);
2720                                 wm_event_free(event);
2721                                 continue;
2722                         }
2723
2724                         CTX_wm_window_set(C, win);
2725
2726                         /* Clear tool-tip on mouse move. */
2727                         if (screen->tool_tip && screen->tool_tip->exit_on_event) {
2728                                 if (ISMOUSE(event->type)) {
2729                                         WM_tooltip_clear(C, win);
2730                                 }
2731                         }
2732
2733                         /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
2734                         CTX_wm_area_set(C, area_event_inside(C, &event->x));
2735                         CTX_wm_region_set(C, region_event_inside(C, &event->x));
2736                         
2737                         /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
2738                         wm_window_make_drawable(wm, win);
2739                         
2740                         wm_region_mouse_co(C, event);
2741
2742
2743                         /* first we do priority handlers, modal + some limited keymaps */
2744                         action |= wm_handlers_do(C, event, &win->modalhandlers);
2745                         
2746                         /* fileread case */
2747                         if (CTX_wm_window(C) == NULL)
2748                                 return;
2749
2750                         /* check for a tooltip */
2751                         if (screen == WM_window_get_active_screen(win)) {
2752                                 if (screen->tool_tip && screen->tool_tip->timer) {
2753                                         if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
2754                                                 WM_tooltip_init(C, win);
2755                                         }
2756                                 }
2757                         }
2758
2759                         /* check dragging, creates new event or frees, adds draw tag */
2760                         wm_event_drag_test(wm, win, event);
2761                         
2762                         /* builtin tweak, if action is break it removes tweak */
2763                         wm_tweakevent_test(C, event, action);
2764
2765                         if ((action & WM_HANDLER_BREAK) == 0) {
2766                                 ScrArea *sa;
2767                                 ARegion *ar;
2768         
2769                                 /* Note: setting subwin active should be done here, after modal handlers have been done */
2770                                 if (event->type == MOUSEMOVE) {
2771                                         /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
2772                                         ED_screen_set_subwinactive(C, event);
2773                                         /* for regions having custom cursors */
2774                                         wm_paintcursor_test(C, event);
2775                                 }
2776 #ifdef WITH_INPUT_NDOF
2777                                 else if (event->type == NDOF_MOTION) {
2778                                         win->addmousemove = true;
2779                                 }
2780 #endif
2781
2782                                 for (sa = screen->areabase.first; sa; sa = sa->next) {
2783                                         /* after restoring a screen from SCREENMAXIMIZED we have to wait
2784                                          * with the screen handling till the region coordinates are updated */
2785                                         if (screen->skip_handling == true) {