Blender  V3.3
wm_event_system.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2007 Blender Foundation. All rights reserved. */
3 
12 #include <cmath>
13 #include <cstdlib>
14 #include <cstring>
15 
16 #include "DNA_listBase.h"
17 #include "DNA_scene_types.h"
18 #include "DNA_screen_types.h"
19 #include "DNA_userdef_types.h"
21 
22 #include "MEM_guardedalloc.h"
23 
24 #include "CLG_log.h"
25 
26 #include "GHOST_C-api.h"
27 
28 #include "BLI_blenlib.h"
29 #include "BLI_dynstr.h"
30 #include "BLI_math.h"
31 #include "BLI_timer.h"
32 #include "BLI_utildefines.h"
33 
34 #include "BKE_context.h"
35 #include "BKE_customdata.h"
36 #include "BKE_global.h"
37 #include "BKE_idprop.h"
38 #include "BKE_lib_remap.h"
39 #include "BKE_main.h"
40 #include "BKE_report.h"
41 #include "BKE_scene.h"
42 #include "BKE_screen.h"
43 #include "BKE_workspace.h"
44 
45 #include "BKE_sound.h"
46 
47 #include "BLT_translation.h"
48 
49 #include "ED_asset.h"
50 #include "ED_fileselect.h"
51 #include "ED_info.h"
52 #include "ED_render.h"
53 #include "ED_screen.h"
54 #include "ED_undo.h"
55 #include "ED_util.h"
56 #include "ED_view3d.h"
57 
58 #include "RNA_access.h"
59 
60 #include "UI_interface.h"
61 
62 #include "PIL_time.h"
63 
64 #include "WM_api.h"
65 #include "WM_message.h"
66 #include "WM_toolsystem.h"
67 #include "WM_types.h"
68 
69 #include "wm.h"
70 #include "wm_event_system.h"
71 #include "wm_event_types.h"
72 #include "wm_surface.h"
73 #include "wm_window.h"
74 
75 #include "DEG_depsgraph.h"
76 #include "DEG_depsgraph_query.h"
77 
90 #define USE_GIZMO_MOUSE_PRIORITY_HACK
91 
92 static void wm_notifier_clear(wmNotifier *note);
93 
96  PointerRNA *properties,
97  ReportList *reports,
99  const bool poll_only,
100  const wmEvent *event);
101 
104 static void wm_operator_free_for_fileselect(wmOperator *file_operator);
105 
107  wmEvent *event_state,
108  const bool is_keyboard,
109  const bool check_double_click);
110 
111 /* -------------------------------------------------------------------- */
116  const wmEvent *event_to_add,
117  const wmEvent *event_to_add_after)
118 {
119  wmEvent *event = MEM_new<wmEvent>(__func__);
120 
121  *event = *event_to_add;
122 
123  if (event_to_add_after == nullptr) {
124  BLI_addtail(&win->event_queue, event);
125  }
126  else {
127  /* NOTE: strictly speaking this breaks const-correctness,
128  * however we're only changing 'next' member. */
129  BLI_insertlinkafter(&win->event_queue, (void *)event_to_add_after, event);
130  }
131  return event;
132 }
133 
134 wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
135 {
136  return wm_event_add_ex(win, event_to_add, nullptr);
137 }
138 
139 wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
140 {
141  if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) {
143  return nullptr;
144  }
145  wmEvent *event = wm_event_add(win, event_to_add);
146 
147  /* Logic for setting previous value is documented on the #wmEvent struct,
148  * see #wm_event_add_ghostevent for the implementation of logic this follows. */
149  copy_v2_v2_int(win->eventstate->xy, event->xy);
150 
151  if (event->type == MOUSEMOVE) {
153  copy_v2_v2_int(event->prev_xy, win->eventstate->xy);
154  }
155  else if (ISKEYBOARD_OR_BUTTON(event->type)) {
156  wm_event_state_update_and_click_set_ex(event, win->eventstate, ISKEYBOARD(event->type), false);
157  }
158  return event;
159 }
160 
161 static void wm_event_custom_free(wmEvent *event)
162 {
163  if ((event->customdata && event->customdata_free) == 0) {
164  return;
165  }
166 
167  /* NOTE: pointer to #ListBase struct elsewhere. */
168  if (event->custom == EVT_DATA_DRAGDROP) {
169  ListBase *lb = static_cast<ListBase *>(event->customdata);
170  WM_drag_free_list(lb);
171  }
172  else {
173  MEM_freeN(event->customdata);
174  }
175 }
176 
177 static void wm_event_custom_clear(wmEvent *event)
178 {
179  event->custom = 0;
180  event->customdata = nullptr;
181  event->customdata_free = false;
182 }
183 
184 void wm_event_free(wmEvent *event)
185 {
186 #ifndef NDEBUG
187  /* Don't use assert here because it's fairly harmless in most cases,
188  * more an issue of correctness, something we should avoid in general. */
189  if ((event->flag & WM_EVENT_IS_REPEAT) && !ISKEYBOARD(event->type)) {
190  printf("%s: 'is_repeat=true' for non-keyboard event, this should not happen.\n", __func__);
191  WM_event_print(event);
192  }
193  if (ISMOUSE_MOTION(event->type) && (event->val != KM_NOTHING)) {
194  printf("%s: 'val != NOTHING' for a cursor motion event, this should not happen.\n", __func__);
195  WM_event_print(event);
196  }
197 #endif
198 
199  wm_event_custom_free(event);
200 
201  MEM_freeN(event);
202 }
203 
205 static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
206 {
207  /* Don't rely on this pointer being valid,
208  * callers should behave as if the memory has been freed.
209  * As this function should be interchangeable with #wm_event_free. */
210 #ifndef NDEBUG
211  {
212  wmEvent *event_copy = static_cast<wmEvent *>(MEM_dupallocN(event));
213  MEM_freeN(event);
214  event = event_copy;
215  }
216 #endif
217 
218  if (win->event_last_handled) {
220  }
221  /* Don't store custom data in the last handled event as we don't have control how long this event
222  * will be stored and the referenced data may become invalid (also it's not needed currently). */
223  wm_event_custom_free(event);
224  wm_event_custom_clear(event);
225  win->event_last_handled = event;
226 }
227 
228 static void wm_event_free_last(wmWindow *win)
229 {
230  wmEvent *event = static_cast<wmEvent *>(BLI_poptail(&win->event_queue));
231  if (event != nullptr) {
232  wm_event_free(event);
233  }
234 }
235 
237 {
238  wmEvent *event;
239  while ((event = static_cast<wmEvent *>(BLI_pophead(&win->event_queue)))) {
240  wm_event_free(event);
241  }
242 }
243 
245 {
246  *event = *(win->eventstate);
247 }
248 
251 /* -------------------------------------------------------------------- */
255 static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
256 {
257  LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) {
258  if ((note->category | note->data | note->subtype | note->action) == type &&
259  note->reference == reference) {
260  return true;
261  }
262  }
263 
264  return false;
265 }
266 
267 void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
268 {
269  if (wm_test_duplicate_notifier(wm, type, reference)) {
270  return;
271  }
272 
273  wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
274 
275  BLI_addtail(&wm->notifier_queue, note);
276 
277  note->window = win;
278 
279  note->category = type & NOTE_CATEGORY;
280  note->data = type & NOTE_DATA;
281  note->subtype = type & NOTE_SUBTYPE;
282  note->action = type & NOTE_ACTION;
283 
284  note->reference = reference;
285 }
286 
287 /* XXX: in future, which notifiers to send to other windows? */
288 void WM_event_add_notifier(const bContext *C, uint type, void *reference)
289 {
291 }
292 
293 void WM_main_add_notifier(unsigned int type, void *reference)
294 {
295  Main *bmain = G_MAIN;
296  wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
297 
298  if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
299  return;
300  }
301 
302  wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
303 
304  BLI_addtail(&wm->notifier_queue, note);
305 
306  note->category = type & NOTE_CATEGORY;
307  note->data = type & NOTE_DATA;
308  note->subtype = type & NOTE_SUBTYPE;
309  note->action = type & NOTE_ACTION;
310 
311  note->reference = reference;
312 }
313 
314 void WM_main_remove_notifier_reference(const void *reference)
315 {
316  Main *bmain = G_MAIN;
317  wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
318 
319  if (wm) {
321  if (note->reference == reference) {
322  /* Don't remove because this causes problems for #wm_event_do_notifiers
323  * which may be looping on the data (deleting screens). */
324  wm_notifier_clear(note);
325  }
326  }
327 
328  /* Remap instead. */
329 #if 0
330  if (wm->message_bus) {
331  WM_msg_id_remove(wm->message_bus, reference);
332  }
333 #endif
334  }
335 }
336 
337 static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
338 {
339  ED_assetlist_storage_id_remap(old_id, new_id);
340 }
341 
342 static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
343 {
344  wmMsgBus *mbus = static_cast<wmMsgBus *>(user_data);
345  if (new_id != nullptr) {
346  WM_msg_id_update(mbus, old_id, new_id);
347  }
348  else {
349  WM_msg_id_remove(mbus, old_id);
350  }
351 }
352 
353 void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
354 {
355  Main *bmain = G_MAIN;
356 
357  LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
358  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
359  LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
360  ED_spacedata_id_remap(area, sl, mappings);
361  }
362  }
363  }
364 
365  BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr);
366 
367  wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
368  if (wm && wm->message_bus) {
370  }
371 }
372 
373 static void wm_notifier_clear(wmNotifier *note)
374 {
375  /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */
376  memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
377 }
378 
379 void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
380 {
382  /* The whole idea of locked interface is to prevent viewport and whatever thread from
383  * modifying the same data. Because of this, we can not perform dependency graph update. */
384  if (wm->is_interface_locked) {
385  return;
386  }
387  /* Combine data-masks so one window doesn't disable UV's in another T26448. */
388  CustomData_MeshMasks win_combine_v3d_datamask = {0};
389  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
390  const Scene *scene = WM_window_get_active_scene(win);
391  const bScreen *screen = WM_window_get_active_screen(win);
392 
393  ED_view3d_screen_datamask(C, scene, screen, &win_combine_v3d_datamask);
394  }
395  /* Update all the dependency graphs of visible view layers. */
396  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
398  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
399  Main *bmain = CTX_data_main(C);
400  /* Copied to set's in scene_update_tagged_recursive() */
401  scene->customdata_mask = win_combine_v3d_datamask;
402  /* XXX, hack so operators can enforce data-masks T26482, GPU render. */
404  /* TODO(sergey): For now all dependency graphs which are evaluated from
405  * workspace are considered active. This will work all fine with "locked"
406  * view layer and time across windows. This is to be granted separately,
407  * and for until then we have to accept ambiguities when object is shared
408  * across visible view layers and has overrides on it. */
409  Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
410  if (is_after_open_file) {
412  }
415  }
416 
418 }
419 
421 {
423  /* Cached: editor refresh callbacks now, they get context. */
424  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
425  const bScreen *screen = WM_window_get_active_screen(win);
426 
427  CTX_wm_window_set(C, win);
428  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
429  if (area->do_refresh) {
432  }
433  }
434  }
435 
436  wm_event_do_depsgraph(C, false);
437 
438  CTX_wm_window_set(C, nullptr);
439 }
440 
442 {
444  if (UNLIKELY(wm == nullptr)) {
445  return;
446  }
447 
448  /* Set the first window as context, so that there is some minimal context. This avoids crashes
449  * when calling code that assumes that there is always a window in the context (which many
450  * operators do). */
451  CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
453  CTX_wm_window_set(C, nullptr);
454 }
455 
457 {
458  /* Run the timer before assigning `wm` in the unlikely case a timer loads a file, see T80028. */
460 
462  if (wm == nullptr) {
463  return;
464  }
465 
466  /* Disable? - Keep for now since its used for window level notifiers. */
467 #if 1
468  /* Cache & catch WM level notifiers, such as frame change, scene/screen set. */
469  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
471  bool do_anim = false;
472  bool clear_info_stats = false;
473 
474  CTX_wm_window_set(C, win);
475 
477  if (note->category == NC_WM) {
478  if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
479  wm->file_saved = 1;
480  wm_window_title(wm, win);
481  }
482  else if (note->data == ND_DATACHANGED) {
483  wm_window_title(wm, win);
484  }
485  else if (note->data == ND_UNDO) {
487  }
488  }
489  if (note->window == win) {
490  if (note->category == NC_SCREEN) {
491  if (note->data == ND_WORKSPACE_SET) {
492  WorkSpace *ref_ws = static_cast<WorkSpace *>(note->reference);
493 
494  UI_popup_handlers_remove_all(C, &win->modalhandlers);
495 
496  WM_window_set_active_workspace(C, win, ref_ws);
497  if (G.debug & G_DEBUG_EVENTS) {
498  printf("%s: Workspace set %p\n", __func__, note->reference);
499  }
500  }
501  else if (note->data == ND_WORKSPACE_DELETE) {
502  WorkSpace *workspace = static_cast<WorkSpace *>(note->reference);
503 
505  workspace, CTX_data_main(C), C, wm); /* XXX: hum, think this over! */
506  if (G.debug & G_DEBUG_EVENTS) {
507  printf("%s: Workspace delete %p\n", __func__, workspace);
508  }
509  }
510  else if (note->data == ND_LAYOUTBROWSE) {
512  static_cast<WorkSpaceLayout *>(note->reference));
513 
514  /* Free popup handlers only T35434. */
515  UI_popup_handlers_remove_all(C, &win->modalhandlers);
516 
517  ED_screen_change(C, ref_screen); /* XXX: hum, think this over! */
518  if (G.debug & G_DEBUG_EVENTS) {
519  printf("%s: screen set %p\n", __func__, note->reference);
520  }
521  }
522  else if (note->data == ND_LAYOUTDELETE) {
523  WorkSpace *workspace = WM_window_get_active_workspace(win);
524  WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(note->reference);
525 
526  ED_workspace_layout_delete(workspace, layout, C); /* XXX: hum, think this over! */
527  if (G.debug & G_DEBUG_EVENTS) {
528  printf("%s: screen delete %p\n", __func__, note->reference);
529  }
530  }
531  }
532  }
533 
534  if (note->window == win ||
535  (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) {
536  if (note->category == NC_SCENE) {
537  if (note->data == ND_FRAME) {
538  do_anim = true;
539  }
540  }
541  }
542  if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
543  clear_info_stats = true;
544  }
545  }
546 
547  if (clear_info_stats) {
548  /* Only do once since adding notifiers is slow when there are many. */
549  ViewLayer *view_layer = CTX_data_view_layer(C);
550  ED_info_stats_clear(wm, view_layer);
552  }
553 
554  if (do_anim) {
555 
556  /* XXX: quick frame changes can cause a crash if frame-change and rendering
557  * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
558  * twice which can depsgraph update the same object at once. */
559  if (G.is_rendering == false) {
560  /* Depsgraph gets called, might send more notifiers. */
563  }
564  }
565  }
566 
567  /* The notifiers are sent without context, to keep it clean. */
568  wmNotifier *note;
569  while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
570  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
572  bScreen *screen = WM_window_get_active_screen(win);
573  WorkSpace *workspace = WM_window_get_active_workspace(win);
574 
575  /* Filter out notifiers. */
576  if (note->category == NC_SCREEN && note->reference && note->reference != screen &&
577  note->reference != workspace && note->reference != WM_window_get_active_layout(win)) {
578  /* Pass. */
579  }
580  else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
581  /* Pass. */
582  }
583  else {
584  /* XXX context in notifiers? */
585  CTX_wm_window_set(C, win);
586 
587 # if 0
588  printf("notifier win %d screen %s cat %x\n",
589  win->winid,
590  win->screen->id.name + 2,
591  note->category);
592 # endif
593  ED_screen_do_listen(C, note);
594 
595  LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
596  wmRegionListenerParams region_params{};
597  region_params.window = win;
598  region_params.area = nullptr;
599  region_params.region = region;
600  region_params.scene = scene;
601  region_params.notifier = note;
602 
603  ED_region_do_listen(&region_params);
604  }
605 
606  ED_screen_areas_iter (win, screen, area) {
607  if ((note->category == NC_SPACE) && note->reference) {
608  /* Filter out notifiers sent to other spaces. RNA sets the reference to the owning ID
609  * though, the screen, so let notifiers through that reference the entire screen. */
610  if (!ELEM(note->reference, area->spacedata.first, screen, scene)) {
611  continue;
612  }
613  }
614  wmSpaceTypeListenerParams area_params{};
615  area_params.window = win;
616  area_params.area = area;
617  area_params.notifier = note;
618  area_params.scene = scene;
619  ED_area_do_listen(&area_params);
620  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
621  wmRegionListenerParams region_params{};
622  region_params.window = win;
623  region_params.area = area;
624  region_params.region = region;
625  region_params.scene = scene;
626  region_params.notifier = note;
627  ED_region_do_listen(&region_params);
628  }
629  }
630  }
631  }
632 
633  MEM_freeN(note);
634  }
635 #endif /* If 1 (postpone disabling for in favor of message-bus), eventually. */
636 
637  /* Handle message bus. */
638  {
639  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
640  CTX_wm_window_set(C, win);
642  }
643  CTX_wm_window_set(C, nullptr);
644  }
645 
647 
648  /* Status bar. */
649  if (wm->winactive) {
650  wmWindow *win = wm->winactive;
651  CTX_wm_window_set(C, win);
653  CTX_wm_window_set(C, nullptr);
654  }
655 
656  /* Auto-run warning. */
658 }
659 
660 static int wm_event_always_pass(const wmEvent *event)
661 {
662  /* Some events we always pass on, to ensure proper communication. */
663  return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
664 }
665 
677  const wmEvent *event,
678  const int action)
679 {
680 #ifndef NDEBUG
681  if (C == nullptr || CTX_wm_window(C)) {
683  "Return value for events that should always pass should never be BREAK.");
684  }
685 #endif
686  UNUSED_VARS_NDEBUG(C, event, action);
687 }
688 
691 /* -------------------------------------------------------------------- */
696  wmEventHandler_UI *handler,
697  const wmEvent *event,
698  int always_pass)
699 {
701  ARegion *region = CTX_wm_region(C);
702  ARegion *menu = CTX_wm_menu(C);
703  static bool do_wheel_ui = true;
704  const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
705 
706  /* UI code doesn't handle return values - it just always returns break.
707  * to make the #DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks. */
708  if (((handler->head.flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) && !ISMOUSE_BUTTON(event->type) &&
709  (event->val == KM_DBL_CLICK)) {
710  return WM_HANDLER_CONTINUE;
711  }
712 
713  /* UI is quite aggressive with swallowing events, like scroll-wheel. */
714  /* I realize this is not extremely nice code... when UI gets key-maps it can be maybe smarter. */
715  if (do_wheel_ui == false) {
716  if (is_wheel) {
717  return WM_HANDLER_CONTINUE;
718  }
719  if (wm_event_always_pass(event) == 0) {
720  do_wheel_ui = true;
721  }
722  }
723 
724  /* Don't block file-select events. Those are triggered by a separate file browser window.
725  * See T75292. */
726  if (event->type == EVT_FILESELECT) {
727  return WM_UI_HANDLER_CONTINUE;
728  }
729 
730  /* We set context to where UI handler came from. */
731  if (handler->context.area) {
732  CTX_wm_area_set(C, handler->context.area);
733  }
734  if (handler->context.region) {
735  CTX_wm_region_set(C, handler->context.region);
736  }
737  if (handler->context.menu) {
738  CTX_wm_menu_set(C, handler->context.menu);
739  }
740 
741  int retval = handler->handle_fn(C, event, handler->user_data);
742 
743  /* Putting back screen context. */
744  if ((retval != WM_UI_HANDLER_BREAK) || always_pass) {
746  CTX_wm_region_set(C, region);
747  CTX_wm_menu_set(C, menu);
748  }
749  else {
750  /* This special cases is for areas and regions that get removed. */
751  CTX_wm_area_set(C, nullptr);
752  CTX_wm_region_set(C, nullptr);
753  CTX_wm_menu_set(C, nullptr);
754  }
755 
756  if (retval == WM_UI_HANDLER_BREAK) {
757  return WM_HANDLER_BREAK;
758  }
759 
760  /* Event not handled in UI, if wheel then we temporarily disable it. */
761  if (is_wheel) {
762  do_wheel_ui = false;
763  }
764 
765  return WM_HANDLER_CONTINUE;
766 }
767 
769  wmWindow *win,
770  ARegion *region,
771  bool reactivate_button)
772 {
773  if (!region) {
774  return;
775  }
776 
777  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &region->handlers) {
778  if (handler_base->type == WM_HANDLER_TYPE_UI) {
779  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
780  BLI_assert(handler->handle_fn != nullptr);
781  wmEvent event;
782  wm_event_init_from_window(win, &event);
783  event.type = EVT_BUT_CANCEL;
784  event.val = reactivate_button ? 0 : 1;
785  event.flag = (eWM_EventFlag)0;
786  handler->handle_fn(C, &event, handler->user_data);
787  }
788  }
789 }
790 
792 {
793  wmWindow *win = CTX_wm_window(C);
794  ARegion *region = CTX_wm_region(C);
795  wm_event_handler_ui_cancel_ex(C, win, region, true);
796 }
797 
800 /* -------------------------------------------------------------------- */
807 {
808  wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
809  ReportList *wm_reports = &wm->reports;
810 
811  /* After adding reports to the global list, reset the report timer. */
812  WM_event_remove_timer(wm, nullptr, wm_reports->reporttimer);
813 
814  /* Records time since last report was added. */
815  wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
816 
817  ReportTimerInfo *rti = MEM_cnew<ReportTimerInfo>(__func__);
818  wm_reports->reporttimer->customdata = rti;
819 }
820 
822 {
823  wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
825  WM_event_remove_timer(wm, nullptr, wm->reports.reporttimer);
826 }
827 
828 #ifdef WITH_INPUT_NDOF
829 void WM_ndof_deadzone_set(float deadzone)
830 {
831  GHOST_setNDOFDeadZone(deadzone);
832 }
833 #endif
834 
835 static void wm_add_reports(ReportList *reports)
836 {
837  /* If the caller owns them, handle this. */
838  if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
839  wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
840 
841  /* Add reports to the global list, otherwise they are not seen. */
842  BLI_movelisttolist(&wm->reports.list, &reports->list);
843 
845  }
846 }
847 
848 void WM_report(eReportType type, const char *message)
849 {
850  ReportList reports;
851  BKE_reports_init(&reports, RPT_STORE);
852  BKE_report(&reports, type, message);
853 
854  wm_add_reports(&reports);
855 
856  BKE_reports_clear(&reports);
857 }
858 
859 void WM_reportf(eReportType type, const char *format, ...)
860 {
861  va_list args;
862 
863  DynStr *ds = BLI_dynstr_new();
864  va_start(args, format);
865  BLI_dynstr_vappendf(ds, format, args);
866  va_end(args);
867 
868  char *str = BLI_dynstr_get_cstring(ds);
869  WM_report(type, str);
870  MEM_freeN(str);
871 
872  BLI_dynstr_free(ds);
873 }
874 
877 /* -------------------------------------------------------------------- */
882 {
883 
885  wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, false);
886 
887  if (!WM_operator_poll(C, ot_macro)) {
888  return false;
889  }
890  }
891 
892  /* Python needs operator type, so we added exception for it. */
893  if (ot->pyop_poll) {
894  return ot->pyop_poll(C, ot);
895  }
896  if (ot->poll) {
897  return ot->poll(C);
898  }
899 
900  return true;
901 }
902 
904 {
905  /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
907  C, ot, nullptr, nullptr, static_cast<wmOperatorCallContext>(context), true, nullptr);
908 }
909 
911 {
912  if (ot->macro.first != nullptr) {
913  /* For macros, check all have exec() we can call. */
915  wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
916  if (otm && !WM_operator_check_ui_empty(otm)) {
917  return false;
918  }
919  }
920  return true;
921  }
922 
923  /* Assume a UI callback will draw something. */
924  if (ot->ui) {
925  return false;
926  }
927 
928  PointerRNA ptr;
930  RNA_STRUCT_BEGIN (&ptr, prop) {
931  int flag = RNA_property_flag(prop);
932  if (flag & PROP_HIDDEN) {
933  continue;
934  }
935  return false;
936  }
938  return true;
939 }
940 
942 {
944  if (area) {
945  ARegion *region = CTX_wm_region(C);
946  if (region && region->regiontype == RGN_TYPE_WINDOW) {
947  area->region_active_win = BLI_findindex(&area->regionbase, region);
948  }
949  }
950 }
951 
955 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
956 {
957  if (G.background == 0 && caller_owns_reports == false) { /* Popup. */
958  if (op->reports->list.first) {
959  /* FIXME: temp setting window, see other call to #UI_popup_menu_reports for why. */
960  wmWindow *win_prev = CTX_wm_window(C);
961  ScrArea *area_prev = CTX_wm_area(C);
962  ARegion *region_prev = CTX_wm_region(C);
963 
964  if (win_prev == nullptr) {
965  CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
966  }
967 
969 
970  CTX_wm_window_set(C, win_prev);
971  CTX_wm_area_set(C, area_prev);
972  CTX_wm_region_set(C, region_prev);
973  }
974  }
975 
976  if (retval & OPERATOR_FINISHED) {
978 
979  if (caller_owns_reports == false) {
980  BKE_reports_print(op->reports, RPT_DEBUG); /* Print out reports to console. */
981  }
982 
983  if (op->type->flag & OPTYPE_REGISTER) {
984  if (G.background == 0) { /* Ends up printing these in the terminal, gets annoying. */
985  /* Report the python string representation of the operator. */
986  char *buf = WM_operator_pystring(C, op, false, true);
988  MEM_freeN(buf);
989  }
990  }
991  }
992 
993  /* Refresh Info Editor with reports immediately, even if op returned #OPERATOR_CANCELLED. */
994  if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
996  }
997  /* If the caller owns them, handle this. */
998  wm_add_reports(op->reports);
999 }
1000 
1006 {
1007  /* Check undo flag here since undo operators are also added to the list,
1008  * to support checking if the same operator is run twice. */
1009  return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
1010 }
1011 
1012 static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
1013 {
1015  enum {
1016  NOP,
1017  SET,
1018  CLEAR,
1019  } hud_status = NOP;
1020 
1021  op->customdata = nullptr;
1022 
1023  if (store) {
1025  }
1026 
1027  /* We don't want to do undo pushes for operators that are being
1028  * called from operators that already do an undo push. Usually
1029  * this will happen for python operators that call C operators. */
1030  if (wm->op_undo_depth == 0) {
1031  if (op->type->flag & OPTYPE_UNDO) {
1032  ED_undo_push_op(C, op);
1033  if (repeat == 0) {
1034  hud_status = CLEAR;
1035  }
1036  }
1037  else if (op->type->flag & OPTYPE_UNDO_GROUPED) {
1039  if (repeat == 0) {
1040  hud_status = CLEAR;
1041  }
1042  }
1043  }
1044 
1045  if (repeat == 0) {
1046  if (G.debug & G_DEBUG_WM) {
1047  char *buf = WM_operator_pystring(C, op, false, true);
1049  MEM_freeN(buf);
1050  }
1051 
1052  if (wm_operator_register_check(wm, op->type)) {
1053  /* Take ownership of reports (in case python provided own). */
1054  op->reports->flag |= RPT_FREE;
1055 
1056  wm_operator_register(C, op);
1058 
1059  if (WM_operator_last_redo(C) == op) {
1060  /* Show the redo panel. */
1061  hud_status = SET;
1062  }
1063  }
1064  else {
1065  WM_operator_free(op);
1066  }
1067  }
1068 
1069  if (hud_status != NOP) {
1070  if (hud_status == SET) {
1071  ScrArea *area = CTX_wm_area(C);
1072  if (area && ((area->flag & AREA_FLAG_OFFSCREEN) == 0)) {
1074  }
1075  }
1076  else if (hud_status == CLEAR) {
1077  ED_area_type_hud_clear(wm, nullptr);
1078  }
1079  else {
1081  }
1082  }
1083 }
1084 
1088 static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, const bool store)
1089 {
1091  int retval = OPERATOR_CANCELLED;
1092 
1094 
1095  if (op == nullptr || op->type == nullptr) {
1096  return retval;
1097  }
1098 
1099  if (0 == WM_operator_poll(C, op->type)) {
1100  return retval;
1101  }
1102 
1103  if (op->type->exec) {
1104  if (op->type->flag & OPTYPE_UNDO) {
1105  wm->op_undo_depth++;
1106  }
1107 
1108  retval = op->type->exec(C, op);
1109  OPERATOR_RETVAL_CHECK(retval);
1110 
1111  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1112  wm->op_undo_depth--;
1113  }
1114  }
1115 
1116  /* XXX(@mont29): Disabled the repeat check to address part 2 of T31840.
1117  * Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason
1118  * why this was needed, but worth to note it in case something turns bad. */
1119  if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */) {
1120  wm_operator_reports(C, op, retval, false);
1121  }
1122 
1123  if (retval & OPERATOR_FINISHED) {
1124  wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0);
1125  }
1126  else if (repeat == 0) {
1127  /* WARNING: modal from exec is bad practice, but avoid crashing. */
1128  if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
1129  WM_operator_free(op);
1130  }
1131  }
1132 
1133  return retval | OPERATOR_HANDLED;
1134 }
1135 
1140 {
1141  int retval = OPERATOR_CANCELLED;
1142 
1143  if (op == nullptr || op->type == nullptr || op->type->exec == nullptr) {
1144  return retval;
1145  }
1146 
1147  retval = op->type->exec(C, op);
1148  OPERATOR_RETVAL_CHECK(retval);
1149 
1150  return retval;
1151 }
1152 
1153 int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
1154 {
1155  return wm_operator_exec(C, op, false, store);
1156 }
1157 
1159 {
1160  return WM_operator_call_ex(C, op, false);
1161 }
1162 
1164 {
1165  return wm_operator_exec_notest(C, op);
1166 }
1167 
1169 {
1170  const int op_flag = OP_IS_REPEAT;
1171  op->flag |= op_flag;
1172  const int ret = wm_operator_exec(C, op, true, true);
1173  op->flag &= ~op_flag;
1174  return ret;
1175 }
1177 {
1178  const int op_flag = OP_IS_REPEAT_LAST;
1179  op->flag |= op_flag;
1180  const int ret = wm_operator_exec(C, op, true, true);
1181  op->flag &= ~op_flag;
1182  return ret;
1183 }
1185 {
1186  if (op->type->exec != nullptr) {
1187  return true;
1188  }
1189  if (op->opm) {
1190  /* For macros, check all have exec() we can call. */
1191  LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
1192  wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
1193  if (otm && otm->exec == nullptr) {
1194  return false;
1195  }
1196  }
1197  return true;
1198  }
1199 
1200  return false;
1201 }
1202 
1204 {
1205  /* May be in the operators list or not. */
1206  wmOperator *op_prev;
1207  if (op->prev == nullptr && op->next == nullptr) {
1209  op_prev = static_cast<wmOperator *>(wm->operators.last);
1210  }
1211  else {
1212  op_prev = op->prev;
1213  }
1214  return (op_prev && (op->type == op_prev->type));
1215 }
1216 
1218  wmOperatorType *ot,
1219  PointerRNA *properties,
1220  ReportList *reports)
1221 {
1222  /* Operator-type names are static still. pass to allocation name for debugging. */
1223  wmOperator *op = MEM_cnew<wmOperator>(ot->idname);
1224 
1225  /* Adding new operator could be function, only happens here now. */
1226  op->type = ot;
1228 
1229  /* Initialize properties, either copy or create. */
1230  op->ptr = MEM_cnew<PointerRNA>("wmOperatorPtrRNA");
1231  if (properties && properties->data) {
1232  op->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data));
1233  }
1234  else {
1235  IDPropertyTemplate val = {0};
1236  op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1237  }
1238  RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
1239 
1240  /* Initialize error reports. */
1241  if (reports) {
1242  op->reports = reports; /* Must be initialized already. */
1243  }
1244  else {
1245  op->reports = MEM_cnew<ReportList>("wmOperatorReportList");
1247  }
1248 
1249  /* Recursive filling of operator macro list. */
1250  if (ot->macro.first) {
1251  static wmOperator *motherop = nullptr;
1252  int root = 0;
1253 
1254  /* Ensure all ops are in execution order in 1 list. */
1255  if (motherop == nullptr) {
1256  motherop = op;
1257  root = 1;
1258  }
1259 
1260  /* If properties exist, it will contain everything needed. */
1261  if (properties) {
1262  wmOperatorTypeMacro *otmacro = static_cast<wmOperatorTypeMacro *>(ot->macro.first);
1263 
1264  RNA_STRUCT_BEGIN (properties, prop) {
1265 
1266  if (otmacro == nullptr) {
1267  break;
1268  }
1269 
1270  /* Skip invalid properties. */
1271  if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
1272  wmOperatorType *otm = WM_operatortype_find(otmacro->idname, false);
1273  PointerRNA someptr = RNA_property_pointer_get(properties, prop);
1274  wmOperator *opm = wm_operator_create(wm, otm, &someptr, nullptr);
1275 
1277 
1278  BLI_addtail(&motherop->macro, opm);
1279  opm->opm = motherop; /* Pointer to mom, for modal(). */
1280 
1281  otmacro = otmacro->next;
1282  }
1283  }
1285  }
1286  else {
1288  wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
1289  wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr);
1290 
1291  BLI_addtail(&motherop->macro, opm);
1292  opm->opm = motherop; /* Pointer to mom, for modal(). */
1293  }
1294  }
1295 
1296  if (root) {
1297  motherop = nullptr;
1298  }
1299  }
1300 
1302 
1303  return op;
1304 }
1305 
1311 {
1312 
1313  bScreen *screen = WM_window_get_active_screen(win);
1314  /* Unlikely but not impossible as this runs after events have been handled. */
1315  if (UNLIKELY(screen == nullptr)) {
1316  return;
1317  }
1318  ED_screen_areas_iter (win, screen, area) {
1319  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1320  if (region->gizmo_map != nullptr) {
1321  if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) {
1322  ED_region_tag_redraw(region);
1323  }
1324  }
1325  }
1326  }
1327 }
1328 
1329 static void wm_region_mouse_co(bContext *C, wmEvent *event)
1330 {
1331  ARegion *region = CTX_wm_region(C);
1332  if (region) {
1333  /* Compatibility convention. */
1334  event->mval[0] = event->xy[0] - region->winrct.xmin;
1335  event->mval[1] = event->xy[1] - region->winrct.ymin;
1336  }
1337  else {
1338  /* These values are invalid (avoid odd behavior by relying on old #wmEvent.mval values). */
1339  event->mval[0] = -1;
1340  event->mval[1] = -1;
1341  }
1342 }
1343 
1348  wmOperatorType *ot,
1349  const wmEvent *event,
1350  PointerRNA *properties,
1351  ReportList *reports,
1352  const bool poll_only,
1353  bool use_last_properties)
1354 {
1355  int retval = OPERATOR_PASS_THROUGH;
1356 
1357  /* This is done because complicated setup is done to call this function
1358  * that is better not duplicated. */
1359  if (poll_only) {
1360  return WM_operator_poll(C, ot);
1361  }
1362 
1363  if (WM_operator_poll(C, ot)) {
1365 
1366  /* If `reports == nullptr`, they'll be initialized. */
1367  wmOperator *op = wm_operator_create(wm, ot, properties, reports);
1368 
1369  const bool is_nested_call = (wm->op_undo_depth != 0);
1370 
1371  if (event != nullptr) {
1372  op->flag |= OP_IS_INVOKE;
1373  }
1374 
1375  /* Initialize setting from previous run. */
1376  if (!is_nested_call && use_last_properties) { /* Not called by a Python script. */
1378  }
1379 
1380  if ((event == nullptr) || (event->type != MOUSEMOVE)) {
1382  2,
1383  "handle evt %d win %p op %s",
1384  event ? event->type : 0,
1385  CTX_wm_screen(C)->active_region,
1386  ot->idname);
1387  }
1388 
1389  if (op->type->invoke && event) {
1390  /* Make a copy of the event as it's `const` and the #wmEvent.mval to be written into. */
1391  wmEvent event_temp = *event;
1392  wm_region_mouse_co(C, &event_temp);
1393 
1394  if (op->type->flag & OPTYPE_UNDO) {
1395  wm->op_undo_depth++;
1396  }
1397 
1398  retval = op->type->invoke(C, op, &event_temp);
1399  OPERATOR_RETVAL_CHECK(retval);
1400 
1401  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1402  wm->op_undo_depth--;
1403  }
1404  }
1405  else if (op->type->exec) {
1406  if (op->type->flag & OPTYPE_UNDO) {
1407  wm->op_undo_depth++;
1408  }
1409 
1410  retval = op->type->exec(C, op);
1411  OPERATOR_RETVAL_CHECK(retval);
1412 
1413  if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
1414  wm->op_undo_depth--;
1415  }
1416  }
1417  else {
1418  /* Debug, important to leave a while, should never happen. */
1419  CLOG_ERROR(WM_LOG_OPERATORS, "invalid operator call '%s'", op->idname);
1420  }
1421 
1422  /* NOTE: if the report is given as an argument then assume the caller will deal with displaying
1423  * them currently Python only uses this. */
1424  if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
1425  /* Only show the report if the report list was not given in the function. */
1426  wm_operator_reports(C, op, retval, (reports != nullptr));
1427  }
1428 
1429  if (retval & OPERATOR_HANDLED) {
1430  /* Do nothing, #wm_operator_exec() has been called somewhere. */
1431  }
1432  else if (retval & OPERATOR_FINISHED) {
1433  const bool store = !is_nested_call && use_last_properties;
1434  wm_operator_finished(C, op, false, store);
1435  }
1436  else if (retval & OPERATOR_RUNNING_MODAL) {
1437  /* Take ownership of reports (in case python provided own). */
1438  op->reports->flag |= RPT_FREE;
1439 
1440  /* Grab cursor during blocking modal operators (X11)
1441  * Also check for macro. */
1442  if (ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) {
1443  int bounds[4] = {-1, -1, -1, -1};
1444  int wrap = WM_CURSOR_WRAP_NONE;
1445 
1446  if (event && (U.uiflag & USER_CONTINUOUS_MOUSE)) {
1447  const wmOperator *op_test = op->opm ? op->opm : op;
1448  const wmOperatorType *ot_test = op_test->type;
1449  if ((ot_test->flag & OPTYPE_GRAB_CURSOR_XY) ||
1450  (op_test->flag & OP_IS_MODAL_GRAB_CURSOR)) {
1452  }
1453  else if (ot_test->flag & OPTYPE_GRAB_CURSOR_X) {
1455  }
1456  else if (ot_test->flag & OPTYPE_GRAB_CURSOR_Y) {
1458  }
1459  }
1460 
1461  if (wrap) {
1462  const rcti *winrect = nullptr;
1463  ARegion *region = CTX_wm_region(C);
1464  ScrArea *area = CTX_wm_area(C);
1465 
1466  /* Wrap only in X for header. */
1467  if (region && RGN_TYPE_IS_HEADER_ANY(region->regiontype)) {
1469  }
1470 
1471  if (region && region->regiontype == RGN_TYPE_WINDOW &&
1472  BLI_rcti_isect_pt_v(&region->winrct, event->xy)) {
1473  winrect = &region->winrct;
1474  }
1475  else if (area && BLI_rcti_isect_pt_v(&area->totrct, event->xy)) {
1476  winrect = &area->totrct;
1477  }
1478 
1479  if (winrect) {
1480  bounds[0] = winrect->xmin;
1481  bounds[1] = winrect->ymax;
1482  bounds[2] = winrect->xmax;
1483  bounds[3] = winrect->ymin;
1484  }
1485  }
1486 
1488  }
1489 
1490  /* Cancel UI handlers, typically tool-tips that can hang around
1491  * while dragging the view or worse, that stay there permanently
1492  * after the modal operator has swallowed all events and passed
1493  * none to the UI handler. */
1495  }
1496  else {
1497  WM_operator_free(op);
1498  }
1499  }
1500 
1501  return retval;
1502 }
1503 
1510  wmOperatorType *ot,
1511  PointerRNA *properties,
1512  ReportList *reports,
1514  const bool poll_only,
1515  const wmEvent *event)
1516 {
1517  int retval;
1518 
1520 
1521  /* Dummy test. */
1522  if (ot) {
1523  wmWindow *window = CTX_wm_window(C);
1524 
1525  if (event == nullptr) {
1526  switch (context) {
1527  case WM_OP_INVOKE_DEFAULT:
1531  case WM_OP_INVOKE_AREA:
1532  case WM_OP_INVOKE_SCREEN:
1533  /* Window is needed for invoke and cancel operators. */
1534  if (window == nullptr) {
1535  if (poll_only) {
1536  CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
1537  }
1538  return 0;
1539  }
1540  else {
1541  event = window->eventstate;
1542  }
1543  break;
1544  default:
1545  event = nullptr;
1546  break;
1547  }
1548  }
1549  else {
1550  switch (context) {
1551  case WM_OP_EXEC_DEFAULT:
1552  case WM_OP_EXEC_REGION_WIN:
1555  case WM_OP_EXEC_AREA:
1556  case WM_OP_EXEC_SCREEN:
1557  event = nullptr;
1558  default:
1559  break;
1560  }
1561  }
1562 
1563  switch (context) {
1564  case WM_OP_EXEC_REGION_WIN:
1570  /* Forces operator to go to the region window/channels/preview, for header menus,
1571  * but we stay in the same region if we are already in one. */
1572  ARegion *region = CTX_wm_region(C);
1573  ScrArea *area = CTX_wm_area(C);
1574  int type = RGN_TYPE_WINDOW;
1575 
1576  switch (context) {
1580  break;
1581 
1585  break;
1586 
1587  case WM_OP_EXEC_REGION_WIN:
1589  default:
1591  break;
1592  }
1593 
1594  if (!(region && region->regiontype == type) && area) {
1595  ARegion *region_other = (type == RGN_TYPE_WINDOW) ?
1598  if (region_other) {
1599  CTX_wm_region_set(C, region_other);
1600  }
1601  }
1602 
1603  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1604 
1605  /* Set region back. */
1606  CTX_wm_region_set(C, region);
1607 
1608  return retval;
1609  }
1610  case WM_OP_EXEC_AREA:
1611  case WM_OP_INVOKE_AREA: {
1612  /* Remove region from context. */
1613  ARegion *region = CTX_wm_region(C);
1614 
1615  CTX_wm_region_set(C, nullptr);
1616  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1617  CTX_wm_region_set(C, region);
1618 
1619  return retval;
1620  }
1621  case WM_OP_EXEC_SCREEN:
1622  case WM_OP_INVOKE_SCREEN: {
1623  /* Remove region + area from context. */
1624  ARegion *region = CTX_wm_region(C);
1625  ScrArea *area = CTX_wm_area(C);
1626 
1627  CTX_wm_region_set(C, nullptr);
1628  CTX_wm_area_set(C, nullptr);
1629  retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1631  CTX_wm_region_set(C, region);
1632 
1633  return retval;
1634  }
1635  case WM_OP_EXEC_DEFAULT:
1636  case WM_OP_INVOKE_DEFAULT:
1637  return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
1638  }
1639  }
1640 
1641  return 0;
1642 }
1643 
1645  wmOperatorType *ot,
1647  PointerRNA *properties,
1648  const wmEvent *event)
1649 {
1651  return wm_operator_call_internal(C, ot, properties, nullptr, context, false, event);
1652 }
1654  const char *opstring,
1656  PointerRNA *properties,
1657  const wmEvent *event)
1658 {
1659  wmOperatorType *ot = WM_operatortype_find(opstring, false);
1660  if (ot) {
1661  return WM_operator_name_call_ptr(C, ot, context, properties, event);
1662  }
1663 
1664  return 0;
1665 }
1666 
1667 bool WM_operator_name_poll(bContext *C, const char *opstring)
1668 {
1669  wmOperatorType *ot = WM_operatortype_find(opstring, false);
1670  if (!ot) {
1671  return false;
1672  }
1673 
1674  return WM_operator_poll(C, ot);
1675 }
1676 
1678  const char *opstring,
1680  IDProperty *properties,
1681  const wmEvent *event)
1682 {
1683  PointerRNA props_ptr;
1684  wmOperatorType *ot = WM_operatortype_find(opstring, false);
1686  &static_cast<wmWindowManager *>(G_MAIN->wm.first)->id, ot->srna, properties, &props_ptr);
1687  return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event);
1688 }
1689 
1690 void WM_menu_name_call(bContext *C, const char *menu_name, short context)
1691 {
1692  wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
1693  PointerRNA ptr;
1695  RNA_string_set(&ptr, "name", menu_name);
1696  WM_operator_name_call_ptr(C, ot, static_cast<wmOperatorCallContext>(context), &ptr, nullptr);
1698 }
1699 
1701  wmOperatorType *ot,
1703  PointerRNA *properties,
1704  ReportList *reports,
1705  const bool is_undo)
1706 {
1707  int retval = OPERATOR_CANCELLED;
1708  /* Not especially nice using undo depth here. It's used so Python never
1709  * triggers undo or stores an operator's last used state. */
1711  if (!is_undo && wm) {
1712  wm->op_undo_depth++;
1713  }
1714 
1715  retval = wm_operator_call_internal(C, ot, properties, reports, context, false, nullptr);
1716 
1717  if (!is_undo && wm && (wm == CTX_wm_manager(C))) {
1718  wm->op_undo_depth--;
1719  }
1720 
1721  return retval;
1722 }
1723 
1726 /* -------------------------------------------------------------------- */
1738 };
1739 
1740 static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
1741 {
1742  uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
1743  if (opwait->optype_params.opptr) {
1744  if (opwait->optype_params.opptr->data) {
1745  IDP_FreeProperty(static_cast<IDProperty *>(opwait->optype_params.opptr->data));
1746  }
1747  MEM_freeN(opwait->optype_params.opptr);
1748  }
1749  if (opwait->context) {
1750  CTX_store_free(opwait->context);
1751  }
1752 
1753  if (opwait->area != nullptr) {
1754  ED_area_status_text(opwait->area, nullptr);
1755  }
1756  else {
1757  ED_workspace_status_text(C, nullptr);
1758  }
1759 
1760  MEM_freeN(opwait);
1761 }
1762 
1763 static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
1764 {
1765  uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
1766  enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE;
1767  state = CONTINUE;
1768 
1769  switch (event->type) {
1770  case LEFTMOUSE: {
1771  if (event->val == KM_PRESS) {
1772  state = EXECUTE;
1773  }
1774  break;
1775  }
1776  /* Useful if the operator isn't convenient to access while the mouse button is held.
1777  * If it takes numeric input for example. */
1778  case EVT_SPACEKEY:
1779  case EVT_RETKEY: {
1780  if (event->val == KM_PRESS) {
1781  state = EXECUTE;
1782  }
1783  break;
1784  }
1785  case RIGHTMOUSE: {
1786  if (event->val == KM_PRESS) {
1787  state = CANCEL;
1788  }
1789  break;
1790  }
1791  case EVT_ESCKEY: {
1792  if (event->val == KM_PRESS) {
1793  state = CANCEL;
1794  }
1795  break;
1796  }
1797  }
1798 
1799  if (state != CONTINUE) {
1800  wmWindow *win = CTX_wm_window(C);
1802 
1803  if (state == EXECUTE) {
1804  CTX_store_set(C, opwait->context);
1806  opwait->optype_params.optype,
1807  opwait->optype_params.opcontext,
1808  opwait->optype_params.opptr,
1809  event);
1810  CTX_store_set(C, nullptr);
1811  }
1812 
1816  opwait,
1817  false);
1818 
1820 
1821  return WM_UI_HANDLER_BREAK;
1822  }
1823 
1824  return WM_UI_HANDLER_CONTINUE;
1825 }
1826 
1828  wmOperatorType *ot,
1829  wmOperatorCallContext opcontext,
1830  PointerRNA *properties,
1831  const wmEvent *event,
1832  const char *drawstr)
1833 {
1834  int flag = ot->flag;
1835 
1837  wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
1838  if (otm != nullptr) {
1839  flag |= otm->flag;
1840  }
1841  }
1842 
1843  if ((flag & OPTYPE_DEPENDS_ON_CURSOR) == 0) {
1844  WM_operator_name_call_ptr(C, ot, opcontext, properties, event);
1845  return;
1846  }
1847 
1848  wmWindow *win = CTX_wm_window(C);
1849  /* The operator context is applied when the operator is called,
1850  * the check for the area needs to be explicitly limited here.
1851  * Useful so it's possible to screen-shot an area without drawing into it's header. */
1852  ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : nullptr;
1853 
1854  {
1855  char header_text[UI_MAX_DRAW_STR];
1856  SNPRINTF(header_text,
1857  "%s %s",
1858  IFACE_("Input pending "),
1859  (drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name));
1860  if (area != nullptr) {
1861  ED_area_status_text(area, header_text);
1862  }
1863  else {
1864  ED_workspace_status_text(C, header_text);
1865  }
1866  }
1867 
1869 
1870  uiOperatorWaitForInput *opwait = MEM_cnew<uiOperatorWaitForInput>(__func__);
1871  opwait->optype_params.optype = ot;
1872  opwait->optype_params.opcontext = opcontext;
1873  opwait->optype_params.opptr = properties;
1874 
1875  opwait->area = area;
1876 
1877  if (properties) {
1878  opwait->optype_params.opptr = MEM_cnew<PointerRNA>(__func__);
1879  *opwait->optype_params.opptr = *properties;
1880  if (properties->data != nullptr) {
1882  static_cast<IDProperty *>(properties->data));
1883  }
1884  }
1885 
1886  bContextStore *store = CTX_store_get(C);
1887  if (store) {
1888  opwait->context = CTX_store_copy(store);
1889  }
1890 
1892  &win->modalhandlers,
1895  opwait,
1897 }
1898 
1901 /* -------------------------------------------------------------------- */
1908 {
1909  /* Future extra custom-data free? */
1910  MEM_freeN(handler);
1911 }
1912 
1918  wmEventHandler_Op *handler,
1919  const wmEvent *event,
1920  ScrArea **r_area,
1921  ARegion **r_region)
1922 {
1923  wmWindow *win = handler->context.win ? handler->context.win : CTX_wm_window(C);
1924  /* It's probably fine to always use #WM_window_get_active_screen() to get the screen. But this
1925  * code has been getting it through context since forever, so play safe and stick to that when
1926  * possible. */
1927  bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
1928 
1929  *r_area = nullptr;
1930  *r_region = nullptr;
1931 
1932  if (screen == nullptr || handler->op == nullptr) {
1933  return;
1934  }
1935 
1936  if (handler->context.area == nullptr) {
1937  /* Pass */
1938  }
1939  else {
1940  ScrArea *area = nullptr;
1941 
1942  ED_screen_areas_iter (win, screen, area_iter) {
1943  if (area_iter == handler->context.area) {
1944  area = area_iter;
1945  break;
1946  }
1947  }
1948 
1949  if (area == nullptr) {
1950  /* When changing screen layouts with running modal handlers (like render display), this
1951  * is not an error to print. */
1952  if (handler->op == nullptr) {
1954  "internal error: handler (%s) has invalid area",
1955  handler->op->type->idname);
1956  }
1957  }
1958  else {
1959  ARegion *region;
1960  wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : nullptr;
1961  *r_area = area;
1962 
1963  if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
1964  region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
1965  if (region) {
1966  handler->context.region = region;
1967  }
1968  }
1969  else {
1970  region = nullptr;
1971  }
1972 
1973  if ((region == nullptr) && handler->context.region) {
1974  if (BLI_findindex(&area->regionbase, handler->context.region) != -1) {
1975  region = handler->context.region;
1976  }
1977  }
1978 
1979  /* No warning print here, after full-area and back regions are remade. */
1980  if (region) {
1981  *r_region = region;
1982  }
1983  }
1984  }
1985 }
1986 
1987 static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
1988 {
1989  ScrArea *area = nullptr;
1990  ARegion *region = nullptr;
1991  wm_handler_op_context_get_if_valid(C, handler, event, &area, &region);
1993  CTX_wm_region_set(C, region);
1994 }
1995 
1997 {
1999 
2000  /* C is zero on freeing database, modal handlers then already were freed. */
2001  wmEventHandler *handler_base;
2002  while ((handler_base = static_cast<wmEventHandler *>(BLI_pophead(handlers)))) {
2003  BLI_assert(handler_base->type != 0);
2004  if (handler_base->type == WM_HANDLER_TYPE_OP) {
2005  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
2006 
2007  if (handler->op) {
2008  wmWindow *win = CTX_wm_window(C);
2009 
2010  if (handler->is_fileselect) {
2011  /* Exit File Browsers referring to this handler/operator. */
2012  LISTBASE_FOREACH (wmWindow *, temp_win, &wm->windows) {
2013  ScrArea *file_area = ED_fileselect_handler_area_find(temp_win, handler->op);
2014  if (!file_area) {
2015  continue;
2016  }
2017  ED_area_exit(C, file_area);
2018  }
2019  }
2020 
2021  if (handler->op->type->cancel) {
2022  ScrArea *area = CTX_wm_area(C);
2023  ARegion *region = CTX_wm_region(C);
2024 
2025  wm_handler_op_context(C, handler, win->eventstate);
2026 
2027  if (handler->op->type->flag & OPTYPE_UNDO) {
2028  wm->op_undo_depth++;
2029  }
2030 
2031  handler->op->type->cancel(C, handler->op);
2032 
2033  if (handler->op->type->flag & OPTYPE_UNDO) {
2034  wm->op_undo_depth--;
2035  }
2036 
2038  CTX_wm_region_set(C, region);
2039  }
2040 
2041  WM_cursor_grab_disable(win, nullptr);
2042 
2043  if (handler->is_fileselect) {
2045  }
2046  else {
2047  WM_operator_free(handler->op);
2048  }
2049  }
2050  }
2051  else if (handler_base->type == WM_HANDLER_TYPE_UI) {
2052  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
2053 
2054  if (handler->remove_fn) {
2055  ScrArea *area = CTX_wm_area(C);
2056  ARegion *region = CTX_wm_region(C);
2057  ARegion *menu = CTX_wm_menu(C);
2058 
2059  if (handler->context.area) {
2060  CTX_wm_area_set(C, handler->context.area);
2061  }
2062  if (handler->context.region) {
2063  CTX_wm_region_set(C, handler->context.region);
2064  }
2065  if (handler->context.menu) {
2066  CTX_wm_menu_set(C, handler->context.menu);
2067  }
2068 
2069  handler->remove_fn(C, handler->user_data);
2070 
2072  CTX_wm_region_set(C, region);
2073  CTX_wm_menu_set(C, menu);
2074  }
2075  }
2076 
2077  wm_event_free_handler(handler_base);
2078  }
2079 }
2080 
2081 static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
2082 {
2083  if (kmi->flag & KMI_INACTIVE) {
2084  return false;
2085  }
2086 
2087  if (winevent->flag & WM_EVENT_IS_REPEAT) {
2088  if (kmi->flag & KMI_REPEAT_IGNORE) {
2089  return false;
2090  }
2091  }
2092 
2093  const int kmitype = WM_userdef_event_map(kmi->type);
2094 
2095  /* The matching rules. */
2096  if (kmitype == KM_TEXTINPUT) {
2097  if (winevent->val == KM_PRESS) { /* Prevent double clicks. */
2098  if (ISKEYBOARD(winevent->type) && winevent->utf8_buf[0]) {
2099  return true;
2100  }
2101  }
2102  }
2103 
2104  if (kmitype != KM_ANY) {
2105  if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
2106  const wmTabletData *wmtab = &winevent->tablet;
2107 
2108  if (winevent->type != LEFTMOUSE) {
2109  /* Tablet events can occur on hover + key-press. */
2110  return false;
2111  }
2112  if ((kmitype == TABLET_STYLUS) && (wmtab->active != EVT_TABLET_STYLUS)) {
2113  return false;
2114  }
2115  if ((kmitype == TABLET_ERASER) && (wmtab->active != EVT_TABLET_ERASER)) {
2116  return false;
2117  }
2118  }
2119  else {
2120  if (winevent->type != kmitype) {
2121  return false;
2122  }
2123  }
2124  }
2125 
2126  if (kmi->val != KM_ANY) {
2127  if (winevent->val != kmi->val) {
2128  return false;
2129  }
2130  }
2131 
2132  if (kmi->val == KM_CLICK_DRAG) {
2133  if (kmi->direction != KM_ANY) {
2134  if (kmi->direction != winevent->direction) {
2135  return false;
2136  }
2137  }
2138  }
2139 
2140  /* Account for rare case of when these keys are used as the 'type' not as modifiers. */
2141  if (kmi->shift != KM_ANY) {
2142  const bool shift = (winevent->modifier & KM_SHIFT) != 0;
2143  if ((shift != (bool)kmi->shift) &&
2144  !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
2145  return false;
2146  }
2147  }
2148  if (kmi->ctrl != KM_ANY) {
2149  const bool ctrl = (winevent->modifier & KM_CTRL) != 0;
2150  if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
2151  return false;
2152  }
2153  }
2154  if (kmi->alt != KM_ANY) {
2155  const bool alt = (winevent->modifier & KM_ALT) != 0;
2156  if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
2157  return false;
2158  }
2159  }
2160  if (kmi->oskey != KM_ANY) {
2161  const bool oskey = (winevent->modifier & KM_OSKEY) != 0;
2162  if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) {
2163  return false;
2164  }
2165  }
2166 
2167  /* Only key-map entry with key-modifier is checked,
2168  * means all keys without modifier get handled too. */
2169  /* That is currently needed to make overlapping events work (when you press A - G fast or so). */
2170  if (kmi->keymodifier) {
2171  if (winevent->keymodifier != kmi->keymodifier) {
2172  return false;
2173  }
2174  }
2175 
2176  return true;
2177 }
2178 
2180  wmOperator *op,
2181  const wmEvent *event)
2182 {
2183  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2184  /* Should already be handled by #wm_user_modal_keymap_set_items. */
2185  BLI_assert(kmi->propvalue_str[0] == '\0');
2186  if (wm_eventmatch(event, kmi)) {
2187  if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) {
2188  return kmi;
2189  }
2190  }
2191  }
2192  return nullptr;
2193 }
2194 
2196  short prev_type;
2197  short prev_val;
2198 
2200 };
2201 
2213  wmOperator *op,
2214  wmEvent *event,
2215  wmEvent_ModalMapStore *event_backup)
2216 {
2217  BLI_assert(event->type != EVT_MODAL_MAP);
2218 
2219  /* Support for modal key-map in macros. */
2220  if (op->opm) {
2221  op = op->opm;
2222  }
2223 
2224  event_backup->dbl_click_disabled = false;
2225 
2226  if (op->type->modalkeymap) {
2228  wmKeyMapItem *kmi = nullptr;
2229 
2230  const wmEvent *event_match = nullptr;
2231  wmEvent event_no_dbl_click;
2232 
2233  if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) {
2234  event_match = event;
2235  }
2236  else if (event->val == KM_DBL_CLICK) {
2237  event_no_dbl_click = *event;
2238  event_no_dbl_click.val = KM_PRESS;
2239  if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, &event_no_dbl_click))) {
2240  event_match = &event_no_dbl_click;
2241  }
2242  }
2243 
2244  if (event_match != nullptr) {
2245  event_backup->prev_type = event->prev_type;
2246  event_backup->prev_val = event->prev_val;
2247 
2248  event->prev_type = event_match->type;
2249  event->prev_val = event_match->val;
2250  event->type = EVT_MODAL_MAP;
2251  event->val = kmi->propvalue;
2252 
2253  /* Avoid double-click events even in the case of #EVT_MODAL_MAP,
2254  * since it's possible users configure double-click key-map items
2255  * which would break when modal functions expect press/release. */
2256  if (event->prev_type == KM_DBL_CLICK) {
2257  event->prev_type = KM_PRESS;
2258  event_backup->dbl_click_disabled = true;
2259  }
2260  }
2261  }
2262 
2263  if (event->type != EVT_MODAL_MAP) {
2264  /* This bypass just disables support for double-click in modal handlers. */
2265  if (event->val == KM_DBL_CLICK) {
2266  event->val = KM_PRESS;
2267  event_backup->dbl_click_disabled = true;
2268  }
2269  }
2270 }
2271 
2279 static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup)
2280 {
2281  if (event->type == EVT_MODAL_MAP) {
2282  event->type = event->prev_type;
2283  event->val = event->prev_val;
2284 
2285  event->prev_type = event_backup->prev_type;
2286  event->prev_val = event_backup->prev_val;
2287  }
2288 
2289  if (event_backup->dbl_click_disabled) {
2290  event->val = KM_DBL_CLICK;
2291  }
2292 }
2293 
2298  ListBase *handlers,
2299  wmEventHandler *handler_base,
2300  wmEvent *event,
2301  PointerRNA *properties,
2302  const char *kmi_idname)
2303 {
2304  int retval = OPERATOR_PASS_THROUGH;
2305 
2306  /* Derived, modal or blocking operator. */
2307  if ((handler_base->type == WM_HANDLER_TYPE_OP) &&
2308  (((wmEventHandler_Op *)handler_base)->op != nullptr)) {
2309  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
2310  wmOperator *op = handler->op;
2311  wmOperatorType *ot = op->type;
2312 
2314  /* Interface is locked and operator is not allowed to run,
2315  * nothing to do in this case. */
2316  }
2317  else if (ot->modal) {
2318  /* We set context to where modal handler came from. */
2320  wmWindow *win = CTX_wm_window(C);
2321  ScrArea *area = CTX_wm_area(C);
2322  ARegion *region = CTX_wm_region(C);
2323 
2324  wm_handler_op_context(C, handler, event);
2325  wm_region_mouse_co(C, event);
2326 
2327  wmEvent_ModalMapStore event_backup;
2328  wm_event_modalkeymap_begin(C, op, event, &event_backup);
2329 
2330  if (ot->flag & OPTYPE_UNDO) {
2331  wm->op_undo_depth++;
2332  }
2333 
2334  /* Warning, after this call all context data and 'event' may be freed. see check below. */
2335  retval = ot->modal(C, op, event);
2336  OPERATOR_RETVAL_CHECK(retval);
2337 
2338  if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
2339  wm->op_undo_depth--;
2340  }
2341 
2342  /* When the window changes the modal modifier may have loaded a new blend file
2343  * (the `system_demo_mode` add-on does this), so we have to assume the event,
2344  * operator, area, region etc have all been freed. */
2345  if ((CTX_wm_window(C) == win)) {
2346 
2347  wm_event_modalkeymap_end(event, &event_backup);
2348 
2349  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2350  wm_operator_reports(C, op, retval, false);
2351 
2352  if (op->type->modalkeymap) {
2354  }
2355  }
2356  else {
2357  /* Not very common, but modal operators may report before finishing. */
2358  if (!BLI_listbase_is_empty(&op->reports->list)) {
2359  wm_add_reports(op->reports);
2360  }
2361  }
2362 
2363  /* Important to run 'wm_operator_finished' before setting the context members to null. */
2364  if (retval & OPERATOR_FINISHED) {
2365  wm_operator_finished(C, op, false, true);
2366  handler->op = nullptr;
2367  }
2368  else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2369  WM_operator_free(op);
2370  handler->op = nullptr;
2371  }
2372 
2373  /* Putting back screen context, `reval` can pass through after modal failures! */
2374  if ((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
2376  CTX_wm_region_set(C, region);
2377  }
2378  else {
2379  /* This special cases is for areas and regions that get removed. */
2380  CTX_wm_area_set(C, nullptr);
2381  CTX_wm_region_set(C, nullptr);
2382  }
2383 
2384  /* Update gizmos during modal handlers. */
2385  wm_gizmomaps_handled_modal_update(C, event, handler);
2386 
2387  /* Remove modal handler, operator itself should have been canceled and freed. */
2388  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2390 
2391  BLI_remlink(handlers, handler);
2392  wm_event_free_handler(&handler->head);
2393 
2394  /* Prevent silly errors from operator users. */
2395  // retval &= ~OPERATOR_PASS_THROUGH;
2396  }
2397  }
2398  }
2399  else {
2400  CLOG_ERROR(WM_LOG_HANDLERS, "missing modal '%s'", op->idname);
2401  }
2402  }
2403  else {
2404  wmOperatorType *ot = WM_operatortype_find(kmi_idname, false);
2405 
2407  bool use_last_properties = true;
2408  PointerRNA tool_properties = {nullptr};
2409 
2410  bToolRef *keymap_tool = nullptr;
2411  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
2412  keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
2413  }
2414  else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
2415  wmGizmoMap *gizmo_map = ((wmEventHandler_Gizmo *)handler_base)->gizmo_map;
2416  wmGizmo *gz = wm_gizmomap_highlight_get(gizmo_map);
2417  if (gz && (gz->flag & WM_GIZMO_OPERATOR_TOOL_INIT)) {
2418  keymap_tool = WM_toolsystem_ref_from_context(C);
2419  }
2420  }
2421 
2422  const bool is_tool = (keymap_tool != nullptr);
2423  const bool use_tool_properties = is_tool;
2424 
2425  if (use_tool_properties) {
2427  keymap_tool, &tool_properties, properties, ot);
2428  properties = &tool_properties;
2429  use_last_properties = false;
2430  }
2431 
2432  retval = wm_operator_invoke(C, ot, event, properties, nullptr, false, use_last_properties);
2433 
2434  if (use_tool_properties) {
2435  WM_operator_properties_free(&tool_properties);
2436  }
2437 
2438  /* Link gizmo if #WM_GIZMOGROUPTYPE_TOOL_INIT is set. */
2439  if (retval & OPERATOR_FINISHED) {
2440  if (is_tool) {
2441  bToolRef_Runtime *tref_rt = keymap_tool->runtime;
2442  if (tref_rt->gizmo_group[0]) {
2443  const char *idname = tref_rt->gizmo_group;
2444  wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
2445  if (gzgt != nullptr) {
2446  if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
2447  ARegion *region = CTX_wm_region(C);
2448  if (region != nullptr) {
2449  wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
2450  WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
2452  gzmap_type, gzgt, region);
2453  /* We can't rely on drawing to initialize gizmo's since disabling
2454  * overlays/gizmos will prevent pre-drawing setup calls. (see T60905) */
2455  WM_gizmogroup_ensure_init(C, gzgroup);
2456  }
2457  }
2458  }
2459  }
2460  }
2461  }
2462  /* Done linking gizmo. */
2463  }
2464  }
2465 
2466  /* Finished and pass through flag as handled. */
2467  if (retval == (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH)) {
2468  return WM_HANDLER_HANDLED;
2469  }
2470 
2471  /* Modal unhandled, break. */
2472  if (retval == (OPERATOR_PASS_THROUGH | OPERATOR_RUNNING_MODAL)) {
2474  }
2475 
2476  if (retval & OPERATOR_PASS_THROUGH) {
2477  return WM_HANDLER_CONTINUE;
2478  }
2479 
2480  return WM_HANDLER_BREAK;
2481 }
2482 
2483 static void wm_operator_free_for_fileselect(wmOperator *file_operator)
2484 {
2485  LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) {
2486  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
2487  if (area->spacetype == SPACE_FILE) {
2488  SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
2489  if (sfile->op == file_operator) {
2490  sfile->op = nullptr;
2491  }
2492  }
2493  }
2494  }
2495 
2496  WM_operator_free(file_operator);
2497 }
2498 
2504  ListBase *handlers,
2505  wmEventHandler_Op *handler,
2506  int val)
2507 {
2509  int action = WM_HANDLER_CONTINUE;
2510 
2511  switch (val) {
2512  case EVT_FILESELECT_FULL_OPEN: {
2513  wmWindow *win = CTX_wm_window(C);
2514  ScrArea *area;
2515 
2517  IFACE_("Blender File View"),
2518  WM_window_pixels_x(win) / 2,
2519  WM_window_pixels_y(win) / 2,
2520  U.file_space_data.temp_win_sizex * UI_DPI_FAC,
2521  U.file_space_data.temp_win_sizey * UI_DPI_FAC,
2522  SPACE_FILE,
2523  U.filebrowser_display_type,
2524  true))) {
2526 
2527  BLI_assert(area->spacetype == SPACE_FILE);
2528 
2529  region_header->flag |= RGN_FLAG_HIDDEN;
2530  /* Header on bottom, #AZone triangle to toggle header looks misplaced at the top. */
2531  region_header->alignment = RGN_ALIGN_BOTTOM;
2532 
2533  /* Settings for file-browser, #sfile is not operator owner but sends events. */
2534  SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
2535  sfile->op = handler->op;
2536 
2538  }
2539  else {
2540  BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
2541  return OPERATOR_CANCELLED;
2542  }
2543 
2544  action = WM_HANDLER_BREAK;
2545  break;
2546  }
2547 
2548  case EVT_FILESELECT_EXEC:
2549  case EVT_FILESELECT_CANCEL:
2551  wmWindow *ctx_win = CTX_wm_window(C);
2552  wmEvent *eventstate = ctx_win->eventstate;
2553  /* The root window of the operation as determined in #WM_event_add_fileselect(). */
2554  wmWindow *root_win = handler->context.win;
2555 
2556  /* Remove link now, for load file case before removing. */
2557  BLI_remlink(handlers, handler);
2558 
2559  if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
2560  /* The window might have been freed already. */
2561  if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
2562  handler->context.win = nullptr;
2563  }
2564  }
2565  else {
2566  ScrArea *ctx_area = CTX_wm_area(C);
2567 
2568  wmWindow *temp_win = nullptr;
2569  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2570  bScreen *screen = WM_window_get_active_screen(win);
2571  ScrArea *file_area = static_cast<ScrArea *>(screen->areabase.first);
2572 
2573  if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
2574  continue;
2575  }
2576 
2577  if (file_area->full) {
2578  /* Users should not be able to maximize/full-screen an area in a temporary screen.
2579  * So if there's a maximized file browser in a temporary screen,
2580  * it was likely opened by #EVT_FILESELECT_FULL_OPEN. */
2581  continue;
2582  }
2583 
2584  int win_size[2];
2585  bool is_maximized;
2586  ED_fileselect_window_params_get(win, win_size, &is_maximized);
2588  static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized);
2589 
2590  if (BLI_listbase_is_single(&file_area->spacedata)) {
2591  BLI_assert(root_win != win);
2592 
2593  wm_window_close(C, wm, win);
2594 
2595  CTX_wm_window_set(C, root_win); /* #wm_window_close() nullptrs. */
2596  /* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */
2597  wm_window_make_drawable(wm, root_win);
2598  /* Ensure correct cursor position, otherwise, popups may close immediately after
2599  * opening (#UI_BLOCK_MOVEMOUSE_QUIT). */
2600  wm_cursor_position_get(root_win, &eventstate->xy[0], &eventstate->xy[1]);
2601  wm->winactive = root_win; /* Reports use this... */
2602  }
2603  else if (file_area->full) {
2604  ED_screen_full_prevspace(C, file_area);
2605  }
2606  else {
2607  ED_area_prevspace(C, file_area);
2608  }
2609 
2610  temp_win = win;
2611  break;
2612  }
2613 
2614  if (!temp_win && ctx_area->full) {
2616  static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false);
2617  ED_screen_full_prevspace(C, ctx_area);
2618  }
2619  }
2620 
2621  CTX_wm_window_set(C, root_win);
2622  wm_handler_op_context(C, handler, eventstate);
2623  /* At this point context is supposed to match the root context determined by
2624  * #WM_event_add_fileselect(). */
2625  BLI_assert(!CTX_wm_area(C) || (CTX_wm_area(C) == handler->context.area));
2626  BLI_assert(!CTX_wm_region(C) || (CTX_wm_region(C) == handler->context.region));
2627 
2628  ScrArea *handler_area = CTX_wm_area(C);
2629  /* Make sure new context area is ready, the operator callback may operate on it. */
2630  if (handler_area) {
2631  ED_area_do_refresh(C, handler_area);
2632  }
2633 
2634  /* Needed for #UI_popup_menu_reports. */
2635 
2636  if (val == EVT_FILESELECT_EXEC) {
2637  int retval;
2638 
2639  if (handler->op->type->flag & OPTYPE_UNDO) {
2640  wm->op_undo_depth++;
2641  }
2642 
2643  retval = handler->op->type->exec(C, handler->op);
2644 
2645  /* XXX check this carefully, `CTX_wm_manager(C) == wm` is a bit hackish. */
2646  if (handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
2647  wm->op_undo_depth--;
2648  }
2649 
2650  /* XXX check this carefully, `CTX_wm_manager(C) == wm` is a bit hackish. */
2651  if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) {
2652  if (handler->op->type->flag & OPTYPE_UNDO) {
2653  ED_undo_push_op(C, handler->op);
2654  }
2655  else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED) {
2656  ED_undo_grouped_push_op(C, handler->op);
2657  }
2658  }
2659 
2660  if (handler->op->reports->list.first) {
2661 
2662  /* FIXME(@campbellbarton): temp setting window, this is really bad!
2663  * only have because lib linking errors need to be seen by users :(
2664  * it can be removed without breaking anything but then no linking errors. */
2665  wmWindow *win_prev = CTX_wm_window(C);
2666  ScrArea *area_prev = CTX_wm_area(C);
2667  ARegion *region_prev = CTX_wm_region(C);
2668 
2669  if (win_prev == nullptr) {
2670  CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
2671  }
2672 
2674  UI_popup_menu_reports(C, handler->op->reports);
2675 
2676  /* XXX: copied from #wm_operator_finished(). */
2677  /* Add reports to the global list, otherwise they are not seen. */
2678  BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
2679 
2680  /* More hacks, since we meddle with reports, banner display doesn't happen automatic. */
2682 
2683  CTX_wm_window_set(C, win_prev);
2684  CTX_wm_area_set(C, area_prev);
2685  CTX_wm_region_set(C, region_prev);
2686  }
2687 
2688  /* For #WM_operator_pystring only, custom report handling is done above. */
2689  wm_operator_reports(C, handler->op, retval, true);
2690 
2691  if (retval & OPERATOR_FINISHED) {
2693  }
2694 
2695  if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
2697  }
2698  }
2699  else {
2700  if (handler->op->type->cancel) {
2701  if (handler->op->type->flag & OPTYPE_UNDO) {
2702  wm->op_undo_depth++;
2703  }
2704 
2705  handler->op->type->cancel(C, handler->op);
2706 
2707  if (handler->op->type->flag & OPTYPE_UNDO) {
2708  wm->op_undo_depth--;
2709  }
2710  }
2712  }
2713 
2714  CTX_wm_area_set(C, nullptr);
2715 
2716  wm_event_free_handler(&handler->head);
2717 
2718  action = WM_HANDLER_BREAK;
2719  break;
2720  }
2721  }
2722 
2723  return action;
2724 }
2725 
2727  ListBase *handlers,
2728  wmEventHandler_Op *handler,
2729  const wmEvent *event)
2730 {
2731  int action = WM_HANDLER_CONTINUE;
2732 
2733  if (event->type != EVT_FILESELECT) {
2734  return action;
2735  }
2736  if (handler->op != (wmOperator *)event->customdata) {
2737  return action;
2738  }
2739 
2740  return wm_handler_fileselect_do(C, handlers, handler, event->val);
2741 }
2742 
2743 static int wm_action_not_handled(int action)
2744 {
2745  return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
2746 }
2747 
2748 static const char *keymap_handler_log_action_str(const int action)
2749 {
2750  if (action & WM_HANDLER_BREAK) {
2751  return "handled";
2752  }
2753  if (action & WM_HANDLER_HANDLED) {
2754  return "handled (and pass on)";
2755  }
2756  return "un-handled";
2757 }
2758 
2759 static const char *keymap_handler_log_kmi_event_str(const wmKeyMapItem *kmi,
2760  char *buf,
2761  size_t buf_maxlen)
2762 {
2763  /* Short representation of the key that was pressed,
2764  * include this since it may differ from the event in minor details
2765  * which can help looking up the key-map definition. */
2766  WM_keymap_item_to_string(kmi, false, buf, buf_maxlen);
2767  return buf;
2768 }
2769 
2771  const wmKeyMapItem *kmi,
2772  char *buf,
2773  size_t buf_maxlen)
2774 {
2775  /* The key-map item properties can further help distinguish this item from others. */
2776  char *kmi_props = nullptr;
2777  if (kmi->properties != nullptr) {
2778  wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
2779  if (ot) {
2780  kmi_props = RNA_pointer_as_string_keywords(C, kmi->ptr, false, false, true, 512);
2781  }
2782  else { /* Fallback. */
2783  kmi_props = IDP_reprN(kmi->properties, nullptr);
2784  }
2785  }
2786  BLI_snprintf(buf, buf_maxlen, "%s(%s)", kmi->idname, kmi_props ? kmi_props : "");
2787  if (kmi_props != nullptr) {
2788  MEM_freeN(kmi_props);
2789  }
2790  return buf;
2791 }
2792 
2793 #define PRINT \
2794  if (do_debug_handler) \
2795  printf
2796 
2798  /* From 'wm_handlers_do_intern'. */
2799  bContext *C,
2800  wmEvent *event,
2801  ListBase *handlers,
2802  wmEventHandler_Keymap *handler,
2803  /* Additional. */
2804  wmKeyMap *keymap,
2805  const bool do_debug_handler)
2806 {
2807  int action = WM_HANDLER_CONTINUE;
2808 
2809  if (keymap == nullptr) {
2810  /* Only callback is allowed to have nullptr key-maps. */
2811  BLI_assert(handler->dynamic.keymap_fn);
2812  }
2813  else {
2814  PRINT("%s: checking '%s' ...", __func__, keymap->idname);
2815 
2816  if (WM_keymap_poll(C, keymap)) {
2817 
2818  PRINT("pass\n");
2819 
2820  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2821  if (wm_eventmatch(event, kmi)) {
2822  wmEventHandler_KeymapPost keymap_post = handler->post;
2823 
2824  action |= wm_handler_operator_call(
2825  C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
2826 
2827  char op_buf[512];
2828  char kmi_buf[128];
2830  2,
2831  "keymap '%s', %s, %s, event: %s",
2832  keymap->idname,
2833  keymap_handler_log_kmi_op_str(C, kmi, op_buf, sizeof(op_buf)),
2835  keymap_handler_log_kmi_event_str(kmi, kmi_buf, sizeof(kmi_buf)));
2836 
2837  if (action & WM_HANDLER_BREAK) {
2838  /* Not always_pass here, it denotes removed handler_base. */
2839  if (keymap_post.post_fn != nullptr) {
2840  keymap_post.post_fn(keymap, kmi, keymap_post.user_data);
2841  }
2842  break;
2843  }
2844  }
2845  }
2846  }
2847  else {
2848  PRINT("fail\n");
2849  }
2850  }
2851 
2852  return action;
2853 }
2854 
2856  /* From 'wm_handlers_do_intern' */
2857  bContext *C,
2858  wmEvent *event,
2859  ListBase *handlers,
2860  wmEventHandler_Gizmo *handler,
2861  /* Additional. */
2862  wmGizmoGroup *gzgroup,
2863  wmKeyMap *keymap,
2864  const bool do_debug_handler,
2865  bool *r_keymap_poll)
2866 {
2867  int action = WM_HANDLER_CONTINUE;
2868  bool keymap_poll = false;
2869 
2870  PRINT("%s: checking '%s' ...", __func__, keymap->idname);
2871 
2872  if (WM_keymap_poll(C, keymap)) {
2873  keymap_poll = true;
2874  PRINT("pass\n");
2875  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2876  if (wm_eventmatch(event, kmi)) {
2877  PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
2878 
2879  CTX_wm_gizmo_group_set(C, gzgroup);
2880 
2881  /* `handler->op` is called later, we want key-map op to be triggered here. */
2882  action |= wm_handler_operator_call(
2883  C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
2884 
2885  CTX_wm_gizmo_group_set(C, nullptr);
2886 
2887  if (action & WM_HANDLER_BREAK) {
2888  if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2889  printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
2890  }
2891  break;
2892  }
2893  if (action & WM_HANDLER_HANDLED) {
2894  if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
2895  printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
2896  }
2897  }
2898  else {
2899  PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
2900  }
2901  }
2902  }
2903  }
2904  else {
2905  PRINT("fail\n");
2906  }
2907 
2908  if (r_keymap_poll) {
2909  *r_keymap_poll = keymap_poll;
2910  }
2911 
2912  return action;
2913 }
2914 
2916  wmWindowManager *wm,
2917  wmEventHandler_Gizmo *handler,
2918  wmEvent *event,
2919  ListBase *handlers,
2920  const bool do_debug_handler)
2921 {
2922  /* Drag events use the previous click location to highlight the gizmos,
2923  * Get the highlight again in case the user dragged off the gizmo. */
2924  const bool is_event_drag = (event->val == KM_CLICK_DRAG);
2925  const bool is_event_modifier = ISKEYMODIFIER(event->type);
2926  /* Only keep the highlight if the gizmo becomes modal as result of event handling.
2927  * Without this check, even un-handled drag events will set the highlight if the drag
2928  * was initiated over a gizmo. */
2929  const bool restore_highlight_unless_activated = is_event_drag;
2930 
2931  int action = WM_HANDLER_CONTINUE;
2932  ScrArea *area = CTX_wm_area(C);
2933  ARegion *region = CTX_wm_region(C);
2934  wmGizmoMap *gzmap = handler->gizmo_map;
2935  BLI_assert(gzmap != nullptr);
2936  wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
2937 
2938  /* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
2939  * noticeable for the node editor - where dragging on a node should move it, see: T73212.
2940  * note we still allow for starting the gizmo drag outside, then travel 'inside' the node. */
2941  if (region->type->clip_gizmo_events_by_ui) {
2942  if (UI_region_block_find_mouse_over(region, event->xy, true)) {
2943  if (gz != nullptr && event->type != EVT_GIZMO_UPDATE) {
2944  if (restore_highlight_unless_activated == false) {
2946  wm_gizmomap_highlight_set(gzmap, C, nullptr, 0);
2947  }
2948  }
2949  return action;
2950  }
2951  }
2952 
2953  struct PrevGizmoData {
2954  wmGizmo *gz_modal;
2955  wmGizmo *gz;
2956  int part;
2957  };
2958  PrevGizmoData prev{};
2959  prev.gz_modal = wm_gizmomap_modal_get(gzmap);
2960  prev.gz = gz;
2961  prev.part = gz ? gz->highlight_part : 0;
2962 
2963  if (region->gizmo_map != handler->gizmo_map) {
2965  }
2966 
2968  wm_region_mouse_co(C, event);
2969 
2970  bool handle_highlight = false;
2971  bool handle_keymap = false;
2972 
2973  /* Handle gizmo highlighting. */
2974  if ((prev.gz_modal == nullptr) &&
2975  ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
2976  handle_highlight = true;
2977  if (is_event_modifier || is_event_drag) {
2978  handle_keymap = true;
2979  }
2980  }
2981  else {
2982  handle_keymap = true;
2983  }
2984 
2985  /* There is no need to handle this event when the key-map isn't being applied
2986  * since any change to the highlight will be restored to the previous value. */
2987  if (restore_highlight_unless_activated) {
2988  if ((handle_highlight == true) && (handle_keymap == false)) {
2989  return action;
2990  }
2991  }
2992 
2993  if (handle_highlight) {
2994  int part = -1;
2995  gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
2996 
2997  /* If no gizmos are/were active, don't clear tool-tips. */
2998  if (gz || prev.gz) {
2999  if ((prev.gz != gz) || (prev.part != part)) {
3001  }
3002  }
3003 
3004  if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
3005  if (gz != nullptr) {
3006  if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
3008  }
3009  }
3010  }
3011  }
3012 
3013  /* Don't use from now on. */
3014  bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL);
3015 
3016  if (handle_keymap) {
3017  /* Handle highlight gizmo. */
3018  if ((gz != nullptr) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
3019  bool keymap_poll = false;
3020  wmGizmoGroup *gzgroup = gz->parent_gzgroup;
3021  wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
3023  C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll);
3024 
3025 #ifdef USE_GIZMO_MOUSE_PRIORITY_HACK
3026  if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) {
3027  if ((event->val == KM_PRESS) && ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
3028 
3029  wmEvent event_test_click = *event;
3030  event_test_click.val = KM_CLICK;
3031 
3032  wmEvent event_test_click_drag = *event;
3033  event_test_click_drag.val = KM_CLICK_DRAG;
3034 
3035  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
3036  if ((kmi->flag & KMI_INACTIVE) == 0) {
3037  if (wm_eventmatch(&event_test_click, kmi) ||
3038  wm_eventmatch(&event_test_click_drag, kmi)) {
3039  wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
3041  is_event_handle_all = true;
3042  break;
3043  }
3044  }
3045  }
3046  }
3047  }
3048  }
3049 #endif /* `USE_GIZMO_MOUSE_PRIORITY_HACK` */
3050  }
3051 
3052  /* Don't use from now on. */
3053  gz = nullptr;
3054 
3055  /* Fallback to selected gizmo (when un-handled). */
3056  if ((action & WM_HANDLER_BREAK) == 0) {
3057  if (WM_gizmomap_is_any_selected(gzmap)) {
3058  const ListBase *groups = WM_gizmomap_group_list(gzmap);
3059  LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) {
3060  if (wm_gizmogroup_is_any_selected(gzgroup)) {
3061  wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
3063  C, event, handlers, handler, gzgroup, keymap, do_debug_handler, nullptr);
3064  if (action & WM_HANDLER_BREAK) {
3065  break;
3066  }
3067  }
3068  }
3069  }
3070  }
3071  }
3072 
3073  if (handle_highlight) {
3074  if (restore_highlight_unless_activated) {
3075  /* Check handling the key-map didn't activate a gizmo. */
3076  wmGizmo *gz_modal = wm_gizmomap_modal_get(gzmap);
3077  if (!(gz_modal && (gz_modal != prev.gz_modal))) {
3078  wm_gizmomap_highlight_set(gzmap, C, prev.gz, prev.part);
3079  }
3080  }
3081  }
3082 
3083  if (is_event_handle_all) {
3084  if (action == WM_HANDLER_CONTINUE) {
3085  action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL;
3086  }
3087  }
3088 
3089  /* Restore the area. */
3091  CTX_wm_region_set(C, region);
3092 
3093  return action;
3094 }
3095 
3098 /* -------------------------------------------------------------------- */
3102 static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, ListBase *handlers)
3103 {
3104  const bool do_debug_handler =
3105  (G.debug & G_DEBUG_HANDLERS) &&
3106  /* Comment this out to flood the console! (if you really want to test). */
3107  !ISMOUSE_MOTION(event->type);
3108 
3110  int action = WM_HANDLER_CONTINUE;
3111 
3112  if (handlers == nullptr) {
3113  wm_event_handler_return_value_check(C, event, action);
3114  return action;
3115  }
3116 
3117  /* Modal handlers can get removed in this loop, we keep the loop this way.
3118  *
3119  * NOTE: check 'handlers->first' because in rare cases the handlers can be cleared
3120  * by the event that's called, for eg:
3121  *
3122  * Calling a python script which changes the area.type, see T32232. */
3123  for (wmEventHandler *handler_base = static_cast<wmEventHandler *>(handlers->first),
3124  *handler_base_next;
3125  handler_base && handlers->first;
3126  handler_base = handler_base_next) {
3127  handler_base_next = handler_base->next;
3128 
3129  /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
3130  if (handler_base->flag & WM_HANDLER_DO_FREE) {
3131  /* Pass. */
3132  }
3133  else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
3134  /* In advance to avoid access to freed event on window close. */
3135  const int always_pass = wm_event_always_pass(event);
3136 
3137  /* Modal+blocking handler_base. */
3138  if (handler_base->flag & WM_HANDLER_BLOCKING) {
3139  action |= WM_HANDLER_BREAK;
3140  }
3141 
3142  /* Handle all types here. */
3143  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
3144  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
3145  wmEventHandler_KeymapResult km_result;
3146  WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
3147  int action_iter = WM_HANDLER_CONTINUE;
3148  for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
3149  wmKeyMap *keymap = km_result.keymaps[km_index];
3151  C, event, handlers, handler, keymap, do_debug_handler);
3152  if (action_iter & WM_HANDLER_BREAK) {
3153  break;
3154  }
3155  }
3156  action |= action_iter;
3157 
3158  /* Clear the tool-tip whenever a key binding is handled, without this tool-tips
3159  * are kept when a modal operators starts (annoying but otherwise harmless). */
3160  if (action & WM_HANDLER_BREAK) {
3161  /* Window may be gone after file read. */
3162  if (CTX_wm_window(C) != nullptr) {
3164  }
3165  }
3166  }
3167  else if (handler_base->type == WM_HANDLER_TYPE_UI) {
3168  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
3169  BLI_assert(handler->handle_fn != nullptr);
3170  if (!wm->is_interface_locked) {
3171  action |= wm_handler_ui_call(C, handler, event, always_pass);
3172  }
3173  }
3174  else if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
3175  wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
3176  if (!wm->is_interface_locked && event->type == EVT_DROP) {
3177  LISTBASE_FOREACH (wmDropBox *, drop, handler->dropboxes) {
3178  /* Other drop custom types allowed. */
3179  if (event->custom == EVT_DATA_DRAGDROP) {
3180  ListBase *lb = (ListBase *)event->customdata;
3181  LISTBASE_FOREACH_MUTABLE (wmDrag *, drag, lb) {
3182  if (drop->poll(C, drag, event)) {
3183  wm_drop_prepare(C, drag, drop);
3184 
3185  /* Pass single matched #wmDrag onto the operator. */
3186  BLI_remlink(lb, drag);
3187  ListBase single_lb = {nullptr};
3188  BLI_addtail(&single_lb, drag);
3189  event->customdata = &single_lb;
3190 
3191  const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop);
3192  int op_retval = wm_operator_call_internal(
3193  C, drop->ot, drop->ptr, nullptr, opcontext, false, event);
3194  OPERATOR_RETVAL_CHECK(op_retval);
3195 
3196  if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
3197  drop->cancel(CTX_data_main(C), drag, drop);
3198  }
3199 
3200  action |= WM_HANDLER_BREAK;
3201 
3202  /* Free the drags. */
3203  WM_drag_free_list(lb);
3204  WM_drag_free_list(&single_lb);
3205 
3206  wm_event_custom_clear(event);
3207 
3208  wm_drop_end(C, drag, drop);
3209 
3210  /* XXX file-read case. */
3211  if (CTX_wm_window(C) == nullptr) {
3212  return action;
3213  }
3214 
3215  /* Escape from drag loop, got freed. */
3216  break;
3217  }
3218  }
3219  /* Always exit all drags on a drop event, even if poll didn't succeed. */
3220  wm_drags_exit(wm, win);
3221  }
3222  }
3223  }
3224  }
3225  else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) {
3226  wmEventHandler_Gizmo *handler = (wmEventHandler_Gizmo *)handler_base;
3227  action |= wm_handlers_do_gizmo_handler(C, wm, handler, event, handlers, do_debug_handler);
3228  }
3229  else if (handler_base->type == WM_HANDLER_TYPE_OP) {
3230  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
3231  if (handler->is_fileselect) {
3232  if (!wm->is_interface_locked) {
3233  /* Screen context changes here. */
3234  action |= wm_handler_fileselect_call(C, handlers, handler, event);
3235  }
3236  }
3237  else {
3238  action |= wm_handler_operator_call(C, handlers, handler_base, event, nullptr, nullptr);
3239  }
3240  }
3241  else {
3242  /* Unreachable (handle all types above). */
3244  }
3245 
3246  if (action & WM_HANDLER_BREAK) {
3247  if (always_pass) {
3248  action &= ~WM_HANDLER_BREAK;
3249  }
3250  else {
3251  break;
3252  }
3253  }
3254  }
3255 
3256  /* File-read case, if the wm is freed then the handler's
3257  * will have been too so the code below need not run. */
3258  if (CTX_wm_window(C) == nullptr) {
3259  return action;
3260  }
3261 
3262  /* Code this for all modal ops, and ensure free only happens here. */
3263 
3264  /* The handler Could be freed already by regular modal ops. */
3265  if (BLI_findindex(handlers, handler_base) != -1) {
3266  /* Modal UI handler can be tagged to be freed. */
3267  if (handler_base->flag & WM_HANDLER_DO_FREE) {
3268  BLI_remlink(handlers, handler_base);
3269  wm_event_free_handler(handler_base);
3270  }
3271  }
3272  }
3273 
3274  if (action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL)) {
3276  }
3277 
3278  /* Do some extra sanity checking before returning the action. */
3279  wm_event_handler_return_value_check(C, event, action);
3280  return action;
3281 }
3282 
3283 #undef PRINT
3284 
3285 /* This calls handlers twice - to solve (double-)click events. */
3286 static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
3287 {
3288  int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers);
3289 
3290  /* Will be nullptr in the file read case. */
3291  wmWindow *win = CTX_wm_window(C);
3292  if (win == nullptr) {
3293  return action;
3294  }
3295 
3296  if (ISMOUSE_MOTION(event->type)) {
3297  /* Test for #KM_CLICK_DRAG events. */
3298 
3299  /* NOTE(@campbellbarton): Needed so drag can be used for editors that support both click
3300  * selection and passing through the drag action to box select. See #WM_generic_select_modal.
3301  * Unlike click, accept `action` when break isn't set.
3302  * Operators can return `OPERATOR_FINISHED | OPERATOR_PASS_THROUGH` which results
3303  * in `action` setting #WM_HANDLER_HANDLED, but not #WM_HANDLER_BREAK. */
3304  if ((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action)) {
3305  if (win->event_queue_check_drag) {
3306  if ((event->flag & WM_EVENT_FORCE_DRAG_THRESHOLD) ||
3307  WM_event_drag_test(event, event->prev_press_xy)) {
3308  win->event_queue_check_drag_handled = true;
3309  const int direction = WM_event_drag_direction(event);
3310 
3311  /* Intentionally leave `event->xy` as-is, event users are expected to use
3312  * `event->prev_press_xy` if they need to access the drag start location. */
3313  const short prev_val = event->val;
3314  const short prev_type = event->type;
3315  const uint8_t prev_modifier = event->modifier;
3316  const short prev_keymodifier = event->keymodifier;
3317 
3318  event->val = KM_CLICK_DRAG;
3319  event->type = event->prev_press_type;
3320  event->modifier = event->prev_press_modifier;
3321  event->keymodifier = event->prev_press_keymodifier;
3322  event->direction = direction;
3323 
3324  CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK_DRAG");
3325 
3326  action |= wm_handlers_do_intern(C, win, event, handlers);
3327 
3328  event->direction = 0;
3329  event->keymodifier = prev_keymodifier;
3330  event->modifier = prev_modifier;
3331  event->val = prev_val;
3332  event->type = prev_type;
3333 
3334  win->event_queue_check_click = false;
3335  if (!((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action))) {
3336  /* Only disable when handled as other handlers may use this drag event. */
3337  CLOG_INFO(WM_LOG_HANDLERS, 3, "canceling CLICK_DRAG: drag was generated & handled");
3338  win->event_queue_check_drag = false;
3339  }
3340  }
3341  }
3342  }
3343  else {
3344  if (win->event_queue_check_drag) {
3345  CLOG_INFO(WM_LOG_HANDLERS, 3, "canceling CLICK_DRAG: motion event was handled");
3346  win->event_queue_check_drag = false;
3347  }
3348  }
3349  }
3350  else if (ISKEYBOARD_OR_BUTTON(event->type)) {
3351  /* All events that don't set #wmEvent.prev_type must be ignored. */
3352 
3353  /* Test for CLICK events. */
3354  if (wm_action_not_handled(action)) {
3355  /* #wmWindow.eventstate stores if previous event was a #KM_PRESS, in case that
3356  * wasn't handled, the #KM_RELEASE will become a #KM_CLICK. */
3357 
3358  if (event->val == KM_PRESS) {
3359  if ((event->flag & WM_EVENT_IS_REPEAT) == 0) {
3360  win->event_queue_check_click = true;
3361 
3362  CLOG_INFO(WM_LOG_HANDLERS, 3, "detecting CLICK_DRAG: press event detected");
3363  win->event_queue_check_drag = true;
3364 
3365  win->event_queue_check_drag_handled = false;
3366  }
3367  }
3368  else if (event->val == KM_RELEASE) {
3369  if (win->event_queue_check_drag) {
3370  if ((event->prev_press_type != event->type) &&
3371  (ISKEYMODIFIER(event->type) || (event->type == event->prev_press_keymodifier))) {
3372  /* Support releasing modifier keys without canceling the drag event, see T89989. */
3373  }
3374  else {
3375  CLOG_INFO(
3376  WM_LOG_HANDLERS, 3, "CLICK_DRAG: canceling (release event didn't match press)");
3377  win->event_queue_check_drag = false;
3378  }
3379  }
3380  }
3381 
3382  if (event->val == KM_RELEASE) {
3383  if (event->prev_press_type == event->type) {
3384  if (event->prev_val == KM_PRESS) {
3385  if (win->event_queue_check_click) {
3386  if (WM_event_drag_test(event, event->prev_press_xy)) {
3387  win->event_queue_check_click = false;
3388  if (win->event_queue_check_drag) {
3390  3,
3391  "CLICK_DRAG: canceling (key-release exceeds drag threshold)");
3392  win->event_queue_check_drag = false;
3393  }
3394  }
3395  else {
3396  /* Position is where the actual click happens, for more
3397  * accurate selecting in case the mouse drifts a little. */
3398  const int xy[2] = {UNPACK2(event->xy)};
3399 
3400  copy_v2_v2_int(event->xy, event->prev_press_xy);
3401  event->val = KM_CLICK;
3402 
3403  CLOG_INFO(WM_LOG_HANDLERS, 1, "CLICK: handling");
3404 
3405  action |= wm_handlers_do_intern(C, win, event, handlers);
3406 
3407  event->val = KM_RELEASE;
3408  copy_v2_v2_int(event->xy, xy);
3409  }
3410  }
3411  }
3412  }
3413  }
3414  else if (event->val == KM_DBL_CLICK) {
3415  /* The underlying event is a press, so try and handle this. */
3416  event->val = KM_PRESS;
3417  action |= wm_handlers_do_intern(C, win, event, handlers);
3418 
3419  /* Revert value if not handled. */
3420  if (wm_action_not_handled(action)) {
3421  event->val = KM_DBL_CLICK;
3422  }
3423  }
3424  }
3425  else {
3426  win->event_queue_check_click = false;
3427 
3428  if (win->event_queue_check_drag) {
3430  3,
3431  "CLICK_DRAG: canceling (button event was handled: value=%d)",
3432  event->val);
3433  win->event_queue_check_drag = false;
3434  }
3435  }
3436  }
3437  else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) {
3438  /* Modifiers which can trigger click event's,
3439  * however we don't want this if the mouse wheel has been used, see T74607. */
3440  if (wm_action_not_handled(action)) {
3441  /* Pass. */
3442  }
3443  else {
3444  if (ISKEYMODIFIER(event->prev_type)) {
3445  win->event_queue_check_click = false;
3446  }
3447  }
3448  }
3449 
3450  wm_event_handler_return_value_check(C, event, action);
3451  return action;
3452 }
3453 
3456 /* -------------------------------------------------------------------- */
3462 static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
3463 {
3464  if (wm_event_always_pass(event)) {
3465  return true;
3466  }
3467  if (BLI_rcti_isect_pt_v(rect, event->xy)) {
3468  return true;
3469  }
3470  return false;
3471 }
3472 
3473 static ScrArea *area_event_inside(bContext *C, const int xy[2])
3474 {
3475  wmWindow *win = CTX_wm_window(C);
3476  bScreen *screen = CTX_wm_screen(C);
3477 
3478  if (screen) {
3479  ED_screen_areas_iter (win, screen, area) {
3480  if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
3481  return area;
3482  }
3483  }
3484  }
3485  return nullptr;
3486 }
3487 
3488 static ARegion *region_event_inside(bContext *C, const int xy[2])
3489 {
3490  bScreen *screen = CTX_wm_screen(C);
3491  ScrArea *area = CTX_wm_area(C);
3492 
3493  if (screen && area) {
3494  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3495  if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
3496  return region;
3497  }
3498  }
3499  }
3500  return nullptr;
3501 }
3502 
3504 {
3505  if (region) {
3506  for (; pc; pc = pc->next) {
3507  if (pc->poll == nullptr || pc->poll(C)) {
3508  wmWindow *win = CTX_wm_window(C);
3509  WM_paint_cursor_tag_redraw(win, region);
3510  }
3511  }
3512  }
3513 }
3514 
3520 static void wm_paintcursor_test(bContext *C, const wmEvent *event)
3521 {
3523 
3524  if (wm->paintcursors.first) {
3525  ARegion *region = CTX_wm_region(C);
3526 
3527  if (region) {
3528  wm_paintcursor_tag(C, static_cast<wmPaintCursor *>(wm->paintcursors.first), region);
3529  }
3530 
3531  /* If previous position was not in current region, we have to set a temp new context. */
3532  if (region == nullptr || !BLI_rcti_isect_pt_v(&region->winrct, event->prev_xy)) {
3533  ScrArea *area = CTX_wm_area(C);
3534 
3537 
3539  C, static_cast<wmPaintCursor *>(wm->paintcursors.first), CTX_wm_region(C));
3540 
3542  CTX_wm_region_set(C, region);
3543  }
3544  }
3545 }
3546 
3548 {
3549  bScreen *screen = WM_window_get_active_screen(win);
3550 
3551  if (BLI_listbase_is_empty(&wm->drags)) {
3552  return WM_HANDLER_CONTINUE;
3553  }
3554 
3555  if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
3556  screen->do_draw_drag = true;
3557  }
3558  else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
3559  wm_drags_exit(wm, win);
3560  WM_drag_free_list(&wm->drags);
3561 
3562  screen->do_draw_drag = true;
3563 
3564  return WM_HANDLER_BREAK;
3565  }
3566  else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
3567  event->type = EVT_DROP;
3568 
3569  /* Create custom-data, first free existing. */
3570  wm_event_custom_free(event);
3571  wm_event_custom_clear(event);
3572 
3573  event->custom = EVT_DATA_DRAGDROP;
3574  event->customdata = &wm->drags;
3575  event->customdata_free = true;
3576 
3577  /* Clear drop icon. */
3578  screen->do_draw_drag = true;
3579 
3580  /* Restore cursor (disabled, see `wm_dragdrop.cc`) */
3581  // WM_cursor_modal_restore(win);
3582  }
3583 
3584  return WM_HANDLER_CONTINUE;
3585 }
3586 
3590 static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
3591 {
3592  if (win->pie_event_type_lock && win->pie_event_type_lock == event->type) {
3593  if (event->val == KM_RELEASE) {
3595  return false;
3596  }
3597  return true;
3598  }
3599  return false;
3600 }
3601 
3610 {
3611  LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) {
3612  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3613  if (BLI_remlink_safe(&win->event_queue, event)) {
3614  wm_event_free(event);
3615  return;
3616  }
3617  }
3618  }
3619 }
3620 
3623 /* -------------------------------------------------------------------- */
3629 #ifdef WITH_XR_OPENXR
3636 static void wm_event_handle_xrevent(bContext *C,
3637  wmWindowManager *wm,
3638  wmWindow *win,
3639  wmEvent *event)
3640 {
3642  if (!area) {
3643  return;
3644  }
3645  BLI_assert(area->spacetype == SPACE_VIEW3D && area->spacedata.first);
3646 
3647  /* Find a valid region for XR operator execution and modal handling. */
3649  if (!region) {
3650  return;
3651  }
3652  BLI_assert(WM_region_use_viewport(area, region)); /* For operators using GPU-based selection. */
3653 
3655  CTX_wm_region_set(C, region);
3656 
3657  int action = wm_handlers_do(C, event, &win->modalhandlers);
3658 
3659  if ((action & WM_HANDLER_BREAK) == 0) {
3660  wmXrActionData *actiondata = static_cast<wmXrActionData *>(event->customdata);
3661  if (actiondata->ot->modal && event->val == KM_RELEASE) {
3662  /* Don't execute modal operators on release. */
3663  }
3664  else {
3665  PointerRNA properties{};
3666  properties.type = actiondata->ot->srna;
3667  properties.data = actiondata->op_properties;
3668  if (actiondata->ot->invoke) {
3669  /* Invoke operator, either executing operator or transferring responsibility to window
3670  * modal handlers. */
3672  actiondata->ot,
3673  event,
3674  actiondata->op_properties ? &properties : nullptr,
3675  nullptr,
3676  false,
3677  false);
3678  }
3679  else {
3680  /* Execute operator. */
3682  wm, actiondata->ot, actiondata->op_properties ? &properties : nullptr, nullptr);
3683  if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
3684  WM_operator_free(op);
3685  }
3686  }
3687  }
3688  }
3689 
3690  CTX_wm_region_set(C, nullptr);
3691  CTX_wm_area_set(C, nullptr);
3692 }
3693 #endif /* WITH_XR_OPENXR */
3694 
3696 {
3697  CTX_wm_region_set(C, region);
3698 
3699  /* Call even on non mouse events, since the. */
3700  wm_region_mouse_co(C, event);
3701 
3702  const wmWindowManager *wm = CTX_wm_manager(C);
3703  if (!BLI_listbase_is_empty(&wm->drags)) {
3704  /* Does polls for drop regions and checks #uiButs. */
3705  /* Need to be here to make sure region context is true. */
3706  if (ELEM(event->type, MOUSEMOVE, EVT_DROP) || ISKEYMODIFIER(event->type)) {
3707  wm_drags_check_ops(C, event);
3708  }
3709  }
3710 
3711  return wm_handlers_do(C, event, &region->handlers);
3712 }
3713 
3722 {
3723  /* Case 1. */
3724  if (wm_event_always_pass(event)) {
3725  int action = WM_HANDLER_CONTINUE;
3726 
3727  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3728  action |= wm_event_do_region_handlers(C, event, region);
3729  }
3730 
3731  wm_event_handler_return_value_check(C, event, action);
3732  return action;
3733  }
3734 
3735  /* Case 2. */
3736  ARegion *region_hovered = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, event->xy);
3737  if (!region_hovered) {
3738  return WM_HANDLER_CONTINUE;
3739  }
3740 
3741  return wm_event_do_region_handlers(C, event, region_hovered);
3742 }
3743 
3745 {
3748 
3749  /* Update key configuration before handling events. */
3750  WM_keyconfig_update(wm);
3752 
3753  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3754  bScreen *screen = WM_window_get_active_screen(win);
3755 
3756  /* Some safety checks - these should always be set! */
3760 
3761  if (screen == nullptr) {
3762  wm_event_free_all(win);
3763  }
3764  else {
3766  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
3768  Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
3769 
3770  if (scene_eval != nullptr) {
3771  const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
3772 
3773  if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
3774  /* Ignore seek here, the audio will be updated to the scene frame after jump during next
3775  * dependency graph update. */
3776  }
3777  else if (is_playing_sound != -1) {
3778  bool is_playing_screen;
3779 
3780  is_playing_screen = (ED_screen_animation_playing(wm) != nullptr);
3781 
3782  if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
3783  ((is_playing_sound == 0) && (is_playing_screen == 1))) {
3784  wmWindow *win_ctx = CTX_wm_window(C);
3785  bScreen *screen_stx = CTX_wm_screen(C);
3786  Scene *scene_ctx = CTX_data_scene(C);
3787 
3788  CTX_wm_window_set(C, win);
3789  CTX_wm_screen_set(C, screen);
3791 
3792  ED_screen_animation_play(C, -1, 1);
3793 
3794  CTX_data_scene_set(C, scene_ctx);
3795  CTX_wm_screen_set(C, screen_stx);
3796  CTX_wm_window_set(C, win_ctx);
3797  }
3798 
3799  if (is_playing_sound == 0) {
3800  const double time = BKE_sound_sync_scene(scene_eval);
3801  if (isfinite(time)) {
3802  int ncfra = round(time * FPS);
3803  if (ncfra != scene->r.cfra) {
3804  scene->r.cfra = ncfra;
3806  WM_event_add_notifier(C, NC_WINDOW, nullptr);
3807  }
3808  }
3809  }
3810  }
3811  }
3812  }
3813 
3814  wmEvent *event;
3815  while ((event = static_cast<wmEvent *>(win->event_queue.first))) {
3816  int action = WM_HANDLER_CONTINUE;
3817 
3818  /* Force handling drag if a key is pressed even if the drag threshold has not been met.
3819  * Needed so tablet actions (which typically use a larger threshold) can click-drag
3820  * then press keys - activating the drag action early.
3821  * Limit to mouse-buttons drag actions interrupted by pressing any non-mouse button.
3822  * Otherwise pressing two keys on the keyboard will interpret this as a drag action. */
3823  if (win->event_queue_check_drag) {
3824  if ((event->val == KM_PRESS) && ((event->flag & WM_EVENT_IS_REPEAT) == 0) &&
3826  event = wm_event_add_mousemove_to_head(win);
3827  event->flag |= WM_EVENT_FORCE_DRAG_THRESHOLD;
3828  }
3829  }
3830  const bool event_queue_check_drag_prev = win->event_queue_check_drag;
3831 
3832  /* Active screen might change during handlers, update pointer. */
3833  screen = WM_window_get_active_screen(win);
3834 
3835  if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ISMOUSE_MOTION(event->type)) {
3836  printf("\n%s: Handling event\n", __func__);
3837  WM_event_print(event);
3838  }
3839 
3840  /* Take care of pie event filter. */
3841  if (wm_event_pie_filter(win, event)) {
3842  if (!ISMOUSE_MOTION(event->type)) {
3843  CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed");
3844  }
3845  BLI_remlink(&win->event_queue, event);
3846  wm_event_free_last_handled(win, event);
3847  continue;
3848  }
3849 
3850  CTX_wm_window_set(C, win);
3851 
3852 #ifdef WITH_XR_OPENXR
3853  if (event->type == EVT_XR_ACTION) {
3854  wm_event_handle_xrevent(C, wm, win, event);
3855  BLI_remlink(&win->event_queue, event);
3856  wm_event_free_last_handled(win, event);
3857  /* Skip mouse event handling below, which is unnecessary for XR events. */
3858  continue;
3859  }
3860 #endif
3861 
3862  /* Clear tool-tip on mouse move. */
3863  if (screen->tool_tip && screen->tool_tip->exit_on_event) {
3864  if (ISMOUSE_MOTION(event->type)) {
3865  if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, event->xy) >
3867  WM_tooltip_clear(C, win);
3868  }
3869  }
3870  }
3871 
3872  /* We let modal handlers get active area/region, also wm_paintcursor_test needs it. */
3873  CTX_wm_area_set(C, area_event_inside(C, event->xy));
3875 
3876  /* MVC demands to not draw in event handlers...
3877  * but we need to leave it for GPU selecting etc. */
3878  wm_window_make_drawable(wm, win);
3879 
3880  wm_region_mouse_co(C, event);
3881 
3882  /* First we do priority handlers, modal + some limited key-maps. */
3883  action |= wm_handlers_do(C, event, &win->modalhandlers);
3884 
3885  /* File-read case. */
3886  if (CTX_wm_window(C) == nullptr) {
3888  return;
3889  }
3890 
3891  /* Check for a tool-tip. */
3892  if (screen == WM_window_get_active_screen(win)) {
3893  if (screen->tool_tip && screen->tool_tip->timer) {
3894  if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
3895  WM_tooltip_init(C, win);
3896  }
3897  }
3898  }
3899 
3900  /* Check dragging, creates new event or frees, adds draw tag. */
3901  action |= wm_event_drag_and_drop_test(wm, win, event);
3902 
3903  if ((action & WM_HANDLER_BREAK) == 0) {
3904  /* NOTE: setting sub-window active should be done here,
3905  * after modal handlers have been done. */
3906  if (event->type == MOUSEMOVE) {
3907  /* State variables in screen, cursors.
3908  * Also used in `wm_draw.c`, fails for modal handlers though. */
3909  ED_screen_set_active_region(C, win, event->xy);
3910  /* For regions having custom cursors. */
3911  wm_paintcursor_test(C, event);
3912  }
3913 #ifdef WITH_INPUT_NDOF
3914  else if (event->type == NDOF_MOTION) {
3915  win->addmousemove = true;
3916  }
3917 #endif
3918 
3919  ED_screen_areas_iter (win, screen, area) {
3920  /* After restoring a screen from SCREENMAXIMIZED we have to wait
3921  * with the screen handling till the region coordinates are updated. */
3922  if (screen->skip_handling) {
3923  /* Restore for the next iteration of wm_event_do_handlers. */
3924  screen->skip_handling = false;
3925  break;
3926  }
3927 
3928  /* Update action-zones if needed,
3929  * done here because it needs to be independent from redraws. */
3930  if (area->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
3931  ED_area_azones_update(area, event->xy);
3932  }
3933 
3934  if (wm_event_inside_rect(event, &area->totrct)) {
3936 
3937  action |= wm_event_do_handlers_area_regions(C, event, area);
3938 
3939  /* File-read case (Python), T29489. */
3940  if (CTX_wm_window(C) == nullptr) {
3942  return;
3943  }
3944 
3945  CTX_wm_region_set(C, nullptr);
3946 
3947  if ((action & WM_HANDLER_BREAK) == 0) {
3948  wm_region_mouse_co(C, event); /* Only invalidates `event->mval` in this case. */
3949  action |= wm_handlers_do(C, event, &area->handlers);
3950  }
3951  CTX_wm_area_set(C, nullptr);
3952 
3953  /* NOTE: do not escape on #WM_HANDLER_BREAK,
3954  * mouse-move needs handled for previous area. */
3955  }
3956  }
3957 
3958  if ((action & WM_HANDLER_BREAK) == 0) {
3959  /* Also some non-modal handlers need active area/region. */
3960  CTX_wm_area_set(C, area_event_inside(C, event->xy));
3962 
3963  wm_region_mouse_co(C, event);
3964 
3965  action |= wm_handlers_do(C, event, &win->handlers);
3966 
3967  /* File-read case. */
3968  if (CTX_wm_window(C) == nullptr) {
3970  return;
3971  }
3972  }
3973  }
3974 
3975  /* If press was handled, we don't want to do click. This way
3976  * press in tool key-map can override click in editor key-map. */
3977  if (ISMOUSE_BUTTON(event->type) && event->val == KM_PRESS &&
3978  !wm_action_not_handled(action)) {
3979  win->event_queue_check_click = false;
3980  }
3981 
3982  /* If the drag even was handled, don't attempt to keep re-handing the same
3983  * drag event on every cursor motion, see: T87511. */
3984  if (win->event_queue_check_drag_handled) {
3985  win->event_queue_check_drag = false;
3986  win->event_queue_check_drag_handled = false;
3987  }
3988 
3989  if (event_queue_check_drag_prev && (win->event_queue_check_drag == false)) {
3991  }
3992 
3993  /* Update previous mouse position for following events to use. */
3994  copy_v2_v2_int(win->eventstate->prev_xy, event->xy);
3995 
3996  /* Un-link and free here, Blender-quit then frees all. */
3997  BLI_remlink(&win->event_queue, event);
3998  wm_event_free_last_handled(win, event);
3999  }
4000 
4001  /* Only add mouse-move when the event queue was read entirely. */
4002  if (win->addmousemove && win->eventstate) {
4003  wmEvent tevent = *(win->eventstate);
4004  // printf("adding MOUSEMOVE %d %d\n", tevent.xy[0], tevent.xy[1]);
4005  tevent.type = MOUSEMOVE;
4006  tevent.val = KM_NOTHING;
4007  tevent.prev_xy[0] = tevent.xy[0];
4008  tevent.prev_xy[1] = tevent.xy[1];
4009  tevent.flag = (eWM_EventFlag)0;
4010  wm_event_add(win, &tevent);
4011  win->addmousemove = 0;
4012  }
4013 
4014  CTX_wm_window_set(C, nullptr);
4015  }
4016 
4017  /* Update key configuration after handling events. */
4018  WM_keyconfig_update(wm);
4020 }
4021 
4024 /* -------------------------------------------------------------------- */
4028 void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval)
4029 {
4030  /* Add to all windows! */
4031  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
4032  wmEvent event = *win->eventstate;
4033 
4034  event.type = EVT_FILESELECT;
4035  event.val = eventval;
4036  event.flag = (eWM_EventFlag)0;
4037  event.customdata = ophandle; /* Only as void pointer type check. */
4038 
4039  wm_event_add(win, &event);
4040  }
4041 }
4042 
4062 {
4063  wmWindow *ctx_win = CTX_wm_window(C);
4064 
4065  for (wmWindow *ctx_win_or_parent = ctx_win; ctx_win_or_parent;
4066  ctx_win_or_parent = ctx_win_or_parent->parent) {
4067  ScrArea *file_area = ED_fileselect_handler_area_find_any_with_op(ctx_win_or_parent);
4068 
4069  if (!file_area) {
4070  return ctx_win_or_parent;
4071  }
4072 
4073  if (file_area->full) {
4074  return ctx_win_or_parent;
4075  }
4076  }
4077 
4078  /* Fallback to the first window. */
4079  const wmWindowManager *wm = CTX_wm_manager(C);
4081  static_cast<const wmWindow *>(wm->windows.first)));
4082  return static_cast<wmWindow *>(wm->windows.first);
4083 }
4084 
4085 /* Operator is supposed to have a filled "path" property. */
4086 /* Optional property: file-type (XXX enum?) */
4087 
4089 {
4091  wmWindow *ctx_win = CTX_wm_window(C);
4092 
4093  /* The following vars define the root context. That is essentially the "parent" context of the
4094  * File Browser operation, to be restored for eventually executing the file operation. */
4096  /* Determined later. */
4097  ScrArea *root_area = nullptr;
4098  ARegion *root_region = nullptr;
4099 
4100  /* Close any popups, like when opening a file browser from the splash. */
4102 
4103  /* Setting the context window unsets the context area & screen. Avoid doing that, so operators
4104  * calling the file browser can operate in the context the browser was opened in. */
4105  if (ctx_win != root_win) {
4106  CTX_wm_window_set(C, root_win);
4107  }
4108 
4109  /* The root window may already have a File Browser open. Cancel it if so, only 1 should be open
4110  * per window. The root context of this operation is also used for the new operation. */
4111  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &root_win->modalhandlers) {
4112  if (handler_base->type == WM_HANDLER_TYPE_OP) {
4113  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
4114  if (handler->is_fileselect == false) {
4115  continue;
4116  }
4117 
4119  C, handler, ctx_win->eventstate, &root_area, &root_region);
4120 
4121  ScrArea *file_area = ED_fileselect_handler_area_find(root_win, handler->op);
4122 
4123  if (file_area) {
4124  CTX_wm_area_set(C, file_area);
4126  }
4127  /* If not found we stop the handler without changing the screen. */
4128  else {
4130  C, &root_win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
4131  }
4132  }
4133  }
4134 
4135  BLI_assert(root_win != nullptr);
4136  /* When not reusing the root context from a previous file browsing operation, use the current
4137  * area & region, if they are inside the root window. */
4138  if (!root_area && ctx_win == root_win) {
4139  root_area = CTX_wm_area(C);
4140  root_region = CTX_wm_region(C);
4141  }
4142 
4143  wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
4144  handler->head.type = WM_HANDLER_TYPE_OP;
4145 
4146  handler->is_fileselect = true;
4147  handler->op = op;
4148  handler->context.win = root_win;
4149  handler->context.area = root_area;
4150  handler->context.region = root_region;
4151 
4152  BLI_addhead(&root_win->modalhandlers, handler);
4153 
4154  /* Check props once before invoking if check is available
4155  * ensures initial properties are valid. */
4156  if (op->type->check) {
4157  op->type->check(C, op); /* Ignore return value. */
4158  }
4159 
4161 
4162  if (ctx_win != root_win) {
4163  CTX_wm_window_set(C, ctx_win);
4164  }
4165 }
4166 
4169 /* -------------------------------------------------------------------- */
4173 #if 0
4174 /* Lets not expose struct outside wm? */
4175 static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
4176 {
4177  handler->flag = flag;
4178 }
4179 #endif
4180 
4182 {
4183  wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
4184  handler->head.type = WM_HANDLER_TYPE_OP;
4185  wmWindow *win = CTX_wm_window(C);
4186 
4187  /* Operator was part of macro. */
4188  if (op->opm) {
4189  /* Give the mother macro to the handler. */
4190  handler->op = op->opm;
4191  /* Mother macro `opm` becomes the macro element. */
4192  handler->op->opm = op;
4193  }
4194  else {
4195  handler->op = op;
4196  }
4197 
4198  handler->context.area = CTX_wm_area(C); /* Means frozen screen context for modal handlers! */
4199  handler->context.region = CTX_wm_region(C);
4200  handler->context.region_type = handler->context.region ? handler->context.region->regiontype :
4201  -1;
4202 
4203  BLI_addhead(&win->modalhandlers, handler);
4204 
4205  if (op->type->modalkeymap) {
4207  }
4208 
4209  return handler;
4210 }
4211 
4212 void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
4213 {
4214  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
4215  if (handler_base->type == WM_HANDLER_TYPE_OP) {
4216  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
4217  /* File-select handler is quite special.
4218  * it needs to keep old area stored in handler, so don't change it. */
4219  if ((handler->context.area == old_area) && (handler->is_fileselect == false)) {
4220  handler->context.area = new_area;
4221  }
4222  }
4223  }
4224 }
4225 
4227  const ARegion *old_region,
4228  ARegion *new_region)
4229 {
4230  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
4231  if (handler_base->type == WM_HANDLER_TYPE_OP) {
4232  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
4233  /* File-select handler is quite special.
4234  * it needs to keep old region stored in handler, so don't change it. */
4235  if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
4236  handler->context.region = new_region;
4237  handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW;
4238  }
4239  }
4240  }
4241 }
4242 
4244 {
4245  if (!keymap) {
4246  CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr key-map");
4247  return nullptr;
4248  }
4249 
4250  /* Only allow same key-map once. */
4251  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4252  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
4253  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
4254  if (handler->keymap == keymap) {
4255  return handler;
4256  }
4257  }
4258  }
4259 
4260  wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
4261  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
4262  BLI_addtail(handlers, handler);
4263  handler->keymap = keymap;
4264 
4265  return handler;
4266 }
4267 
4281  wmWindow *win,
4282  wmEventHandler_Keymap *handler,
4283  wmEventHandler_KeymapResult *km_result,
4284  /* Extra arguments. */
4285  const bool with_gizmos)
4286 {
4287  memset(km_result, 0x0, sizeof(*km_result));
4288 
4289  const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)];
4290  int keymap_id_list_len = 0;
4291 
4292  /* NOTE(@campbellbarton): If `win` is nullptr, this function may not behave as expected.
4293  * Assert since this should not happen in practice.
4294  * If it does, the window could be looked up in `wm` using the `area`.
4295  * Keep nullptr checks in run-time code since any crashes here are difficult to redo. */
4296  BLI_assert_msg(win != nullptr, "The window should always be set for tool interactions!");
4297  const Scene *scene = win ? win->scene : nullptr;
4298 
4299  ScrArea *area = static_cast<ScrArea *>(handler->dynamic.user_data);
4300  handler->keymap_tool = nullptr;
4301  bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : nullptr;
4302 
4303  if (tref_rt && tref_rt->keymap[0]) {
4304  keymap_id_list[keymap_id_list_len++] = tref_rt->keymap;
4305  }
4306 
4307  bool is_gizmo_visible = false;
4308  bool is_gizmo_highlight = false;
4309 
4310  if ((tref_rt && tref_rt->keymap_fallback[0]) &&
4312  bool add_keymap = false;
4313  /* Support for the gizmo owning the tool key-map. */
4314 
4315  if (tref_rt->flag & TOOLREF_FLAG_FALLBACK_KEYMAP) {
4316  add_keymap = true;
4317  }
4318 
4319  if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
4320  wmGizmoMap *gzmap = nullptr;
4321  wmGizmoGroup *gzgroup = nullptr;
4322  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
4323  if (region->gizmo_map != nullptr) {
4324  gzmap = region->gizmo_map;
4325  gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
4326  if (gzgroup != nullptr) {
4327  break;
4328  }
4329  }
4330  }
4331  if (gzgroup != nullptr) {
4333  /* If all are hidden, don't override. */
4334  is_gizmo_visible = true;
4335  wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
4336  if (highlight) {
4337  is_gizmo_highlight = true;
4338  }
4339  add_keymap = true;
4340  }
4341  }
4342  }
4343 
4344  if (add_keymap) {
4345  keymap_id_list[keymap_id_list_len++] = tref_rt->keymap_fallback;
4346  }
4347  }
4348 
4349  if (is_gizmo_visible && !is_gizmo_highlight) {
4350  if (keymap_id_list_len == 2) {
4351  SWAP(const char *, keymap_id_list[0], keymap_id_list[1]);
4352  }
4353  }
4354 
4355  for (int i = 0; i < keymap_id_list_len; i++) {
4356  const char *keymap_id = keymap_id_list[i];
4357  BLI_assert(keymap_id && keymap_id[0]);
4358 
4360  &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
4361  /* We shouldn't use key-maps from unrelated spaces. */
4362  if (km == nullptr) {
4363  printf("Key-map: '%s' not found for tool '%s'\n", keymap_id, area->runtime.tool->idname);
4364  continue;
4365  }
4366  handler->keymap_tool = area->runtime.tool;
4367  km_result->keymaps[km_result->keymaps_len++] = km;
4368  }
4369 }
4370 
4372  wmWindow *win,
4373  wmEventHandler_Keymap *handler,
4374  wmEventHandler_KeymapResult *km_result)
4375 {
4376  wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, true);
4377 }
4378 
4380  wmWindow *win,
4381  wmEventHandler_Keymap *handler,
4382  wmEventHandler_KeymapResult *km_result)
4383 {
4384  wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
4385 }
4386 
4388  ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
4389 {
4390  if (!keymap_fn) {
4391  CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr keymap_fn");
4392  return nullptr;
4393  }
4394 
4395  /* Only allow same key-map once. */
4396  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4397  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
4398  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
4399  if (handler->dynamic.keymap_fn == keymap_fn) {
4400  /* Maximizing the view needs to update the area. */
4401  handler->dynamic.user_data = user_data;
4402  return handler;
4403  }
4404  }
4405  }
4406 
4407  wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
4408  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
4409  BLI_addtail(handlers, handler);
4410  handler->dynamic.keymap_fn = keymap_fn;
4411  handler->dynamic.user_data = user_data;
4412 
4413  return handler;
4414 }
4415 
4417  wmKeyMap *keymap,
4418  int UNUSED(priority))
4419 {
4420  WM_event_remove_keymap_handler(handlers, keymap);
4421 
4422  wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>("event key-map handler");
4423  handler->head.type = WM_HANDLER_TYPE_KEYMAP;
4424 
4425  BLI_addhead(handlers, handler);
4426  handler->keymap = keymap;
4427 
4428  return handler;
4429 }
4430 
4431 static bool event_or_prev_in_rect(const wmEvent *event, const rcti *rect)
4432 {
4433  if (BLI_rcti_isect_pt_v(rect, event->xy)) {
4434  return true;
4435  }
4436  if (event->type == MOUSEMOVE && BLI_rcti_isect_pt_v(rect, event->prev_xy)) {
4437  return true;
4438  }
4439  return false;
4440 }
4441 
4442 static bool handler_region_v2d_mask_test(const ARegion *region, const wmEvent *event)
4443 {
4444  rcti rect = region->v2d.mask;
4445  BLI_rcti_translate(&rect, region->winrct.xmin, region->winrct.ymin);
4446  return event_or_prev_in_rect(event, &rect);
4447 }
4448 
4450  wmKeyMap *keymap,
4451  EventHandlerPoll poll)
4452 {
4453  wmEventHandler_Keymap *handler = WM_event_add_keymap_handler(handlers, keymap);
4454  if (handler == nullptr) {
4455  return nullptr;
4456  }
4457 
4458  handler->head.poll = poll;
4459  return handler;
4460 }
4461 
4463 {
4465 }
4466 
4468 {
4469  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4470  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
4471  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
4472  if (handler->keymap == keymap) {
4473  BLI_remlink(handlers, handler);
4474  wm_event_free_handler(&handler->head);
4475  break;
4476  }
4477  }
4478  }
4479 }
4480 
4482  void(keymap_tag)(wmKeyMap *keymap,
4483  wmKeyMapItem *kmi,
4484  void *user_data),
4485  void *user_data)
4486 {
4487  handler->post.post_fn = keymap_tag;
4488  handler->post.user_data = user_data;
4489 }
4490 
4492  ListBase *handlers,
4493  wmUIHandlerFunc handle_fn,
4494  wmUIHandlerRemoveFunc remove_fn,
4495  void *user_data,
4496  const char flag)
4497 {
4498  wmEventHandler_UI *handler = MEM_cnew<wmEventHandler_UI>(__func__);
4499  handler->head.type = WM_HANDLER_TYPE_UI;
4500  handler->handle_fn = handle_fn;
4501  handler->remove_fn = remove_fn;
4502  handler->user_data = user_data;
4503  if (C) {
4504  handler->context.area = CTX_wm_area(C);
4505  handler->context.region = CTX_wm_region(C);
4506  handler->context.menu = CTX_wm_menu(C);
4507  }
4508  else {
4509  handler->context.area = nullptr;
4510  handler->context.region = nullptr;
4511  handler->context.menu = nullptr;
4512  }
4513 
4514  BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
4515  handler->head.flag = flag;
4516 
4517  BLI_addhead(handlers, handler);
4518 
4519  return handler;
4520 }
4521 
4523  wmUIHandlerFunc handle_fn,
4524  wmUIHandlerRemoveFunc remove_fn,
4525  void *user_data,
4526  const bool postpone)
4527 {
4528  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4529  if (handler_base->type == WM_HANDLER_TYPE_UI) {
4530  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
4531  if ((handler->handle_fn == handle_fn) && (handler->remove_fn == remove_fn) &&
4532  (handler->user_data == user_data)) {
4533  /* Handlers will be freed in #wm_handlers_do(). */
4534  if (postpone) {
4535  handler->head.flag |= WM_HANDLER_DO_FREE;
4536  }
4537  else {
4538  BLI_remlink(handlers, handler);
4539  wm_event_free_handler(&handler->head);
4540  }
4541  break;
4542  }
4543  }
4544  }
4545 }
4546 
4548  ListBase *handlers,
4549  wmUIHandlerFunc handle_fn,
4550  wmUIHandlerRemoveFunc remove_fn)
4551 {
4552  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
4553  if (handler_base->type == WM_HANDLER_TYPE_UI) {
4554  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
4555  if ((handler->handle_fn == handle_fn) && (handler->remove_fn == remove_fn)) {
4556  remove_fn(C, handler->user_data);
4557  BLI_remlink(handlers, handler);
4558  wm_event_free_handler(&handler->head);
4559  }
4560  }
4561  }
4562 }
4563 
4565 {
4566  /* Only allow same dropbox once. */
4567  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
4568  if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
4569  wmEventHandler_Dropbox *handler = (wmEventHandler_Dropbox *)handler_base;
4570  if (handler->dropboxes == dropboxes) {
4571  return handler;
4572  }
4573  }
4574  }
4575 
4576  wmEventHandler_Dropbox *handler = MEM_cnew<wmEventHandler_Dropbox>(__func__);
4577  handler->head.type = WM_HANDLER_TYPE_DROPBOX;
4578 
4579  /* Dropbox stored static, no free or copy. */
4580  handler->dropboxes = dropboxes;
4581  BLI_addhead(handlers, handler);
4582 
4583  return handler;
4584 }
4585 
4587 {
4588  /* XXX(@ton): solution works, still better check the real cause. */
4589 
4590  LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
4591  if (handler_base->type == WM_HANDLER_TYPE_UI) {
4592  wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
4593  if (handler->context.area == area) {
4594  BLI_remlink(handlers, handler);
4595  wm_event_free_handler(handler_base);
4596  }
4597  }
4598  }
4599 }
4600 
4602 {
4603  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
4604  if (handler_base->type != WM_HANDLER_TYPE_OP) {
4605  continue;
4606  }
4607  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
4608  if (handler->op && handler->op->type == ot) {
4609  return handler->op;
4610  }
4611  }
4612  return nullptr;
4613 }
4614 
4615 #if 0
4616 static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
4617 {
4618  BLI_remlink(handlers, handler);
4619  wm_event_free_handler(handler);
4620 }
4621 #endif
4622 
4624 {
4625  win->addmousemove = 1;
4626 }
4627 
4630 /* -------------------------------------------------------------------- */
4637 static int convert_key(GHOST_TKey key)
4638 {
4639  if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
4640  return (EVT_AKEY + ((int)key - GHOST_kKeyA));
4641  }
4642  if (key >= GHOST_kKey0 && key <= GHOST_kKey9) {
4643  return (EVT_ZEROKEY + ((int)key - GHOST_kKey0));
4644  }
4645  if (key >= GHOST_kKeyNumpad0 && key <= GHOST_kKeyNumpad9) {
4646  return (EVT_PAD0 + ((int)key - GHOST_kKeyNumpad0));
4647  }
4648  if (key >= GHOST_kKeyF1 && key <= GHOST_kKeyF24) {
4649  return (EVT_F1KEY + ((int)key - GHOST_kKeyF1));
4650  }
4651 
4652  switch (key) {
4653  case GHOST_kKeyBackSpace:
4654  return EVT_BACKSPACEKEY;
4655  case GHOST_kKeyTab:
4656  return EVT_TABKEY;
4657  case GHOST_kKeyLinefeed:
4658  return EVT_LINEFEEDKEY;
4659  case GHOST_kKeyClear:
4660  return EVENT_NONE;
4661  case GHOST_kKeyEnter:
4662  return EVT_RETKEY;
4663 
4664  case GHOST_kKeyEsc:
4665  return EVT_ESCKEY;
4666  case GHOST_kKeySpace:
4667  return EVT_SPACEKEY;
4668  case GHOST_kKeyQuote:
4669  return EVT_QUOTEKEY;
4670  case GHOST_kKeyComma:
4671  return EVT_COMMAKEY;
4672  case GHOST_kKeyMinus:
4673  return EVT_MINUSKEY;
4674  case GHOST_kKeyPlus:
4675  return EVT_PLUSKEY;
4676  case GHOST_kKeyPeriod:
4677  return EVT_PERIODKEY;
4678  case GHOST_kKeySlash:
4679  return EVT_SLASHKEY;
4680 
4681  case GHOST_kKeySemicolon:
4682  return EVT_SEMICOLONKEY;
4683  case GHOST_kKeyEqual:
4684  return EVT_EQUALKEY;
4685 
4686  case GHOST_kKeyLeftBracket:
4687  return EVT_LEFTBRACKETKEY;
4689  return EVT_RIGHTBRACKETKEY;
4690  case GHOST_kKeyBackslash:
4691  return EVT_BACKSLASHKEY;
4692  case GHOST_kKeyAccentGrave:
4693  return EVT_ACCENTGRAVEKEY;
4694 
4695  case GHOST_kKeyLeftShift:
4696  return EVT_LEFTSHIFTKEY;
4697  case GHOST_kKeyRightShift:
4698  return EVT_RIGHTSHIFTKEY;
4699  case GHOST_kKeyLeftControl:
4700  return EVT_LEFTCTRLKEY;
4702  return EVT_RIGHTCTRLKEY;
4703  case GHOST_kKeyOS:
4704  return EVT_OSKEY;
4705  case GHOST_kKeyLeftAlt:
4706  return EVT_LEFTALTKEY;
4707  case GHOST_kKeyRightAlt:
4708  return EVT_RIGHTALTKEY;
4709  case GHOST_kKeyApp:
4710  return EVT_APPKEY;
4711 
4712  case GHOST_kKeyCapsLock:
4713  return EVT_CAPSLOCKKEY;
4714  case GHOST_kKeyNumLock:
4715  return EVENT_NONE;
4716  case GHOST_kKeyScrollLock:
4717  return EVENT_NONE;
4718 
4719  case GHOST_kKeyLeftArrow:
4720  return EVT_LEFTARROWKEY;
4721  case GHOST_kKeyRightArrow:
4722  return EVT_RIGHTARROWKEY;
4723  case GHOST_kKeyUpArrow:
4724  return EVT_UPARROWKEY;
4725  case GHOST_kKeyDownArrow:
4726  return EVT_DOWNARROWKEY;
4727 
4728  case GHOST_kKeyPrintScreen:
4729  return EVENT_NONE;
4730  case GHOST_kKeyPause:
4731  return EVT_PAUSEKEY;
4732 
4733  case GHOST_kKeyInsert:
4734  return EVT_INSERTKEY;
4735  case GHOST_kKeyDelete:
4736  return EVT_DELKEY;
4737  case GHOST_kKeyHome:
4738  return EVT_HOMEKEY;
4739  case GHOST_kKeyEnd:
4740  return EVT_ENDKEY;
4741  case GHOST_kKeyUpPage:
4742  return EVT_PAGEUPKEY;
4743  case GHOST_kKeyDownPage:
4744  return EVT_PAGEDOWNKEY;
4745 
4747  return EVT_PADPERIOD;
4748  case GHOST_kKeyNumpadEnter:
4749  return EVT_PADENTER;
4750  case GHOST_kKeyNumpadPlus:
4751  return EVT_PADPLUSKEY;
4752  case GHOST_kKeyNumpadMinus:
4753  return EVT_PADMINUS;
4755  return EVT_PADASTERKEY;
4756  case GHOST_kKeyNumpadSlash:
4757  return EVT_PADSLASHKEY;
4758 
4759  case GHOST_kKeyGrLess:
4760  return EVT_GRLESSKEY;
4761 
4762  case GHOST_kKeyMediaPlay:
4763  return EVT_MEDIAPLAY;
4764  case GHOST_kKeyMediaStop:
4765  return EVT_MEDIASTOP;
4766  case GHOST_kKeyMediaFirst:
4767  return EVT_MEDIAFIRST;
4768  case GHOST_kKeyMediaLast:
4769  return EVT_MEDIALAST;
4770 
4771  case GHOST_kKeyUnknown:
4772  return EVT_UNKNOWNKEY;
4773 
4774 #if defined(__GNUC__) || defined(__clang__)
4775  /* Ensure all members of this enum are handled, otherwise generate a compiler warning.
4776  * Note that these members have been handled, these ranges are to satisfy the compiler. */
4777  case GHOST_kKeyF1 ... GHOST_kKeyF24:
4778  case GHOST_kKeyA ... GHOST_kKeyZ:
4780  case GHOST_kKey0 ... GHOST_kKey9: {
4782  break;
4783  }
4784 #else
4785  default: {
4786  break;
4787  }
4788 #endif
4789  }
4790 
4791  CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", (int)key);
4792  return EVENT_NONE;
4793 }
4794 
4795 static void wm_eventemulation(wmEvent *event, bool test_only)
4796 {
4797  /* Store last middle-mouse event value to make emulation work
4798  * when modifier keys are released first.
4799  * This really should be in a data structure somewhere. */
4800  static int emulating_event = EVENT_NONE;
4801 
4802  /* Middle-mouse emulation. */
4803  if (U.flag & USER_TWOBUTTONMOUSE) {
4804 
4805  if (event->type == LEFTMOUSE) {
4806  const uint8_t mod_test = (
4807 #if !defined(WIN32)
4808  (U.mouse_emulate_3_button_modifier == USER_EMU_MMB_MOD_OSKEY) ? KM_OSKEY : KM_ALT
4809 #else
4810  /* Disable for WIN32 for now because it accesses the start menu. */
4811  KM_ALT
4812 #endif
4813  );
4814 
4815  if (event->val == KM_PRESS) {
4816  if (event->modifier & mod_test) {
4817  event->modifier &= ~mod_test;
4818  event->type = MIDDLEMOUSE;
4819 
4820  if (!test_only) {
4821  emulating_event = MIDDLEMOUSE;
4822  }
4823  }
4824  }
4825  else if (event->val == KM_RELEASE) {
4826  /* Only send middle-mouse release if emulated. */
4827  if (emulating_event == MIDDLEMOUSE) {
4828  event->type = MIDDLEMOUSE;
4829  event->modifier &= ~mod_test;
4830  }
4831 
4832  if (!test_only) {
4833  emulating_event = EVENT_NONE;
4834  }
4835  }
4836  }
4837  }
4838 
4839  /* Numeric-pad emulation. */
4840  if (U.flag & USER_NONUMPAD) {
4841  switch (event->type) {
4842  case EVT_ZEROKEY:
4843  event->type = EVT_PAD0;
4844  break;
4845  case EVT_ONEKEY:
4846  event->type = EVT_PAD1;
4847  break;
4848  case EVT_TWOKEY:
4849  event->type = EVT_PAD2;
4850  break;
4851  case EVT_THREEKEY:
4852  event->type = EVT_PAD3;
4853  break;
4854  case EVT_FOURKEY:
4855  event->type = EVT_PAD4;
4856  break;
4857  case EVT_FIVEKEY:
4858  event->type = EVT_PAD5;
4859  break;
4860  case EVT_SIXKEY:
4861  event->type = EVT_PAD6;
4862  break;
4863  case EVT_SEVENKEY:
4864  event->type = EVT_PAD7;
4865  break;
4866  case EVT_EIGHTKEY:
4867  event->type = EVT_PAD8;
4868  break;
4869  case EVT_NINEKEY:
4870  event->type = EVT_PAD9;
4871  break;
4872  case EVT_MINUSKEY:
4873  event->type = EVT_PADMINUS;
4874  break;
4875  case EVT_EQUALKEY:
4876  event->type = EVT_PADPLUSKEY;
4877  break;
4878  case EVT_BACKSLASHKEY:
4879  event->type = EVT_PADSLASHKEY;
4880  break;
4881  }
4882  }
4883 }
4884 
4886 {
4887  wmTabletData tablet_data{};
4888  tablet_data.active = EVT_TABLET_NONE;
4889  tablet_data.pressure = 1.0f;
4890  tablet_data.x_tilt = 0.0f;
4891  tablet_data.y_tilt = 0.0f;
4892  tablet_data.is_motion_absolute = false;
4893  return tablet_data;
4894 }
4895 
4897 {
4898  *tablet_data = wm_event_tablet_data_default();
4899 }
4900 
4902 {
4903  if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) {
4904  wmtab->active = (int)tablet_data->Active;
4905  wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
4906  wmtab->x_tilt = tablet_data->Xtilt;
4907  wmtab->y_tilt = tablet_data->Ytilt;
4908  /* We could have a preference to support relative tablet motion (we can't detect that). */
4909  wmtab->is_motion_absolute = true;
4910  // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
4911  }
4912  else {
4913  *wmtab = wm_event_tablet_data_default();
4914  // printf("%s: not using tablet\n", __func__);
4915  }
4916 }
4917 
4918 #ifdef WITH_INPUT_NDOF
4919 /* Adds custom-data to event. */
4920 static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
4921 {
4922  wmNDOFMotionData *data = MEM_cnew<wmNDOFMotionData>("Custom-data NDOF");
4923 
4924  const float ts = U.ndof_sensitivity;
4925  const float rs = U.ndof_orbit_sensitivity;
4926 
4927  mul_v3_v3fl(data->tvec, &ghost->tx, ts);
4928  mul_v3_v3fl(data->rvec, &ghost->rx, rs);
4929 
4930  if (U.ndof_flag & NDOF_PAN_YZ_SWAP_AXIS) {
4931  float t;
4932  t = data->tvec[1];
4933  data->tvec[1] = -data->tvec[2];
4934  data->tvec[2] = t;
4935  }
4936 
4937  data->dt = ghost->dt;
4938 
4939  data->progress = (wmProgress)ghost->progress;
4940 
4941  event->custom = EVT_DATA_NDOF_MOTION;
4942  event->customdata = data;
4943  event->customdata_free = true;
4944 }
4945 #endif /* WITH_INPUT_NDOF */
4946 
4947 /* Imperfect but probably usable... draw/enable drags to other windows. */
4949 {
4950  /* If GHOST doesn't support window positioning, don't use this feature at all. */
4951  const static int8_t supports_window_position = GHOST_SupportsWindowPosition();
4952  if (!supports_window_position) {
4953  return nullptr;
4954  }
4955 
4956  if (wm->windows.first == wm->windows.last) {
4957  return nullptr;
4958  }
4959 
4960  /* In order to use window size and mouse position (pixels), we have to use a WM function. */
4961 
4962  /* Check if outside, include top window bar. */
4963  int event_xy[2] = {UNPACK2(event->xy)};
4964  if (event_xy[0] < 0 || event_xy[1] < 0 || event_xy[0] > WM_window_pixels_x(win) ||
4965  event_xy[1] > WM_window_pixels_y(win) + 30) {
4966  /* Let's skip windows having modal handlers now. */
4967  /* Potential XXX ugly... I wouldn't have added a `modalhandlers` list
4968  * (introduced in rev 23331, ton). */
4969  LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) {
4970  if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) {
4971  return nullptr;
4972  }
4973  }
4974 
4975  wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy);
4976  if (win_other && win_other != win) {
4977  copy_v2_v2_int(event->xy, event_xy);
4978  return win_other;
4979  }
4980  }
4981  return nullptr;
4982 }
4983 
4984 static bool wm_event_is_double_click(const wmEvent *event)
4985 {
4986  if ((event->type == event->prev_type) && (event->prev_val == KM_RELEASE) &&
4987  (event->val == KM_PRESS)) {
4988  if (ISMOUSE_BUTTON(event->type) && WM_event_drag_test(event, event->prev_press_xy)) {
4989  /* Pass. */
4990  }
4991  else {
4992  if ((PIL_check_seconds_timer() - event->prev_press_time) * 1000 < U.dbl_click_time) {
4993  return true;
4994  }
4995  }
4996  }
4997 
4998  return false;
4999 }
5000 
5004 static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state)
5005 {
5006  event->prev_val = event_state->prev_val = event_state->val;
5007  event->prev_type = event_state->prev_type = event_state->type;
5008 }
5009 
5010 static void wm_event_prev_click_set(wmEvent *event_state)
5011 {
5012  event_state->prev_press_time = PIL_check_seconds_timer();
5013  event_state->prev_press_type = event_state->type;
5014  event_state->prev_press_modifier = event_state->modifier;
5015  event_state->prev_press_keymodifier = event_state->keymodifier;
5016  event_state->prev_press_xy[0] = event_state->xy[0];
5017  event_state->prev_press_xy[1] = event_state->xy[1];
5018 }
5019 
5020 static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
5021 {
5022  wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
5023 
5024  /* Some painting operators want accurate mouse events, they can
5025  * handle in between mouse move moves, others can happily ignore
5026  * them for better performance. */
5027  if (event_last && event_last->type == MOUSEMOVE) {
5028  event_last->type = INBETWEEN_MOUSEMOVE;
5029  event_last->flag = (eWM_EventFlag)0;
5030  }
5031 
5032  wmEvent *event_new = wm_event_add(win, event);
5033  if (event_last == nullptr) {
5034  event_last = win->eventstate;
5035  }
5036 
5037  copy_v2_v2_int(event_new->prev_xy, event_last->xy);
5038  return event_new;
5039 }
5040 
5042 {
5043  /* Use the last handled event instead of `win->eventstate` because the state of the modifiers
5044  * and previous values should be set based on the last state, not using values from the future.
5045  * So this gives an accurate simulation of mouse motion before the next event is handled. */
5046  const wmEvent *event_last = win->event_last_handled;
5047 
5048  wmEvent tevent;
5049  if (event_last) {
5050  tevent = *event_last;
5051 
5052  tevent.flag = (eWM_EventFlag)0;
5053  tevent.utf8_buf[0] = '\0';
5054 
5055  wm_event_custom_clear(&tevent);
5056  }
5057  else {
5058  memset(&tevent, 0x0, sizeof(tevent));
5059  }
5060 
5061  tevent.type = MOUSEMOVE;
5062  tevent.val = KM_NOTHING;
5063  copy_v2_v2_int(tevent.prev_xy, tevent.xy);
5064 
5065  wmEvent *event_new = wm_event_add(win, &tevent);
5066  BLI_remlink(&win->event_queue, event_new);
5067  BLI_addhead(&win->event_queue, event_new);
5068 
5069  copy_v2_v2_int(event_new->prev_xy, event_last->xy);
5070  return event_new;
5071 }
5072 
5073 static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int deltax, int deltay)
5074 {
5075  /* Ignore in between track-pad events for performance, we only need high accuracy
5076  * for painting with mouse moves, for navigation using the accumulated value is ok. */
5077  wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
5078  if (event_last && event_last->type == event->type) {
5079  deltax += event_last->xy[0] - event_last->prev_xy[0];
5080  deltay += event_last->xy[1] - event_last->prev_xy[1];
5081 
5082  wm_event_free_last(win);
5083  }
5084 
5085  /* Set prev_xy, the delta is computed from this in operators. */
5086  wmEvent *event_new = wm_event_add(win, event);
5087  event_new->prev_xy[0] = event_new->xy[0] - deltax;
5088  event_new->prev_xy[1] = event_new->xy[1] - deltay;
5089 
5090  return event_new;
5091 }
5092 
5100  wmEvent *event_state,
5101  const bool is_keyboard,
5102  const bool check_double_click)
5103 {
5105  BLI_assert(ELEM(event->val, KM_PRESS, KM_RELEASE));
5106 
5107  /* Only copy these flags into the `event_state`. */
5108  const eWM_EventFlag event_state_flag_mask = WM_EVENT_IS_REPEAT;
5109 
5110  wm_event_prev_values_set(event, event_state);
5111 
5112  /* Copy to event state. */
5113  event_state->val = event->val;
5114  event_state->type = event->type;
5115  /* It's important only to write into the `event_state` modifier for keyboard
5116  * events because emulate MMB clears one of the modifiers in `event->modifier`,
5117  * making the second press not behave as if the modifier is pressed, see T96279. */
5118  if (is_keyboard) {
5119  event_state->modifier = event->modifier;
5120  }
5121  event_state->flag = (event->flag & event_state_flag_mask);
5122  /* NOTE: It's important that `keymodifier` is handled in the keyboard event handling logic
5123  * since the `event_state` and the `event` are not kept in sync. */
5124 
5125  /* Double click test. */
5126  if (check_double_click && wm_event_is_double_click(event)) {
5127  CLOG_INFO(WM_LOG_HANDLERS, 1, "DBL_CLICK: detected");
5128  event->val = KM_DBL_CLICK;
5129  }
5130  else if (event->val == KM_PRESS) {
5131  if ((event->flag & WM_EVENT_IS_REPEAT) == 0) {
5132  wm_event_prev_click_set(event_state);
5133  }
5134  }
5135 }
5136 
5138  wmEvent *event_state,
5139  const GHOST_TEventType type)
5140 {
5141  const bool is_keyboard = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventKeyUp);
5142  const bool check_double_click = true;
5143  wm_event_state_update_and_click_set_ex(event, event_state, is_keyboard, check_double_click);
5144 }
5145 
5146 /* Returns true when the two events corresponds to a press of the same key with the same modifiers.
5147  */
5148 static bool wm_event_is_same_key_press(const wmEvent &event_a, const wmEvent &event_b)
5149 {
5150  if (event_a.val != KM_PRESS || event_b.val != KM_PRESS) {
5151  return false;
5152  }
5153 
5154  if (event_a.modifier != event_b.modifier || event_a.type != event_b.type) {
5155  return false;
5156  }
5157 
5158  return true;
5159 }
5160 
5169 static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent &event)
5170 {
5171  if (BLI_listbase_is_empty(&win->event_queue)) {
5172  /* If the queue is empty never ignore the event.
5173  * Empty queue at this point means that the events are handled fast enough, and there is no
5174  * reason to ignore anything. */
5175  return false;
5176  }
5177 
5178  if ((event.flag & WM_EVENT_IS_REPEAT) == 0) {
5179  /* Only ignore repeat events from the keyboard, and allow accumulation of non-repeat events.
5180  *
5181  * The goal of this check is to allow events coming from a keyboard macro software, which can
5182  * generate events quicker than the main loop handles them. In this case we want all events to
5183  * be handled (unless the keyboard macro software tags them as repeat) because otherwise it
5184  * will become impossible to get reliable results of automated events testing. */
5185  return false;
5186  }
5187 
5188  const wmEvent &last_event = *reinterpret_cast<const wmEvent *>(win->event_queue.last);
5189 
5190  return wm_event_is_same_key_press(last_event, event);
5191 }
5192 
5193 void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
5194 {
5195  if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
5196  return;
5197  }
5198 
5209  wmEvent event, *event_state = win->eventstate;
5210 
5211  /* Initialize and copy state (only mouse x y and modifiers). */
5212  event = *event_state;
5213  event.flag = (eWM_EventFlag)0;
5214 
5225  event.prev_type = event.type;
5226  event.prev_val = event.val;
5227 
5228  /* Ensure the event state is correct, any deviation from this may cause bugs.
5229  *
5230  * NOTE: #EVENT_NONE is set when unknown keys are pressed,
5231  * while not common, avoid a false alarm. */
5232 #ifndef NDEBUG
5233  if ((event_state->type || event_state->val) && /* Ignore cleared event state. */
5234  !(ISKEYBOARD_OR_BUTTON(event_state->type) || (event_state->type == EVENT_NONE))) {
5236  "Non-keyboard/mouse button found in 'win->eventstate->type = %d'",
5237  event_state->type);
5238  }
5239  if ((event_state->prev_type || event_state->prev_val) && /* Ignore cleared event state. */
5240  !(ISKEYBOARD_OR_BUTTON(event_state->prev_type) || (event_state->type == EVENT_NONE))) {
5242  "Non-keyboard/mouse button found in 'win->eventstate->prev_type = %d'",
5243  event_state->prev_type);
5244  }
5245 #endif
5246 
5247  switch (type) {
5248  /* Mouse move, also to inactive window (X11 does this). */
5249  case GHOST_kEventCursorMove: {
5250  GHOST_TEventCursorData *cd = static_cast<GHOST_TEventCursorData *>(customdata);
5251 
5252  copy_v2_v2_int(event.xy, &cd->x);
5253  wm_stereo3d_mouse_offset_apply(win, event.xy);
5254  wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
5255 
5256  event.type = MOUSEMOVE;
5257  event.val = KM_NOTHING;
5258  {
5259  wmEvent *event_new = wm_event_add_mousemove(win, &event);
5260  copy_v2_v2_int(event_state->xy, event_new->xy);
5261  event_state->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute;
5262  }
5263 
5264  /* Also add to other window if event is there, this makes overdraws disappear nicely. */
5265  /* It remaps mouse-coord to other window in event. */
5266  wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
5267  if (win_other) {
5268  wmEvent event_other = *win_other->eventstate;
5269 
5270  /* See comment for this operation on `event` for details. */
5271  event_other.prev_type = event_other.type;
5272  event_other.prev_val = event_other.val;
5273 
5274  copy_v2_v2_int(event_other.xy, event.xy);
5275  event_other.type = MOUSEMOVE;
5276  event_other.val = KM_NOTHING;
5277  {
5278  wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other);
5279  copy_v2_v2_int(win_other->eventstate->xy, event_new->xy);
5281  }
5282  }
5283 
5284  break;
5285  }
5286  case GHOST_kEventTrackpad: {
5287  GHOST_TEventTrackpadData *pd = static_cast<GHOST_TEventTrackpadData *>(customdata);
5288  switch (pd->subtype) {
5290  event.type = MOUSEZOOM;
5291  pd->deltaX = -pd->deltaX;
5292  pd->deltaY = -pd->deltaY;
5293  break;
5295  event.type = MOUSESMARTZOOM;
5296  break;
5298  event.type = MOUSEROTATE;
5299  break;
5301  default:
5302  event.type = MOUSEPAN;
5303  break;
5304  }
5305 
5306  event.xy[0] = event_state->xy[0] = pd->x;
5307  event.xy[1] = event_state->xy[1] = pd->y;
5308  event.val = KM_NOTHING;
5309 
5310  /* The direction is inverted from the device due to system preferences. */
5311  if (pd->isDirectionInverted) {
5312  event.flag |= WM_EVENT_SCROLL_INVERT;
5313  }
5314 
5315  wm_event_add_trackpad(win, &event, pd->deltaX, -pd->deltaY);
5316  break;
5317  }
5318  /* Mouse button. */
5320  case GHOST_kEventButtonUp: {
5321  GHOST_TEventButtonData *bd = static_cast<GHOST_TEventButtonData *>(customdata);
5322 
5323  /* Get value and type from Ghost. */
5324  event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
5325 
5326  if (bd->button == GHOST_kButtonMaskLeft) {
5327  event.type = LEFTMOUSE;
5328  }
5329  else if (bd->button == GHOST_kButtonMaskRight) {
5330  event.type = RIGHTMOUSE;
5331  }
5332  else if (bd->button == GHOST_kButtonMaskButton4) {
5333  event.type = BUTTON4MOUSE;
5334  }
5335  else if (bd->button == GHOST_kButtonMaskButton5) {
5336  event.type = BUTTON5MOUSE;
5337  }
5338  else if (bd->button == GHOST_kButtonMaskButton6) {
5339  event.type = BUTTON6MOUSE;
5340  }
5341  else if (bd->button == GHOST_kButtonMaskButton7) {
5342  event.type = BUTTON7MOUSE;
5343  }
5344  else {
5345  event.type = MIDDLEMOUSE;
5346  }
5347 
5348  /* Get tablet data. */
5349  wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
5350 
5351  wm_eventemulation(&event, false);
5353 
5354  /* Add to other window if event is there (not to both!). */
5355  wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
5356  if (win_other) {
5357  wmEvent event_other = *win_other->eventstate;
5358 
5359  /* See comment for this operation on `event` for details. */
5360  event_other.prev_type = event_other.type;
5361  event_other.prev_val = event_other.val;
5362 
5363  copy_v2_v2_int(event_other.xy, event.xy);
5364 
5365  event_other.type = event.type;
5366  event_other.val = event.val;
5367  event_other.tablet = event.tablet;
5368 
5369  wm_event_add(win_other, &event_other);
5370  }
5371  else {
5372  wm_event_add(win, &event);
5373  }
5374 
5375  break;
5376  }
5377  /* Keyboard. */
5378  case GHOST_kEventKeyDown:
5379  case GHOST_kEventKeyUp: {
5380  GHOST_TEventKeyData *kd = static_cast<GHOST_TEventKeyData *>(customdata);
5381  event.type = convert_key(kd->key);
5382  if (UNLIKELY(event.type == EVENT_NONE)) {
5383  break;
5384  }
5385 
5386  /* Might be not null terminated. */
5387  memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
5388  if (kd->is_repeat) {
5389  event.flag |= WM_EVENT_IS_REPEAT;
5390  }
5391  event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE;
5392 
5393  wm_eventemulation(&event, false);
5394 
5395  /* Exclude arrow keys, escape, etc from text input. */
5396  if (type == GHOST_kEventKeyUp) {
5397  /* Ghost should do this already for key up. */
5398  if (event.utf8_buf[0]) {
5400  "ghost on your platform is misbehaving, utf8 events on key up!");
5401  }
5402  event.utf8_buf[0] = '\0';
5403  }
5404  else {
5405  if (event.utf8_buf[0] < 32 && event.utf8_buf[0] > 0) {
5406  event.utf8_buf[0] = '\0';
5407  }
5408  }
5409 
5410  if (event.utf8_buf[0]) {
5411  /* NOTE(@campbellbarton): Detect non-ASCII characters stored in `utf8_buf`,
5412  * ideally this would never happen but it can't be ruled out for X11 which has
5413  * special handling of Latin1 when building without UTF8 support.
5414  * Avoid regressions by adding this conversions, it should eventually be removed. */
5415  if ((event.utf8_buf[0] >= 0x80) && (event.utf8_buf[1] == '\0')) {
5416  const uint c = (uint)event.utf8_buf[0];
5417  int utf8_buf_len = BLI_str_utf8_from_unicode(c, event.utf8_buf, sizeof(event.utf8_buf));
5419  "ghost detected non-ASCII single byte character '%u', converting to utf8 "
5420  "('%.*s', length=%d)",
5421  c,
5422  utf8_buf_len,
5423  event.utf8_buf,
5424  utf8_buf_len);
5425  }
5426 
5427  if (BLI_str_utf8_size(event.utf8_buf) == -1) {
5429  "ghost detected an invalid unicode character '%d'",
5430  (int)(unsigned char)event.utf8_buf[0]);
5431  event.utf8_buf[0] = '\0';
5432  }
5433  }
5434 
5435  switch (event.type) {
5436  case EVT_LEFTSHIFTKEY:
5437  case EVT_RIGHTSHIFTKEY: {
5438  SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_SHIFT);
5439  break;
5440  }
5441  case EVT_LEFTCTRLKEY:
5442  case EVT_RIGHTCTRLKEY: {
5443  SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_CTRL);
5444  break;
5445  }
5446  case EVT_LEFTALTKEY:
5447  case EVT_RIGHTALTKEY: {
5448  SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_ALT);
5449  break;
5450  }
5451  case EVT_OSKEY: {
5452  SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_OSKEY);
5453  break;
5454  }
5455  default: {
5456  if (event.val == KM_PRESS) {
5457  if (event.keymodifier == 0) {
5458  /* Only set in `eventstate`, for next event. */
5459  event_state->keymodifier = event.type;
5460  }
5461  }
5462  else {
5463  BLI_assert(event.val == KM_RELEASE);
5464  if (event.keymodifier == event.type) {
5465  event.keymodifier = event_state->keymodifier = 0;
5466  }
5467  }
5468 
5469  /* This case happens on holding a key pressed,
5470  * it should not generate press events with the same key as modifier. */
5471  if (event.keymodifier == event.type) {
5472  event.keymodifier = 0;
5473  }
5474  else if (event.keymodifier == EVT_UNKNOWNKEY) {
5475  /* This case happens with an external number-pad, and also when using 'dead keys'
5476  * (to compose complex latin characters e.g.), it's not really clear why.
5477  * Since it's impossible to map a key modifier to an unknown key,
5478  * it shouldn't harm to clear it. */
5479  event_state->keymodifier = event.keymodifier = 0;
5480  }
5481  break;
5482  }
5483  }
5484 
5485  /* It's important `event.modifier` has been initialized first. */
5487 
5488  /* If test_break set, it catches this. Do not set with modifier presses.
5489  * Exclude modifiers because MS-Windows uses these to bring up the task manager.
5490  *
5491  * NOTE: in general handling events here isn't great design as
5492  * event handling should be managed by the event handling loop.
5493  * Make an exception for `G.is_break` as it ensures we can always cancel operations
5494  * such as rendering or baking no matter which operation is currently handling events. */
5495  if ((event.type == EVT_ESCKEY) && (event.val == KM_PRESS) && (event.modifier == 0)) {
5496  G.is_break = true;
5497  }
5498 
5499  if (!wm_event_is_ignorable_key_press(win, event)) {
5500  wm_event_add(win, &event);
5501  }
5502 
5503  break;
5504  }
5505 
5506  case GHOST_kEventWheel: {
5507  GHOST_TEventWheelData *wheelData = static_cast<GHOST_TEventWheelData *>(customdata);
5508 
5509  if (wheelData->z > 0) {
5510  event.type = WHEELUPMOUSE;
5511  }
5512  else {
5513  event.type = WHEELDOWNMOUSE;
5514  }
5515 
5516  event.val = KM_PRESS;
5517  wm_event_add(win, &event);
5518 
5519  break;
5520  }
5521  case GHOST_kEventTimer: {
5522  event.type = TIMER;
5523  event.custom = EVT_DATA_TIMER;
5524  event.customdata = customdata;
5525  event.val = KM_NOTHING;
5526  event.keymodifier = 0;
5527  wm_event_add(win, &event);
5528 
5529  break;
5530  }
5531 
5532 #ifdef WITH_INPUT_NDOF
5533  case GHOST_kEventNDOFMotion: {
5534  event.type = NDOF_MOTION;
5535  event.val = KM_NOTHING;
5536  attach_ndof_data(&event, static_cast<const GHOST_TEventNDOFMotionData *>(customdata));
5537  wm_event_add(win, &event);
5538 
5539  CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]);
5540  break;
5541  }
5542 
5543  case GHOST_kEventNDOFButton: {
5544  GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
5545 
5546  event.type = NDOF_BUTTON_NONE + e->button;
5547 
5548  switch (e->action) {
5549  case GHOST_kPress:
5550  event.val = KM_PRESS;
5551  break;
5552  case GHOST_kRelease:
5553  event.val = KM_RELEASE;
5554  break;
5555  default:
5557  }
5558 
5559  event.custom = 0;
5560  event.customdata = nullptr;
5561 
5563 
5564  wm_event_add(win, &event);
5565 
5566  break;
5567  }
5568 #endif /* WITH_INPUT_NDOF */
5569 
5570  case GHOST_kEventUnknown:
5571  case GHOST_kNumEventTypes:
5572  break;
5573 
5575  event.type = WINDEACTIVATE;
5576  wm_event_add(win, &event);
5577 
5578  break;
5579  }
5580 
5581 #ifdef WITH_INPUT_IME
5583  event.val = KM_PRESS;
5584  win->ime_data = static_cast<wmIMEData *>(customdata);
5585  win->ime_data->is_ime_composing = true;
5586  event.type = WM_IME_COMPOSITE_START;
5587  wm_event_add(win, &event);
5588  break;
5589  }
5591  event.val = KM_PRESS;
5592  event.type = WM_IME_COMPOSITE_EVENT;
5593  wm_event_add(win, &event);
5594  break;
5595  }
5597  event.val = KM_PRESS;
5598  if (win->ime_data) {
5599  win->ime_data->is_ime_composing = false;
5600  }
5601  event.type = WM_IME_COMPOSITE_END;
5602  wm_event_add(win, &event);
5603  break;
5604  }
5605 #endif /* WITH_INPUT_IME */
5606  }
5607 
5608 #if 0
5609  WM_event_print(&event);
5610 #endif
5611 }
5612 
5613 #ifdef WITH_XR_OPENXR
5614 void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
5615 {
5617 
5618  wmEvent event{};
5619  event.type = EVT_XR_ACTION;
5620  event.val = val;
5621  event.flag = (eWM_EventFlag)0;
5622  event.custom = EVT_DATA_XR;
5623  event.customdata = actiondata;
5624  event.customdata_free = true;
5625 
5626  wm_event_add(win, &event);
5627 }
5628 #endif /* WITH_XR_OPENXR */
5629 
5632 /* -------------------------------------------------------------------- */
5641 {
5643 
5644  if (wm->is_interface_locked) {
5645  if ((ot->flag & OPTYPE_LOCK_BYPASS) == 0) {
5646  return false;
5647  }
5648  }
5649 
5650  return true;
5651 }
5652 
5654 {
5655  /* This will prevent events from being handled while interface is locked
5656  *
5657  * Use a "local" flag for now, because currently no other areas could
5658  * benefit of locked interface anyway (aka using G.is_interface_locked
5659  * wouldn't be useful anywhere outside of window manager, so let's not
5660  * pollute global context with such an information for now).
5661  */
5662  wm->is_interface_locked = lock ? 1 : 0;
5663 
5664  /* This will prevent drawing regions which uses non-thread-safe data.
5665  * Currently it'll be just a 3D viewport.
5666  *
5667  * TODO(sergey): Make it different locked states, so different jobs
5668  * could lock different areas of blender and allow
5669  * interaction with others?
5670  */
5672 }
5673 
5676 /* -------------------------------------------------------------------- */
5681  wmWindow *win,
5682  wmEventHandler_Keymap *handler,
5683  wmEventHandler_KeymapResult *km_result)
5684 {
5685  if (handler->dynamic.keymap_fn != nullptr) {
5686  handler->dynamic.keymap_fn(wm, win, handler, km_result);
5687  BLI_assert(handler->keymap == nullptr);
5688  }
5689  else {
5690  memset(km_result, 0x0, sizeof(*km_result));
5691  wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
5692  BLI_assert(keymap != nullptr);
5693  if (keymap != nullptr) {
5694  km_result->keymaps[km_result->keymaps_len++] = keymap;
5695  }
5696  }
5697 }
5698 
5700 {
5701  LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
5702  if (wm_eventmatch(event, kmi)) {
5703  wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
5705  return kmi;
5706  }
5707  }
5708  }
5709  return nullptr;
5710 }
5711 
5713  bContext *C, wmWindowManager *wm, wmWindow *win, ListBase *handlers, const wmEvent *event)
5714 {
5715  LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
5716  /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
5717  if (handler_base->flag & WM_HANDLER_DO_FREE) {
5718  /* Pass. */
5719  }
5720  else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
5721  if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
5722  wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
5723  wmEventHandler_KeymapResult km_result;
5724  WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
5725  for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
5726  wmKeyMap *keymap = km_result.keymaps[km_index];
5727  if (WM_keymap_poll(C, keymap)) {
5728  wmKeyMapItem *kmi = WM_event_match_keymap_item(C, keymap, event);
5729  if (kmi != nullptr) {
5730  return kmi;
5731  }
5732  }
5733  }
5734  }
5735  }
5736  }
5737  return nullptr;
5738 }
5739 
5742 /* -------------------------------------------------------------------- */
5753  short space_type;
5757 };
5758 
5765  char text[3][2][128];
5768 };
5769 
5771  const wmEvent *event,
5772  short space_type,
5773  short region_type,
5774  const bToolRef *tref)
5775 {
5776  state->modifier = event->modifier;
5777  state->space_type = space_type;
5778  state->region_type = region_type;
5779  state->tref = tref ? *tref : bToolRef{};
5780 }
5781 
5783  int button_index,
5784  int type_index)
5785 {
5786  if (win->cursor_keymap_status != nullptr) {
5787  CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
5788  const char *msg = cd->text[button_index][type_index];
5789  if (*msg) {
5790  return msg;
5791  }
5792  }
5793  return nullptr;
5794 }
5795 
5797 {
5798  if (screen->state == SCREENFULL) {
5799  return nullptr;
5800  }
5801  ScrArea *area_statusbar = nullptr;
5803  if (area->spacetype == SPACE_STATUSBAR) {
5804  area_statusbar = area;
5805  break;
5806  }
5807  }
5808  return area_statusbar;
5809 }
5810 
5812 {
5813  bScreen *screen = WM_window_get_active_screen(win);
5814  ScrArea *area = WM_window_status_area_find(win, screen);
5815  if (area != nullptr) {
5817  }
5818 }
5819 
5821 {
5822  bScreen *screen = WM_window_get_active_screen(win);
5823  ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
5824  if (area_statusbar == nullptr) {
5826  return;
5827  }
5828 
5829  CursorKeymapInfo *cd;
5830  if (UNLIKELY(win->cursor_keymap_status == nullptr)) {
5831  win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__);
5832  }
5833  cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
5834 
5835  /* Detect unchanged state (early exit). */
5836  if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
5837  return;
5838  }
5839 
5840  /* Now perform more comprehensive check,
5841  * still keep this fast since it happens on mouse-move. */
5843  cd->state_event = *win->eventstate;
5844 
5845  /* Find active region and associated area. */
5846  ARegion *region = screen->active_region;
5847  if (region == nullptr) {
5848  return;
5849  }
5850 
5851  ScrArea *area = nullptr;
5852  ED_screen_areas_iter (win, screen, area_iter) {
5853  if (BLI_findindex(&area_iter->regionbase, region) != -1) {
5854  area = area_iter;
5855  break;
5856  }
5857  }
5858  if (area == nullptr) {
5859  return;
5860  }
5861 
5862  /* Keep as-is. */
5863  if (ELEM(area->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
5864  return;
5865  }
5866  if (ELEM(region->regiontype,
5871  RGN_TYPE_HUD)) {
5872  return;
5873  }
5874  /* Fallback to window. */
5877  }
5878 
5879  /* Detect changes to the state. */
5880  {
5881  bToolRef *tref = nullptr;
5882  if ((region->regiontype == RGN_TYPE_WINDOW) &&
5883  ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
5884  ViewLayer *view_layer = WM_window_get_active_view_layer(win);
5885  WorkSpace *workspace = WM_window_get_active_workspace(win);
5886  bToolKey tkey{};
5887  tkey.space_type = area->spacetype;
5888  tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
5889  tref = WM_toolsystem_ref_find(workspace, &tkey);
5890  }
5891  wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
5892  if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
5893  return;
5894  }
5895  }
5896 
5897  /* Changed context found, detect changes to key-map and refresh the status bar. */
5898  const struct {
5899  int button_index;
5900  int type_index; /* 0: press or click, 1: drag. */
5901  int event_type;
5902  int event_value;
5903  } event_data[] = {
5904  {0, 0, LEFTMOUSE, KM_PRESS},
5905  {0, 0, LEFTMOUSE, KM_CLICK},
5906  {0, 0, LEFTMOUSE, KM_CLICK_DRAG},
5907 
5908  {1, 0, MIDDLEMOUSE, KM_PRESS},
5909  {1, 0, MIDDLEMOUSE, KM_CLICK},
5910  {1, 0, MIDDLEMOUSE, KM_CLICK_DRAG},
5911 
5912  {2, 0, RIGHTMOUSE, KM_PRESS},
5913  {2, 0, RIGHTMOUSE, KM_CLICK},
5914  {2, 0, RIGHTMOUSE, KM_CLICK_DRAG},
5915  };
5916 
5917  for (int button_index = 0; button_index < 3; button_index++) {
5918  cd->text[button_index][0][0] = '\0';
5919  cd->text[button_index][1][0] = '\0';
5920  }
5921 
5922  CTX_wm_window_set(C, win);
5924  CTX_wm_region_set(C, region);
5925 
5926  ListBase *handlers[] = {
5927  &region->handlers,
5928  &area->handlers,
5929  &win->handlers,
5930  };
5931 
5933  for (int data_index = 0; data_index < ARRAY_SIZE(event_data); data_index++) {
5934  const int button_index = event_data[data_index].button_index;
5935  const int type_index = event_data[data_index].type_index;
5936  if (cd->text[button_index][type_index][0] != 0) {
5937  continue;
5938  }
5939  wmEvent test_event = *win->eventstate;
5940  test_event.type = event_data[data_index].event_type;
5941  test_event.val = event_data[data_index].event_value;
5942  test_event.flag = (eWM_EventFlag)0;
5943  wm_eventemulation(&test_event, true);
5944  wmKeyMapItem *kmi = nullptr;
5945  for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
5947  C, wm, win, handlers[handler_index], &test_event);
5948  if (kmi) {
5949  break;
5950  }
5951  }
5952  if (kmi) {
5953  wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
5954  const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname;
5955  STRNCPY(cd->text[button_index][type_index], name);
5956  }
5957  }
5958 
5959  if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
5960  ED_area_tag_redraw(area_statusbar);
5961  }
5962 
5963  CTX_wm_window_set(C, nullptr);
5964 }
5965 
5968 /* -------------------------------------------------------------------- */
5973 {
5975  wmKeyMap *keymap = nullptr;
5976  wmOperator *op = nullptr;
5977  LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
5978  if (handler_base->type == WM_HANDLER_TYPE_OP) {
5979  wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
5980  if (handler->op != nullptr) {
5981  /* 'handler->keymap' could be checked too, seems not to be used. */
5982  wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap);
5983  if (keymap_test && keymap_test->modal_items) {
5984  keymap = keymap_test;
5985  op = handler->op;
5986  break;
5987  }
5988  }
5989  }
5990  }
5991  if (keymap == nullptr || keymap->modal_items == nullptr) {
5992  return false;
5993  }
5994  const EnumPropertyItem *items = static_cast<const EnumPropertyItem *>(keymap->modal_items);
5995 
5996  uiLayout *row = uiLayoutRow(layout, true);
5997  for (int i = 0; items[i].identifier; i++) {
5998  if (!items[i].identifier[0]) {
5999  continue;
6000  }
6001  if ((keymap->poll_modal_item != nullptr) &&
6002  (keymap->poll_modal_item(op, items[i].value) == false)) {
6003  continue;
6004  }
6005 
6006  bool show_text = true;
6007 
6008  {
6009  /* WARNING: O(n^2). */
6010  wmKeyMapItem *kmi = nullptr;
6011  for (kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next) {
6012  if (kmi->propvalue == items[i].value) {
6013  break;
6014  }
6015  }
6016  if (kmi != nullptr) {
6017  if (kmi->val == KM_RELEASE) {
6018  /* Assume release events just disable something which was toggled on. */
6019  continue;
6020  }
6021  if (uiTemplateEventFromKeymapItem(row, items[i].name, kmi, false)) {
6022  show_text = false;
6023  }
6024  }
6025  }
6026  if (show_text) {
6027  char buf[UI_MAX_DRAW_STR];
6028  int available_len = sizeof(buf);
6029  char *p = buf;
6031  op->type, items[i].value, true, UI_MAX_SHORTCUT_STR, &available_len, &p);
6032  p -= 1;
6033  if (p > buf) {
6034  BLI_snprintf(p, available_len, ": %s", items[i].name);
6035  uiItemL(row, buf, 0);
6036  }
6037  }
6038  }
6039  return true;
6040 }
6041 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
void CTX_store_set(bContext *C, bContextStore *store)
Definition: context.c:188
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
struct ARegion * CTX_wm_menu(const bContext *C)
Definition: context.c:760
void CTX_data_scene_set(bContext *C, struct Scene *scene)
Definition: context.c:1271
void CTX_wm_menu_set(bContext *C, struct ARegion *menu)
Definition: context.c:1020
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
Definition: context.c:1025
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
bContextStore * CTX_store_copy(bContextStore *store)
Definition: context.c:209
void CTX_store_free(bContextStore *store)
Definition: context.c:217
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
void CTX_wm_screen_set(bContext *C, struct bScreen *screen)
Definition: context.c:984
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:966
struct ReportList * CTX_wm_reports(const bContext *C)
Definition: context.c:775
void CTX_wm_operator_poll_msg_clear(struct bContext *C)
Definition: context.c:1030
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:997
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
bContextStore * CTX_store_get(bContext *C)
Definition: context.c:183
CustomData interface, see also DNA_customdata_types.h.
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition: customdata.cc:77
#define G_MAIN
Definition: BKE_global.h:267
@ G_DEBUG_HANDLERS
Definition: BKE_global.h:178
@ G_DEBUG_WM
Definition: BKE_global.h:179
@ G_DEBUG_EVENTS
Definition: BKE_global.h:177
@ G_FLAG_EVENT_SIMULATE
Definition: BKE_global.h:151
char * IDP_reprN(const struct IDProperty *prop, uint *r_len)
struct IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:887
void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL()
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BKE_id_remapper_iter(const struct IDRemapper *id_remapper, IDRemapperIterFunction func, void *user_data)
void BKE_report_print_level_set(ReportList *reports, eReportType level)
Definition: report.c:204
void BKE_reports_clear(ReportList *reports)
Definition: report.c:63
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:50
void BKE_reports_print(ReportList *reports, eReportType level)
Definition: report.c:267
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.cc:2648
struct Depsgraph * BKE_scene_ensure_depsgraph(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer)
Definition: scene.cc:3456
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
void BKE_spacedata_draw_locks(bool set)
Definition: screen.c:516
struct ARegion * BKE_area_find_region_active_win(struct ScrArea *area)
Definition: screen.c:883
struct ARegion * BKE_area_find_region_xy(struct ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition: screen.c:898
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:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define BLI_INLINE
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:50
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:256
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:281
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
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:123
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:265
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void * BLI_poptail(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:230
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:559
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:485
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: string_utf8.c:452
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, size_t outbuf_len) ATTR_NONNULL(2)
Definition: string_utf8.c:575
unsigned int uint
Definition: BLI_sys_types.h:67
void BLI_timer_execute(void)
Definition: BLI_timer.c:117
#define UNPACK2(a)
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
#define CLOG_STR_INFO_N(clg_ref, level, str)
Definition: CLG_log.h:200
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, bool do_time)
void DEG_make_active(struct Depsgraph *depsgraph)
Definition: depsgraph.cc:325
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ IDP_GROUP
Definition: DNA_ID.h:141
@ ID_RECALC_FRAME_CHANGE
Definition: DNA_ID.h:841
These structs are the foundation for all linked lists in the library system.
@ SCE_WORKSPACE_TOOL_FALLBACK
#define FPS
@ AREA_FLAG_OFFSCREEN
@ AREA_FLAG_ACTIONZONES_UPDATE
@ RGN_FLAG_HIDDEN
@ SCREENFULL
@ 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
@ RGN_ALIGN_BOTTOM
#define RGN_TYPE_ANY
#define RGN_TYPE_IS_HEADER_ANY(regiontype)
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_FILE
@ SPACE_VIEW3D
@ 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
@ OP_IS_REPEAT_LAST
@ OP_IS_MODAL_CURSOR_REGION
@ OP_IS_MODAL_GRAB_CURSOR
@ KMI_REPEAT_IGNORE
#define OPERATOR_RETVAL_CHECK(ret)
@ TOOLREF_FLAG_FALLBACK_KEYMAP
void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new)
Definition: asset_list.cc:538
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:601
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, const int temp_win_size[2], bool is_maximized)
Definition: filesel.c:631
void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], bool *is_maximized)
struct ScrArea * ED_fileselect_handler_area_find_any_with_op(const struct wmWindow *win)
void ED_info_stats_clear(struct wmWindowManager *wm, struct ViewLayer *view_layer)
Definition: info_stats.cc:462
void ED_preview_restart_queue_work(const struct bContext *C)
ARegion * ED_area_find_region_xy_visual(const ScrArea *area, int regiontype, const int event_xy[2])
Definition: area_query.c:178
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:729
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note)
Definition: screen_edit.c:583
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area)
Definition: screen_edit.c:1275
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:1522
#define ED_screen_areas_iter(win, screen, area_name)
Definition: ED_screen.h:267
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:792
void ED_area_prevspace(struct bContext *C, ScrArea *area)
Definition: area.c:2567
void ED_region_do_listen(struct wmRegionListenerParams *params)
Definition: area.c:127
int ED_screen_animation_play(struct bContext *C, int sync, int mode)
Definition: screen_ops.c:4811
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph)
Definition: screen_edit.c:1694
void ED_area_exit(struct bContext *C, struct ScrArea *area)
Definition: screen_edit.c:714
struct AZone * ED_area_azones_update(ScrArea *area, const int mouse_xy[2])
Definition: screen_ops.c:974
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:829
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_area_do_listen(struct wmSpaceTypeListenerParams *params)
Definition: area.c:159
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:167
bool ED_workspace_delete(struct WorkSpace *workspace, struct Main *bmain, struct bContext *C, struct wmWindowManager *wm) ATTR_NONNULL()
void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area)
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
bool ED_screen_change(struct bContext *C, struct bScreen *screen)
Change the active screen.
Definition: screen_edit.c:1135
bool ED_undo_is_state_valid(struct bContext *C)
Definition: ed_undo.c:65
void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op)
Definition: ed_undo.c:410
void ED_undo_push_op(struct bContext *C, struct wmOperator *op)
Definition: ed_undo.c:404
void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings)
Definition: ed_util.c:452
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.
bool GHOST_SupportsWindowPosition(void)
@ GHOST_kTrackpadEventMagnify
Definition: GHOST_Types.h:455
@ GHOST_kTrackpadEventSmartMagnify
Definition: GHOST_Types.h:456
@ GHOST_kTrackpadEventRotate
Definition: GHOST_Types.h:453
@ GHOST_kTrackpadEventScroll
Definition: GHOST_Types.h:452
GHOST_TEventType
Definition: GHOST_Types.h:169
@ GHOST_kEventWheel
Definition: GHOST_Types.h:175
@ GHOST_kEventTimer
Definition: GHOST_Types.h:205
@ GHOST_kEventImeComposition
Definition: GHOST_Types.h:208
@ GHOST_kEventCursorMove
Definition: GHOST_Types.h:172
@ GHOST_kEventButtonUp
Definition: GHOST_Types.h:174
@ GHOST_kEventTrackpad
Definition: GHOST_Types.h:176
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:191
@ GHOST_kEventButtonDown
Definition: GHOST_Types.h:173
@ GHOST_kEventKeyDown
Definition: GHOST_Types.h:183
@ GHOST_kEventImeCompositionStart
Definition: GHOST_Types.h:207
@ GHOST_kEventImeCompositionEnd
Definition: GHOST_Types.h:209
@ GHOST_kEventUnknown
Definition: GHOST_Types.h:170
@ GHOST_kEventKeyUp
Definition: GHOST_Types.h:184
@ GHOST_kNumEventTypes
Definition: GHOST_Types.h:211
@ GHOST_kTabletModeNone
Definition: GHOST_Types.h:84
GHOST_TKey
Definition: GHOST_Types.h:259
@ GHOST_kKeyInsert
Definition: GHOST_Types.h:346
@ GHOST_kKeySemicolon
Definition: GHOST_Types.h:288
@ GHOST_kKeyMediaPlay
Definition: GHOST_Types.h:398
@ GHOST_kKeyZ
Definition: GHOST_Types.h:317
@ GHOST_kKeyQuote
Definition: GHOST_Types.h:269
@ GHOST_kKeyAccentGrave
Definition: GHOST_Types.h:322
@ GHOST_kKeyLeftAlt
Definition: GHOST_Types.h:328
@ GHOST_kKeyRightShift
Definition: GHOST_Types.h:325
@ GHOST_kKeyNumLock
Definition: GHOST_Types.h:335
@ GHOST_kKeyEnter
Definition: GHOST_Types.h:265
@ GHOST_kKeyNumpadSlash
Definition: GHOST_Types.h:369
@ GHOST_kKeyRightArrow
Definition: GHOST_Types.h:339
@ GHOST_kKeyF24
Definition: GHOST_Types.h:395
@ GHOST_kKeyPause
Definition: GHOST_Types.h:344
@ GHOST_kKeyCapsLock
Definition: GHOST_Types.h:334
@ GHOST_kKeyApp
Definition: GHOST_Types.h:332
@ GHOST_kKeyMinus
Definition: GHOST_Types.h:271
@ GHOST_kKeyMediaStop
Definition: GHOST_Types.h:399
@ GHOST_kKeyBackSpace
Definition: GHOST_Types.h:261
@ GHOST_kKey0
Definition: GHOST_Types.h:277
@ GHOST_kKeyDownPage
Definition: GHOST_Types.h:351
@ GHOST_kKeyGrLess
Definition: GHOST_Types.h:331
@ GHOST_kKeyDownArrow
Definition: GHOST_Types.h:341
@ GHOST_kKeyClear
Definition: GHOST_Types.h:264
@ GHOST_kKeyNumpadPeriod
Definition: GHOST_Types.h:364
@ GHOST_kKeyF1
Definition: GHOST_Types.h:372
@ GHOST_kKeyNumpadAsterisk
Definition: GHOST_Types.h:368
@ GHOST_kKeyPrintScreen
Definition: GHOST_Types.h:343
@ GHOST_kKeyLeftControl
Definition: GHOST_Types.h:326
@ GHOST_kKeyLeftBracket
Definition: GHOST_Types.h:319
@ GHOST_kKeyTab
Definition: GHOST_Types.h:262
@ GHOST_kKeyComma
Definition: GHOST_Types.h:270
@ GHOST_kKeyRightBracket
Definition: GHOST_Types.h:320
@ GHOST_kKeyBackslash
Definition: GHOST_Types.h:321
@ GHOST_kKeyOS
Definition: GHOST_Types.h:330
@ GHOST_kKeyLinefeed
Definition: GHOST_Types.h:263
@ GHOST_kKeyRightAlt
Definition: GHOST_Types.h:329
@ GHOST_kKeyPeriod
Definition: GHOST_Types.h:273
@ GHOST_kKeyNumpadPlus
Definition: GHOST_Types.h:366
@ GHOST_kKeyUpPage
Definition: GHOST_Types.h:350
@ GHOST_kKey9
Definition: GHOST_Types.h:286
@ GHOST_kKeyLeftArrow
Definition: GHOST_Types.h:338
@ GHOST_kKeyEqual
Definition: GHOST_Types.h:289
@ GHOST_kKeyHome
Definition: GHOST_Types.h:348
@ GHOST_kKeyNumpad9
Definition: GHOST_Types.h:363
@ GHOST_kKeyEnd
Definition: GHOST_Types.h:349
@ GHOST_kKeyUpArrow
Definition: GHOST_Types.h:340
@ GHOST_kKeyDelete
Definition: GHOST_Types.h:347
@ GHOST_kKeyNumpad0
Definition: GHOST_Types.h:354
@ GHOST_kKeyA
Definition: GHOST_Types.h:292
@ GHOST_kKeyMediaFirst
Definition: GHOST_Types.h:400
@ GHOST_kKeyRightControl
Definition: GHOST_Types.h:327
@ GHOST_kKeyEsc
Definition: GHOST_Types.h:267
@ GHOST_kKeyPlus
Definition: GHOST_Types.h:272
@ GHOST_kKeyUnknown
Definition: GHOST_Types.h:260
@ GHOST_kKeyScrollLock
Definition: GHOST_Types.h:336
@ GHOST_kKeySlash
Definition: GHOST_Types.h:274
@ GHOST_kKeyNumpadEnter
Definition: GHOST_Types.h:365
@ GHOST_kKeyNumpadMinus
Definition: GHOST_Types.h:367
@ GHOST_kKeyLeftShift
Definition: GHOST_Types.h:324
@ GHOST_kKeyMediaLast
Definition: GHOST_Types.h:401
@ GHOST_kKeySpace
Definition: GHOST_Types.h:268
@ GHOST_kButtonMaskRight
Definition: GHOST_Types.h:160
@ GHOST_kButtonMaskButton4
Definition: GHOST_Types.h:161
@ GHOST_kButtonMaskLeft
Definition: GHOST_Types.h:158
@ GHOST_kButtonMaskButton7
Definition: GHOST_Types.h:165
@ GHOST_kButtonMaskButton6
Definition: GHOST_Types.h:164
@ GHOST_kButtonMaskButton5
Definition: GHOST_Types.h:162
_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 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:569
#define RNA_STRUCT_END
Definition: RNA_access.h:589
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
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:91
#define UI_DPI_FAC
Definition: UI_interface.h:305
#define UI_MAX_SHORTCUT_STR
Definition: UI_interface.h:93
bool uiTemplateEventFromKeymapItem(struct uiLayout *layout, const char *text, const struct wmKeyMapItem *kmi, bool text_fallback)
void() wmEventHandler_KeymapDynamicFn(wmWindowManager *wm, struct wmWindow *win, struct wmEventHandler_Keymap *handler, struct wmEventHandler_KeymapResult *km_result)
Definition: WM_api.h:339
void(* wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata)
Definition: WM_api.h:379
@ WM_HANDLER_BLOCKING
Definition: WM_api.h:431
@ WM_HANDLER_DO_FREE
Definition: WM_api.h:435
@ WM_HANDLER_ACCEPT_DBL_CLICK
Definition: WM_api.h:432
bool(* EventHandlerPoll)(const ARegion *region, const struct wmEvent *event)
Definition: WM_api.h:320
int(* wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata)
Definition: WM_api.h:378
@ 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:29
@ KM_NOTHING
Definition: WM_types.h:266
@ KM_ANY
Definition: WM_types.h:265
@ KM_PRESS
Definition: WM_types.h:267
@ KM_CLICK_DRAG
Definition: WM_types.h:275
@ KM_DBL_CLICK
Definition: WM_types.h:270
@ KM_RELEASE
Definition: WM_types.h:268
@ KM_CLICK
Definition: WM_types.h:269
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_LOCK_BYPASS
Definition: WM_types.h:171
@ OPTYPE_UNDO_GROUPED
Definition: WM_types.h:173
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:154
@ OPTYPE_REGISTER
Definition: WM_types.h:146
@ OPTYPE_GRAB_CURSOR_X
Definition: WM_types.h:156
@ OPTYPE_GRAB_CURSOR_Y
Definition: WM_types.h:158
#define NC_WINDOW
Definition: WM_types.h:325
#define ND_FILEREAD
Definition: WM_types.h:360
#define NC_GEOM
Definition: WM_types.h:343
#define WM_UI_HANDLER_CONTINUE
Definition: WM_types.h:298
#define ND_SPACE_INFO
Definition: WM_types.h:464
struct CLG_LogRef * WM_LOG_EVENTS
eWM_EventFlag
Definition: WM_types.h:600
@ WM_EVENT_FORCE_DRAG_THRESHOLD
Definition: WM_types.h:618
@ WM_EVENT_SCROLL_INVERT
Definition: WM_types.h:606
@ WM_EVENT_IS_REPEAT
Definition: WM_types.h:613
struct CLG_LogRef * WM_LOG_HANDLERS
#define NC_WM
Definition: WM_types.h:324
#define WM_OP_CONTEXT_HAS_AREA(type)
Definition: WM_types.h:216
@ WM_CURSOR_WRAP_X
Definition: WM_types.h:190
@ WM_CURSOR_WRAP_XY
Definition: WM_types.h:192
@ WM_CURSOR_WRAP_Y
Definition: WM_types.h:191
@ WM_CURSOR_WRAP_NONE
Definition: WM_types.h:189
#define NOTE_ACTION
Definition: WM_types.h:522
#define ND_DATACHANGED
Definition: WM_types.h:362
#define NC_SCREEN
Definition: WM_types.h:327
#define NC_SCENE
Definition: WM_types.h:328
#define ND_WORKSPACE_DELETE
Definition: WM_types.h:377
#define NOTE_DATA
Definition: WM_types.h:357
#define ND_SPACE_INFO_REPORT
Definition: WM_types.h:463
#define ND_UNDO
Definition: WM_types.h:365
#define WM_EVENT_CURSOR_MOTION_THRESHOLD
Definition: WM_types.h:757
#define ND_FRAME
Definition: WM_types.h:382
#define NOTE_SUBTYPE
Definition: WM_types.h:498
wmOperatorCallContext
Definition: WM_types.h:199
@ WM_OP_INVOKE_REGION_WIN
Definition: WM_types.h:202
@ WM_OP_EXEC_REGION_WIN
Definition: WM_types.h:209
@ WM_OP_INVOKE_SCREEN
Definition: WM_types.h:206
@ WM_OP_INVOKE_AREA
Definition: WM_types.h:205
@ WM_OP_EXEC_REGION_PREVIEW
Definition: WM_types.h:211
@ WM_OP_EXEC_SCREEN
Definition: WM_types.h:213
@ WM_OP_INVOKE_REGION_PREVIEW
Definition: WM_types.h:204
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
@ WM_OP_EXEC_REGION_CHANNELS
Definition: WM_types.h:210
@ WM_OP_INVOKE_REGION_CHANNELS
Definition: WM_types.h:203
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
@ WM_OP_EXEC_AREA
Definition: WM_types.h:212
@ KM_CTRL
Definition: WM_types.h:239
@ KM_ALT
Definition: WM_types.h:240
@ KM_OSKEY
Definition: WM_types.h:242
@ KM_SHIFT
Definition: WM_types.h:238
#define ND_FILESAVE
Definition: WM_types.h:361
#define ND_WORKSPACE_SET
Definition: WM_types.h:376
#define NOTE_CATEGORY
Definition: WM_types.h:323
#define ND_LAYOUTBROWSE
Definition: WM_types.h:370
#define NC_OBJECT
Definition: WM_types.h:329
#define ND_LAYOUTDELETE
Definition: WM_types.h:371
struct CLG_LogRef * WM_LOG_OPERATORS
wmProgress
Definition: WM_types.h:760
@ KM_TEXTINPUT
Definition: WM_types.h:260
#define WM_UI_HANDLER_BREAK
Definition: WM_types.h:299
#define NC_SPACE
Definition: WM_types.h:342
volatile int lock
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)
const int state
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define SET(a, b, c, d, k, s, Ti)
#define G(x, y, z)
bool isfinite(uchar)
Definition: scene/image.cpp:31
static unsigned c
Definition: RandGen.cpp:83
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
static void area(int d1, int d2, int e1, int e2, float weights[2])
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
char * RNA_pointer_as_string_keywords(bContext *C, PointerRNA *ptr, const bool as_function, const bool all_args, const bool nested_args, const int max_prop_length)
Definition: rna_access.c:5477
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3493
int RNA_property_flag(PropertyRNA *prop)
Definition: rna_access.c:1055
unsigned char uint8_t
Definition: stdint.h:78
signed char int8_t
Definition: stdint.h:75
bool clip_gizmo_events_by_ui
Definition: BKE_screen.h:213
ListBase handlers
short alignment
short regiontype
struct wmGizmoMap * gizmo_map
struct ARegionType * type
CursorKeymapInfo_State state
char text[3][2][128]
const char * identifier
Definition: RNA_types.h:461
GHOST_TabletData tablet
Definition: GHOST_Types.h:442
GHOST_TButton button
Definition: GHOST_Types.h:440
GHOST_TabletData tablet
Definition: GHOST_Types.h:435
GHOST_TTrackpadEventSubTypes subtype
Definition: GHOST_Types.h:461
GHOST_TTabletMode Active
Definition: GHOST_Types.h:98
Definition: DNA_ID.h:368
int recalc
Definition: DNA_ID.h:390
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase wm
Definition: BKE_main.h:197
ListBase screens
Definition: BKE_main.h:183
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct wmTimer * reporttimer
struct CustomData_MeshMasks customdata_mask
struct ToolSettings * toolsettings
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:38
bToolRef_Runtime * runtime
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
wmOperatorCallParams optype_params
wmEventHandler head
struct wmGizmoMap * gizmo_map
wmEventHandler_KeymapDynamicFn * keymap_fn
void(* post_fn)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data)
wmKeyMap * keymaps[3]
Definition: WM_api.h:335
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::@1207 context
wmUIHandlerRemoveFunc remove_fn
struct wmEventHandler_UI::@1206 context
struct ARegion * menu
wmUIHandlerFunc handle_fn
struct ScrArea * area
struct ARegion * region
wmEventHandler head
EventHandlerPoll poll
enum eWM_EventHandlerType type
short customdata_free
Definition: WM_types.h:713
short custom
Definition: WM_types.h:712
short prev_press_keymodifier
Definition: WM_types.h:742
short val
Definition: WM_types.h:680
double prev_press_time
Definition: WM_types.h:747
short prev_type
Definition: WM_types.h:720
int xy[2]
Definition: WM_types.h:682
uint8_t prev_press_modifier
Definition: WM_types.h:740
char utf8_buf[6]
Definition: WM_types.h:690
int prev_xy[2]
Definition: WM_types.h:728
short keymodifier
Definition: WM_types.h:702
uint8_t modifier
Definition: WM_types.h:693
wmTabletData tablet
Definition: WM_types.h:705
eWM_EventFlag flag
Definition: WM_types.h:707
short prev_val
Definition: WM_types.h:722
int prev_press_xy[2]
Definition: WM_types.h:738
short type
Definition: WM_types.h:678
int8_t direction
Definition: WM_types.h:696
short prev_press_type
Definition: WM_types.h:733
void * customdata
Definition: WM_types.h:715
eWM_GizmoFlagGroupTypeFlag flag
struct wmKeyMap * keymap
struct wmGizmoMapType_Params gzmap_params
struct wmGizmoGroupType * type
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:308
unsigned int action
Definition: WM_types.h:308
unsigned int category
Definition: WM_types.h:308
const struct wmWindow * window
Definition: WM_types.h:306
unsigned int subtype
Definition: WM_types.h:308
void * reference
Definition: WM_types.h:310
struct wmOperatorType * optype
Definition: WM_types.h:1008
struct PointerRNA * opptr
Definition: WM_types.h:1009
wmOperatorCallContext opcontext
Definition: WM_types.h:1010
struct wmOperatorTypeMacro * next
struct IDProperty * properties
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
struct wmKeyMap * modalkeymap
Definition: WM_types.h:987
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
int cursor_pending
Definition: WM_types.h:996
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * translation_context
Definition: WM_types.h:891
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:954
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
bool(* pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:990
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
ListBase macro
Definition: WM_types.h:984
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:19
bool(* poll)(struct bContext *C)
Definition: wm.h:23
struct wmWindow * window
Definition: BKE_screen.h:124
struct wmWindow * window
Definition: BKE_screen.h:56
char is_motion_absolute
Definition: WM_types.h:632
float pressure
Definition: WM_types.h:626
float x_tilt
Definition: WM_types.h:628
float y_tilt
Definition: WM_types.h:630
void * customdata
Definition: WM_types.h:869
bool exit_on_event
Definition: WM_types.h:1260
struct wmTimer * timer
Definition: WM_types.h:1246
int event_xy[2]
Definition: WM_types.h:1262
struct wmMsgBus * message_bus
struct ReportList reports
struct wmWindow * winactive
struct wmKeyConfig * userconf
struct wmWindow * parent
struct wmEvent * eventstate
struct wmEvent * event_last_handled
struct Scene * scene
struct wmIMEData * ime_data
char event_queue_check_drag_handled
ScrAreaMap global_areas
double PIL_check_seconds_timer(void)
Definition: time.c:64
void wm_operator_register(bContext *C, wmOperator *op)
Definition: wm.c:365
void WM_operator_free(wmOperator *op)
Definition: wm.c:290
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:191
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
Definition: wm_cursors.c:289
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
Definition: wm_cursors.c:226
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:200
void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
Definition: wm_cursors.c:263
void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop)
Definition: wm_dragdrop.cc:458
void wm_drop_end(bContext *C, wmDrag *UNUSED(drag), wmDropBox *UNUSED(drop))
Definition: wm_dragdrop.cc:476
wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop))
Definition: wm_dragdrop.cc:501
void wm_drags_check_ops(bContext *C, const wmEvent *event)
Definition: wm_dragdrop.cc:481
void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
Definition: wm_dragdrop.cc:244
void WM_drag_free_list(ListBase *lb)
Definition: wm_dragdrop.cc:333
static ListBase dropboxes
Definition: wm_dragdrop.cc:60
int xy[2]
Definition: wm_draw.c:135
bool WM_region_use_viewport(ScrArea *area, ARegion *region)
Definition: wm_draw.c:509
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(region))
Definition: wm_draw.c:1294
int WM_event_drag_direction(const wmEvent *event)
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)
constexpr wmTabletData wm_event_tablet_data_default()
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 void wm_event_custom_free(wmEvent *event)
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])
static void wm_handler_op_context_get_if_valid(bContext *C, wmEventHandler_Op *handler, const wmEvent *event, ScrArea **r_area, ARegion **r_region)
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
static const char * keymap_handler_log_kmi_event_str(const wmKeyMapItem *kmi, char *buf, size_t buf_maxlen)
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 wmEvent * wm_event_add_mousemove_to_head(wmWindow *win)
wmKeyMapItem * WM_event_match_keymap_item_from_handlers(bContext *C, wmWindowManager *wm, wmWindow *win, ListBase *handlers, const wmEvent *event)
void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void wm_event_do_handlers(bContext *C)
static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
wmOperator * WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot)
static void wm_event_state_update_and_click_set(wmEvent *event, wmEvent *event_state, const GHOST_TEventType type)
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)
ScrArea * WM_window_status_area_find(wmWindow *win, bScreen *screen)
static void wm_event_state_update_and_click_set_ex(wmEvent *event, wmEvent *event_state, const bool is_keyboard, const bool check_double_click)
static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup)
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)
static wmWindow * wm_event_find_fileselect_root_window_from_context(const bContext *C)
static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent &event)
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)
bool WM_operator_name_poll(bContext *C, const char *opstring)
static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, ListBase *handlers)
static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
void WM_event_remove_area_handler(ListBase *handlers, void *area)
static const char * keymap_handler_log_kmi_op_str(bContext *C, const wmKeyMapItem *kmi, char *buf, size_t buf_maxlen)
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_region_tag_draw_on_gizmo_delay_refresh_for_tweak(wmWindow *win)
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)
static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result, const bool with_gizmos)
wmKeyMapItem * WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wmEvent *event)
void WM_report(eReportType type, const char *message)
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 int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
void WM_event_get_keymaps_from_handler(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
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)
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)
static int wm_event_do_region_handlers(bContext *C, wmEvent *event, ARegion *region)
int WM_operator_repeat(bContext *C, wmOperator *op)
void wm_event_free_all(wmWindow *win)
void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
static void wm_event_cursor_store(CursorKeymapInfo_State *state, const wmEvent *event, short space_type, short region_type, const bToolRef *tref)
static void wm_region_mouse_co(bContext *C, wmEvent *event)
int WM_operator_call_notest(bContext *C, wmOperator *op)
static int wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
bool WM_operator_check_ui_empty(wmOperatorType *ot)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
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)
static int wm_event_do_handlers_area_regions(bContext *C, wmEvent *event, ScrArea *area)
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)
#define PRINT
void WM_operator_region_active_win_set(bContext *C)
void WM_reportf(eReportType type, const char *format,...)
static ARegion * region_event_inside(bContext *C, const int xy[2])
wmEventHandler_Keymap * WM_event_add_keymap_handler_dynamic(ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
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 bool wm_event_is_same_key_press(const wmEvent &event_a, const wmEvent &event_b)
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
static void wm_event_handler_ui_cancel(bContext *C)
static int wm_operator_exec_notest(bContext *C, wmOperator *op)
void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, wmOperatorType *ot, wmOperatorCallContext opcontext, PointerRNA *properties, const wmEvent *event, const char *drawstr)
static const char * keymap_handler_log_action_str(const int action)
static void wm_add_reports(ReportList *reports)
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)
static int wm_operator_invoke(bContext *C, wmOperatorType *ot, const wmEvent *event, PointerRNA *properties, ReportList *reports, const bool poll_only, bool use_last_properties)
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)
int WM_operator_name_call_with_properties(bContext *C, const char *opstring, wmOperatorCallContext context, IDProperty *properties, const wmEvent *event)
BLI_INLINE void wm_event_handler_return_value_check(const bContext *C, const wmEvent *event, const int action)
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)
static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
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)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const 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)
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)
static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, const wmOperatorCallContext context, const bool poll_only, const wmEvent *event)
static void wm_operator_free_for_fileselect(wmOperator *file_operator)
static void wm_event_prev_click_set(wmEvent *event_state)
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)
static void wm_event_modalkeymap_begin(const bContext *C, wmOperator *op, wmEvent *event, wmEvent_ModalMapStore *event_backup)
void wm_event_do_notifiers(bContext *C)
int WM_operator_call_py(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, ReportList *reports, const bool is_undo)
static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler_base, wmEvent *event, PointerRNA *properties, const char *kmi_idname)
static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
static void wm_event_custom_clear(wmEvent *event)
void WM_event_get_keymap_from_toolsystem_with_gizmos(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
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)
@ EVT_TABLET_NONE
@ EVT_TABLET_STYLUS
@ EVT_TABLET_ERASER
#define ISKEYBOARD_OR_BUTTON(event_type)
#define ISMOUSE_MOTION(event_type)
#define ISMOUSE_WHEEL(event_type)
@ 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_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
@ 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
@ 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_XR_ACTION
@ EVT_RETKEY
@ BUTTON5MOUSE
#define ISKEYMODIFIER(event_type)
@ EVT_FILESELECT_FULL_OPEN
@ EVT_FILESELECT_CANCEL
@ EVT_FILESELECT_EXTERNAL_CANCEL
@ EVT_FILESELECT_EXEC
#define ISTIMER(event_type)
#define ISMOUSE_GESTURE(event_type)
#define ISKEYBOARD(event_type)
@ EVT_DATA_NDOF_MOTION
@ EVT_DATA_DRAGDROP
@ EVT_DATA_TIMER
@ EVT_DATA_XR
PointerRNA * ptr
Definition: wm_files.c:3480
void wm_test_autorun_warning(bContext *C)
Definition: wm_files.c:3519
wmOperatorType * ot
Definition: wm_files.c:3479
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:227
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:808
bool wm_gizmomap_highlight_set(wmGizmoMap *gzmap, const bContext *C, wmGizmo *gz, int part)
Definition: wm_gizmo_map.c:983
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)
bool WM_gizmomap_tag_delay_refresh_for_tweak_check(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:317
void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:308
wmGizmoGroup * WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname)
Definition: wm_gizmo_map.c:202
wmGizmo * wm_gizmomap_highlight_find(wmGizmoMap *gzmap, bContext *C, const wmEvent *event, int *r_part)
Definition: wm_gizmo_map.c:723
void WM_gizmoconfig_update(struct Main *bmain)
const ListBase * WM_gizmomap_group_list(wmGizmoMap *gzmap)
Definition: wm_gizmo_map.c:222
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:967
void WM_keyconfig_update(wmWindowManager *wm)
Definition: wm_keymap.c:1829
int WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact, char *result, const int result_len)
Definition: wm_keymap.c:1213
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
Definition: wm_keymap.c:1943
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
Definition: wm_keymap.c:432
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:267
bool WM_operator_last_properties_store(wmOperator *op)
Definition: wm_operators.c:854
bool WM_operator_last_properties_init(wmOperator *op)
Definition: wm_operators.c:839
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:701
wmOperator * WM_operator_last_redo(const bContext *C)
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
Definition: wm_stereo.c:165
void wm_surfaces_do_depsgraph(bContext *C)
Definition: wm_surface.c:47
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:83
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:57
void WM_tooltip_clear(bContext *C, wmWindow *win)
Definition: wm_tooltip.c:80
void WM_tooltip_init(bContext *C, wmWindow *win)
Definition: wm_tooltip.c:95
void WM_tooltip_timer_init(bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init)
Definition: wm_tooltip.c:62
wmWindow * WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mval[2])
Definition: wm_window.c:1904
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
int WM_window_pixels_y(const wmWindow *win)
Definition: wm_window.c:2082
void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
Definition: wm_window.c:2271
void wm_window_title(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:417
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
Definition: wm_window.c:2290
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:366
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2300
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
Definition: wm_window.c:1028
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Definition: wm_window.c:2217
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
Definition: wm_window.c:2266
bool WM_window_is_temp_screen(const wmWindow *win)
Definition: wm_window.c:2311
int WM_window_pixels_x(const wmWindow *win)
Definition: wm_window.c:2076
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2183
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630
void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
Definition: wm_window.c:960
ScrArea * WM_xr_session_area_get(const wmXrData *xr)