Blender  V2.93
wm_event_system.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "DNA_listBase.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_userdef_types.h"
37 
38 #include "MEM_guardedalloc.h"
39 
40 #include "CLG_log.h"
41 
42 #include "GHOST_C-api.h"
43 
44 #include "BLI_blenlib.h"
45 #include "BLI_dynstr.h"
46 #include "BLI_math.h"
47 #include "BLI_timer.h"
48 #include "BLI_utildefines.h"
49 
50 #include "BKE_context.h"
51 #include "BKE_customdata.h"
52 #include "BKE_global.h"
53 #include "BKE_idprop.h"
54 #include "BKE_main.h"
55 #include "BKE_report.h"
56 #include "BKE_scene.h"
57 #include "BKE_screen.h"
58 #include "BKE_workspace.h"
59 
60 #include "BKE_sound.h"
61 
62 #include "BLT_translation.h"
63 
64 #include "ED_fileselect.h"
65 #include "ED_info.h"
66 #include "ED_screen.h"
67 #include "ED_undo.h"
68 #include "ED_util.h"
69 #include "ED_view3d.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_message.h"
79 #include "WM_toolsystem.h"
80 #include "WM_types.h"
81 
82 #include "wm.h"
83 #include "wm_event_system.h"
84 #include "wm_event_types.h"
85 #include "wm_window.h"
86 
87 #include "DEG_depsgraph.h"
88 #include "DEG_depsgraph_query.h"
89 
102 #define USE_GIZMO_MOUSE_PRIORITY_HACK
103 
104 static void wm_notifier_clear(wmNotifier *note);
105 
108  PointerRNA *properties,
109  ReportList *reports,
110  const short context,
111  const bool poll_only,
112  wmEvent *event);
113 
115 
116 /* -------------------------------------------------------------------- */
121  const wmEvent *event_to_add,
122  const wmEvent *event_to_add_after)
123 {
124  wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
125 
126  *event = *event_to_add;
127 
128  if (event_to_add_after == NULL) {
129  BLI_addtail(&win->event_queue, event);
130  }
131  else {
132  /* Note: strictly speaking this breaks const-correctness,
133  * however we're only changing 'next' member. */
134  BLI_insertlinkafter(&win->event_queue, (void *)event_to_add_after, event);
135  }
136  return event;
137 }
138 
139 wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
140 {
141  return wm_event_add_ex(win, event_to_add, NULL);
142 }
143 
144 wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
145 {
146  if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) {
148  return NULL;
149  }
150  wmEvent *event = wm_event_add(win, event_to_add);
151 
152  /* Logic for setting previous value is documented on the #wmEvent struct,
153  * see #wm_event_add_ghostevent for the implementation of logic this follows. */
154 
155  win->eventstate->x = event->x;
156  win->eventstate->y = event->y;
157 
158  if (event->type == MOUSEMOVE) {
159  win->eventstate->prevx = event->prevx = win->eventstate->x;
160  win->eventstate->prevy = event->prevy = win->eventstate->y;
161  }
162  else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) {
163  win->eventstate->prevval = event->prevval = win->eventstate->val;
164  win->eventstate->prevtype = event->prevtype = win->eventstate->type;
165 
166  win->eventstate->val = event->val;
167  win->eventstate->type = event->type;
168 
169  if (event->val == KM_PRESS) {
170  if (event->is_repeat == false) {
171  win->eventstate->prevclickx = event->x;
172  win->eventstate->prevclicky = event->y;
173  }
174  }
175  }
176  return event;
177 }
178 
179 void wm_event_free(wmEvent *event)
180 {
181 #ifndef NDEBUG
182  /* Don't use assert here because it's fairly harmless in most cases,
183  * more an issue of correctness, something we should avoid in general. */
184  if (event->is_repeat && !ISKEYBOARD(event->type)) {
185  printf("%s: 'is_repeat=true' for non-keyboard event, this should not happen.\n", __func__);
186  WM_event_print(event);
187  }
188 #endif
189 
190  if (event->customdata) {
191  if (event->customdatafree) {
192  /* Note: pointer to listbase struct elsewhere. */
193  if (event->custom == EVT_DATA_DRAGDROP) {
194  ListBase *lb = event->customdata;
195  WM_drag_free_list(lb);
196  }
197  else {
198  MEM_freeN(event->customdata);
199  }
200  }
201  }
202 
203  MEM_freeN(event);
204 }
205 
206 static void wm_event_free_last(wmWindow *win)
207 {
208  wmEvent *event = BLI_poptail(&win->event_queue);
209  if (event != NULL) {
210  wm_event_free(event);
211  }
212 }
213 
215 {
216  wmEvent *event;
217  while ((event = BLI_pophead(&win->event_queue))) {
218  wm_event_free(event);
219  }
220 }
221 
223 {
224  *event = *(win->eventstate);
225 }
226 
229 /* -------------------------------------------------------------------- */
233 static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
234 {
235  LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) {
236  if ((note->category | note->data | note->subtype | note->action) == type &&
237  note->reference == reference) {
238  return true;
239  }
240  }
241 
242  return false;
243 }
244 
245 void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
246 {
247  if (wm_test_duplicate_notifier(wm, type, reference)) {
248  return;
249  }
250 
251  wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
252 
253  BLI_addtail(&wm->notifier_queue, note);
254 
255  note->window = win;
256 
257  note->category = type & NOTE_CATEGORY;
258  note->data = type & NOTE_DATA;
259  note->subtype = type & NOTE_SUBTYPE;
260  note->action = type & NOTE_ACTION;
261 
262  note->reference = reference;
263 }
264 
265 /* XXX: in future, which notifiers to send to other windows? */
266 void WM_event_add_notifier(const bContext *C, uint type, void *reference)
267 {
269 }
270 
271 void WM_main_add_notifier(unsigned int type, void *reference)
272 {
273  Main *bmain = G_MAIN;
274  wmWindowManager *wm = bmain->wm.first;
275 
276  if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
277  return;
278  }
279 
280  wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
281 
282  BLI_addtail(&wm->notifier_queue, note);
283 
284  note->category = type & NOTE_CATEGORY;
285  note->data = type & NOTE_DATA;
286  note->subtype = type & NOTE_SUBTYPE;
287  note->action = type & NOTE_ACTION;
288 
289  note->reference = reference;
290 }
291 
295 void WM_main_remove_notifier_reference(const void *reference)
296 {
297  Main *bmain = G_MAIN;
298  wmWindowManager *wm = bmain->wm.first;
299 
300  if (wm) {
302  if (note->reference == reference) {
303  /* Don't remove because this causes problems for #wm_event_do_notifiers
304  * which may be looping on the data (deleting screens). */
305  wm_notifier_clear(note);
306  }
307  }
308 
309  /* Remap instead. */
310 #if 0
311  if (wm->message_bus) {
312  WM_msg_id_remove(wm->message_bus, reference);
313  }
314 #endif
315  }
316 }
317 
319 {
320  Main *bmain = G_MAIN;
321 
322  LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
323  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
324  LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
325  ED_spacedata_id_remap(area, sl, old_id, new_id);
326  }
327  }
328  }
329 
330  wmWindowManager *wm = bmain->wm.first;
331  if (wm && wm->message_bus) {
332  struct wmMsgBus *mbus = wm->message_bus;
333  if (new_id != NULL) {
334  WM_msg_id_update(mbus, old_id, new_id);
335  }
336  else {
337  WM_msg_id_remove(mbus, old_id);
338  }
339  }
340 }
341 
342 static void wm_notifier_clear(wmNotifier *note)
343 {
344  /* NULL the entire notifier, only leaving (next, prev) members intact. */
345  memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
346 }
347 
348 void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
349 {
351  /* The whole idea of locked interface is to prevent viewport and whatever
352  * thread from modifying the same data. Because of this, we can not perform
353  * dependency graph update.
354  */
355  if (wm->is_interface_locked) {
356  return;
357  }
358  /* Combine datamasks so one window doesn't disable UV's in another T26448. */
359  CustomData_MeshMasks win_combine_v3d_datamask = {0};
360  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
361  const Scene *scene = WM_window_get_active_scene(win);
362  const bScreen *screen = WM_window_get_active_screen(win);
363 
364  ED_view3d_screen_datamask(C, scene, screen, &win_combine_v3d_datamask);
365  }
366  /* Update all the dependency graphs of visible view layers. */
367  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
369  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
370  Main *bmain = CTX_data_main(C);
371  /* Copied to set's in scene_update_tagged_recursive() */
372  scene->customdata_mask = win_combine_v3d_datamask;
373  /* XXX, hack so operators can enforce datamasks T26482, gl render */
375  /* TODO(sergey): For now all dependency graphs which are evaluated from
376  * workspace are considered active. This will work all fine with "locked"
377  * view layer and time across windows. This is to be granted separately,
378  * and for until then we have to accept ambiguities when object is shared
379  * across visible view layers and has overrides on it.
380  */
381  Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
382  if (is_after_open_file) {
385  }
388  }
389 }
390 
397 {
399  /* Cached: editor refresh callbacks now, they get context. */
400  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
401  const bScreen *screen = WM_window_get_active_screen(win);
402 
403  CTX_wm_window_set(C, win);
404  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
405  if (area->do_refresh) {
408  }
409  }
410  }
411 
412  wm_event_do_depsgraph(C, false);
413 
415 }
416 
418 {
420  if (UNLIKELY(wm == NULL)) {
421  return;
422  }
423 
424  /* Set the first window as context, so that there is some minimal context. This avoids crashes
425  * when calling code that assumes that there is always a window in the context (which many
426  * operators do). */
430 }
431 
432 /* Called in mainloop. */
434 {
435  /* Run the timer before assigning 'wm' in the unlikely case a timer loads a file, see T80028. */
437 
439  if (wm == NULL) {
440  return;
441  }
442 
443  /* Disable? - Keep for now since its used for window level notifiers. */
444 #if 1
445  /* Cache & catch WM level notifiers, such as frame change, scene/screen set. */
446  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
448  bool do_anim = false;
449  bool clear_info_stats = false;
450 
451  CTX_wm_window_set(C, win);
452 
454  if (note->category == NC_WM) {
455  if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
456  wm->file_saved = 1;
457  wm_window_title(wm, win);
458  }
459  else if (note->data == ND_DATACHANGED) {
460  wm_window_title(wm, win);
461  }
462  }
463  if (note->window == win) {
464  if (note->category == NC_SCREEN) {
465  if (note->data == ND_WORKSPACE_SET) {
466  WorkSpace *ref_ws = note->reference;
467 
468  UI_popup_handlers_remove_all(C, &win->modalhandlers);
469 
470  WM_window_set_active_workspace(C, win, ref_ws);
471  if (G.debug & G_DEBUG_EVENTS) {
472  printf("%s: Workspace set %p\n", __func__, note->reference);
473  }
474  }
475  else if (note->data == ND_WORKSPACE_DELETE) {
476  WorkSpace *workspace = note->reference;
477 
479  workspace, CTX_data_main(C), C, wm); /* XXX hrms, think this over! */
480  if (G.debug & G_DEBUG_EVENTS) {
481  printf("%s: Workspace delete %p\n", __func__, workspace);
482  }
483  }
484  else if (note->data == ND_LAYOUTBROWSE) {
485  bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
486 
487  /* free popup handlers only T35434. */
488  UI_popup_handlers_remove_all(C, &win->modalhandlers);
489 
490  ED_screen_change(C, ref_screen); /* XXX hrms, think this over! */
491  if (G.debug & G_DEBUG_EVENTS) {
492  printf("%s: screen set %p\n", __func__, note->reference);
493  }
494  }
495  else if (note->data == ND_LAYOUTDELETE) {
496  WorkSpace *workspace = WM_window_get_active_workspace(win);
497  WorkSpaceLayout *layout = note->reference;
498 
499  ED_workspace_layout_delete(workspace, layout, C); /* XXX hrms, think this over! */
500  if (G.debug & G_DEBUG_EVENTS) {
501  printf("%s: screen delete %p\n", __func__, note->reference);
502  }
503  }
504  }
505  }
506 
507  if (note->window == win ||
508  (note->window == NULL && (note->reference == NULL || note->reference == scene))) {
509  if (note->category == NC_SCENE) {
510  if (note->data == ND_FRAME) {
511  do_anim = true;
512  }
513  }
514  }
515  if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
516  clear_info_stats = true;
517  }
518  }
519 
520  if (clear_info_stats) {
521  /* Only do once since adding notifiers is slow when there are many. */
522  ViewLayer *view_layer = CTX_data_view_layer(C);
523  ED_info_stats_clear(view_layer);
525  }
526 
527  if (do_anim) {
528 
529  /* XXX, quick frame changes can cause a crash if framechange and rendering
530  * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
531  * twice which can depgraph update the same object at once */
532  if (G.is_rendering == false) {
533  /* Depsgraph gets called, might send more notifiers. */
536  }
537  }
538  }
539 
540  /* The notifiers are sent without context, to keep it clean. */
541  wmNotifier *note;
542  while ((note = BLI_pophead(&wm->notifier_queue))) {
543  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
545  bScreen *screen = WM_window_get_active_screen(win);
546  WorkSpace *workspace = WM_window_get_active_workspace(win);
547 
548  /* Filter out notifiers. */
549  if (note->category == NC_SCREEN && note->reference && note->reference != screen &&
550  note->reference != workspace && note->reference != WM_window_get_active_layout(win)) {
551  /* Pass. */
552  }
553  else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
554  /* Pass. */
555  }
556  else {
557  /* XXX context in notifiers? */
558  CTX_wm_window_set(C, win);
559 
560 # if 0
561  printf("notifier win %d screen %s cat %x\n",
562  win->winid,
563  win->screen->id.name + 2,
564  note->category);
565 # endif
566  ED_screen_do_listen(C, note);
567 
568  LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
569  wmRegionListenerParams region_params = {
570  .window = win,
571  .area = NULL,
572  .region = region,
573  .scene = scene,
574  .notifier = note,
575  };
576  ED_region_do_listen(&region_params);
577  }
578 
579  ED_screen_areas_iter (win, screen, area) {
580  if ((note->category == NC_SPACE) && note->reference) {
581  /* Filter out notifiers sent to other spaces. RNA sets the reference to the owning ID
582  * though, the screen, so let notifiers through that reference the entire screen. */
583  if (!ELEM(note->reference, area->spacedata.first, screen)) {
584  continue;
585  }
586  }
587  wmSpaceTypeListenerParams area_params = {
588  .window = win,
589  .area = area,
590  .notifier = note,
591  .scene = scene,
592  };
593  ED_area_do_listen(&area_params);
594  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
595  wmRegionListenerParams region_params = {
596  .window = win,
597  .area = area,
598  .region = region,
599  .scene = scene,
600  .notifier = note,
601  };
602  ED_region_do_listen(&region_params);
603  }
604  }
605  }
606  }
607 
608  MEM_freeN(note);
609  }
610 #endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
611 
612  /* Handle message bus. */
613  {
614  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
615  CTX_wm_window_set(C, win);
617  }
619  }
620 
622 
623  /* Status bar */
624  if (wm->winactive) {
625  wmWindow *win = wm->winactive;
626  CTX_wm_window_set(C, win);
629  }
630 
631  /* Autorun warning */
633 }
634 
635 static int wm_event_always_pass(const wmEvent *event)
636 {
637  /* Some events we always pass on, to ensure proper communication. */
638  return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
639 }
640 
643 /* -------------------------------------------------------------------- */
648  wmEventHandler_UI *handler,
649  const wmEvent *event,
650  int always_pass)
651 {
653  ARegion *region = CTX_wm_region(C);
654  ARegion *menu = CTX_wm_menu(C);
655  static bool do_wheel_ui = true;
656  const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
657 
658  /* UI code doesn't handle return values - it just always returns break.
659  * to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks. */
660  if (((handler->head.flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) && !ISMOUSE_BUTTON(event->type) &&
661  (event->val == KM_DBL_CLICK)) {
662  return WM_HANDLER_CONTINUE;
663  }
664 
665  /* UI is quite aggressive with swallowing events, like scroll-wheel. */
666  /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter. */
667  if (do_wheel_ui == false) {
668  if (is_wheel) {
669  return WM_HANDLER_CONTINUE;
670  }
671  if (wm_event_always_pass(event) == 0) {
672  do_wheel_ui = true;
673  }
674  }
675 
676  /* Don't block file-select events. Those are triggered by a separate file browser window.
677  * See T75292. */
678  if (event->type == EVT_FILESELECT) {
679  return WM_UI_HANDLER_CONTINUE;
680  }
681 
682  /* We set context to where UI handler came from. */
683  if (handler->context.area) {
684  CTX_wm_area_set(C, handler->context.area);
685  }
686  if (handler->context.region) {
687  CTX_wm_region_set(C, handler->context.region);
688  }
689  if (handler->context.menu) {
690  CTX_wm_menu_set(C, handler->context.menu);
691  }
692 
693  int retval = handler->handle_fn(C, event, handler->user_data);
694 
695  /* putting back screen context */
696  if ((retval != WM_UI_HANDLER_BREAK) || always_pass) {
698  CTX_wm_region_set(C, region);
699  CTX_wm_menu_set(C, menu);
700  }
701  else {
702  /* This special cases is for areas and regions that get removed. */
706  }
707 
708  if (retval == WM_UI_HANDLER_BREAK) {
709  return WM_HANDLER_BREAK;
710  }
711 
712  /* event not handled in UI, if wheel then we temporarily disable it */
713  if (is_wheel) {
714  do_wheel_ui = false;
715  }
716 
717  return WM_HANDLER_CONTINUE;
718 }
719 
721  wmWindow *win,
722  ARegion *region,
723  bool reactivate_button)
724 {
725  if (!region) {
726  return;
727  }
728 
729  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &region->handlers) {
730  if (handler_base->type == WM_HANDLER_TYPE_UI) {
731  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
732  BLI_assert(handler->handle_fn != NULL);
733  wmEvent event;
734  wm_event_init_from_window(win, &event);
735  event.type = EVT_BUT_CANCEL;
736  event.val = reactivate_button ? 0 : 1;
737  event.is_repeat = false;
738  handler->handle_fn(C, &event, handler->user_data);
739  }
740  }
741 }
742 
744 {
745  wmWindow *win = CTX_wm_window(C);
746  ARegion *region = CTX_wm_region(C);
747  wm_event_handler_ui_cancel_ex(C, win, region, true);
748 }
749 
752 /* -------------------------------------------------------------------- */
762 {
763  wmWindowManager *wm = G_MAIN->wm.first;
764  ReportList *wm_reports = &wm->reports;
765 
766  /* After adding reports to the global list, reset the report timer. */
767  WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
768 
769  /* Records time since last report was added */
770  wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
771 
772  ReportTimerInfo *rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
773  wm_reports->reporttimer->customdata = rti;
774 }
775 
780 {
781  wmWindowManager *wm = bmain->wm.first;
784 }
785 
786 #ifdef WITH_INPUT_NDOF
787 void WM_ndof_deadzone_set(float deadzone)
788 {
789  GHOST_setNDOFDeadZone(deadzone);
790 }
791 #endif
792 
793 static void wm_add_reports(ReportList *reports)
794 {
795  /* If the caller owns them, handle this. */
796  if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
797  wmWindowManager *wm = G_MAIN->wm.first;
798 
799  /* add reports to the global list, otherwise they are not seen */
800  BLI_movelisttolist(&wm->reports.list, &reports->list);
801 
803  }
804 }
805 
806 void WM_report(ReportType type, const char *message)
807 {
808  ReportList reports;
809  BKE_reports_init(&reports, RPT_STORE);
810  BKE_report(&reports, type, message);
811 
812  wm_add_reports(&reports);
813 
814  BKE_reports_clear(&reports);
815 }
816 
817 void WM_reportf(ReportType type, const char *format, ...)
818 {
819  va_list args;
820 
821  DynStr *ds = BLI_dynstr_new();
822  va_start(args, format);
823  BLI_dynstr_vappendf(ds, format, args);
824  va_end(args);
825 
826  char *str = BLI_dynstr_get_cstring(ds);
827  WM_report(type, str);
828  MEM_freeN(str);
829 
830  BLI_dynstr_free(ds);
831 }
832 
835 /* -------------------------------------------------------------------- */
840 {
841 
843  wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0);
844 
845  if (!WM_operator_poll(C, ot_macro)) {
846  return false;
847  }
848  }
849 
850  /* Python needs operator type, so we added exception for it. */
851  if (ot->pyop_poll) {
852  return ot->pyop_poll(C, ot);
853  }
854  if (ot->poll) {
855  return ot->poll(C);
856  }
857 
858  return true;
859 }
860 
861 /* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
863 {
864  return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
865 }
866 
868 {
869  if (ot->macro.first != NULL) {
870  /* For macros, check all have exec() we can call. */
872  wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
873  if (otm && !WM_operator_check_ui_empty(otm)) {
874  return false;
875  }
876  }
877  return true;
878  }
879 
880  /* Assume a UI callback will draw something. */
881  if (ot->ui) {
882  return false;
883  }
884 
885  PointerRNA ptr;
887  RNA_STRUCT_BEGIN (&ptr, prop) {
888  int flag = RNA_property_flag(prop);
889  if (flag & PROP_HIDDEN) {
890  continue;
891  }
892  return false;
893  }
895  return true;
896 }
897 
904 {
906  if (area) {
907  ARegion *region = CTX_wm_region(C);
908  if (region && region->regiontype == RGN_TYPE_WINDOW) {
909  area->region_active_win = BLI_findindex(&area->regionbase, region);
910  }
911  }
912 }
913 
914 /* (caller_owns_reports == true) when called from python. */
915 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
916 {
917  if (G.background == 0 && caller_owns_reports == false) { /* popup */
918  if (op->reports->list.first) {
919  /* FIXME, temp setting window, see other call to UI_popup_menu_reports for why. */
920  wmWindow *win_prev = CTX_wm_window(C);
921  ScrArea *area_prev = CTX_wm_area(C);
922  ARegion *region_prev = CTX_wm_region(C);
923 
924  if (win_prev == NULL) {
925  CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
926  }
927 
929 
930  CTX_wm_window_set(C, win_prev);
931  CTX_wm_area_set(C, area_prev);
932  CTX_wm_region_set(C, region_prev);
933  }
934  }
935 
936  if (retval & OPERATOR_FINISHED) {
938 
939  if (caller_owns_reports == false) {
940  BKE_reports_print(op->reports, RPT_DEBUG); /* Print out reports to console. */
941  }
942 
943  if (op->type->flag & OPTYPE_REGISTER) {
944  if (G.background == 0) { /* Ends up printing these in the terminal, gets annoying. */
945  /* Report the python string representation of the operator. */
946  char *buf = WM_operator_pystring(C, op, false, true);
948  MEM_freeN(buf);
949  }
950  }
951  }
952 
953  /* Refresh Info Editor with reports immediately, even if op returned OPERATOR_CANCELLED. */
954  if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
956  }
957  /* If the caller owns them, handle this. */
958  wm_add_reports(op->reports);
959 }
960 
966 {
967  /* Check undo flag here since undo operators are also added to the list,
968  * to support checking if the same operator is run twice. */
969  return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
970 }
971 
972 static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
973 {
975  enum {
976  NOP,
977  SET,
978  CLEAR,
979  } hud_status = NOP;
980 
981  op->customdata = NULL;
982 
983  if (store) {
985  }
986 
987  /* We don't want to do undo pushes for operators that are being
988  * called from operators that already do an undo push. Usually
989  * this will happen for python operators that call C operators. */
990  if (wm->op_undo_depth == 0) {
991  if (op->type->flag & OPTYPE_UNDO) {
992  ED_undo_push_op(C, op);
993  if (repeat == 0) {
994  hud_status = CLEAR;
995  }
996  }
997  else if (op->type->flag & OPTYPE_UNDO_GROUPED) {
999  if (repeat == 0) {
1000  hud_status = CLEAR;
1001  }
1002  }
1003  }
1004 
1005  if (repeat == 0) {
1006  if (G.debug & G_DEBUG_WM) {
1007  char *buf = WM_operator_pystring(C, op, false, true);
1009  MEM_freeN(buf);
1010  }
1011 
1012  if (wm_operator_register_check(wm, op->type)) {
1013  /* take ownership of reports (in case python provided own) */
1014  op->reports->flag |= RPT_FREE;
1015 
1016  wm_operator_register(C, op);
1018 
1019  if (WM_operator_last_redo(C) == op) {
1020  /* Show the redo panel. */
1021  hud_status = SET;
1022  }
1023  }
1024  else {
1025  WM_operator_free(op);
1026  }
1027  }
1028 
1029  if (hud_status != NOP) {
1030  if (hud_status == SET) {
1031  ScrArea *area = CTX_wm_area(C);
1032  if (area) {
1034  }
1035  }
1036  else if (hud_status == CLEAR) {
1038  }
1039  else {
1041  }
1042  }
1043 }
1044 
1045 /* If repeat is true, it doesn't register again, nor does it free. */
1046 static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, const bool store)
1047 {
1049  int retval = OPERATOR_CANCELLED;
1050 
1052 
1053  if (op == NULL || op->type == NULL) {
1054  return retval;
1055  }
1056 
1057  if (0 == WM_operator_poll(C, op->type)) {
1058  return retval;
1059  }
1060 
1061  if (op->type->exec) {
1062  if (op->type->flag & OPTYPE_UNDO) {
1063  wm->op_undo_depth++;
1064  }
1065 
1066  retval = op->type->exec(C, op);
1067  OPERATOR_RETVAL_CHECK(retval);
1068 
1069  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1070  wm->op_undo_depth--;
1071  }
1072  }
1073 
1074  /* XXX(mont29) Disabled the repeat check to address part 2 of T31840.
1075  * Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason
1076  * why this was needed, but worth to note it in case something turns bad. */
1077  if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */) {
1078  wm_operator_reports(C, op, retval, false);
1079  }
1080 
1081  if (retval & OPERATOR_FINISHED) {
1082  wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0);
1083  }
1084  else if (repeat == 0) {
1085  /* warning: modal from exec is bad practice, but avoid crashing. */
1086  if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
1087  WM_operator_free(op);
1088  }
1089  }
1090 
1091  return retval | OPERATOR_HANDLED;
1092 }
1093 
1094 /* Simply calls exec with basic checks. */
1096 {
1097  int retval = OPERATOR_CANCELLED;
1098 
1099  if (op == NULL || op->type == NULL || op->type->exec == NULL) {
1100  return retval;
1101  }
1102 
1103  retval = op->type->exec(C, op);
1104  OPERATOR_RETVAL_CHECK(retval);
1105 
1106  return retval;
1107 }
1108 
1116 int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
1117 {
1118  return wm_operator_exec(C, op, false, store);
1119 }
1120 
1122 {
1123  return WM_operator_call_ex(C, op, false);
1124 }
1125 
1132 {
1133  return wm_operator_exec_notest(C, op);
1134 }
1135 
1140 {
1141  const int op_flag = OP_IS_REPEAT;
1142  op->flag |= op_flag;
1143  const int ret = wm_operator_exec(C, op, true, true);
1144  op->flag &= ~op_flag;
1145  return ret;
1146 }
1148 {
1149  const int op_flag = OP_IS_REPEAT_LAST;
1150  op->flag |= op_flag;
1151  const int ret = wm_operator_exec(C, op, true, true);
1152  op->flag &= ~op_flag;
1153  return ret;
1154 }
1162 {
1163  if (op->type->exec != NULL) {
1164  return true;
1165  }
1166  if (op->opm) {
1167  /* for macros, check all have exec() we can call */
1168  LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
1169  wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
1170  if (otm && otm->exec == NULL) {
1171  return false;
1172  }
1173  }
1174  return true;
1175  }
1176 
1177  return false;
1178 }
1179 
1181 {
1182  /* May be in the operators list or not. */
1183  wmOperator *op_prev;
1184  if (op->prev == NULL && op->next == NULL) {
1186  op_prev = wm->operators.last;
1187  }
1188  else {
1189  op_prev = op->prev;
1190  }
1191  return (op_prev && (op->type == op_prev->type));
1192 }
1193 
1195  wmOperatorType *ot,
1196  PointerRNA *properties,
1197  ReportList *reports)
1198 {
1199  /* XXX operatortype names are static still. for debug */
1200  wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
1201 
1202  /* XXX adding new operator could be function, only happens here now */
1203  op->type = ot;
1205 
1206  /* Initialize properties, either copy or create. */
1207  op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
1208  if (properties && properties->data) {
1209  op->properties = IDP_CopyProperty(properties->data);
1210  }
1211  else {
1212  IDPropertyTemplate val = {0};
1213  op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1214  }
1215  RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
1216 
1217  /* Initialize error reports. */
1218  if (reports) {
1219  op->reports = reports; /* Must be initialized already. */
1220  }
1221  else {
1222  op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
1224  }
1225 
1226  /* Recursive filling of operator macro list. */
1227  if (ot->macro.first) {
1228  static wmOperator *motherop = NULL;
1229  int root = 0;
1230 
1231  /* Ensure all ops are in execution order in 1 list. */
1232  if (motherop == NULL) {
1233  motherop = op;
1234  root = 1;
1235  }
1236 
1237  /* If properties exist, it will contain everything needed. */
1238  if (properties) {
1239  wmOperatorTypeMacro *otmacro = ot->macro.first;
1240 
1241  RNA_STRUCT_BEGIN (properties, prop) {
1242 
1243  if (otmacro == NULL) {
1244  break;
1245  }
1246 
1247  /* Skip invalid properties. */
1248  if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
1249  wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
1250  PointerRNA someptr = RNA_property_pointer_get(properties, prop);
1251  wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
1252 
1254 
1255  BLI_addtail(&motherop->macro, opm);
1256  opm->opm = motherop; /* Pointer to mom, for modal(). */
1257 
1258  otmacro = otmacro->next;
1259  }
1260  }
1262  }
1263  else {
1265  wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
1266  wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL);
1267 
1268  BLI_addtail(&motherop->macro, opm);
1269  opm->opm = motherop; /* Pointer to mom, for modal(). */
1270  }
1271  }
1272 
1273  if (root) {
1274  motherop = NULL;
1275  }
1276  }
1277 
1279 
1280  return op;
1281 }
1282 
1283 static void wm_region_mouse_co(bContext *C, wmEvent *event)
1284 {
1285  ARegion *region = CTX_wm_region(C);
1286  if (region) {
1287  /* Compatibility convention. */
1288  event->mval[0] = event->x - region->winrct.xmin;
1289  event->mval[1] = event->y - region->winrct.ymin;
1290  }
1291  else {
1292  /* These values are invalid (avoid odd behavior by relying on old mval values). */
1293  event->mval[0] = -1;
1294  event->mval[1] = -1;
1295  }
1296 }
1297 
1302  wmOperatorType *ot,
1303  wmEvent *event,
1304  PointerRNA *properties,
1305  ReportList *reports,
1306  const bool poll_only,
1307  bool use_last_properties)
1308 {
1309  int retval = OPERATOR_PASS_THROUGH;
1310 
1311  /* This is done because complicated setup is done to call this function
1312  * that is better not duplicated. */
1313  if (poll_only) {
1314  return WM_operator_poll(C, ot);
1315  }
1316 
1317  if (WM_operator_poll(C, ot)) {
1319 
1320  /* If reports == NULL, they'll be initialized. */
1321  wmOperator *op = wm_operator_create(wm, ot, properties, reports);
1322 
1323  const bool is_nested_call = (wm->op_undo_depth != 0);
1324 
1325  if (event != NULL) {
1326  op->flag |= OP_IS_INVOKE;
1327  }
1328 
1329  /* Initialize setting from previous run. */
1330  if (!is_nested_call && use_last_properties) { /* Not called by py script. */
1332  }
1333 
1334  if ((event == NULL) || (event->type != MOUSEMOVE)) {
1336  2,
1337  "handle evt %d win %p op %s",
1338  event ? event->type : 0,
1339  CTX_wm_screen(C)->active_region,
1340  ot->idname);
1341  }
1342 
1343  if (op->type->invoke && event) {
1344  wm_region_mouse_co(C, event);
1345 
1346  if (op->type->flag & OPTYPE_UNDO) {
1347  wm->op_undo_depth++;
1348  }
1349 
1350  retval = op->type->invoke(C, op, event);
1351  OPERATOR_RETVAL_CHECK(retval);
1352 
1353  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1354  wm->op_undo_depth--;
1355  }
1356  }
1357  else if (op->type->exec) {
1358  if (op->type->flag & OPTYPE_UNDO) {
1359  wm->op_undo_depth++;
1360  }
1361 
1362  retval = op->type->exec(C, op);
1363  OPERATOR_RETVAL_CHECK(retval);
1364 
1365  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1366  wm->op_undo_depth--;
1367  }
1368  }
1369  else {
1370  /* Debug, important to leave a while, should never happen. */
1371  CLOG_ERROR(WM_LOG_OPERATORS, "invalid operator call '%s'", op->idname);
1372  }
1373 
1374  /* Note, if the report is given as an argument then assume the caller will deal with displaying
1375  * them currently Python only uses this. */
1376  if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
1377  /* Only show the report if the report list was not given in the function. */
1378  wm_operator_reports(C, op, retval, (reports != NULL));
1379  }
1380 
1381  if (retval & OPERATOR_HANDLED) {
1382  /* Do nothing, wm_operator_exec() has been called somewhere. */
1383  }
1384  else if (retval & OPERATOR_FINISHED) {
1385  const bool store = !is_nested_call && use_last_properties;
1386  wm_operator_finished(C, op, false, store);
1387  }
1388  else if (retval & OPERATOR_RUNNING_MODAL) {
1389  /* Take ownership of reports (in case python provided own). */
1390  op->reports->flag |= RPT_FREE;
1391 
1392  /* Grab cursor during blocking modal ops (X11)
1393  * Also check for macro.
1394  */
1395  if (ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
1396  int bounds[4] = {-1, -1, -1, -1};
1397  int wrap = WM_CURSOR_WRAP_NONE;
1398 
1399  if (event && (U.uiflag & USER_CONTINUOUS_MOUSE)) {
1400  const wmOperator *op_test = op->opm ? op->opm : op;
1401  const wmOperatorType *ot_test = op_test->type;
1402  if ((ot_test->flag & OPTYPE_GRAB_CURSOR_XY) ||
1403  (op_test->flag & OP_IS_MODAL_GRAB_CURSOR)) {
1405  }
1406  else if (ot_test->flag & OPTYPE_GRAB_CURSOR_X) {
1408  }
1409  else if (ot_test->flag & OPTYPE_GRAB_CURSOR_Y) {
1411  }
1412  }
1413 
1414  if (wrap) {
1415  const rcti *winrect = NULL;
1416  ARegion *region = CTX_wm_region(C);
1417  ScrArea *area = CTX_wm_area(C);
1418 
1419  /* Wrap only in X for header. */
1420  if (region && RGN_TYPE_IS_HEADER_ANY(region->regiontype)) {
1422  }
1423 
1424  if (region && region->regiontype == RGN_TYPE_WINDOW &&
1425  BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
1426  winrect = &region->winrct;
1427  }
1428  else if (area && BLI_rcti_isect_pt_v(&area->totrct, &event->x)) {
1429  winrect = &area->totrct;
1430  }
1431 
1432  if (winrect) {
1433  bounds[0] = winrect->xmin;
1434  bounds[1] = winrect->ymax;
1435  bounds[2] = winrect->xmax;
1436  bounds[3] = winrect->ymin;
1437  }
1438  }
1439 
1441  }
1442 
1443  /* Cancel UI handlers, typically tooltips that can hang around
1444  * while dragging the view or worse, that stay there permanently
1445  * after the modal operator has swallowed all events and passed
1446  * none to the UI handler. */
1448  }
1449  else {
1450  WM_operator_free(op);
1451  }
1452  }
1453 
1454  return retval;
1455 }
1456 
1463  wmOperatorType *ot,
1464  PointerRNA *properties,
1465  ReportList *reports,
1466  const short context,
1467  const bool poll_only,
1468  wmEvent *event)
1469 {
1470  int retval;
1471 
1473 
1474  /* Dummy test. */
1475  if (ot) {
1476  wmWindow *window = CTX_wm_window(C);
1477 
1478  if (event == NULL) {
1479  switch (context) {
1480  case WM_OP_INVOKE_DEFAULT:
1484  case WM_OP_INVOKE_AREA:
1485  case WM_OP_INVOKE_SCREEN:
1486  /* Window is needed for invoke and cancel operators. */
1487  if (window == NULL) {
1488  if (poll_only) {
1489  CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
1490  }
1491  return 0;
1492  }
1493  else {
1494  event = window->eventstate;
1495  }
1496  break;
1497  default:
1498  event = NULL;
1499  break;
1500  }
1501  }
1502  else {
1503  switch (context) {
1504  case WM_OP_EXEC_DEFAULT:
1505  case WM_OP_EXEC_REGION_WIN:
1508  case WM_OP_EXEC_AREA:
1509  case WM_OP_EXEC_SCREEN:
1510  event = NULL;
1511  default:
1512  break;
1513  }
1514  }
1515 
1516  switch (context) {
1517  case WM_OP_EXEC_REGION_WIN:
1523  /* Forces operator to go to the region window/channels/preview, for header menus,
1524  * but we stay in the same region if we are already in one.
1525  */
1526  ARegion *region = CTX_wm_region(C);
1527  ScrArea *area = CTX_wm_area(C);
1528  int type = RGN_TYPE_WINDOW;
1529 
1530  switch (context) {
1534  break;
1535 
1539  break;
1540 
1541  case WM_OP_EXEC_REGION_WIN:
1543  default:
1545  break;
1546  }
1547 
1548  if (!(region && region->regiontype == type) && area) {
1549  ARegion *region_other = (type == RGN_TYPE_WINDOW) ?
1552  if (region_other) {
1553  CTX_wm_region_set(C, region_other);
1554  }
1555  }
1556 
1557  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1558 
1559  /* Set region back. */
1560  CTX_wm_region_set(C, region);
1561 
1562  return retval;
1563  }
1564  case WM_OP_EXEC_AREA:
1565  case WM_OP_INVOKE_AREA: {
1566  /* Remove region from context. */
1567  ARegion *region = CTX_wm_region(C);
1568 
1570  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1571  CTX_wm_region_set(C, region);
1572 
1573  return retval;
1574  }
1575  case WM_OP_EXEC_SCREEN:
1576  case WM_OP_INVOKE_SCREEN: {
1577  /* Remove region + area from context. */
1578  ARegion *region = CTX_wm_region(C);
1579  ScrArea *area = CTX_wm_area(C);
1580 
1583  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1585  CTX_wm_region_set(C, region);
1586 
1587  return retval;
1588  }
1589  case WM_OP_EXEC_DEFAULT:
1590  case WM_OP_INVOKE_DEFAULT:
1591  return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1592  }
1593  }
1594 
1595  return 0;
1596 }
1597 
1598 /* Invokes operator in context. */
1600  wmOperatorType *ot,
1601  short context,
1602  PointerRNA *properties)
1603 {
1605  return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL);
1606 }
1607 int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
1608 {
1609  wmOperatorType *ot = WM_operatortype_find(opstring, 0);
1610  if (ot) {
1611  return WM_operator_name_call_ptr(C, ot, context, properties);
1612  }
1613 
1614  return 0;
1615 }
1616 
1618  const char *opstring,
1619  short context,
1620  struct IDProperty *properties)
1621 {
1622  PointerRNA props_ptr;
1623  wmOperatorType *ot = WM_operatortype_find(opstring, false);
1624  RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr);
1625  return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
1626 }
1627 
1631 void WM_menu_name_call(bContext *C, const char *menu_name, short context)
1632 {
1633  wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
1634  PointerRNA ptr;
1636  RNA_string_set(&ptr, "name", menu_name);
1639 }
1640 
1649  wmOperatorType *ot,
1650  short context,
1651  PointerRNA *properties,
1652  ReportList *reports,
1653  const bool is_undo)
1654 {
1655  int retval = OPERATOR_CANCELLED;
1656  /* Not especially nice using undo depth here. It's used so Python never
1657  * triggers undo or stores an operator's last used state. */
1659  if (!is_undo && wm) {
1660  wm->op_undo_depth++;
1661  }
1662 
1663  retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL);
1664 
1665  if (!is_undo && wm && (wm == CTX_wm_manager(C))) {
1666  wm->op_undo_depth--;
1667  }
1668 
1669  return retval;
1670 }
1671 
1674 /* -------------------------------------------------------------------- */
1680 /* Future extra customadata free? */
1682 {
1683  MEM_freeN(handler);
1684 }
1685 
1686 /* Only set context when area/region is part of screen. */
1687 static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
1688 {
1689  wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
1690  /* It's probably fine to always use WM_window_get_active_screen() to get the screen. But this
1691  * code has been getting it through context since forever, so play safe and stick to that when
1692  * possible. */
1693  bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
1694 
1695  if (screen == NULL || handler->op == NULL) {
1696  return;
1697  }
1698 
1699  if (handler->context.area == NULL) {
1701  }
1702  else {
1703  ScrArea *area = NULL;
1704 
1705  ED_screen_areas_iter (win, screen, area_iter) {
1706  if (area_iter == handler->context.area) {
1707  area = area_iter;
1708  break;
1709  }
1710  }
1711 
1712  if (area == NULL) {
1713  /* When changing screen layouts with running modal handlers (like render display), this
1714  * is not an error to print. */
1715  if (handler->op == NULL) {
1717  "internal error: handler (%s) has invalid area",
1718  handler->op->type->idname);
1719  }
1720  }
1721  else {
1722  ARegion *region;
1723  wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
1725 
1726  if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
1727  region = BKE_area_find_region_xy(area, handler->context.region_type, event->x, event->y);
1728  if (region) {
1729  handler->context.region = region;
1730  }
1731  }
1732  else {
1733  region = NULL;
1734  }
1735 
1736  if (region == NULL) {
1737  LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
1738  region = region_iter;
1739  if (region == handler->context.region) {
1740  break;
1741  }
1742  }
1743  }
1744 
1745  /* XXX no warning print here, after full-area and back regions are remade. */
1746  if (region) {
1747  CTX_wm_region_set(C, region);
1748  }
1749  }
1750  }
1751 }
1752 
1753 /* Called on exit or remove area, only here call cancel callback. */
1755 {
1757 
1758  /* C is zero on freeing database, modal handlers then already were freed */
1759  wmEventHandler *handler_base;
1760  while ((handler_base = BLI_pophead(handlers))) {
1761  BLI_assert(handler_base->type != 0);
1762  if (handler_base->type == WM_HANDLER_TYPE_OP) {
1763  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
1764 
1765  if (handler->op) {
1766  wmWindow *win = CTX_wm_window(C);
1767 
1768  if (handler->is_fileselect) {
1769  /* Exit File Browsers referring to this handler/operator. */
1770  LISTBASE_FOREACH (wmWindow *, temp_win, &wm->windows) {
1771  ScrArea *file_area = ED_fileselect_handler_area_find(temp_win, handler->op);
1772  if (!file_area) {
1773  continue;
1774  }
1775  ED_area_exit(C, file_area);
1776  }
1777  }
1778 
1779  if (handler->op->type->cancel) {
1780  ScrArea *area = CTX_wm_area(C);
1781  ARegion *region = CTX_wm_region(C);
1782 
1783  wm_handler_op_context(C, handler, win->eventstate);
1784 
1785  if (handler->op->type->flag & OPTYPE_UNDO) {
1786  wm->op_undo_depth++;
1787  }
1788 
1789  handler->op->type->cancel(C, handler->op);
1790 
1791  if (handler->op->type->flag & OPTYPE_UNDO) {
1792  wm->op_undo_depth--;
1793  }
1794 
1796  CTX_wm_region_set(C, region);
1797  }
1798 
1800  WM_operator_free(handler->op);
1801  }
1802  }
1803  else if (handler_base->type == WM_HANDLER_TYPE_UI) {
1804  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
1805 
1806  if (handler->remove_fn) {
1807  ScrArea *area = CTX_wm_area(C);
1808  ARegion *region = CTX_wm_region(C);
1809  ARegion *menu = CTX_wm_menu(C);
1810 
1811  if (handler->context.area) {
1812  CTX_wm_area_set(C, handler->context.area);
1813  }
1814  if (handler->context.region) {
1815  CTX_wm_region_set(C, handler->context.region);
1816  }
1817  if (handler->context.menu) {
1818  CTX_wm_menu_set(C, handler->context.menu);
1819  }
1820 
1821  handler->remove_fn(C, handler->user_data);
1822 
1824  CTX_wm_region_set(C, region);
1825  CTX_wm_menu_set(C, menu);
1826  }
1827  }
1828 
1829  wm_event_free_handler(handler_base);
1830  }
1831 }
1832 
1833 static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
1834 {
1835  if (kmi->flag & KMI_INACTIVE) {
1836  return false;
1837  }
1838 
1839  if (winevent->is_repeat) {
1840  if (kmi->flag & KMI_REPEAT_IGNORE) {
1841  return false;
1842  }
1843  }
1844 
1845  const int kmitype = WM_userdef_event_map(kmi->type);
1846 
1847  /* The matching rules. */
1848  if (kmitype == KM_TEXTINPUT) {
1849  if (winevent->val == KM_PRESS) { /* Prevent double clicks. */
1850  /* NOT using ISTEXTINPUT anymore because (at least on Windows) some key codes above 255
1851  * could have printable ascii keys - BUG T30479. */
1852  if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) {
1853  return true;
1854  }
1855  }
1856  }
1857 
1858  if (kmitype != KM_ANY) {
1859  if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
1860  const wmTabletData *wmtab = &winevent->tablet;
1861 
1862  if (winevent->type != LEFTMOUSE) {
1863  /* Tablet events can occur on hover + keypress. */
1864  return false;
1865  }
1866  if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) {
1867  return false;
1868  }
1869  if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) {
1870  return false;
1871  }
1872  }
1873  else {
1874  if (winevent->type != kmitype) {
1875  return false;
1876  }
1877  }
1878  }
1879 
1880  if (kmi->val != KM_ANY) {
1881  if (winevent->val != kmi->val) {
1882  return false;
1883  }
1884  }
1885 
1886  /* Modifiers also check bits, so it allows modifier order.
1887  * Account for rare case of when these keys are used as the 'type' not as modifiers. */
1888  if (kmi->shift != KM_ANY) {
1889  if ((winevent->shift != kmi->shift) && !(winevent->shift & kmi->shift) &&
1890  !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
1891  return false;
1892  }
1893  }
1894  if (kmi->ctrl != KM_ANY) {
1895  if (winevent->ctrl != kmi->ctrl && !(winevent->ctrl & kmi->ctrl) &&
1896  !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
1897  return false;
1898  }
1899  }
1900  if (kmi->alt != KM_ANY) {
1901  if (winevent->alt != kmi->alt && !(winevent->alt & kmi->alt) &&
1902  !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
1903  return false;
1904  }
1905  }
1906  if (kmi->oskey != KM_ANY) {
1907  if (winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey) &&
1908  (winevent->type != EVT_OSKEY)) {
1909  return false;
1910  }
1911  }
1912 
1913  /* Only keymap entry with keymodifier is checked,
1914  * means all keys without modifier get handled too. */
1915  /* That is currently needed to make overlapping events work (when you press A - G fast or so). */
1916  if (kmi->keymodifier) {
1917  if (winevent->keymodifier != kmi->keymodifier) {
1918  return false;
1919  }
1920  }
1921 
1922  return true;
1923 }
1924 
1926  wmOperator *op,
1927  const wmEvent *event)
1928 {
1929  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
1930  /* Should already be handled by #wm_user_modal_keymap_set_items. */
1931  BLI_assert(kmi->propvalue_str[0] == '\0');
1932  if (wm_eventmatch(event, kmi)) {
1933  if ((keymap->poll_modal_item == NULL) || (keymap->poll_modal_item(op, kmi->propvalue))) {
1934  return kmi;
1935  }
1936  }
1937  }
1938  return NULL;
1939 }
1940 
1942  short prevtype;
1943  short prevval;
1944 
1946 };
1947 
1959  wmOperator *op,
1960  wmEvent *event,
1961  struct wmEvent_ModalMapStore *event_backup)
1962 {
1963  BLI_assert(event->type != EVT_MODAL_MAP);
1964 
1965  /* Support for modal keymap in macros. */
1966  if (op->opm) {
1967  op = op->opm;
1968  }
1969 
1970  event_backup->dbl_click_disabled = false;
1971 
1972  if (op->type->modalkeymap) {
1974  wmKeyMapItem *kmi = NULL;
1975 
1976  const wmEvent *event_match = NULL;
1977  wmEvent event_no_dbl_click;
1978 
1979  if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) {
1980  event_match = event;
1981  }
1982  else if (event->val == KM_DBL_CLICK) {
1983  event_no_dbl_click = *event;
1984  event_no_dbl_click.val = KM_PRESS;
1985  if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, &event_no_dbl_click))) {
1986  event_match = &event_no_dbl_click;
1987  }
1988  }
1989 
1990  if (event_match != NULL) {
1991  event_backup->prevtype = event->prevtype;
1992  event_backup->prevval = event->prevval;
1993 
1994  event->prevtype = event_match->type;
1995  event->prevval = event_match->val;
1996  event->type = EVT_MODAL_MAP;
1997  event->val = kmi->propvalue;
1998 
1999  /* Avoid double-click events even in the case of 'EVT_MODAL_MAP',
2000  * since it's possible users configure double-click keymap items
2001  * which would break when modal functions expect press/release. */
2002  if (event->prevtype == KM_DBL_CLICK) {
2003  event->prevtype = KM_PRESS;
2004  event_backup->dbl_click_disabled = true;
2005  }
2006  }
2007  }
2008 
2009  if (event->type != EVT_MODAL_MAP) {
2010  /* This bypass just disables support for double-click in modal handlers. */
2011  if (event->val == KM_DBL_CLICK) {
2012  event->val = KM_PRESS;
2013  event_backup->dbl_click_disabled = true;
2014  }
2015  }
2016 }
2017 
2026  const struct wmEvent_ModalMapStore *event_backup)
2027 {
2028  if (event->type == EVT_MODAL_MAP) {
2029  event->type = event->prevtype;
2030  event->val = event->prevval;
2031 
2032  event->prevtype = event_backup->prevtype;
2033  event->prevval = event_backup->prevval;
2034  }
2035 
2036  if (event_backup->dbl_click_disabled) {
2037  event->val = KM_DBL_CLICK;
2038  }
2039 }
2040 
2041 /* Warning: this function removes a modal handler, when finished */
2043  ListBase *handlers,
2044  wmEventHandler *handler_base,
2045  wmEvent *event,
2046  PointerRNA *properties,
2047  const char *kmi_idname)
2048 {
2049  int retval = OPERATOR_PASS_THROUGH;
2050 
2051  /* Derived, modal or blocking operator. */
2052  if ((handler_base->type == WM_HANDLER_TYPE_OP) &&
2053  (((wmEventHandler_Op *)handler_base)->op != NULL)) {
2054  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
2055  wmOperator *op = handler->op;
2056  wmOperatorType *ot = op->type;
2057 
2059  /* Interface is locked and operator is not allowed to run,
2060  * nothing to do in this case.
2061  */
2062  }
2063  else if (ot->modal) {
2064  /* We set context to where modal handler came from. */
2066  wmWindow *win = CTX_wm_window(C);
2067  ScrArea *area = CTX_wm_area(C);
2068  ARegion *region = CTX_wm_region(C);
2069 
2070  wm_handler_op_context(C, handler, event);
2071  wm_region_mouse_co(C, event);
2072 
2073  struct wmEvent_ModalMapStore event_backup;
2074  wm_event_modalkeymap_begin(C, op, event, &event_backup);
2075 
2076  if (ot->flag & OPTYPE_UNDO) {
2077  wm->op_undo_depth++;
2078  }
2079 
2080  /* Warning, after this call all context data and 'event' may be freed. see check below. */
2081  retval = ot->modal(C, op, event);
2082  OPERATOR_RETVAL_CHECK(retval);
2083 
2084  if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
2085  wm->op_undo_depth--;
2086  }
2087 
2088  /* When the window changes the the modal modifier may have loaded a new blend file
2089  * (the `system_demo_mode` add-on does this), so we have to assume the event,
2090  * operator, area, region etc have all been freed. */
2091  if ((CTX_wm_window(C) == win)) {
2092 
2093  wm_event_modalkeymap_end(event, &event_backup);
2094 
2095  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2096  wm_operator_reports(C, op, retval, false);
2097 
2098  if (op->type->modalkeymap) {
2100  }
2101  }
2102  else {
2103  /* Not very common, but modal operators may report before finishing. */
2104  if (!BLI_listbase_is_empty(&op->reports->list)) {
2105  wm_add_reports(op->reports);
2106  }
2107  }
2108 
2109  /* Important to run 'wm_operator_finished' before NULLing the context members. */
2110  if (retval & OPERATOR_FINISHED) {
2111  wm_operator_finished(C, op, false, true);
2112  handler->op = NULL;
2113  }
2114  else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2115  WM_operator_free(op);
2116  handler->op = NULL;
2117  }
2118 
2119  /* Putting back screen context, reval can pass through after modal failures! */
2120  if ((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
2122  CTX_wm_region_set(C, region);
2123  }
2124  else {
2125  /* This special cases is for areas and regions that get removed. */
2128  }
2129 
2130  /* /update gizmos during modal handlers. */
2131  wm_gizmomaps_handled_modal_update(C, event, handler);
2132 
2133  /* Remove modal handler, operator itself should have been canceled and freed. */
2134  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2136 
2137  BLI_remlink(handlers, handler);
2138  wm_event_free_handler(&handler->head);
2139 
2140  /* prevent silly errors from operator users */
2141  // retval &= ~OPERATOR_PASS_THROUGH;
2142  }
2143  }
2144  }
2145  else {
2146  CLOG_ERROR(WM_LOG_HANDLERS, "missing modal '%s'", op->idname);
2147  }
2148  }
2149  else {
2150  wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
2151 
2153  bool use_last_properties = true;
2154  PointerRNA tool_properties = {0};
2155 
2156  bToolRef *keymap_tool = NULL;
2157  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
2158  keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
2159  }
2160  else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
2161  wmGizmoMap *gizmo_map = ((wmEventHandler_Gizmo *)handler_base)->gizmo_map;
2162  wmGizmo *gz = wm_gizmomap_highlight_get(gizmo_map);
2163  if (gz && (gz->flag & WM_GIZMO_OPERATOR_TOOL_INIT)) {
2164  keymap_tool = WM_toolsystem_ref_from_context(C);
2165  }
2166  }
2167 
2168  const bool is_tool = (keymap_tool != NULL);
2169  const bool use_tool_properties = is_tool;
2170 
2171  if (use_tool_properties) {
2173  keymap_tool, &tool_properties, properties, ot);
2174  properties = &tool_properties;
2175  use_last_properties = false;
2176  }
2177 
2178  retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
2179 
2180  if (use_tool_properties) {
2181  WM_operator_properties_free(&tool_properties);
2182  }
2183 
2184  /* Link gizmo if 'WM_GIZMOGROUPTYPE_TOOL_INIT' is set. */
2185  if (retval & OPERATOR_FINISHED) {
2186  if (is_tool) {
2187  bToolRef_Runtime *tref_rt = keymap_tool->runtime;
2188  if (tref_rt->gizmo_group[0]) {
2189  const char *idname = tref_rt->gizmo_group;
2190  wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
2191  if (gzgt != NULL) {
2192  if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
2193  ARegion *region = CTX_wm_region(C);
2194  if (region != NULL) {
2195  wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
2196  WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
2198  gzmap_type, gzgt, region);
2199  /* We can't rely on drawing to initialize gizmo's since disabling
2200  * overlays/gizmos will prevent pre-drawing setup calls. (see T60905) */
2201  WM_gizmogroup_ensure_init(C, gzgroup);
2202  }
2203  }
2204  }
2205  }
2206  }
2207  }
2208  /* Done linking gizmo. */
2209  }
2210  }
2211  /* Finished and pass through flag as handled. */
2212 
2213  /* Finished and pass through flag as handled. */
2214  if (retval == (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH)) {
2215  return WM_HANDLER_HANDLED;
2216  }
2217 
2218  /* Modal unhandled, break. */
2219  if (retval == (OPERATOR_PASS_THROUGH | OPERATOR_RUNNING_MODAL)) {
2221  }
2222 
2223  if (retval & OPERATOR_PASS_THROUGH) {
2224  return WM_HANDLER_CONTINUE;
2225  }
2226 
2227  return WM_HANDLER_BREAK;
2228 }
2229 
2230 /* Fileselect handlers are only in the window queue,
2231  * so it's safe to switch screens or area types. */
2233  ListBase *handlers,
2234  wmEventHandler_Op *handler,
2235  int val)
2236 {
2238  int action = WM_HANDLER_CONTINUE;
2239 
2240  switch (val) {
2241  case EVT_FILESELECT_FULL_OPEN: {
2242  wmWindow *win = CTX_wm_window(C);
2243  ScrArea *area;
2244 
2246  IFACE_("Blender File View"),
2247  WM_window_pixels_x(win) / 2,
2248  WM_window_pixels_y(win) / 2,
2249  U.file_space_data.temp_win_sizex * UI_DPI_FAC,
2250  U.file_space_data.temp_win_sizey * UI_DPI_FAC,
2251  SPACE_FILE,
2252  U.filebrowser_display_type,
2253  true))) {
2255 
2256  BLI_assert(area->spacetype == SPACE_FILE);
2257 
2258  region_header->flag |= RGN_FLAG_HIDDEN;
2259  /* Header on bottom, AZone triangle to toggle header looks misplaced at the top. */
2260  region_header->alignment = RGN_ALIGN_BOTTOM;
2261 
2262  /* Settings for filebrowser, #sfile is not operator owner but sends events. */
2263  SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
2264  sfile->op = handler->op;
2265 
2267  }
2268  else {
2269  BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
2270  return OPERATOR_CANCELLED;
2271  }
2272 
2273  action = WM_HANDLER_BREAK;
2274  break;
2275  }
2276 
2277  case EVT_FILESELECT_EXEC:
2278  case EVT_FILESELECT_CANCEL:
2280  wmWindow *ctx_win = CTX_wm_window(C);
2281 
2282  /* Remove link now, for load file case before removing. */
2283  BLI_remlink(handlers, handler);
2284 
2285  if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
2286  /* The window might have been freed already. */
2287  if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
2288  handler->context.win = NULL;
2289  }
2290  }
2291  else {
2292  ScrArea *ctx_area = CTX_wm_area(C);
2293 
2294  wmWindow *temp_win = NULL;
2295  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2296  bScreen *screen = WM_window_get_active_screen(win);
2297  ScrArea *file_area = screen->areabase.first;
2298 
2299  if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
2300  continue;
2301  }
2302 
2303  if (file_area->full) {
2304  /* Users should not be able to maximize/fullscreen an area in a temporary screen. So if
2305  * there's a maximized file browser in a temporary screen, it was likely opened by
2306  * #EVT_FILESELECT_FULL_OPEN. */
2307  continue;
2308  }
2309 
2310  int win_size[2];
2311  bool is_maximized;
2312  ED_fileselect_window_params_get(win, win_size, &is_maximized);
2313  ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
2314 
2315  if (BLI_listbase_is_single(&file_area->spacedata)) {
2316  BLI_assert(ctx_win != win);
2317 
2318  wm_window_close(C, wm, win);
2319 
2320  CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */
2321  /* Some operators expect a drawable context (for EVT_FILESELECT_EXEC). */
2322  wm_window_make_drawable(wm, ctx_win);
2323  /* Ensure correct cursor position, otherwise, popups may close immediately after
2324  * opening (UI_BLOCK_MOVEMOUSE_QUIT). */
2325  wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
2326  wm->winactive = ctx_win; /* Reports use this... */
2327  if (handler->context.win == win) {
2328  handler->context.win = NULL;
2329  }
2330  }
2331  else if (file_area->full) {
2332  ED_screen_full_prevspace(C, file_area);
2333  }
2334  else {
2335  ED_area_prevspace(C, file_area);
2336  }
2337 
2338  temp_win = win;
2339  break;
2340  }
2341 
2342  if (!temp_win && ctx_area->full) {
2344  ED_screen_full_prevspace(C, ctx_area);
2345  }
2346  }
2347 
2348  wm_handler_op_context(C, handler, ctx_win->eventstate);
2349  ScrArea *handler_area = CTX_wm_area(C);
2350  /* Make sure new context area is ready, the operator callback may operate on it. */
2351  if (handler_area) {
2352  ED_area_do_refresh(C, handler_area);
2353  }
2354 
2355  /* Needed for #UI_popup_menu_reports. */
2356 
2357  if (val == EVT_FILESELECT_EXEC) {
2358  int retval;
2359 
2360  if (handler->op->type->flag & OPTYPE_UNDO) {
2361  wm->op_undo_depth++;
2362  }
2363 
2364  retval = handler->op->type->exec(C, handler->op);
2365 
2366  /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
2367  if (handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
2368  wm->op_undo_depth--;
2369  }
2370 
2371  /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
2372  if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
2373  if (handler->op->type->flag & OPTYPE_UNDO) {
2374  ED_undo_push_op(C, handler->op);
2375  }
2376  else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED) {
2377  ED_undo_grouped_push_op(C, handler->op);
2378  }
2379  }
2380 
2381  if (handler->op->reports->list.first) {
2382 
2383  /* FIXME, temp setting window, this is really bad!
2384  * only have because lib linking errors need to be seen by users :(
2385  * it can be removed without breaking anything but then no linking errors - campbell */
2386  wmWindow *win_prev = CTX_wm_window(C);
2387  ScrArea *area_prev = CTX_wm_area(C);
2388  ARegion *region_prev = CTX_wm_region(C);
2389 
2390  if (win_prev == NULL) {
2391  CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
2392  }
2393 
2395  UI_popup_menu_reports(C, handler->op->reports);
2396 
2397  /* XXX - copied from 'wm_operator_finished()' */
2398  /* add reports to the global list, otherwise they are not seen */
2399  BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
2400 
2401  /* More hacks, since we meddle with reports, banner display doesn't happen automaticM */
2403 
2404  CTX_wm_window_set(C, win_prev);
2405  CTX_wm_area_set(C, area_prev);
2406  CTX_wm_region_set(C, region_prev);
2407  }
2408 
2409  /* For WM_operator_pystring only, custom report handling is done above. */
2410  wm_operator_reports(C, handler->op, retval, true);
2411 
2412  if (retval & OPERATOR_FINISHED) {
2414  }
2415 
2416  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2417  WM_operator_free(handler->op);
2418  }
2419  }
2420  else {
2421  if (handler->op->type->cancel) {
2422  if (handler->op->type->flag & OPTYPE_UNDO) {
2423  wm->op_undo_depth++;
2424  }
2425 
2426  handler->op->type->cancel(C, handler->op);
2427 
2428  if (handler->op->type->flag & OPTYPE_UNDO) {
2429  wm->op_undo_depth--;
2430  }
2431  }
2432 
2433  WM_operator_free(handler->op);
2434  }
2435 
2437 
2438  wm_event_free_handler(&handler->head);
2439 
2440  action = WM_HANDLER_BREAK;
2441  break;
2442  }
2443  }
2444 
2445  return action;
2446 }
2447 
2449  ListBase *handlers,
2450  wmEventHandler_Op *handler,
2451  const wmEvent *event)
2452 {
2453  int action = WM_HANDLER_CONTINUE;
2454 
2455  if (event->type != EVT_FILESELECT) {
2456  return action;
2457  }
2458  if (handler->op != (wmOperator *)event->customdata) {
2459  return action;
2460  }
2461 
2462  return wm_handler_fileselect_do(C, handlers, handler, event->val);
2463 }
2464 
2465 static int wm_action_not_handled(int action)
2466 {
2467  return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
2468 }
2469 
2470 #define PRINT \
2471  if (do_debug_handler) \
2472  printf
2473 
2475  /* From 'wm_handlers_do_intern'. */
2476  bContext *C,
2477  wmEvent *event,
2478  ListBase *handlers,
2479  wmEventHandler_Keymap *handler,
2480  /* Additional. */
2481  wmKeyMap *keymap,
2482  const bool do_debug_handler)
2483 {
2484  int action = WM_HANDLER_CONTINUE;
2485 
2486  if (keymap == NULL) {
2487  /* Only callback is allowed to have NULL keymaps. */
2488  BLI_assert(handler->dynamic.keymap_fn);
2489  }
2490  else {
2491  PRINT("%s: checking '%s' ...", __func__, keymap->idname);
2492 
2493  if (WM_keymap_poll(C, keymap)) {
2494 
2495  PRINT("pass\n");
2496 
2497  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2498  if (wm_eventmatch(event, kmi)) {
2499  struct wmEventHandler_KeymapPost keymap_post = handler->post;
2500 
2501  PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
2502 
2503  action |= wm_handler_operator_call(
2504  C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
2505 
2506  if (action & WM_HANDLER_BREAK) {
2507  /* Not always_pass here, it denotes removed handler_base. */
2508  CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
2509  if (keymap_post.post_fn != NULL) {
2510  keymap_post.post_fn(keymap, kmi, keymap_post.user_data);
2511  }
2512  break;
2513  }
2514  if (action & WM_HANDLER_HANDLED) {
2515  CLOG_INFO(WM_LOG_HANDLERS, 2, "handled - and pass on! '%s'", kmi->idname);
2516  }
2517  else {
2518  CLOG_INFO(WM_LOG_HANDLERS, 2, "un-handled '%s'", kmi->idname);
2519  }
2520  }
2521  }
2522  }
2523  else {
2524  PRINT("fail\n");
2525  }
2526  }
2527 
2528  return action;
2529 }
2530 
2532  /* From 'wm_handlers_do_intern' */
2533  bContext *C,
2534  wmEvent *event,
2535  ListBase *handlers,
2536  wmEventHandler_Gizmo *handler,
2537  /* Additional. */
2538  wmGizmoGroup *gzgroup,
2539  wmKeyMap *keymap,
2540  const bool do_debug_handler,
2541  bool *r_keymap_poll)
2542 {
2543  int action = WM_HANDLER_CONTINUE;
2544  bool keymap_poll = false;
2545 
2546  PRINT("%s: checking '%s' ...", __func__, keymap->idname);
2547 
2548  if (WM_keymap_poll(C, keymap)) {
2549  keymap_poll = true;
2550  PRINT("pass\n");
2551  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2552  if (wm_eventmatch(event, kmi)) {
2553  PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
2554 
2555  CTX_wm_gizmo_group_set(C, gzgroup);
2556 
2557  /* handler->op is called later, we want keymap op to be triggered here. */
2558  action |= wm_handler_operator_call(
2559  C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
2560 
2562 
2563  if (action & WM_HANDLER_BREAK) {
2564  if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2565  printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
2566  }
2567  break;
2568  }
2569  if (action & WM_HANDLER_HANDLED) {
2570  if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2571  printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
2572  }
2573  }
2574  else {
2575  PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
2576  }
2577  }
2578  }
2579  }
2580  else {
2581  PRINT("fail\n");
2582  }
2583 
2584  if (r_keymap_poll) {
2585  *r_keymap_poll = keymap_poll;
2586  }
2587 
2588  return action;
2589 }
2590 
2592  wmWindowManager *wm,
2593  wmEventHandler_Gizmo *handler,
2594  wmEvent *event,
2595  ListBase *handlers,
2596  const bool do_debug_handler)
2597 {
2598  /* Drag events use the previous click location to highlight the gizmos,
2599  * Get the highlight again in case the user dragged off the gizmo. */
2600  const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG);
2601  const bool is_event_modifier = ISKEYMODIFIER(event->type);
2602  /* Only keep the highlight if the gizmo becomes modal as result of event handling.
2603  * Without this check, even un-handled drag events will set the highlight if the drag
2604  * was initiated over a gizmo. */
2605  const bool restore_highlight_unless_activated = is_event_drag;
2606 
2607  int action = WM_HANDLER_CONTINUE;
2608  ScrArea *area = CTX_wm_area(C);
2609  ARegion *region = CTX_wm_region(C);
2610  wmGizmoMap *gzmap = handler->gizmo_map;
2611  BLI_assert(gzmap != NULL);
2612  wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
2613 
2614  /* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
2615  * noticeable for the node editor - where dragging on a node should move it, see: T73212.
2616  * note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */
2617  if (region->type->clip_gizmo_events_by_ui) {
2618  if (UI_region_block_find_mouse_over(region, &event->x, true)) {
2619  if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
2620  if (restore_highlight_unless_activated == false) {
2622  wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
2623  }
2624  }
2625  return action;
2626  }
2627  }
2628 
2629  struct {
2630  wmGizmo *gz_modal;
2631  wmGizmo *gz;
2632  int part;
2633  } prev = {
2634  .gz_modal = wm_gizmomap_modal_get(gzmap),
2635  .gz = gz,
2636  .part = gz ? gz->highlight_part : 0,
2637  };
2638 
2639  if (region->gizmo_map != handler->gizmo_map) {
2641  }
2642 
2644  wm_region_mouse_co(C, event);
2645 
2646  bool handle_highlight = false;
2647  bool handle_keymap = false;
2648 
2649  /* Handle gizmo highlighting. */
2650  if ((prev.gz_modal == NULL) &&
2651  ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
2652  handle_highlight = true;
2653  if (is_event_modifier || is_event_drag) {
2654  handle_keymap = true;
2655  }
2656  }
2657  else {
2658  handle_keymap = true;
2659  }
2660 
2661  /* There is no need to handle this event when the key-map isn't being applied
2662  * since any change to the highlight will be restored to the previous value. */
2663  if (restore_highlight_unless_activated) {
2664  if ((handle_highlight == true) && (handle_keymap == false)) {
2665  return action;
2666  }
2667  }
2668 
2669  if (handle_highlight) {
2670  int part = -1;
2671  gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
2672 
2673  /* If no gizmos are/were active, don't clear tool-tips. */
2674  if (gz || prev.gz) {
2675  if ((prev.gz != gz) || (prev.part != part)) {
2677  }
2678  }
2679 
2680  if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
2681  if (gz != NULL) {
2682  if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
2684  }
2685  }
2686  }
2687  }
2688 
2689  /* Don't use from now on. */
2690  bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL);
2691 
2692  if (handle_keymap) {
2693  /* Handle highlight gizmo. */
2694  if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
2695  bool keymap_poll = false;
2696  wmGizmoGroup *gzgroup = gz->parent_gzgroup;
2697  wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
2699  C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll);
2700 
2701 #ifdef USE_GIZMO_MOUSE_PRIORITY_HACK
2702  if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) {
2703  if ((event->val == KM_PRESS) && ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
2704 
2705  wmEvent event_test_click = *event;
2706  event_test_click.val = KM_CLICK;
2707 
2708  wmEvent event_test_click_drag = *event;
2709  event_test_click_drag.val = KM_CLICK_DRAG;
2710 
2711  wmEvent event_test_tweak = *event;
2712  event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE);
2713  event_test_tweak.val = KM_ANY;
2714 
2715  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2716  if ((kmi->flag & KMI_INACTIVE) == 0) {
2717  if (wm_eventmatch(&event_test_click, kmi) ||
2718  wm_eventmatch(&event_test_click_drag, kmi) ||
2719  wm_eventmatch(&event_test_tweak, kmi)) {
2720  wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
2722  is_event_handle_all = true;
2723  break;
2724  }
2725  }
2726  }
2727  }
2728  }
2729  }
2730 #endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */
2731  }
2732 
2733  /* Don't use from now on. */
2734  gz = NULL;
2735 
2736  /* Fallback to selected gizmo (when un-handled). */
2737  if ((action & WM_HANDLER_BREAK) == 0) {
2738  if (WM_gizmomap_is_any_selected(gzmap)) {
2739  const ListBase *groups = WM_gizmomap_group_list(gzmap);
2740  LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) {
2741  if (wm_gizmogroup_is_any_selected(gzgroup)) {
2742  wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
2744  C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
2745  if (action & WM_HANDLER_BREAK) {
2746  break;
2747  }
2748  }
2749  }
2750  }
2751  }
2752  }
2753 
2754  if (handle_highlight) {
2755  if (restore_highlight_unless_activated) {
2756  /* Check handling the key-map didn't activate a gizmo. */
2757  wmGizmo *gz_modal = wm_gizmomap_modal_get(gzmap);
2758  if (!(gz_modal && (gz_modal != prev.gz_modal))) {
2759  wm_gizmomap_highlight_set(gzmap, C, prev.gz, prev.part);
2760  }
2761  }
2762  }
2763 
2764  if (is_event_handle_all) {
2765  if (action == WM_HANDLER_CONTINUE) {
2766  action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL;
2767  }
2768  }
2769 
2770  /* restore the area */
2772  CTX_wm_region_set(C, region);
2773 
2774  return action;
2775 }
2776 
2779 /* -------------------------------------------------------------------- */
2783 static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
2784 {
2785  const bool do_debug_handler =
2786  (G.debug & G_DEBUG_HANDLERS) &&
2787  /* Comment this out to flood the console! (if you really want to test). */
2789 
2791  int action = WM_HANDLER_CONTINUE;
2792  int always_pass;
2793 
2794  if (handlers == NULL) {
2795  return action;
2796  }
2797 
2798  /* Modal handlers can get removed in this loop, we keep the loop this way.
2799  *
2800  * Note: check 'handlers->first' because in rare cases the handlers can be cleared
2801  * by the event that's called, for eg:
2802  *
2803  * Calling a python script which changes the area.type, see T32232. */
2804  for (wmEventHandler *handler_base = handlers->first, *handler_base_next;
2805  handler_base && handlers->first;
2806  handler_base = handler_base_next) {
2807  handler_base_next = handler_base->next;
2808 
2809  /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
2810  if (handler_base->flag & WM_HANDLER_DO_FREE) {
2811  /* Pass. */
2812  }
2813  else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
2814  /* In advance to avoid access to freed event on window close. */
2815  always_pass = wm_event_always_pass(event);
2816 
2817  /* Modal+blocking handler_base. */
2818  if (handler_base->flag & WM_HANDLER_BLOCKING) {
2819  action |= WM_HANDLER_BREAK;
2820  }
2821 
2822  /* Handle all types here. */
2823  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
2824  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
2825  wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
2827  C, event, handlers, handler, keymap, do_debug_handler);
2828 
2829  /* Clear the tool-tip whenever a key binding is handled, without this tool-tips
2830  * are kept when a modal operators starts (annoying but otherwise harmless). */
2831  if (action & WM_HANDLER_BREAK) {
2832  /* Window may be gone after file read. */
2833  if (CTX_wm_window(C) != NULL) {
2835  }
2836  }
2837  }
2838  else if (handler_base->type == WM_HANDLER_TYPE_UI) {
2839  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
2840  BLI_assert(handler->handle_fn != NULL);
2841  if (!wm->is_interface_locked) {
2842  action |= wm_handler_ui_call(C, handler, event, always_pass);
2843  }
2844  }
2845  else if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
2846  wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
2847  if (!wm->is_interface_locked && event->type == EVT_DROP) {
2848  LISTBASE_FOREACH (wmDropBox *, drop, handler->dropboxes) {
2849  /* Other drop custom types allowed. */
2850  if (event->custom == EVT_DATA_DRAGDROP) {
2851  ListBase *lb = (ListBase *)event->customdata;
2852  LISTBASE_FOREACH (wmDrag *, drag, lb) {
2853  const char *tooltip = NULL;
2854  if (drop->poll(C, drag, event, &tooltip)) {
2855  /* Optionally copy drag information to operator properties. Don't call it if the
2856  * operator fails anyway, it might do more than just set properties (e.g.
2857  * typically import an asset). */
2858  if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) {
2859  drop->copy(drag, drop);
2860  }
2861 
2862  /* Pass single matched wmDrag onto the operator. */
2863  BLI_remlink(lb, drag);
2864  ListBase single_lb = {drag, drag};
2865  event->customdata = &single_lb;
2866 
2867  int op_retval = wm_operator_call_internal(
2868  C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event);
2869  OPERATOR_RETVAL_CHECK(op_retval);
2870 
2871  if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
2872  drop->cancel(CTX_data_main(C), drag, drop);
2873  }
2874 
2875  action |= WM_HANDLER_BREAK;
2876 
2877  /* Free the drags. */
2878  WM_drag_free_list(lb);
2879  WM_drag_free_list(&single_lb);
2880 
2881  event->customdata = NULL;
2882  event->custom = 0;
2883 
2884  /* XXX fileread case. */
2885  if (CTX_wm_window(C) == NULL) {
2886  return action;
2887  }
2888 
2889  /* Escape from drag loop, got freed. */
2890  break;
2891  }
2892  }
2893  }
2894  }
2895  }
2896  }
2897  else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
2898  wmEventHandler_Gizmo *handler = (wmEventHandler_Gizmo *)handler_base;
2899  action |= wm_handlers_do_gizmo_handler(C, wm, handler, event, handlers, do_debug_handler);
2900  }
2901  else if (handler_base->type == WM_HANDLER_TYPE_OP) {
2902  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
2903  if (handler->is_fileselect) {
2904  if (!wm->is_interface_locked) {
2905  /* Screen context changes here. */
2906  action |= wm_handler_fileselect_call(C, handlers, handler, event);
2907  }
2908  }
2909  else {
2910  action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
2911  }
2912  }
2913  else {
2914  /* Unreachable (handle all types above). */
2916  }
2917 
2918  if (action & WM_HANDLER_BREAK) {
2919  if (always_pass) {
2920  action &= ~WM_HANDLER_BREAK;
2921  }
2922  else {
2923  break;
2924  }
2925  }
2926  }
2927 
2928  /* XXX fileread case, if the wm is freed then the handler's
2929  * will have been too so the code below need not run. */
2930  if (CTX_wm_window(C) == NULL) {
2931  return action;
2932  }
2933 
2934  /* XXX code this for all modal ops, and ensure free only happens here. */
2935 
2936  /* Modal UI handler can be tagged to be freed. */
2937  if (BLI_findindex(handlers, handler_base) !=
2938  -1) { /* Could be freed already by regular modal ops. */
2939  if (handler_base->flag & WM_HANDLER_DO_FREE) {
2940  BLI_remlink(handlers, handler_base);
2941  wm_event_free_handler(handler_base);
2942  }
2943  }
2944  }
2945 
2946  if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL)) {
2948  }
2949 
2950  return action;
2951 }
2952 
2953 #undef PRINT
2954 
2955 /* This calls handlers twice - to solve (double-)click events. */
2956 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
2957 {
2958  int action = wm_handlers_do_intern(C, event, handlers);
2959 
2960  /* Will be NULL in the file read case. */
2961  wmWindow *win = CTX_wm_window(C);
2962  if (win == NULL) {
2963  return action;
2964  }
2965 
2966  if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
2967  /* Test for CLICK_DRAG events. */
2968  if (wm_action_not_handled(action)) {
2969  if (win->event_queue_check_drag) {
2970  if (WM_event_drag_test(event, &event->prevclickx)) {
2971  win->event_queue_check_drag_handled = true;
2972 
2973  int x = event->x;
2974  int y = event->y;
2975  short val = event->val;
2976  short type = event->type;
2977 
2978  event->x = event->prevclickx;
2979  event->y = event->prevclicky;
2980  event->val = KM_CLICK_DRAG;
2981  event->type = event->prevtype;
2982 
2983  CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG");
2984 
2985  action |= wm_handlers_do_intern(C, event, handlers);
2986 
2987  event->val = val;
2988  event->type = type;
2989  event->x = x;
2990  event->y = y;
2991 
2992  win->event_queue_check_click = false;
2993  if (!wm_action_not_handled(action)) {
2994  /* Only disable when handled as other handlers may use this drag event. */
2995  win->event_queue_check_drag = false;
2996  }
2997  }
2998  }
2999  }
3000  else {
3001  win->event_queue_check_drag = false;
3002  }
3003  }
3004  else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) {
3005  /* All events that don't set wmEvent.prevtype must be ignored. */
3006 
3007  /* Test for CLICK events. */
3008  if (wm_action_not_handled(action)) {
3009  /* eventstate stores if previous event was a KM_PRESS, in case that
3010  * wasn't handled, the KM_RELEASE will become a KM_CLICK */
3011 
3012  if (event->val == KM_PRESS) {
3013  if (event->is_repeat == false) {
3014  win->event_queue_check_click = true;
3015  win->event_queue_check_drag = true;
3016  win->event_queue_check_drag_handled = false;
3017  }
3018  }
3019  else if (event->val == KM_RELEASE) {
3020  win->event_queue_check_drag = false;
3021  }
3022 
3023  if (event->prevtype == event->type) {
3024 
3025  if (event->val == KM_RELEASE) {
3026  if (event->prevval == KM_PRESS) {
3027  if (win->event_queue_check_click == true) {
3028  if (WM_event_drag_test(event, &event->prevclickx)) {
3029  win->event_queue_check_click = false;
3030  win->event_queue_check_drag = false;
3031  }
3032  else {
3033  /* Position is where the actual click happens, for more
3034  * accurate selecting in case the mouse drifts a little. */
3035  int x = event->x;
3036  int y = event->y;
3037 
3038  event->x = event->prevclickx;
3039  event->y = event->prevclicky;
3040  event->val = KM_CLICK;
3041 
3042  CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
3043 
3044  action |= wm_handlers_do_intern(C, event, handlers);
3045 
3046  event->val = KM_RELEASE;
3047  event->x = x;
3048  event->y = y;
3049  }
3050  }
3051  }
3052  }
3053  else if (event->val == KM_DBL_CLICK) {
3054  /* The underlying event is a press, so try and handle this. */
3055  event->val = KM_PRESS;
3056  action |= wm_handlers_do_intern(C, event, handlers);
3057 
3058  /* revert value if not handled */
3059  if (wm_action_not_handled(action)) {
3060  event->val = KM_DBL_CLICK;
3061  }
3062  }
3063  }
3064  }
3065  else {
3066  win->event_queue_check_click = false;
3067  win->event_queue_check_drag = false;
3068  }
3069  }
3070  else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) {
3071  /* Modifiers which can trigger click event's,
3072  * however we don't want this if the mouse wheel has been used, see T74607. */
3073  if (wm_action_not_handled(action)) {
3074  /* pass */
3075  }
3076  else {
3077  if (ISKEYMODIFIER(event->prevtype)) {
3078  win->event_queue_check_click = false;
3079  }
3080  }
3081  }
3082 
3083  return action;
3084 }
3085 
3088 /* -------------------------------------------------------------------- */
3094 static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
3095 {
3096  if (wm_event_always_pass(event)) {
3097  return true;
3098  }
3099  if (BLI_rcti_isect_pt_v(rect, &event->x)) {
3100  return true;
3101  }
3102  return false;
3103 }
3104 
3105 static bool wm_event_inside_region(const wmEvent *event, const ARegion *region)
3106 {
3107  if (wm_event_always_pass(event)) {
3108  return true;
3109  }
3110  return ED_region_contains_xy(region, &event->x);
3111 }
3112 
3113 static ScrArea *area_event_inside(bContext *C, const int xy[2])
3114 {
3115  wmWindow *win = CTX_wm_window(C);
3116  bScreen *screen = CTX_wm_screen(C);
3117 
3118  if (screen) {
3119  ED_screen_areas_iter (win, screen, area) {
3120  if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
3121  return area;
3122  }
3123  }
3124  }
3125  return NULL;
3126 }
3127 
3128 static ARegion *region_event_inside(bContext *C, const int xy[2])
3129 {
3130  bScreen *screen = CTX_wm_screen(C);
3131  ScrArea *area = CTX_wm_area(C);
3132 
3133  if (screen && area) {
3134  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3135  if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
3136  return region;
3137  }
3138  }
3139  }
3140  return NULL;
3141 }
3142 
3144 {
3145  if (region) {
3146  for (; pc; pc = pc->next) {
3147  if (pc->poll == NULL || pc->poll(C)) {
3148  wmWindow *win = CTX_wm_window(C);
3149  WM_paint_cursor_tag_redraw(win, region);
3150  }
3151  }
3152  }
3153 }
3154 
3155 /* Called on mousemove, check updates for paintcursors. */
3156 /* Context was set on active area and region. */
3157 static void wm_paintcursor_test(bContext *C, const wmEvent *event)
3158 {
3160 
3161  if (wm->paintcursors.first) {
3162  ARegion *region = CTX_wm_region(C);
3163 
3164  if (region) {
3165  wm_paintcursor_tag(C, wm->paintcursors.first, region);
3166  }
3167 
3168  /* If previous position was not in current region, we have to set a temp new context. */
3169  if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, &event->prevx)) {
3170  ScrArea *area = CTX_wm_area(C);
3171 
3174 
3176 
3178  CTX_wm_region_set(C, region);
3179  }
3180  }
3181 }
3182 
3184 {
3185  bScreen *screen = WM_window_get_active_screen(win);
3186 
3187  if (BLI_listbase_is_empty(&wm->drags)) {
3188  return;
3189  }
3190 
3191  if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
3192  screen->do_draw_drag = true;
3193  }
3194  else if (event->type == EVT_ESCKEY) {
3195  WM_drag_free_list(&wm->drags);
3196 
3197  screen->do_draw_drag = true;
3198  }
3199  else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
3200  event->type = EVT_DROP;
3201 
3202  /* Create customdata, first free existing. */
3203  if (event->customdata) {
3204  if (event->customdatafree) {
3205  MEM_freeN(event->customdata);
3206  }
3207  }
3208 
3209  event->custom = EVT_DATA_DRAGDROP;
3210  event->customdata = &wm->drags;
3211  event->customdatafree = 1;
3212 
3213  /* Clear drop icon. */
3214  screen->do_draw_drag = true;
3215 
3216  /* restore cursor (disabled, see wm_dragdrop.c) */
3217  // WM_cursor_modal_restore(win);
3218  }
3219 }
3220 
3221 /* Filter out all events of the pie that spawned the last pie unless it's a release event. */
3222 static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
3223 {
3224  if (win->pie_event_type_lock && win->pie_event_type_lock == event->type) {
3225  if (event->val == KM_RELEASE) {
3227  return false;
3228  }
3229  return true;
3230  }
3231  return false;
3232 }
3233 
3242 {
3243  LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) {
3244  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3245  if (BLI_remlink_safe(&win->event_queue, event)) {
3246  wm_event_free(event);
3247  return;
3248  }
3249  }
3250  }
3251 }
3252 
3255 /* -------------------------------------------------------------------- */
3261 /* Called in main loop. */
3262 /* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
3264 {
3267 
3268  /* Update key configuration before handling events. */
3269  WM_keyconfig_update(wm);
3271 
3272  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3273  bScreen *screen = WM_window_get_active_screen(win);
3274 
3275  /* Some safety checks - these should always be set! */
3279 
3280  if (screen == NULL) {
3281  wm_event_free_all(win);
3282  }
3283  else {
3285  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
3287  Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
3288 
3289  if (scene_eval != NULL) {
3290  const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
3291 
3292  if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) {
3293  /* Ignore seek here, the audio will be updated to the scene frame after jump during next
3294  * dependency graph update. */
3295  }
3296  else if (is_playing_sound != -1) {
3297  bool is_playing_screen;
3298 
3299  is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
3300 
3301  if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
3302  ((is_playing_sound == 0) && (is_playing_screen == 1))) {
3303  wmWindow *win_ctx = CTX_wm_window(C);
3304  bScreen *screen_stx = CTX_wm_screen(C);
3305  Scene *scene_ctx = CTX_data_scene(C);
3306 
3307  CTX_wm_window_set(C, win);
3308  CTX_wm_screen_set(C, screen);
3310 
3311  ED_screen_animation_play(C, -1, 1);
3312 
3313  CTX_data_scene_set(C, scene_ctx);
3314  CTX_wm_screen_set(C, screen_stx);
3315  CTX_wm_window_set(C, win_ctx);
3316  }
3317 
3318  if (is_playing_sound == 0) {
3319  const double time = BKE_sound_sync_scene(scene_eval);
3320  if (isfinite(time)) {
3321  int ncfra = round(time * FPS);
3322  if (ncfra != scene->r.cfra) {
3323  scene->r.cfra = ncfra;
3326  }
3327  }
3328  }
3329  }
3330  }
3331  }
3332 
3333  wmEvent *event;
3334  while ((event = win->event_queue.first)) {
3335  int action = WM_HANDLER_CONTINUE;
3336 
3337  /* Active screen might change during handlers, update pointer. */
3338  screen = WM_window_get_active_screen(win);
3339 
3340  if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) &&
3341  !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
3342  printf("\n%s: Handling event\n", __func__);
3343  WM_event_print(event);
3344  }
3345 
3346  /* Take care of pie event filter. */
3347  if (wm_event_pie_filter(win, event)) {
3348  if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
3349  CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed");
3350  }
3351  BLI_remlink(&win->event_queue, event);
3352  wm_event_free(event);
3353  continue;
3354  }
3355 
3356  CTX_wm_window_set(C, win);
3357 
3358  /* Clear tool-tip on mouse move. */
3359  if (screen->tool_tip && screen->tool_tip->exit_on_event) {
3360  if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
3361  if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, &event->x) > U.move_threshold) {
3362  WM_tooltip_clear(C, win);
3363  }
3364  }
3365  }
3366 
3367  /* We let modal handlers get active area/region, also wm_paintcursor_test needs it. */
3368  CTX_wm_area_set(C, area_event_inside(C, &event->x));
3370 
3371  /* MVC demands to not draw in event handlers...
3372  * but we need to leave it for ogl selecting etc. */
3373  wm_window_make_drawable(wm, win);
3374 
3375  wm_region_mouse_co(C, event);
3376 
3377  /* First we do priority handlers, modal + some limited keymaps. */
3378  action |= wm_handlers_do(C, event, &win->modalhandlers);
3379 
3380  /* Fileread case. */
3381  if (CTX_wm_window(C) == NULL) {
3383  return;
3384  }
3385 
3386  /* Check for a tooltip. */
3387  if (screen == WM_window_get_active_screen(win)) {
3388  if (screen->tool_tip && screen->tool_tip->timer) {
3389  if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
3390  WM_tooltip_init(C, win);
3391  }
3392  }
3393  }
3394 
3395  /* Check dragging, creates new event or frees, adds draw tag. */
3396  wm_event_drag_and_drop_test(wm, win, event);
3397 
3398  /* Builtin tweak, if action is break it removes tweak. */
3399  wm_tweakevent_test(C, event, action);
3400 
3401  if ((action & WM_HANDLER_BREAK) == 0) {
3402  /* Note: setting subwin active should be done here, after modal handlers have been done */
3403  if (event->type == MOUSEMOVE) {
3404  /* State variables in screen, cursors.
3405  * Also used in wm_draw.c, fails for modal handlers though. */
3406  ED_screen_set_active_region(C, win, &event->x);
3407  /* For regions having custom cursors. */
3408  wm_paintcursor_test(C, event);
3409  }
3410 #ifdef WITH_INPUT_NDOF
3411  else if (event->type == NDOF_MOTION) {
3412  win->addmousemove = true;
3413  }
3414 #endif
3415 
3416  ED_screen_areas_iter (win, screen, area) {
3417  /* After restoring a screen from SCREENMAXIMIZED we have to wait
3418  * with the screen handling till the region coordinates are updated. */
3419  if (screen->skip_handling == true) {
3420  /* Restore for the next iteration of wm_event_do_handlers. */
3421  screen->skip_handling = false;
3422  break;
3423  }
3424 
3425  /* Update azones if needed - done here because it needs to be independent from redraws.
3426  */
3427  if (area->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
3428  ED_area_azones_update(area, &event->x);
3429  }
3430 
3431  if (wm_event_inside_rect(event, &area->totrct)) {
3433 
3434  if ((action & WM_HANDLER_BREAK) == 0) {
3435  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3436  if (wm_event_inside_region(event, region)) {
3437 
3438  CTX_wm_region_set(C, region);
3439 
3440  /* Call even on non mouse events, since the */
3441  wm_region_mouse_co(C, event);
3442 
3443  if (!BLI_listbase_is_empty(&wm->drags)) {
3444  /* Does polls for drop regions and checks #uiButs. */
3445  /* Need to be here to make sure region context is true. */
3446  if (ELEM(event->type, MOUSEMOVE, EVT_DROP) || ISKEYMODIFIER(event->type)) {
3447  wm_drags_check_ops(C, event);
3448  }
3449  }
3450 
3451  action |= wm_handlers_do(C, event, &region->handlers);
3452 
3453  /* Fileread case (python), T29489. */
3454  if (CTX_wm_window(C) == NULL) {
3456  return;
3457  }
3458 
3459  if (action & WM_HANDLER_BREAK) {
3460  break;
3461  }
3462  }
3463  }
3464  }
3465 
3467 
3468  if ((action & WM_HANDLER_BREAK) == 0) {
3469  wm_region_mouse_co(C, event); /* Only invalidates event->mval in this case. */
3470  action |= wm_handlers_do(C, event, &area->handlers);
3471  }
3473 
3474  /* NOTE: do not escape on WM_HANDLER_BREAK,
3475  * mousemove needs handled for previous area. */
3476  }
3477  }
3478 
3479  if ((action & WM_HANDLER_BREAK) == 0) {
3480  /* Also some non-modal handlers need active area/region. */
3481  CTX_wm_area_set(C, area_event_inside(C, &event->x));
3483 
3484  wm_region_mouse_co(C, event);
3485 
3486  action |= wm_handlers_do(C, event, &win->handlers);
3487 
3488  /* Fileread case. */
3489  if (CTX_wm_window(C) == NULL) {
3491  return;
3492  }
3493  }
3494  }
3495 
3496  /* If press was handled, we don't want to do click. This way
3497  * press in tool keymap can override click in editor keymap.*/
3498  if (ISMOUSE_BUTTON(event->type) && event->val == KM_PRESS &&
3499  !wm_action_not_handled(action)) {
3500  win->event_queue_check_click = false;
3501  }
3502 
3503  /* If the drag even was handled, don't attempt to keep re-handing the same
3504  * drag event on every cursor motion, see: T87511. */
3505  if (win->event_queue_check_drag_handled) {
3506  win->event_queue_check_drag = false;
3507  win->event_queue_check_drag_handled = false;
3508  }
3509 
3510  /* Update previous mouse position for following events to use. */
3511  win->eventstate->prevx = event->x;
3512  win->eventstate->prevy = event->y;
3513 
3514  /* Unlink and free here, blender-quit then frees all. */
3515  BLI_remlink(&win->event_queue, event);
3516  wm_event_free(event);
3517  }
3518 
3519  /* Only add mouse-move when the event queue was read entirely. */
3520  if (win->addmousemove && win->eventstate) {
3521  wmEvent tevent = *(win->eventstate);
3522  // printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
3523  tevent.type = MOUSEMOVE;
3524  tevent.prevx = tevent.x;
3525  tevent.prevy = tevent.y;
3526  tevent.is_repeat = false;
3527  wm_event_add(win, &tevent);
3528  win->addmousemove = 0;
3529  }
3530 
3532  }
3533 
3534  /* Update key configuration after handling events. */
3535  WM_keyconfig_update(wm);
3537 }
3538 
3541 /* -------------------------------------------------------------------- */
3545 void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval)
3546 {
3547  /* Add to all windows! */
3548  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3549  wmEvent event = *win->eventstate;
3550 
3551  event.type = EVT_FILESELECT;
3552  event.val = eventval;
3553  event.customdata = ophandle; /* Only as void pointer type check. */
3554 
3555  wm_event_add(win, &event);
3556  }
3557 }
3558 
3559 /* Operator is supposed to have a filled "path" property. */
3560 /* Optional property: filetype (XXX enum?) */
3561 
3569 {
3571  wmWindow *win = CTX_wm_window(C);
3572  const bool is_temp_screen = WM_window_is_temp_screen(win);
3573 
3574  /* Close any popups, like when opening a file browser from the splash. */
3576 
3577  if (!is_temp_screen) {
3578  /* Only allow 1 file selector open per window. */
3579  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
3580  if (handler_base->type == WM_HANDLER_TYPE_OP) {
3581  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
3582  if (handler->is_fileselect == false) {
3583  continue;
3584  }
3585 
3586  ScrArea *file_area = ED_fileselect_handler_area_find(win, handler->op);
3587 
3588  if (file_area) {
3589  CTX_wm_area_set(C, file_area);
3591  }
3592  /* If not found we stop the handler without changing the screen. */
3593  else {
3596  }
3597  }
3598  }
3599  }
3600 
3601  wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
3602  handler->head.type = WM_HANDLER_TYPE_OP;
3603 
3604  handler->is_fileselect = true;
3605  handler->op = op;
3606  handler->context.win = CTX_wm_window(C);
3607  handler->context.area = CTX_wm_area(C);
3608  handler->context.region = CTX_wm_region(C);
3609 
3610  BLI_addhead(&win->modalhandlers, handler);
3611 
3612  /* Check props once before invoking if check is available
3613  * ensures initial properties are valid. */
3614  if (op->type->check) {
3615  op->type->check(C, op); /* Ignore return value. */
3616  }
3617 
3619 }
3620 
3623 /* -------------------------------------------------------------------- */
3627 #if 0
3628 /* lets not expose struct outside wm? */
3629 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
3630 {
3631  handler->flag = flag;
3632 }
3633 #endif
3634 
3636 {
3637  wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
3638  handler->head.type = WM_HANDLER_TYPE_OP;
3639  wmWindow *win = CTX_wm_window(C);
3640 
3641  /* Operator was part of macro. */
3642  if (op->opm) {
3643  /* Give the mother macro to the handler. */
3644  handler->op = op->opm;
3645  /* Mother macro opm becomes the macro element. */
3646  handler->op->opm = op;
3647  }
3648  else {
3649  handler->op = op;
3650  }
3651 
3652  handler->context.area = CTX_wm_area(C); /* Means frozen screen context for modal handlers! */
3653  handler->context.region = CTX_wm_region(C);
3654  handler->context.region_type = handler->context.region ? handler->context.region->regiontype :
3655  -1;
3656 
3657  BLI_addhead(&win->modalhandlers, handler);
3658 
3659  if (op->type->modalkeymap) {
3661  }
3662 
3663  return handler;
3664 }
3665 
3670 void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
3671 {
3672  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
3673  if (handler_base->type == WM_HANDLER_TYPE_OP) {
3674  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
3675  /* Fileselect handler is quite special...
3676  * it needs to keep old area stored in handler, so don't change it. */
3677  if ((handler->context.area == old_area) && (handler->is_fileselect == false)) {
3678  handler->context.area = new_area;
3679  }
3680  }
3681  }
3682 }
3683 
3689  const ARegion *old_region,
3690  ARegion *new_region)
3691 {
3692  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
3693  if (handler_base->type == WM_HANDLER_TYPE_OP) {
3694  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
3695  /* Fileselect handler is quite special...
3696  * it needs to keep old region stored in handler, so don't change it. */
3697  if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
3698  handler->context.region = new_region;
3699  handler->context.region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
3700  }
3701  }
3702  }
3703 }
3704 
3706 {
3707  if (!keymap) {
3708  CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap");
3709  return NULL;
3710  }
3711 
3712  /* Only allow same keymap once. */
3713  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
3714  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
3715  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
3716  if (handler->keymap == keymap) {
3717  return handler;
3718  }
3719  }
3720  }
3721 
3722  wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
3723  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
3724  BLI_addtail(handlers, handler);
3725  handler->keymap = keymap;
3726 
3727  return handler;
3728 }
3729 
3743  wmEventHandler_Keymap *handler)
3744 {
3745  ScrArea *area = handler->dynamic.user_data;
3746  handler->keymap_tool = NULL;
3747  bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
3748  if (tref_rt && tref_rt->keymap_fallback[0]) {
3749  const char *keymap_id = NULL;
3750 
3751  /* Support for the gizmo owning the tool keymap. */
3752  if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') {
3753  wmGizmoMap *gzmap = NULL;
3754  wmGizmoGroup *gzgroup = NULL;
3755  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3756  if (region->gizmo_map != NULL) {
3757  gzmap = region->gizmo_map;
3758  gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
3759  if (gzgroup != NULL) {
3760  break;
3761  }
3762  }
3763  }
3764  if (gzgroup != NULL) {
3766  /* If all are hidden, don't override. */
3767  if (gzgroup->use_fallback_keymap) {
3768  wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
3769  if (highlight == NULL) {
3770  keymap_id = tref_rt->keymap_fallback;
3771  }
3772  }
3773  }
3774  }
3775  }
3776 
3777  if (keymap_id && keymap_id[0]) {
3779  &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
3780  /* We shouldn't use keymaps from unrelated spaces. */
3781  if (km != NULL) {
3782  handler->keymap_tool = area->runtime.tool;
3783  return km;
3784  }
3785  printf(
3786  "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
3787  }
3788  }
3789  return NULL;
3790 }
3791 
3793 {
3794  ScrArea *area = handler->dynamic.user_data;
3795  handler->keymap_tool = NULL;
3796  bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
3797  if (tref_rt && tref_rt->keymap[0]) {
3798  const char *keymap_id = tref_rt->keymap;
3799  {
3801  &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
3802  /* We shouldn't use keymaps from unrelated spaces. */
3803  if (km != NULL) {
3804  handler->keymap_tool = area->runtime.tool;
3805  return km;
3806  }
3807  printf(
3808  "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
3809  }
3810  }
3811  return NULL;
3812 }
3813 
3815  ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
3816 {
3817  if (!keymap_fn) {
3818  CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn");
3819  return NULL;
3820  }
3821 
3822  /* Only allow same keymap once. */
3823  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
3824  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
3825  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
3826  if (handler->dynamic.keymap_fn == keymap_fn) {
3827  /* Maximizing the view needs to update the area. */
3828  handler->dynamic.user_data = user_data;
3829  return handler;
3830  }
3831  }
3832  }
3833 
3834  wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
3835  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
3836  BLI_addtail(handlers, handler);
3837  handler->dynamic.keymap_fn = keymap_fn;
3838  handler->dynamic.user_data = user_data;
3839 
3840  return handler;
3841 }
3842 
3843 /* Priorities not implemented yet, for time being just insert in begin of list. */
3845  wmKeyMap *keymap,
3846  int UNUSED(priority))
3847 {
3849 
3850  wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), "event keymap handler");
3851  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
3852 
3853  BLI_addhead(handlers, handler);
3854  handler->keymap = keymap;
3855 
3856  return handler;
3857 }
3858 
3859 static bool event_or_prev_in_rect(const wmEvent *event, const rcti *rect)
3860 {
3861  if (BLI_rcti_isect_pt(rect, event->x, event->y)) {
3862  return true;
3863  }
3864  if (event->type == MOUSEMOVE && BLI_rcti_isect_pt(rect, event->prevx, event->prevy)) {
3865  return true;
3866  }
3867  return false;
3868 }
3869 
3870 static bool handler_region_v2d_mask_test(const ARegion *region, const wmEvent *event)
3871 {
3872  rcti rect = region->v2d.mask;
3873  BLI_rcti_translate(&rect, region->winrct.xmin, region->winrct.ymin);
3874  return event_or_prev_in_rect(event, &rect);
3875 }
3876 
3878  wmKeyMap *keymap,
3879  EventHandlerPoll poll)
3880 {
3882  if (handler == NULL) {
3883  return NULL;
3884  }
3885 
3886  handler->head.poll = poll;
3887  return handler;
3888 }
3889 
3891 {
3893 }
3894 
3896 {
3897  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
3898  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
3899  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
3900  if (handler->keymap == keymap) {
3901  BLI_remlink(handlers, handler);
3902  wm_event_free_handler(&handler->head);
3903  break;
3904  }
3905  }
3906  }
3907 }
3908 
3910  void(keymap_tag)(wmKeyMap *keymap,
3911  wmKeyMapItem *kmi,
3912  void *user_data),
3913  void *user_data)
3914 {
3915  handler->post.post_fn = keymap_tag;
3916  handler->post.user_data = user_data;
3917 }
3918 
3920  ListBase *handlers,
3921  wmUIHandlerFunc handle_fn,
3922  wmUIHandlerRemoveFunc remove_fn,
3923  void *user_data,
3924  const char flag)
3925 {
3926  wmEventHandler_UI *handler = MEM_callocN(sizeof(*handler), __func__);
3927  handler->head.type = WM_HANDLER_TYPE_UI;
3928  handler->handle_fn = handle_fn;
3929  handler->remove_fn = remove_fn;
3930  handler->user_data = user_data;
3931  if (C) {
3932  handler->context.area = CTX_wm_area(C);
3933  handler->context.region = CTX_wm_region(C);
3934  handler->context.menu = CTX_wm_menu(C);
3935  }
3936  else {
3937  handler->context.area = NULL;
3938  handler->context.region = NULL;
3939  handler->context.menu = NULL;
3940  }
3941 
3942  BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
3943  handler->head.flag = flag;
3944 
3945  BLI_addhead(handlers, handler);
3946 
3947  return handler;
3948 }
3949 
3950 /* Set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do(). */
3952  wmUIHandlerFunc handle_fn,
3953  wmUIHandlerRemoveFunc remove_fn,
3954  void *user_data,
3955  const bool postpone)
3956 {
3957  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
3958  if (handler_base->type == WM_HANDLER_TYPE_UI) {
3959  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
3960  if ((handler->handle_fn == handle_fn) && (handler->remove_fn == remove_fn) &&
3961  (handler->user_data == user_data)) {
3962  /* Handlers will be freed in wm_handlers_do(). */
3963  if (postpone) {
3964  handler->head.flag |= WM_HANDLER_DO_FREE;
3965  }
3966  else {
3967  BLI_remlink(handlers, handler);
3968  wm_event_free_handler(&handler->head);
3969  }
3970  break;
3971  }
3972  }
3973  }
3974 }
3975 
3977  ListBase *handlers,
3978  wmUIHandlerFunc handle_fn,
3979  wmUIHandlerRemoveFunc remove_fn)
3980 {
3981  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
3982  if (handler_base->type == WM_HANDLER_TYPE_UI) {
3983  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
3984  if ((handler->handle_fn == handle_fn) && (handler->remove_fn == remove_fn)) {
3985  remove_fn(C, handler->user_data);
3986  BLI_remlink(handlers, handler);
3987  wm_event_free_handler(&handler->head);
3988  }
3989  }
3990  }
3991 }
3992 
3994 {
3995  /* Only allow same dropbox once. */
3996  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
3997  if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
3998  wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
3999  if (handler->dropboxes == dropboxes) {
4000  return handler;
4001  }
4002  }
4003  }
4004 
4005  wmEventHandler_Dropbox *handler = MEM_callocN(sizeof(*handler), __func__);
4006  handler->head.type = WM_HANDLER_TYPE_DROPBOX;
4007 
4008  /* Dropbox stored static, no free or copy. */
4009  handler->dropboxes = dropboxes;
4010  BLI_addhead(handlers, handler);
4011 
4012  return handler;
4013 }
4014 
4015 /* XXX solution works, still better check the real cause (ton) */
4017 {
4018  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
4019  if (handler_base->type == WM_HANDLER_TYPE_UI) {
4020  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
4021  if (handler->context.area == area) {
4022  BLI_remlink(handlers, handler);
4023  wm_event_free_handler(handler_base);
4024  }
4025  }
4026  }
4027 }
4028 
4029 #if 0
4030 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
4031 {
4032  BLI_remlink(handlers, handler);
4033  wm_event_free_handler(handler);
4034 }
4035 #endif
4036 
4038 {
4039  win->addmousemove = 1;
4040 }
4041 
4044 /* -------------------------------------------------------------------- */
4048 static int convert_key(GHOST_TKey key)
4049 {
4050  if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
4051  return (EVT_AKEY + ((int)key - GHOST_kKeyA));
4052  }
4053  if (key >= GHOST_kKey0 && key <= GHOST_kKey9) {
4054  return (EVT_ZEROKEY + ((int)key - GHOST_kKey0));
4055  }
4056  if (key >= GHOST_kKeyNumpad0 && key <= GHOST_kKeyNumpad9) {
4057  return (EVT_PAD0 + ((int)key - GHOST_kKeyNumpad0));
4058  }
4059  if (key >= GHOST_kKeyF1 && key <= GHOST_kKeyF24) {
4060  return (EVT_F1KEY + ((int)key - GHOST_kKeyF1));
4061  }
4062 
4063  switch (key) {
4064  case GHOST_kKeyBackSpace:
4065  return EVT_BACKSPACEKEY;
4066  case GHOST_kKeyTab:
4067  return EVT_TABKEY;
4068  case GHOST_kKeyLinefeed:
4069  return EVT_LINEFEEDKEY;
4070  case GHOST_kKeyClear:
4071  return 0;
4072  case GHOST_kKeyEnter:
4073  return EVT_RETKEY;
4074 
4075  case GHOST_kKeyEsc:
4076  return EVT_ESCKEY;
4077  case GHOST_kKeySpace:
4078  return EVT_SPACEKEY;
4079  case GHOST_kKeyQuote:
4080  return EVT_QUOTEKEY;
4081  case GHOST_kKeyComma:
4082  return EVT_COMMAKEY;
4083  case GHOST_kKeyMinus:
4084  return EVT_MINUSKEY;
4085  case GHOST_kKeyPlus:
4086  return EVT_PLUSKEY;
4087  case GHOST_kKeyPeriod:
4088  return EVT_PERIODKEY;
4089  case GHOST_kKeySlash:
4090  return EVT_SLASHKEY;
4091 
4092  case GHOST_kKeySemicolon:
4093  return EVT_SEMICOLONKEY;
4094  case GHOST_kKeyEqual:
4095  return EVT_EQUALKEY;
4096 
4097  case GHOST_kKeyLeftBracket:
4098  return EVT_LEFTBRACKETKEY;
4100  return EVT_RIGHTBRACKETKEY;
4101  case GHOST_kKeyBackslash:
4102  return EVT_BACKSLASHKEY;
4103  case GHOST_kKeyAccentGrave:
4104  return EVT_ACCENTGRAVEKEY;
4105 
4106  case GHOST_kKeyLeftShift:
4107  return EVT_LEFTSHIFTKEY;
4108  case GHOST_kKeyRightShift:
4109  return EVT_RIGHTSHIFTKEY;
4110  case GHOST_kKeyLeftControl:
4111  return EVT_LEFTCTRLKEY;
4113  return EVT_RIGHTCTRLKEY;
4114  case GHOST_kKeyOS:
4115  return EVT_OSKEY;
4116  case GHOST_kKeyLeftAlt:
4117  return EVT_LEFTALTKEY;
4118  case GHOST_kKeyRightAlt:
4119  return EVT_RIGHTALTKEY;
4120  case GHOST_kKeyApp:
4121  return EVT_APPKEY;
4122 
4123  case GHOST_kKeyCapsLock:
4124  return EVT_CAPSLOCKKEY;
4125  case GHOST_kKeyNumLock:
4126  return 0;
4127  case GHOST_kKeyScrollLock:
4128  return 0;
4129 
4130  case GHOST_kKeyLeftArrow:
4131  return EVT_LEFTARROWKEY;
4132  case GHOST_kKeyRightArrow:
4133  return EVT_RIGHTARROWKEY;
4134  case GHOST_kKeyUpArrow:
4135  return EVT_UPARROWKEY;
4136  case GHOST_kKeyDownArrow:
4137  return EVT_DOWNARROWKEY;
4138 
4139  case GHOST_kKeyPrintScreen:
4140  return 0;
4141  case GHOST_kKeyPause:
4142  return EVT_PAUSEKEY;
4143 
4144  case GHOST_kKeyInsert:
4145  return EVT_INSERTKEY;
4146  case GHOST_kKeyDelete:
4147  return EVT_DELKEY;
4148  case GHOST_kKeyHome:
4149  return EVT_HOMEKEY;
4150  case GHOST_kKeyEnd:
4151  return EVT_ENDKEY;
4152  case GHOST_kKeyUpPage:
4153  return EVT_PAGEUPKEY;
4154  case GHOST_kKeyDownPage:
4155  return EVT_PAGEDOWNKEY;
4156 
4158  return EVT_PADPERIOD;
4159  case GHOST_kKeyNumpadEnter:
4160  return EVT_PADENTER;
4161  case GHOST_kKeyNumpadPlus:
4162  return EVT_PADPLUSKEY;
4163  case GHOST_kKeyNumpadMinus:
4164  return EVT_PADMINUS;
4166  return EVT_PADASTERKEY;
4167  case GHOST_kKeyNumpadSlash:
4168  return EVT_PADSLASHKEY;
4169 
4170  case GHOST_kKeyGrLess:
4171  return EVT_GRLESSKEY;
4172 
4173  case GHOST_kKeyMediaPlay:
4174  return EVT_MEDIAPLAY;
4175  case GHOST_kKeyMediaStop:
4176  return EVT_MEDIASTOP;
4177  case GHOST_kKeyMediaFirst:
4178  return EVT_MEDIAFIRST;
4179  case GHOST_kKeyMediaLast:
4180  return EVT_MEDIALAST;
4181 
4182  default:
4183  return EVT_UNKNOWNKEY; /* GHOST_kKeyUnknown */
4184  }
4185 }
4186 
4187 static void wm_eventemulation(wmEvent *event, bool test_only)
4188 {
4189  /* Store last middle-mouse event value to make emulation work
4190  * when modifier keys are released first.
4191  * This really should be in a data structure somewhere. */
4192  static int emulating_event = EVENT_NONE;
4193 
4194  /* Middle-mouse emulation. */
4195  if (U.flag & USER_TWOBUTTONMOUSE) {
4196 
4197  if (event->type == LEFTMOUSE) {
4198  short *mod = (
4199 #if !defined(WIN32)
4200  (U.mouse_emulate_3_button_modifier == USER_EMU_MMB_MOD_OSKEY) ? &event->oskey :
4201  &event->alt
4202 #else
4203  /* Disable for WIN32 for now because it accesses the start menu. */
4204  &event->alt
4205 #endif
4206  );
4207 
4208  if (event->val == KM_PRESS) {
4209  if (*mod) {
4210  *mod = 0;
4211  event->type = MIDDLEMOUSE;
4212 
4213  if (!test_only) {
4214  emulating_event = MIDDLEMOUSE;
4215  }
4216  }
4217  }
4218  else if (event->val == KM_RELEASE) {
4219  /* Only send middle-mouse release if emulated. */
4220  if (emulating_event == MIDDLEMOUSE) {
4221  event->type = MIDDLEMOUSE;
4222  *mod = 0;
4223  }
4224 
4225  if (!test_only) {
4226  emulating_event = EVENT_NONE;
4227  }
4228  }
4229  }
4230  }
4231 
4232  /* Numpad emulation. */
4233  if (U.flag & USER_NONUMPAD) {
4234  switch (event->type) {
4235  case EVT_ZEROKEY:
4236  event->type = EVT_PAD0;
4237  break;
4238  case EVT_ONEKEY:
4239  event->type = EVT_PAD1;
4240  break;
4241  case EVT_TWOKEY:
4242  event->type = EVT_PAD2;
4243  break;
4244  case EVT_THREEKEY:
4245  event->type = EVT_PAD3;
4246  break;
4247  case EVT_FOURKEY:
4248  event->type = EVT_PAD4;
4249  break;
4250  case EVT_FIVEKEY:
4251  event->type = EVT_PAD5;
4252  break;
4253  case EVT_SIXKEY:
4254  event->type = EVT_PAD6;
4255  break;
4256  case EVT_SEVENKEY:
4257  event->type = EVT_PAD7;
4258  break;
4259  case EVT_EIGHTKEY:
4260  event->type = EVT_PAD8;
4261  break;
4262  case EVT_NINEKEY:
4263  event->type = EVT_PAD9;
4264  break;
4265  case EVT_MINUSKEY:
4266  event->type = EVT_PADMINUS;
4267  break;
4268  case EVT_EQUALKEY:
4269  event->type = EVT_PADPLUSKEY;
4270  break;
4271  case EVT_BACKSLASHKEY:
4272  event->type = EVT_PADSLASHKEY;
4273  break;
4274  }
4275  }
4276 }
4277 
4280  .pressure = 1.0f,
4281  .x_tilt = 0.0f,
4282  .y_tilt = 0.0f,
4283  .is_motion_absolute = false,
4284 };
4285 
4287 {
4288  *tablet_data = wm_event_tablet_data_default;
4289 }
4290 
4292 {
4293  if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
4294  wmtab->active = (int)tablet_data->Active;
4295  wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
4296  wmtab->x_tilt = tablet_data->Xtilt;
4297  wmtab->y_tilt = tablet_data->Ytilt;
4298  /* We could have a preference to support relative tablet motion (we can't detect that). */
4299  wmtab->is_motion_absolute = true;
4300  // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
4301  }
4302  else {
4304  // printf("%s: not using tablet\n", __func__);
4305  }
4306 }
4307 
4308 #ifdef WITH_INPUT_NDOF
4309 /* Adds customdata to event. */
4310 static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
4311 {
4312  wmNDOFMotionData *data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
4313 
4314  const float ts = U.ndof_sensitivity;
4315  const float rs = U.ndof_orbit_sensitivity;
4316 
4317  mul_v3_v3fl(data->tvec, &ghost->tx, ts);
4318  mul_v3_v3fl(data->rvec, &ghost->rx, rs);
4319 
4320  if (U.ndof_flag & NDOF_PAN_YZ_SWAP_AXIS) {
4321  float t;
4322  t = data->tvec[1];
4323  data->tvec[1] = -data->tvec[2];
4324  data->tvec[2] = t;
4325  }
4326 
4327  data->dt = ghost->dt;
4328 
4329  data->progress = (wmProgress)ghost->progress;
4330 
4331  event->custom = EVT_DATA_NDOF_MOTION;
4332  event->customdata = data;
4333  event->customdatafree = 1;
4334 }
4335 #endif /* WITH_INPUT_NDOF */
4336 
4337 /* Imperfect but probably usable... draw/enable drags to other windows. */
4339 {
4340  int mval[2] = {event->x, event->y};
4341 
4342  if (wm->windows.first == wm->windows.last) {
4343  return NULL;
4344  }
4345 
4346  /* In order to use window size and mouse position (pixels), we have to use a WM function. */
4347 
4348  /* check if outside, include top window bar... */
4349  if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) ||
4350  mval[1] > WM_window_pixels_y(win) + 30) {
4351  /* Let's skip windows having modal handlers now */
4352  /* potential XXX ugly... I wouldn't have added a modalhandlers list
4353  * (introduced in rev 23331, ton). */
4354  LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) {
4355  if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) {
4356  return NULL;
4357  }
4358  }
4359 
4360  wmWindow *win_other;
4361  if (WM_window_find_under_cursor(wm, win, win, mval, &win_other, mval)) {
4362  event->x = mval[0];
4363  event->y = mval[1];
4364  return win_other;
4365  }
4366  }
4367  return NULL;
4368 }
4369 
4370 static bool wm_event_is_double_click(const wmEvent *event)
4371 {
4372  if ((event->type == event->prevtype) && (event->prevval == KM_RELEASE) &&
4373  (event->val == KM_PRESS)) {
4374  if (ISMOUSE(event->type) && WM_event_drag_test(event, &event->prevclickx)) {
4375  /* Pass. */
4376  }
4377  else {
4378  if ((PIL_check_seconds_timer() - event->prevclicktime) * 1000 < U.dbl_click_time) {
4379  return true;
4380  }
4381  }
4382  }
4383 
4384  return false;
4385 }
4386 
4390 static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state)
4391 {
4392  event->prevval = event_state->prevval = event_state->val;
4393  event->prevtype = event_state->prevtype = event_state->type;
4394 }
4395 
4396 static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state)
4397 {
4398  event->prevclicktime = event_state->prevclicktime = PIL_check_seconds_timer();
4399  event->prevclickx = event_state->prevclickx = event_state->x;
4400  event->prevclicky = event_state->prevclicky = event_state->y;
4401 }
4402 
4403 static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
4404 {
4405  wmEvent *event_last = win->event_queue.last;
4406 
4407  /* Some painting operators want accurate mouse events, they can
4408  * handle in between mouse move moves, others can happily ignore
4409  * them for better performance. */
4410  if (event_last && event_last->type == MOUSEMOVE) {
4411  event_last->type = INBETWEEN_MOUSEMOVE;
4412  }
4413 
4414  wmEvent *event_new = wm_event_add(win, event);
4415  if (event_last == NULL) {
4416  event_last = win->eventstate;
4417  }
4418 
4419  copy_v2_v2_int(&event_new->prevx, &event_last->x);
4420  return event_new;
4421 }
4422 
4423 static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int deltax, int deltay)
4424 {
4425  /* Ignore in between trackpad events for performance, we only need high accuracy
4426  * for painting with mouse moves, for navigation using the accumulated value is ok. */
4427  wmEvent *event_last = win->event_queue.last;
4428  if (event_last && event_last->type == event->type) {
4429  deltax += event_last->x - event_last->prevx;
4430  deltay += event_last->y - event_last->prevy;
4431 
4432  wm_event_free_last(win);
4433  }
4434 
4435  /* Set prevx/prevy, the delta is computed from this in operators. */
4436  wmEvent *event_new = wm_event_add(win, event);
4437  event_new->prevx = event_new->x - deltax;
4438  event_new->prevy = event_new->y - deltay;
4439 
4440  return event_new;
4441 }
4442 
4446 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
4447 {
4448  if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
4449  return;
4450  }
4451 
4462  wmEvent event, *event_state = win->eventstate;
4463 
4464  /* Initialize and copy state (only mouse x y and modifiers). */
4465  event = *event_state;
4466  event.is_repeat = false;
4467 
4478  event.prevtype = event.type;
4479  event.prevval = event.val;
4480 
4481  /* Ensure the event state is correct, any deviation from this may cause bugs. */
4482 #ifndef NDEBUG
4483  if ((event_state->type || event_state->val) && /* Ignore cleared event state. */
4484  !(ISMOUSE_BUTTON(event_state->type) || ISKEYBOARD(event_state->type))) {
4486  "Non-keyboard/mouse button found in 'win->eventstate->type = %d'",
4487  event_state->type);
4488  }
4489  if ((event_state->prevtype || event_state->prevval) && /* Ignore cleared event state. */
4490  !(ISMOUSE_BUTTON(event_state->prevtype) || ISKEYBOARD(event_state->prevtype))) {
4492  "Non-keyboard/mouse button found in 'win->eventstate->prevtype = %d'",
4493  event_state->prevtype);
4494  }
4495 #endif
4496 
4497  switch (type) {
4498  /* Mouse move, also to inactive window (X11 does this). */
4499  case GHOST_kEventCursorMove: {
4500  GHOST_TEventCursorData *cd = customdata;
4501 
4502  copy_v2_v2_int(&event.x, &cd->x);
4503  wm_stereo3d_mouse_offset_apply(win, &event.x);
4504  wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
4505 
4506  event.type = MOUSEMOVE;
4507  {
4508  wmEvent *event_new = wm_event_add_mousemove(win, &event);
4509  copy_v2_v2_int(&event_state->x, &event_new->x);
4510  event_state->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
4511  }
4512 
4513  /* Also add to other window if event is there, this makes overdraws disappear nicely. */
4514  /* It remaps mousecoord to other window in event. */
4515  wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
4516  if (win_other) {
4517  wmEvent event_other = *win_other->eventstate;
4518 
4519  /* See comment for this operation on `event` for details. */
4520  event_other.prevtype = event_other.type;
4521  event_other.prevval = event_other.val;
4522 
4523  copy_v2_v2_int(&event_other.x, &event.x);
4524  event_other.type = MOUSEMOVE;
4525  {
4526  wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other);
4527  copy_v2_v2_int(&win_other->eventstate->x, &event_new->x);
4529  }
4530  }
4531 
4532  break;
4533  }
4534  case GHOST_kEventTrackpad: {
4535  GHOST_TEventTrackpadData *pd = customdata;
4536  switch (pd->subtype) {
4538  event.type = MOUSEZOOM;
4539  pd->deltaX = -pd->deltaX;
4540  pd->deltaY = -pd->deltaY;
4541  break;
4543  event.type = MOUSESMARTZOOM;
4544  break;
4546  event.type = MOUSEROTATE;
4547  break;
4549  default:
4550  event.type = MOUSEPAN;
4551  break;
4552  }
4553 
4554  event.x = event_state->x = pd->x;
4555  event.y = event_state->y = pd->y;
4556  event.val = KM_NOTHING;
4557 
4558  /* The direction is inverted from the device due to system preferences. */
4559  event.is_direction_inverted = pd->isDirectionInverted;
4560 
4561  wm_event_add_trackpad(win, &event, pd->deltaX, -pd->deltaY);
4562  break;
4563  }
4564  /* Mouse button. */
4566  case GHOST_kEventButtonUp: {
4567  GHOST_TEventButtonData *bd = customdata;
4568 
4569  /* Get value and type from Ghost. */
4570  event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
4571 
4572  if (bd->button == GHOST_kButtonMaskLeft) {
4573  event.type = LEFTMOUSE;
4574  }
4575  else if (bd->button == GHOST_kButtonMaskRight) {
4576  event.type = RIGHTMOUSE;
4577  }
4578  else if (bd->button == GHOST_kButtonMaskButton4) {
4579  event.type = BUTTON4MOUSE;
4580  }
4581  else if (bd->button == GHOST_kButtonMaskButton5) {
4582  event.type = BUTTON5MOUSE;
4583  }
4584  else if (bd->button == GHOST_kButtonMaskButton6) {
4585  event.type = BUTTON6MOUSE;
4586  }
4587  else if (bd->button == GHOST_kButtonMaskButton7) {
4588  event.type = BUTTON7MOUSE;
4589  }
4590  else {
4591  event.type = MIDDLEMOUSE;
4592  }
4593 
4594  /* Get tablet data. */
4595  wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
4596 
4597  wm_eventemulation(&event, false);
4598  wm_event_prev_values_set(&event, event_state);
4599 
4600  /* Copy to event state. */
4601  event_state->val = event.val;
4602  event_state->type = event.type;
4603 
4604  /* Double click test. */
4605  if (wm_event_is_double_click(&event)) {
4606  CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
4607  event.val = KM_DBL_CLICK;
4608  }
4609  if (event.val == KM_PRESS) {
4610  wm_event_prev_click_set(&event, event_state);
4611  }
4612 
4613  /* Add to other window if event is there (not to both!). */
4614  wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
4615  if (win_other) {
4616  wmEvent event_other = *win_other->eventstate;
4617 
4618  /* See comment for this operation on `event` for details. */
4619  event_other.prevtype = event_other.type;
4620  event_other.prevval = event_other.val;
4621 
4622  copy_v2_v2_int(&event_other.x, &event.x);
4623 
4624  event_other.type = event.type;
4625  event_other.val = event.val;
4626  event_other.tablet = event.tablet;
4627 
4628  wm_event_add(win_other, &event_other);
4629  }
4630  else {
4631  wm_event_add(win, &event);
4632  }
4633 
4634  break;
4635  }
4636  /* Keyboard. */
4637  case GHOST_kEventKeyDown:
4638  case GHOST_kEventKeyUp: {
4639  GHOST_TEventKeyData *kd = customdata;
4640  short keymodifier = KM_NOTHING;
4641  event.type = convert_key(kd->key);
4642  event.ascii = kd->ascii;
4643  /* Might be not NULL terminated. */
4644  memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
4645  event.is_repeat = kd->is_repeat;
4646  event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE;
4647 
4648  wm_eventemulation(&event, false);
4649  wm_event_prev_values_set(&event, event_state);
4650 
4651  /* Copy to event state. */
4652  event_state->val = event.val;
4653  event_state->type = event.type;
4654  event_state->is_repeat = event.is_repeat;
4655 
4656  /* Exclude arrow keys, esc, etc from text input. */
4657  if (type == GHOST_kEventKeyUp) {
4658  event.ascii = '\0';
4659 
4660  /* Ghost should do this already for key up. */
4661  if (event.utf8_buf[0]) {
4663  "ghost on your platform is misbehaving, utf8 events on key up!");
4664  }
4665  event.utf8_buf[0] = '\0';
4666  }
4667  else {
4668  if (event.ascii < 32 && event.ascii > 0) {
4669  event.ascii = '\0';
4670  }
4671  if (event.utf8_buf[0] < 32 && event.utf8_buf[0] > 0) {
4672  event.utf8_buf[0] = '\0';
4673  }
4674  }
4675 
4676  if (event.utf8_buf[0]) {
4677  if (BLI_str_utf8_size(event.utf8_buf) == -1) {
4679  "ghost detected an invalid unicode character '%d'",
4680  (int)(unsigned char)event.utf8_buf[0]);
4681  event.utf8_buf[0] = '\0';
4682  }
4683  }
4684 
4685  /* Assigning both first and second is strange. - campbell */
4686  switch (event.type) {
4687  case EVT_LEFTSHIFTKEY:
4688  case EVT_RIGHTSHIFTKEY:
4689  if (event.val == KM_PRESS) {
4690  if (event_state->ctrl || event_state->alt || event_state->oskey) {
4691  keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
4692  }
4693  else {
4694  keymodifier = KM_MOD_FIRST;
4695  }
4696  }
4697  event.shift = event_state->shift = keymodifier;
4698  break;
4699  case EVT_LEFTCTRLKEY:
4700  case EVT_RIGHTCTRLKEY:
4701  if (event.val == KM_PRESS) {
4702  if (event_state->shift || event_state->alt || event_state->oskey) {
4703  keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
4704  }
4705  else {
4706  keymodifier = KM_MOD_FIRST;
4707  }
4708  }
4709  event.ctrl = event_state->ctrl = keymodifier;
4710  break;
4711  case EVT_LEFTALTKEY:
4712  case EVT_RIGHTALTKEY:
4713  if (event.val == KM_PRESS) {
4714  if (event_state->ctrl || event_state->shift || event_state->oskey) {
4715  keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
4716  }
4717  else {
4718  keymodifier = KM_MOD_FIRST;
4719  }
4720  }
4721  event.alt = event_state->alt = keymodifier;
4722  break;
4723  case EVT_OSKEY:
4724  if (event.val == KM_PRESS) {
4725  if (event_state->ctrl || event_state->alt || event_state->shift) {
4726  keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND);
4727  }
4728  else {
4729  keymodifier = KM_MOD_FIRST;
4730  }
4731  }
4732  event.oskey = event_state->oskey = keymodifier;
4733  break;
4734  default:
4735  if (event.val == KM_PRESS && event.keymodifier == 0) {
4736  /* Only set in eventstate, for next event. */
4737  event_state->keymodifier = event.type;
4738  }
4739  else if (event.val == KM_RELEASE && event.keymodifier == event.type) {
4740  event.keymodifier = event_state->keymodifier = 0;
4741  }
4742  break;
4743  }
4744 
4745  /* Double click test. */
4746  /* If previous event was same type, and previous was release, and now it presses... */
4747  if (wm_event_is_double_click(&event)) {
4748  CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
4749  event.val = KM_DBL_CLICK;
4750  }
4751 
4752  /* This case happens on holding a key pressed, it should not generate
4753  * press events events with the same key as modifier. */
4754  if (event.keymodifier == event.type) {
4755  event.keymodifier = 0;
4756  }
4757 
4758  /* This case happens with an external numpad, and also when using 'dead keys'
4759  * (to compose complex latin characters e.g.), it's not really clear why.
4760  * Since it's impossible to map a key modifier to an unknown key,
4761  * it shouldn't harm to clear it. */
4762  if (event.keymodifier == EVT_UNKNOWNKEY) {
4763  event_state->keymodifier = event.keymodifier = 0;
4764  }
4765 
4766  /* If test_break set, it catches this. Do not set with modifier presses.
4767  * XXX Keep global for now? */
4768  if ((event.type == EVT_ESCKEY && event.val == KM_PRESS) &&
4769  /* Check other modifiers because ms-windows uses these to bring up the task manager. */
4770  (event.shift == 0 && event.ctrl == 0 && event.alt == 0)) {
4771  G.is_break = true;
4772  }
4773 
4774  /* Double click test - only for press. */
4775  if (event.val == KM_PRESS) {
4776  /* Don't reset timer & location when holding the key generates repeat events. */
4777  if (event.is_repeat == false) {
4778  wm_event_prev_click_set(&event, event_state);
4779  }
4780  }
4781 
4782  wm_event_add(win, &event);
4783 
4784  break;
4785  }
4786 
4787  case GHOST_kEventWheel: {
4788  GHOST_TEventWheelData *wheelData = customdata;
4789 
4790  if (wheelData->z > 0) {
4791  event.type = WHEELUPMOUSE;
4792  }
4793  else {
4794  event.type = WHEELDOWNMOUSE;
4795  }
4796 
4797  event.val = KM_PRESS;
4798  wm_event_add(win, &event);
4799 
4800  break;
4801  }
4802  case GHOST_kEventTimer: {
4803  event.type = TIMER;
4804  event.custom = EVT_DATA_TIMER;
4805  event.customdata = customdata;
4806  event.val = KM_NOTHING;
4807  event.keymodifier = 0;
4808  wm_event_add(win, &event);
4809 
4810  break;
4811  }
4812 
4813 #ifdef WITH_INPUT_NDOF
4814  case GHOST_kEventNDOFMotion: {
4815  event.type = NDOF_MOTION;
4816  event.val = KM_NOTHING;
4817  attach_ndof_data(&event, customdata);
4818  wm_event_add(win, &event);
4819 
4820  CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.x, event.y);
4821  break;
4822  }
4823 
4824  case GHOST_kEventNDOFButton: {
4825  GHOST_TEventNDOFButtonData *e = customdata;
4826 
4827  event.type = NDOF_BUTTON_NONE + e->button;
4828 
4829  switch (e->action) {
4830  case GHOST_kPress:
4831  event.val = KM_PRESS;
4832  break;
4833  case GHOST_kRelease:
4834  event.val = KM_RELEASE;
4835  break;
4836  }
4837 
4838  event.custom = 0;
4839  event.customdata = NULL;
4840 
4841  wm_event_add(win, &event);
4842 
4843  break;
4844  }
4845 #endif /* WITH_INPUT_NDOF */
4846 
4847  case GHOST_kEventUnknown:
4848  case GHOST_kNumEventTypes:
4849  break;
4850 
4852  event.type = WINDEACTIVATE;
4853  wm_event_add(win, &event);
4854 
4855  break;
4856  }
4857 
4858 #ifdef WITH_INPUT_IME
4860  event.val = KM_PRESS;
4861  win->ime_data = customdata;
4862  win->ime_data->is_ime_composing = true;
4863  event.type = WM_IME_COMPOSITE_START;
4864  wm_event_add(win, &event);
4865  break;
4866  }
4868  event.val = KM_PRESS;
4869  event.type = WM_IME_COMPOSITE_EVENT;
4870  wm_event_add(win, &event);
4871  break;
4872  }
4874  event.val = KM_PRESS;
4875  if (win->ime_data) {
4876  win->ime_data->is_ime_composing = false;
4877  }
4878  event.type = WM_IME_COMPOSITE_END;
4879  wm_event_add(win, &event);
4880  break;
4881  }
4882 #endif /* WITH_INPUT_IME */
4883  }
4884 
4885 #if 0
4886  WM_event_print(&event);
4887 #endif
4888 }
4889 
4892 /* -------------------------------------------------------------------- */
4901 {
4903 
4904  if (wm->is_interface_locked) {
4905  if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
4906  return false;
4907  }
4908  }
4909 
4910  return true;
4911 }
4912 
4914 {
4915  /* This will prevent events from being handled while interface is locked
4916  *
4917  * Use a "local" flag for now, because currently no other areas could
4918  * benefit of locked interface anyway (aka using G.is_interface_locked
4919  * wouldn't be useful anywhere outside of window manager, so let's not
4920  * pollute global context with such an information for now).
4921  */
4922  wm->is_interface_locked = lock ? 1 : 0;
4923 
4924  /* This will prevent drawing regions which uses non-threadsafe data.
4925  * Currently it'll be just a 3D viewport.
4926  *
4927  * TODO(sergey): Make it different locked states, so different jobs
4928  * could lock different areas of blender and allow
4929  * interaction with others?
4930  */
4932 }
4933 
4936 /* -------------------------------------------------------------------- */
4941 {
4942  wmKeyMap *keymap;
4943  if (handler->dynamic.keymap_fn != NULL) {
4944  keymap = handler->dynamic.keymap_fn(wm, handler);
4945  BLI_assert(handler->keymap == NULL);
4946  }
4947  else {
4948  keymap = WM_keymap_active(wm, handler->keymap);
4949  BLI_assert(keymap != NULL);
4950  }
4951  return keymap;
4952 }
4953 
4955 {
4957  if (wm_eventmatch(event, kmi)) {
4958  wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
4960  return kmi;
4961  }
4962  }
4963  }
4964  return NULL;
4965 }
4966 
4968  wmWindowManager *wm,
4969  ListBase *handlers,
4970  const wmEvent *event)
4971 {
4972  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4973  /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
4974  if (handler_base->flag & WM_HANDLER_DO_FREE) {
4975  /* Pass. */
4976  }
4977  else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
4978  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
4979  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
4981  if (keymap && WM_keymap_poll(C, keymap)) {
4983  if (kmi != NULL) {
4984  return kmi;
4985  }
4986  }
4987  }
4988  }
4989  }
4990  return NULL;
4991 }
4992 
4995 /* -------------------------------------------------------------------- */
5005  struct {
5006  short shift, ctrl, alt, oskey;
5008  short space_type;
5010  /* Never use, just compare memory for changes. */
5012 };
5013 
5015  /* 0: mouse button index
5016  * 1: event type (click/press, drag)
5017  * 2: text.
5018  */
5019  char text[3][2][128];
5022 };
5023 
5025  const wmEvent *event,
5026  short space_type,
5027  short region_type,
5028  const bToolRef *tref)
5029 {
5030  state->modifiers.shift = event->shift;
5031  state->modifiers.ctrl = event->ctrl;
5032  state->modifiers.alt = event->alt;
5033  state->modifiers.oskey = event->oskey;
5034  state->space_type = space_type;
5035  state->region_type = region_type;
5036  state->tref = tref ? *tref : (bToolRef){0};
5037 }
5038 
5040  int button_index,
5041  int type_index)
5042 {
5043  if (win->cursor_keymap_status != NULL) {
5044  struct CursorKeymapInfo *cd = win->cursor_keymap_status;
5045  const char *msg = cd->text[button_index][type_index];
5046  if (*msg) {
5047  return msg;
5048  }
5049  }
5050  return NULL;
5051 }
5052 
5058 {
5059  if (screen->state == SCREENFULL) {
5060  return NULL;
5061  }
5062  ScrArea *area_statusbar = NULL;
5064  if (area->spacetype == SPACE_STATUSBAR) {
5065  area_statusbar = area;
5066  break;
5067  }
5068  }
5069  return area_statusbar;
5070 }
5071 
5073 {
5074  bScreen *screen = WM_window_get_active_screen(win);
5075  ScrArea *area = WM_window_status_area_find(win, screen);
5076  if (area != NULL) {
5078  }
5079 }
5080 
5082 {
5083  bScreen *screen = WM_window_get_active_screen(win);
5084  ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
5085  if (area_statusbar == NULL) {
5087  return;
5088  }
5089 
5090  struct CursorKeymapInfo *cd;
5091  if (UNLIKELY(win->cursor_keymap_status == NULL)) {
5092  win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
5093  }
5094  cd = win->cursor_keymap_status;
5095 
5096  /* Detect unchanged state (early exit). */
5097  if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
5098  return;
5099  }
5100 
5101  /* Now perform more comprehensive check,
5102  * still keep this fast since it happens on mouse-move. */
5103  struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
5104  cd->state_event = *win->eventstate;
5105 
5106  /* Find active region and associated area. */
5107  ARegion *region = screen->active_region;
5108  if (region == NULL) {
5109  return;
5110  }
5111 
5112  ScrArea *area = NULL;
5113  ED_screen_areas_iter (win, screen, area_iter) {
5114  if (BLI_findindex(&area_iter->regionbase, region) != -1) {
5115  area = area_iter;
5116  break;
5117  }
5118  }
5119  if (area == NULL) {
5120  return;
5121  }
5122 
5123  /* Keep as-is. */
5124  if (ELEM(area->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
5125  return;
5126  }
5127  if (ELEM(region->regiontype,
5132  RGN_TYPE_HUD)) {
5133  return;
5134  }
5135  /* Fallback to window. */
5138  }
5139 
5140  /* Detect changes to the state. */
5141  {
5142  bToolRef *tref = NULL;
5143  if ((region->regiontype == RGN_TYPE_WINDOW) &&
5144  ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
5145  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
5146  WorkSpace *workspace = WM_window_get_active_workspace(win);
5147  const bToolKey tkey = {
5148  .space_type = area->spacetype,
5149  .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
5150  };
5151  tref = WM_toolsystem_ref_find(workspace, &tkey);
5152  }
5153  wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
5154  if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
5155  return;
5156  }
5157  }
5158 
5159  /* Changed context found, detect changes to keymap and refresh the status bar. */
5160  const struct {
5161  int button_index;
5162  int type_index; /* 0: press or click, 1: drag. */
5163  int event_type;
5164  int event_value;
5165  } event_data[] = {
5166  {0, 0, LEFTMOUSE, KM_PRESS},
5167  {0, 0, LEFTMOUSE, KM_CLICK},
5168  {0, 1, EVT_TWEAK_L, KM_ANY},
5169 
5170  {1, 0, MIDDLEMOUSE, KM_PRESS},
5171  {1, 0, MIDDLEMOUSE, KM_CLICK},
5172  {1, 1, EVT_TWEAK_M, KM_ANY},
5173 
5174  {2, 0, RIGHTMOUSE, KM_PRESS},
5175  {2, 0, RIGHTMOUSE, KM_CLICK},
5176  {2, 1, EVT_TWEAK_R, KM_ANY},
5177  };
5178 
5179  for (int button_index = 0; button_index < 3; button_index++) {
5180  cd->text[button_index][0][0] = '\0';
5181  cd->text[button_index][1][0] = '\0';
5182  }
5183 
5184  CTX_wm_window_set(C, win);
5186  CTX_wm_region_set(C, region);
5187 
5188  ListBase *handlers[] = {
5189  &region->handlers,
5190  &area->handlers,
5191  &win->handlers,
5192  };
5193 
5195  for (int data_index = 0; data_index < ARRAY_SIZE(event_data); data_index++) {
5196  const int button_index = event_data[data_index].button_index;
5197  const int type_index = event_data[data_index].type_index;
5198  if (cd->text[button_index][type_index][0] != 0) {
5199  continue;
5200  }
5201  wmEvent test_event = *win->eventstate;
5202  test_event.type = event_data[data_index].event_type;
5203  test_event.val = event_data[data_index].event_value;
5204  wm_eventemulation(&test_event, true);
5205  wmKeyMapItem *kmi = NULL;
5206  for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
5207  kmi = WM_event_match_keymap_item_from_handlers(C, wm, handlers[handler_index], &test_event);
5208  if (kmi) {
5209  break;
5210  }
5211  }
5212  if (kmi) {
5214  const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname;
5215  STRNCPY(cd->text[button_index][type_index], name);
5216  }
5217  }
5218 
5219  if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
5220  ED_area_tag_redraw(area_statusbar);
5221  }
5222 
5224 }
5225 
5228 /* -------------------------------------------------------------------- */
5233 {
5235  wmKeyMap *keymap = NULL;
5236  wmOperator *op = NULL;
5237  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
5238  if (handler_base->type == WM_HANDLER_TYPE_OP) {
5239  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
5240  if (handler->op != NULL) {
5241  /* 'handler->keymap' could be checked too, seems not to be used. */
5242  wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap);
5243  if (keymap_test && keymap_test->modal_items) {
5244  keymap = keymap_test;
5245  op = handler->op;
5246  break;
5247  }
5248  }
5249  }
5250  }
5251  if (keymap == NULL || keymap->modal_items == NULL) {
5252  return false;
5253  }
5254  const EnumPropertyItem *items = keymap->modal_items;
5255 
5256  uiLayout *row = uiLayoutRow(layout, true);
5257  for (int i = 0; items[i].identifier; i++) {
5258  if (!items[i].identifier[0]) {
5259  continue;
5260  }
5261  if ((keymap->poll_modal_item != NULL) &&
5262  (keymap->poll_modal_item(op, items[i].value) == false)) {
5263  continue;
5264  }
5265 
5266  bool show_text = true;
5267 
5268  {
5269  /* Warning: O(n^2). */
5270  wmKeyMapItem *kmi = NULL;
5271  for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
5272  if (kmi->propvalue == items[i].value) {
5273  break;
5274  }
5275  }
5276  if (kmi != NULL) {
5277  if (kmi->val == KM_RELEASE) {
5278  /* Assume release events just disable something which was toggled on. */
5279  continue;
5280  }
5281  if (uiTemplateEventFromKeymapItem(row, items[i].name, kmi, false)) {
5282  show_text = false;
5283  }
5284  }
5285  }
5286  if (show_text) {
5287  char buf[UI_MAX_DRAW_STR];
5288  int available_len = sizeof(buf);
5289  char *p = buf;
5291  op->type, items[i].value, true, UI_MAX_SHORTCUT_STR, &available_len, &p);
5292  p -= 1;
5293  if (p > buf) {
5294  BLI_snprintf(p, available_len, ": %s", items[i].name);
5295  uiItemL(row, buf, 0);
5296  }
5297  }
5298  }
5299  return true;
5300 }
5301 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:985
struct ARegion * CTX_wm_menu(const bContext *C)
Definition: context.c:736
void CTX_data_scene_set(bContext *C, struct Scene *scene)
Definition: context.c:1197
void CTX_wm_menu_set(bContext *C, struct ARegion *menu)
Definition: context.c:996
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
Definition: context.c:1001
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
void CTX_wm_screen_set(bContext *C, struct bScreen *screen)
Definition: context.c:960
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:942
struct ReportList * CTX_wm_reports(const bContext *C)
Definition: context.c:751
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1401
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:973
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
CustomData interface, see also DNA_customdata_types.h.
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition: customdata.c:76
#define G_MAIN
Definition: BKE_global.h:232
@ G_DEBUG_HANDLERS
Definition: BKE_global.h:137
@ G_DEBUG_WM
Definition: BKE_global.h:138
@ G_DEBUG_EVENTS
Definition: BKE_global.h:136
@ G_FLAG_EVENT_SIMULATE
Definition: BKE_global.h:113
void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL()
struct IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:907
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BKE_reports_print(ReportList *reports, ReportType level)
Definition: report.c:282
void BKE_report_print_level_set(ReportList *reports, ReportType level)
Definition: report.c:227
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reports_clear(ReportList *reports)
Definition: report.c:84
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:66
struct Depsgraph * BKE_scene_get_depsgraph(const struct Scene *scene, const struct ViewLayer *view_layer)
void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bmain)
Definition: scene.c:2713
struct Depsgraph * BKE_scene_ensure_depsgraph(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer)
Definition: scene.c:3526
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
void BKE_spacedata_draw_locks(bool set)
Definition: screen.c:547
struct ARegion * BKE_area_find_region_active_win(struct ScrArea *area)
Definition: screen.c:918
struct ARegion * BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y)
Definition: screen.c:933
double BKE_sound_sync_scene(struct Scene *scene)
int BKE_sound_scene_playing(struct Scene *scene)
struct bScreen * BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#define BLI_assert(a)
Definition: BLI_assert.h:58
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:71
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:358
char * BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:323
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:159
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:120
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void * BLI_poptail(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:269
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE int len_manhattan_v2v2_int(const int a[2], const int b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition: rct.c:597
bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y)
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
int BLI_str_utf8_size(const char *p) ATTR_NONNULL()
Definition: string_utf8.c:495
unsigned int uint
Definition: BLI_sys_types.h:83
void BLI_timer_execute(void)
Definition: BLI_timer.c:133
#define ARRAY_SIZE(arr)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define IFACE_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:203
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:201
#define CLOG_STR_INFO_N(clg_ref, level, str)
Definition: CLG_log.h:214
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_make_active(struct Depsgraph *depsgraph)
Definition: depsgraph.cc:344
void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const bool do_time)
void DEG_graph_relations_update(struct Depsgraph *graph)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ ID_RECALC_AUDIO_SEEK
Definition: DNA_ID.h:660
@ IDP_GROUP
Definition: DNA_ID.h:101
These structs are the foundation for all linked lists in the library system.
#define FPS
@ RGN_ALIGN_BOTTOM
@ SCREENFULL
@ AREA_FLAG_ACTIONZONES_UPDATE
@ RGN_FLAG_HIDDEN
#define RGN_TYPE_IS_HEADER_ANY(regiontype)
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_TEMPORARY
@ RGN_TYPE_WINDOW
@ RGN_TYPE_HUD
@ RGN_TYPE_PREVIEW
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ RGN_TYPE_TOOL_PROPS
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_FILE
@ USER_CONTINUOUS_MOUSE
@ USER_EMU_MMB_MOD_OSKEY
@ USER_TOOLTIPS
@ USER_NONUMPAD
@ USER_TWOBUTTONMOUSE
@ NDOF_PAN_YZ_SWAP_AXIS
#define OP_MAX_TYPENAME
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_HANDLED
@ OPERATOR_PASS_THROUGH
@ KMI_REPEAT_IGNORE
@ OP_IS_REPEAT_LAST
@ OP_IS_MODAL_CURSOR_REGION
@ OP_IS_MODAL_GRAB_CURSOR
#define OPERATOR_RETVAL_CHECK(ret)
struct bToolRef bToolRef
struct ScrArea * ED_fileselect_handler_area_find(const struct wmWindow *win, const struct wmOperator *file_operator)
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile)
Definition: filesel.c:548
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, const int temp_win_size[], const bool is_maximized)
void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], bool *is_maximized)
void ED_info_stats_clear(struct ViewLayer *view_layer)
Definition: info_stats.c:439
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:745
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note)
Definition: screen_edit.c:466
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area)
Definition: screen_edit.c:1168
ScrArea * ED_screen_temp_space_open(struct bContext *C, const char *title, int x, int y, int sizex, int sizey, eSpace_Type space_type, int display_type, bool dialog)
Definition: screen_edit.c:1438
#define ED_screen_areas_iter(win, screen, area_name)
Definition: ED_screen.h:189
void ED_area_prevspace(struct bContext *C, ScrArea *area)
Definition: area.c:2515
void ED_region_do_listen(struct wmRegionListenerParams *params)
Definition: area.c:144
int ED_screen_animation_play(struct bContext *C, int sync, int mode)
Definition: screen_ops.c:4641
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph)
Definition: screen_edit.c:1617
void ED_area_exit(struct bContext *C, struct ScrArea *area)
Definition: screen_edit.c:603
bool ED_workspace_layout_delete(struct WorkSpace *workspace, struct WorkSpaceLayout *layout_old, struct bContext *C) ATTR_NONNULL()
bScreen * ED_screen_animation_playing(const struct wmWindowManager *wm)
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2])
Definition: screen_edit.c:719
void ED_area_do_listen(struct wmSpaceTypeListenerParams *params)
Definition: area.c:167
void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep)
void ED_area_do_refresh(struct bContext *C, ScrArea *area)
Definition: area.c:176
bool ED_workspace_delete(struct WorkSpace *workspace, struct Main *bmain, struct bContext *C, struct wmWindowManager *wm) ATTR_NONNULL()
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2])
void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area)
struct AZone * ED_area_azones_update(ScrArea *area, const int mouse_xy[])
bool ED_screen_change(struct bContext *C, struct bScreen *screen)
Change the active screen.
Definition: screen_edit.c:1039
bool ED_undo_is_state_valid(struct bContext *C)
Definition: ed_undo.c:82
void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op)
Definition: ed_undo.c:422
void ED_undo_push_op(struct bContext *C, struct wmOperator *op)
Definition: ed_undo.c:416
void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id)
Definition: ed_util.c:428
void ED_view3d_screen_datamask(const struct bContext *C, const struct Scene *scene, const struct bScreen *screen, struct CustomData_MeshMasks *r_cddata_masks)
GHOST C-API function and type declarations.
@ GHOST_kTrackpadEventMagnify
Definition: GHOST_Types.h:458
@ GHOST_kTrackpadEventSmartMagnify
Definition: GHOST_Types.h:459
@ GHOST_kTrackpadEventRotate
Definition: GHOST_Types.h:456
@ GHOST_kTrackpadEventScroll
Definition: GHOST_Types.h:455
@ GHOST_kEventWheel
Mouse button event.
Definition: GHOST_Types.h:183
@ GHOST_kEventTimer
Definition: GHOST_Types.h:213
@ GHOST_kEventImeComposition
Definition: GHOST_Types.h:216
@ GHOST_kEventCursorMove
Definition: GHOST_Types.h:180
@ GHOST_kEventButtonUp
Mouse button event.
Definition: GHOST_Types.h:182
@ GHOST_kEventTrackpad
Mouse wheel event.
Definition: GHOST_Types.h:184
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:199
@ GHOST_kEventButtonDown
Mouse move event.
Definition: GHOST_Types.h:181
@ GHOST_kEventKeyDown
Trackpad event.
Definition: GHOST_Types.h:191
@ GHOST_kEventImeCompositionStart
Definition: GHOST_Types.h:215
@ GHOST_kEventImeCompositionEnd
Definition: GHOST_Types.h:217
@ GHOST_kEventUnknown
Definition: GHOST_Types.h:178
@ GHOST_kEventKeyUp
Definition: GHOST_Types.h:192
@ GHOST_kNumEventTypes
Definition: GHOST_Types.h:219
@ GHOST_kTabletModeNone
Definition: GHOST_Types.h:101
GHOST_TKey
Definition: GHOST_Types.h:267
@ GHOST_kKeyInsert
Definition: GHOST_Types.h:354
@ GHOST_kKeySemicolon
Definition: GHOST_Types.h:296
@ GHOST_kKeyMediaPlay
Definition: GHOST_Types.h:406
@ GHOST_kKeyZ
Definition: GHOST_Types.h:325
@ GHOST_kKeyQuote
Definition: GHOST_Types.h:277
@ GHOST_kKeyAccentGrave
Definition: GHOST_Types.h:330
@ GHOST_kKeyLeftAlt
Definition: GHOST_Types.h:336
@ GHOST_kKeyRightShift
Definition: GHOST_Types.h:333
@ GHOST_kKeyNumLock
Definition: GHOST_Types.h:343
@ GHOST_kKeyEnter
Definition: GHOST_Types.h:273
@ GHOST_kKeyNumpadSlash
Definition: GHOST_Types.h:377
@ GHOST_kKeyRightArrow
Definition: GHOST_Types.h:347
@ GHOST_kKeyF24
Definition: GHOST_Types.h:403
@ GHOST_kKeyPause
Definition: GHOST_Types.h:352
@ GHOST_kKeyCapsLock
Definition: GHOST_Types.h:342
@ GHOST_kKeyApp
Definition: GHOST_Types.h:340
@ GHOST_kKeyMinus
Definition: GHOST_Types.h:279
@ GHOST_kKeyMediaStop
Definition: GHOST_Types.h:407
@ GHOST_kKeyBackSpace
Definition: GHOST_Types.h:269
@ GHOST_kKey0
Definition: GHOST_Types.h:285
@ GHOST_kKeyDownPage
Definition: GHOST_Types.h:359
@ GHOST_kKeyGrLess
Definition: GHOST_Types.h:339
@ GHOST_kKeyDownArrow
Definition: GHOST_Types.h:349
@ GHOST_kKeyClear
Definition: GHOST_Types.h:272
@ GHOST_kKeyNumpadPeriod
Definition: GHOST_Types.h:372
@ GHOST_kKeyF1
Definition: GHOST_Types.h:380
@ GHOST_kKeyNumpadAsterisk
Definition: GHOST_Types.h:376
@ GHOST_kKeyPrintScreen
Definition: GHOST_Types.h:351
@ GHOST_kKeyLeftControl
Definition: GHOST_Types.h:334
@ GHOST_kKeyLeftBracket
Definition: GHOST_Types.h:327
@ GHOST_kKeyTab
Definition: GHOST_Types.h:270
@ GHOST_kKeyComma
Definition: GHOST_Types.h:278
@ GHOST_kKeyRightBracket
Definition: GHOST_Types.h:328
@ GHOST_kKeyBackslash
Definition: GHOST_Types.h:329
@ GHOST_kKeyOS
Definition: GHOST_Types.h:338
@ GHOST_kKeyLinefeed
Definition: GHOST_Types.h:271
@ GHOST_kKeyRightAlt
Definition: GHOST_Types.h:337
@ GHOST_kKeyPeriod
Definition: GHOST_Types.h:281
@ GHOST_kKeyNumpadPlus
Definition: GHOST_Types.h:374
@ GHOST_kKeyUpPage
Definition: GHOST_Types.h:358
@ GHOST_kKey9
Definition: GHOST_Types.h:294
@ GHOST_kKeyLeftArrow
Definition: GHOST_Types.h:346
@ GHOST_kKeyEqual
Definition: GHOST_Types.h:297
@ GHOST_kKeyHome
Definition: GHOST_Types.h:356
@ GHOST_kKeyNumpad9
Definition: GHOST_Types.h:371
@ GHOST_kKeyEnd
Definition: GHOST_Types.h:357
@ GHOST_kKeyUpArrow
Definition: GHOST_Types.h:348
@ GHOST_kKeyDelete
Definition: GHOST_Types.h:355
@ GHOST_kKeyNumpad0
Definition: GHOST_Types.h:362
@ GHOST_kKeyA
Definition: GHOST_Types.h:300
@ GHOST_kKeyMediaFirst
Definition: GHOST_Types.h:408
@ GHOST_kKeyRightControl
Definition: GHOST_Types.h:335
@ GHOST_kKeyEsc
Definition: GHOST_Types.h:275
@ GHOST_kKeyPlus
Definition: GHOST_Types.h:280
@ GHOST_kKeyScrollLock
Definition: GHOST_Types.h:344
@ GHOST_kKeySlash
Definition: GHOST_Types.h:282
@ GHOST_kKeyNumpadEnter
Definition: GHOST_Types.h:373
@ GHOST_kKeyNumpadMinus
Definition: GHOST_Types.h:375
@ GHOST_kKeyLeftShift
Definition: GHOST_Types.h:332
@ GHOST_kKeyMediaLast
Definition: GHOST_Types.h:409
@ GHOST_kKeySpace
Definition: GHOST_Types.h:276
@ GHOST_kButtonMaskRight
Definition: GHOST_Types.h:168
@ GHOST_kButtonMaskButton4
Definition: GHOST_Types.h:169
@ GHOST_kButtonMaskLeft
Definition: GHOST_Types.h:166
@ GHOST_kButtonMaskButton7
Definition: GHOST_Types.h:173
@ GHOST_kButtonMaskButton6
Definition: GHOST_Types.h:172
@ GHOST_kButtonMaskButton5
Definition: GHOST_Types.h:170
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Platform independent time functions.
#define RNA_STRUCT_BEGIN(sptr, prop)
Definition: RNA_access.h:1274
#define RNA_STRUCT_END
Definition: RNA_access.h:1294
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
uiBlock * UI_region_block_find_mouse_over(const struct ARegion *region, const int xy[2], bool only_clip)
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
void uiItemL(uiLayout *layout, const char *name, int icon)
void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL()
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
#define UI_DPI_FAC
Definition: UI_interface.h:309
#define UI_MAX_SHORTCUT_STR
Definition: UI_interface.h:92
bool uiTemplateEventFromKeymapItem(struct uiLayout *layout, const char *text, const struct wmKeyMapItem *kmi, bool text_fallback)
@ WM_HANDLER_BLOCKING
Definition: WM_api.h:314
@ WM_HANDLER_DO_FREE
Definition: WM_api.h:318
@ WM_HANDLER_ACCEPT_DBL_CLICK
Definition: WM_api.h:315
void(* wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata)
Definition: WM_api.h:283
struct wmKeyMap *() wmEventHandler_KeymapDynamicFn(wmWindowManager *wm, struct wmEventHandler_Keymap *handler) ATTR_WARN_UNUSED_RESULT
Definition: WM_api.h:252
bool(* EventHandlerPoll)(const ARegion *region, const struct wmEvent *event)
Definition: WM_api.h:240
int(* wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata)
Definition: WM_api.h:282
@ WM_GIZMO_HIDDEN_KEYMAP
@ WM_GIZMO_EVENT_HANDLE_ALL
@ WM_GIZMO_OPERATOR_TOOL_INIT
@ WM_GIZMO_NO_TOOLTIP
@ WM_GIZMOGROUPTYPE_TOOL_INIT
@ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP
#define WM_TOOLSYSTEM_SPACE_MASK
Definition: WM_toolsystem.h:43
#define KM_MOD_SECOND
Definition: WM_types.h:234
#define NC_WINDOW
Definition: WM_types.h:277
#define ND_FILEREAD
Definition: WM_types.h:311
#define NC_GEOM
Definition: WM_types.h:294
#define WM_UI_HANDLER_CONTINUE
Definition: WM_types.h:250
#define ND_SPACE_INFO
Definition: WM_types.h:416
struct CLG_LogRef * WM_LOG_EVENTS
struct CLG_LogRef * WM_LOG_HANDLERS
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_LOCK_BYPASS
Definition: WM_types.h:178
@ OPTYPE_UNDO_GROUPED
Definition: WM_types.h:180
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:161
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ OPTYPE_GRAB_CURSOR_X
Definition: WM_types.h:163
@ OPTYPE_GRAB_CURSOR_Y
Definition: WM_types.h:165
#define NC_WM
Definition: WM_types.h:276
#define KM_CLICK
Definition: WM_types.h:244
#define NOTE_ACTION
Definition: WM_types.h:461
#define KM_ANY
Definition: WM_types.h:240
@ WM_OP_INVOKE_REGION_WIN
Definition: WM_types.h:198
@ WM_OP_EXEC_REGION_WIN
Definition: WM_types.h:205
@ WM_OP_INVOKE_SCREEN
Definition: WM_types.h:202
@ WM_OP_INVOKE_AREA
Definition: WM_types.h:201
@ WM_OP_EXEC_REGION_PREVIEW
Definition: WM_types.h:207
@ WM_OP_EXEC_SCREEN
Definition: WM_types.h:209
@ WM_OP_INVOKE_REGION_PREVIEW
Definition: WM_types.h:200
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:197
@ WM_OP_EXEC_REGION_CHANNELS
Definition: WM_types.h:206
@ WM_OP_INVOKE_REGION_CHANNELS
Definition: WM_types.h:199
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:204
@ WM_OP_EXEC_AREA
Definition: WM_types.h:208
#define ND_DATACHANGED
Definition: WM_types.h:313
#define NC_SCREEN
Definition: WM_types.h:278
#define KM_CLICK_DRAG
Definition: WM_types.h:246
#define NC_SCENE
Definition: WM_types.h:279
#define ND_WORKSPACE_DELETE
Definition: WM_types.h:329
#define NOTE_DATA
Definition: WM_types.h:308
@ WM_CURSOR_WRAP_X
Definition: WM_types.h:186
@ WM_CURSOR_WRAP_XY
Definition: WM_types.h:188
@ WM_CURSOR_WRAP_Y
Definition: WM_types.h:187
@ WM_CURSOR_WRAP_NONE
Definition: WM_types.h:185
#define KM_PRESS
Definition: WM_types.h:242
#define ND_SPACE_INFO_REPORT
Definition: WM_types.h:415
#define ND_FRAME
Definition: WM_types.h:334
#define KM_TEXTINPUT
Definition: WM_types.h:237
#define KM_NOTHING
Definition: WM_types.h:241
#define NOTE_SUBTYPE
Definition: WM_types.h:438
#define KM_MOD_FIRST
Definition: WM_types.h:233
#define ND_FILESAVE
Definition: WM_types.h:312
#define ND_WORKSPACE_SET
Definition: WM_types.h:328
#define NOTE_CATEGORY
Definition: WM_types.h:275
#define ND_LAYOUTBROWSE
Definition: WM_types.h:321
#define NC_OBJECT
Definition: WM_types.h:280
#define ND_LAYOUTDELETE
Definition: WM_types.h:322
struct CLG_LogRef * WM_LOG_OPERATORS
wmProgress
Definition: WM_types.h:651
#define KM_DBL_CLICK
Definition: WM_types.h:245
#define WM_UI_HANDLER_BREAK
Definition: WM_types.h:251
#define NC_SPACE
Definition: WM_types.h:293
#define KM_RELEASE
Definition: WM_types.h:243
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
unsigned int U
Definition: btGjkEpa3.h:78
double time
Scene scene
const Depsgraph * depsgraph
void * user_data
#define str(s)
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong state[N]
bool isfinite(uchar)
Definition: image.cpp:44
static void area(int d1, int d2, int e1, int e2, float weights[2])
static GPUContext * wrap(Context *ctx)
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:6550
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1145
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3641
int RNA_property_flag(PropertyRNA *prop)
Definition: rna_access.c:1192
struct SELECTID_Context context
Definition: select_engine.c:47
bool clip_gizmo_events_by_ui
Definition: BKE_screen.h:231
ListBase handlers
short alignment
short regiontype
struct wmGizmoMap * gizmo_map
struct ARegionType * type
struct CursorKeymapInfo_State::@1153 modifiers
char text[3][2][128]
struct CursorKeymapInfo_State state
const char * identifier
Definition: RNA_types.h:446
GHOST_TButtonMask button
Definition: GHOST_Types.h:443
GHOST_TabletData tablet
Definition: GHOST_Types.h:445
GHOST_TabletData tablet
Definition: GHOST_Types.h:438
GHOST_TTrackpadEventSubTypes subtype
Definition: GHOST_Types.h:464
GHOST_TTabletMode Active
Definition: GHOST_Types.h:113
Definition: DNA_ID.h:273
int recalc
Definition: DNA_ID.h:295
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase wm
Definition: BKE_main.h:175
ListBase screens
Definition: BKE_main.h:161
void * data
Definition: RNA_types.h:52
struct wmTimer * reporttimer
struct CustomData_MeshMasks customdata_mask
struct RenderData r
struct CustomData_MeshMasks customdata_mask_modal
ListBase areabase
ListBase spacedata
bScreen * full
struct wmOperator * op
Wrapper for bScreen.
char do_draw_drag
ListBase regionbase
char skip_handling
struct wmTooltipState * tool_tip
ListBase areabase
struct ARegion * active_region
int space_type
Definition: WM_toolsystem.h:47
bToolRef_Runtime * runtime
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
wmEventHandler head
struct wmGizmoMap * gizmo_map
wmEventHandler_KeymapDynamicFn * keymap_fn
void(* post_fn)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data)
struct wmEventHandler_KeymapPost post
struct wmEventHandler_KeymapDynamic dynamic
struct bToolRef * keymap_tool
wmEventHandler head
struct wmWindow * win
struct ScrArea * area
struct ARegion * region
struct wmEventHandler_Op::@1171 context
struct wmEventHandler_UI::@1170 context
wmUIHandlerRemoveFunc remove_fn
struct ARegion * menu
wmUIHandlerFunc handle_fn
struct ScrArea * area
struct ARegion * region
wmEventHandler head
EventHandlerPoll poll
enum eWM_EventHandlerType type
int prevclickx
Definition: WM_types.h:608
int y
Definition: WM_types.h:581
short custom
Definition: WM_types.h:627
short shift
Definition: WM_types.h:618
short ctrl
Definition: WM_types.h:618
short val
Definition: WM_types.h:579
int prevclicky
Definition: WM_types.h:608
double prevclicktime
Definition: WM_types.h:606
short oskey
Definition: WM_types.h:618
short customdatafree
Definition: WM_types.h:628
char utf8_buf[6]
Definition: WM_types.h:589
short keymodifier
Definition: WM_types.h:620
short prevtype
Definition: WM_types.h:602
int prevy
Definition: WM_types.h:614
wmTabletData tablet
Definition: WM_types.h:623
int x
Definition: WM_types.h:581
short prevval
Definition: WM_types.h:604
short alt
Definition: WM_types.h:618
int prevx
Definition: WM_types.h:614
short type
Definition: WM_types.h:577
char ascii
Definition: WM_types.h:591
char is_repeat
Definition: WM_types.h:599
void * customdata
Definition: WM_types.h:631
eWM_GizmoFlagGroupTypeFlag flag
struct wmKeyMap * keymap
struct wmGizmoMapType_Params gzmap_params
struct wmGizmoGroupType * type
bool use_fallback_keymap
struct wmGizmoGroup * parent_gzgroup
int highlight_part
struct wmKeyMap * keymap
eWM_GizmoFlag flag
struct PointerRNA * ptr
struct wmKeyMapItem * next
bool(* poll_modal_item)(const struct wmOperator *op, int value)
const void * modal_items
unsigned int data
Definition: WM_types.h:260
unsigned int action
Definition: WM_types.h:260
unsigned int category
Definition: WM_types.h:260
const struct wmWindow * window
Definition: WM_types.h:258
unsigned int subtype
Definition: WM_types.h:260
void * reference
Definition: WM_types.h:262
struct wmOperatorTypeMacro * next
struct IDProperty * properties
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
struct wmKeyMap * modalkeymap
Definition: WM_types.h:820
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:787
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:744
bool(* pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:823
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
ListBase macro
Definition: WM_types.h:817
struct ReportList * reports
IDProperty * properties
struct wmOperator * next
struct wmOperator * prev
struct wmOperatorType * type
struct PointerRNA * ptr
struct wmOperator * opm
struct wmPaintCursor * next
Definition: wm.h:35
bool(* poll)(struct bContext *C)
Definition: wm.h:39
struct wmWindow * window
Definition: BKE_screen.h:142
struct wmWindow * window
Definition: BKE_screen.h:71
char is_motion_absolute
Definition: WM_types.h:547
float pressure
Definition: WM_types.h:541
float x_tilt
Definition: WM_types.h:543
float y_tilt
Definition: WM_types.h:545
void * customdata
Definition: WM_types.h:702
bool exit_on_event
Definition: WM_types.h:980
struct wmTimer * timer
Definition: WM_types.h:966
int event_xy[2]
Definition: WM_types.h:982
struct wmMsgBus * message_bus
struct ReportList reports
struct wmKeyConfig * userconf
struct wmWindow * winactive
struct wmEvent * eventstate
struct wmIMEData * ime_data
char event_queue_check_drag_handled
ScrAreaMap global_areas
double PIL_check_seconds_timer(void)
Definition: time.c:80
ccl_device_inline int mod(int x, int m)
Definition: util_math.h:405
#define SET(a, b, c, d, k, s, Ti)
#define G(x, y, z)
void wm_operator_register(bContext *C, wmOperator *op)
Definition: wm.c:376
void WM_operator_free(wmOperator *op)
Definition: wm.c:292
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
Definition: wm_cursors.c:311
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
Definition: wm_cursors.c:246
void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
Definition: wm_cursors.c:283
void wm_drags_check_ops(bContext *C, const wmEvent *event)
Definition: wm_dragdrop.c:301
void WM_drag_free_list(struct ListBase *lb)
Definition: wm_dragdrop.c:212
static ListBase dropboxes
Definition: wm_dragdrop.c:61
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(region))
Definition: wm_draw.c:1025
void WM_event_print(const wmEvent *event)
bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
int WM_userdef_event_map(int kmitype)
float wm_pressure_curve(float pressure)
int WM_operator_repeat_last(bContext *C, wmOperator *op)
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout)
wmEventHandler_UI * WM_event_add_ui_handler(const bContext *C, ListBase *handlers, wmUIHandlerFunc handle_fn, wmUIHandlerRemoveFunc remove_fn, void *user_data, const char flag)
static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, const bool store)
static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler_Op *handler, const wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
static ScrArea * area_event_inside(bContext *C, const int xy[2])
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
static wmKeyMapItem * wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, wmOperator *op, const wmEvent *event)
static void wm_eventemulation(wmEvent *event, bool test_only)
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
static void wm_event_cursor_store(struct CursorKeymapInfo_State *state, const wmEvent *event, short space_type, short region_type, const bToolRef *tref)
void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void wm_event_do_handlers(bContext *C)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
wmKeyMap * WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler)
void WM_window_status_area_tag_redraw(wmWindow *win)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, short context, struct IDProperty *properties)
ScrArea * WM_window_status_area_find(wmWindow *win, bScreen *screen)
static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state)
static wmEvent * wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
static int convert_key(GHOST_TKey key)
wmEvent * wm_event_add(wmWindow *win, const wmEvent *event_to_add)
void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
static int wm_handlers_do_keymap_with_gizmo_handler(bContext *C, wmEvent *event, ListBase *handlers, wmEventHandler_Gizmo *handler, wmGizmoGroup *gzgroup, wmKeyMap *keymap, const bool do_debug_handler, bool *r_keymap_poll)
void WM_report_banners_cancel(Main *bmain)
static bool wm_event_inside_region(const wmEvent *event, const ARegion *region)
void WM_event_remove_area_handler(ListBase *handlers, void *area)
struct wmEventHandler_Keymap * WM_event_add_keymap_handler_dynamic(ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
static bool handler_region_v2d_mask_test(const ARegion *region, const wmEvent *event)
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
static void wm_event_modalkeymap_begin(const bContext *C, wmOperator *op, wmEvent *event, struct wmEvent_ModalMapStore *event_backup)
static int wm_action_not_handled(int action)
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
const char * WM_window_cursor_keymap_status_get(const wmWindow *win, int button_index, int type_index)
void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wmKeyMapItem * WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wmEvent *event)
static void wm_event_modalkeymap_end(wmEvent *event, const struct wmEvent_ModalMapStore *event_backup)
static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state)
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
void WM_report_banner_show(void)
static wmOperator * wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports)
void WM_event_free_ui_handler_all(bContext *C, ListBase *handlers, wmUIHandlerFunc handle_fn, wmUIHandlerRemoveFunc remove_fn)
wmKeyMapItem * WM_event_match_keymap_item_from_handlers(bContext *C, wmWindowManager *wm, ListBase *handlers, const wmEvent *event)
static int wm_handlers_do_keymap_with_keymap_handler(bContext *C, wmEvent *event, ListBase *handlers, wmEventHandler_Keymap *handler, wmKeyMap *keymap, const bool do_debug_handler)
int WM_operator_repeat(bContext *C, wmOperator *op)
void wm_event_free_all(wmWindow *win)
void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
static void wm_region_mouse_co(bContext *C, wmEvent *event)
int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
int WM_operator_call_notest(bContext *C, wmOperator *op)
void WM_report(ReportType type, const char *message)
bool WM_operator_check_ui_empty(wmOperatorType *ot)
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
void WM_reportf(ReportType type, const char *format,...)
wmEvent * WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
wmEvent * wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
int WM_operator_call_py(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties, ReportList *reports, const bool is_undo)
static bool wm_event_is_double_click(const wmEvent *event)
static wmWindow * wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
static void wm_event_free_last(wmWindow *win)
static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, const bool poll_only, bool use_last_properties)
#define PRINT
void WM_operator_region_active_win_set(bContext *C)
void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
static ARegion * region_event_inside(bContext *C, const int xy[2])
wmEventHandler_Keymap * WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap)
static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
static void wm_event_handler_ui_cancel(bContext *C)
static int wm_operator_exec_notest(bContext *C, wmOperator *op)
static void wm_add_reports(ReportList *reports)
static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, const short context, const bool poll_only, wmEvent *event)
wmKeyMap * WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, wmEventHandler_Keymap *handler)
void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc handle_fn, wmUIHandlerRemoveFunc remove_fn, void *user_data, const bool postpone)
int WM_operator_call(bContext *C, wmOperator *op)
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
wmEventHandler_Keymap * WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority))
static void wm_notifier_clear(wmNotifier *note)
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
wmEventHandler_Keymap * WM_event_add_keymap_handler_poll(ListBase *handlers, wmKeyMap *keymap, EventHandlerPoll poll)
static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHandler_Op *handler, int val)
static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
void WM_main_remove_notifier_reference(const void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
static void wm_event_execute_timers(bContext *C)
void wm_event_handler_ui_cancel_ex(bContext *C, wmWindow *win, ARegion *region, bool reactivate_button)
static int wm_handler_ui_call(bContext *C, wmEventHandler_UI *handler, const wmEvent *event, int always_pass)
static void wm_paintcursor_test(bContext *C, const wmEvent *event)
static const wmTabletData wm_event_tablet_data_default
void wm_event_free(wmEvent *event)
static bool event_or_prev_in_rect(const wmEvent *event, const rcti *rect)
static int wm_handlers_do_gizmo_handler(bContext *C, wmWindowManager *wm, wmEventHandler_Gizmo *handler, wmEvent *event, ListBase *handlers, const bool do_debug_handler)
void WM_event_set_keymap_handler_post_callback(wmEventHandler_Keymap *handler, void(keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data), void *user_data)
static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
wmKeyMap * WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandler_Keymap *handler)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval)
void wm_event_free_handler(wmEventHandler *handler)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
void wm_event_do_notifiers(bContext *C)
static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler_base, wmEvent *event, PointerRNA *properties, const char *kmi_idname)
static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
static int wm_event_always_pass(const wmEvent *event)
static wmEvent * wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int deltax, int deltay)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
void WM_event_add_mousemove(wmWindow *win)
static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
#define WM_HANDLER_HANDLED
@ WM_HANDLER_TYPE_UI
@ WM_HANDLER_TYPE_OP
@ WM_HANDLER_TYPE_KEYMAP
@ WM_HANDLER_TYPE_GIZMO
@ WM_HANDLER_TYPE_DROPBOX
#define WM_HANDLER_BREAK
#define WM_HANDLER_CONTINUE
#define WM_HANDLER_MODAL
#define ISMOUSE_BUTTON(event_type)
#define ISTWEAK(event_type)
@ EVT_TABLET_NONE
@ EVT_TABLET_STYLUS
@ EVT_TABLET_ERASER
@ EVT_PAD8
@ EVT_PAD2
@ MOUSEPAN
@ BUTTON7MOUSE
@ RIGHTMOUSE
@ EVT_SIXKEY
@ EVT_BUT_CANCEL
@ EVT_QUOTEKEY
@ EVT_PADPERIOD
@ TIMER
@ EVT_PAD4
@ EVT_PADASTERKEY
@ BUTTON6MOUSE
@ EVT_PLUSKEY
@ EVT_PAD0
@ EVT_FOURKEY
@ EVT_MODAL_MAP
@ EVT_RIGHTCTRLKEY
@ WM_IME_COMPOSITE_EVENT
@ MOUSEZOOM
@ EVT_F1KEY
@ EVT_PERIODKEY
@ EVT_PADSLASHKEY
@ EVT_COMMAKEY
@ EVT_MEDIAPLAY
@ EVT_LEFTBRACKETKEY
@ EVT_MEDIAFIRST
@ EVT_ZEROKEY
@ EVT_PAD9
@ EVT_DELKEY
@ EVT_SEVENKEY
@ EVT_TABKEY
@ EVT_DOWNARROWKEY
@ EVT_MEDIASTOP
@ EVT_AKEY
@ EVT_PAD3
@ EVT_MINUSKEY
@ MOUSEROTATE
@ WHEELUPMOUSE
@ EVT_PAGEUPKEY
@ EVT_OSKEY
@ EVT_TWEAK_M
@ EVT_PAGEDOWNKEY
@ EVT_LEFTCTRLKEY
@ TABLET_ERASER
@ EVT_EQUALKEY
@ EVT_RIGHTARROWKEY
@ EVT_PADENTER
@ EVT_NINEKEY
@ EVT_SPACEKEY
@ EVT_CAPSLOCKKEY
@ BUTTON4MOUSE
@ WHEELDOWNMOUSE
@ EVT_PAD6
@ EVT_PAD5
@ EVT_HOMEKEY
@ TABLET_STYLUS
@ EVENT_NONE
@ MOUSEMOVE
@ EVT_FILESELECT
@ EVT_RIGHTBRACKETKEY
@ EVT_UNKNOWNKEY
@ WM_IME_COMPOSITE_END
@ EVT_ENDKEY
@ EVT_RIGHTALTKEY
@ EVT_MEDIALAST
@ WM_IME_COMPOSITE_START
@ EVT_LINEFEEDKEY
@ EVT_TWEAK_R
@ MOUSESMARTZOOM
@ NDOF_BUTTON_NONE
@ EVT_BACKSLASHKEY
@ EVT_FIVEKEY
@ EVT_APPKEY
@ EVT_ACCENTGRAVEKEY
@ EVT_PADMINUS
@ EVT_ONEKEY
@ EVT_UPARROWKEY
@ LEFTMOUSE
@ EVT_SLASHKEY
@ EVT_EIGHTKEY
@ EVT_LEFTARROWKEY
@ NDOF_MOTION
@ EVT_INSERTKEY
@ MIDDLEMOUSE
@ TIMERREPORT
@ EVT_LEFTALTKEY
@ EVT_ESCKEY
@ EVT_THREEKEY
@ EVT_BACKSPACEKEY
@ EVT_TWEAK_L
@ INBETWEEN_MOUSEMOVE
@ EVT_GIZMO_UPDATE
@ EVT_DROP
@ EVT_PAD1
@ EVT_TWOKEY
@ EVT_GRLESSKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_PAUSEKEY
@ EVT_PAD7
@ EVT_LEFTSHIFTKEY
@ EVT_PADPLUSKEY
@ WINDEACTIVATE
@ EVT_SEMICOLONKEY
@ EVT_RETKEY
@ BUTTON5MOUSE
#define ISMOUSE_WHEEL(event_type)
@ EVT_DATA_NDOF_MOTION
@ EVT_DATA_DRAGDROP
@ EVT_DATA_TIMER
#define ISKEYMODIFIER(event_type)
#define ISTIMER(event_type)
#define ISMOUSE_GESTURE(event_type)
#define ISKEYBOARD(event_type)
@ EVT_FILESELECT_FULL_OPEN
@ EVT_FILESELECT_CANCEL
@ EVT_FILESELECT_EXTERNAL_CANCEL
@ EVT_FILESELECT_EXEC
#define ISMOUSE(event_type)
PointerRNA * ptr
Definition: wm_files.c:3157
void wm_test_autorun_warning(bContext *C)
Definition: wm_files.c:3196
wmOperatorType * ot
Definition: wm_files.c:3156
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
void WM_gizmogroup_ensure_init(const bContext *C, wmGizmoGroup *gzgroup)
bool WM_gizmo_group_type_ensure_ptr_ex(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type)
bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
wmGizmoGroup * WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt, ARegion *region)
wmGizmoGroupType * WM_gizmogrouptype_find(const char *idname, bool quiet)
wmGizmoMapType * WM_gizmomaptype_ensure(const struct wmGizmoMapType_Params *gzmap_params)
bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:244
wmGizmo * wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandler_Op *handler)
Definition: wm_gizmo_map.c:810
bool wm_gizmomap_highlight_set(wmGizmoMap *gzmap, const bContext *C, wmGizmo *gz, int part)
Definition: wm_gizmo_map.c:999
struct ARegion * WM_gizmomap_tooltip_init(struct bContext *C, struct ARegion *region, int *UNUSED(r_pass), double *UNUSED(pass_delay), bool *r_exit_on_event)
void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:323
wmGizmoGroup * WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname)
Definition: wm_gizmo_map.c:219
wmGizmo * wm_gizmomap_highlight_find(wmGizmoMap *gzmap, bContext *C, const wmEvent *event, int *r_part)
Definition: wm_gizmo_map.c:724
void WM_gizmoconfig_update(struct Main *bmain)
const ListBase * WM_gizmomap_group_list(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:239
wmGizmo * wm_gizmomap_modal_get(wmGizmoMap *gzmap)
void wm_gizmomap_handler_context_gizmo(bContext *UNUSED(C), wmEventHandler_Gizmo *UNUSED(handler))
Definition: wm_gizmo_map.c:983
void WM_keyconfig_update(wmWindowManager *wm)
Definition: wm_keymap.c:1781
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
Definition: wm_keymap.c:1895
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
Definition: wm_keymap.c:451
wmKeyMap * WM_keymap_list_find_spaceid_or_empty(ListBase *lb, const char *idname, int spaceid, int regionid)
Definition: wm_keymap.c:836
char * WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot, const int propvalue, const bool compact, const int max_len, int *r_available_len, char **r_result)
Definition: wm_keymap.c:1270
void WM_msg_id_update(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst)
void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
const char * WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
char * WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, const bool macro_args)
Definition: wm_operators.c:303
bool WM_operator_last_properties_store(wmOperator *op)
Definition: wm_operators.c:782
bool WM_operator_last_properties_init(wmOperator *op)
Definition: wm_operators.c:767
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:584
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:711
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:620
wmOperator * WM_operator_last_redo(const bContext *C)
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy)
Definition: wm_stereo.c:184
void WM_toolsystem_ref_properties_init_for_keymap(bToolRef *tref, PointerRNA *dst_ptr, PointerRNA *src_ptr, wmOperatorType *ot)
bToolRef * WM_toolsystem_ref_find(WorkSpace *workspace, const bToolKey *tkey)
Definition: wm_toolsystem.c:97
int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *area, int space_type)
struct bToolRef * WM_toolsystem_ref_from_context(struct bContext *C)
Definition: wm_toolsystem.c:71
void WM_tooltip_clear(bContext *C, wmWindow *win)
Definition: wm_tooltip.c:94
void WM_tooltip_init(bContext *C, wmWindow *win)
Definition: wm_tooltip.c:109
void WM_tooltip_timer_init(bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init)
Definition: wm_tooltip.c:76
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1669
int WM_window_pixels_y(const wmWindow *win)
Definition: wm_window.c:2136
void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
Definition: wm_window.c:2340
void wm_window_title(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:440
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
Definition: wm_window.c:2359
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:389
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2372
bool WM_window_find_under_cursor(const wmWindowManager *wm, const wmWindow *win_ignore, const wmWindow *win, const int mval[2], wmWindow **r_win, int r_mval[2])
Definition: wm_window.c:1922
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:1054
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Definition: wm_window.c:2286
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
Definition: wm_window.c:2335
bool WM_window_is_temp_screen(const wmWindow *win)
Definition: wm_window.c:2383
int WM_window_pixels_x(const wmWindow *win)
Definition: wm_window.c:2130
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2249
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632
void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
Definition: wm_window.c:986