diff options
author | Peter Kim <pk15950@gmail.com> | 2022-09-08 07:00:12 +0300 |
---|---|---|
committer | Peter Kim <pk15950@gmail.com> | 2022-09-08 07:00:12 +0300 |
commit | 00dcfdf916c69672210b006e62d966f1bc2fbeb7 (patch) | |
tree | 0cbb1b91fe26c750197126085b74224a795a103c /source/blender/windowmanager/intern | |
parent | a39532670f6b668da7be5810fb1f844b82feeba3 (diff) | |
parent | d5934974219135102f364f57c45a8b1465e2b8d9 (diff) |
Merge branch 'master' into xr-devxr-dev
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 21 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_cursors.c | 15 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_dragdrop.cc (renamed from source/blender/windowmanager/intern/wm_dragdrop.c) | 155 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_draw.c | 200 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_query.c | 31 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.cc | 287 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 39 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_gesture.c | 16 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 37 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 11 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_playanim.c | 32 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_splash_screen.c | 81 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_stereo.c | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_toolsystem.c | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 231 |
15 files changed, 749 insertions, 418 deletions
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index d113669a998..fccd959f929 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -15,6 +15,7 @@ #include <stddef.h> #include <string.h> +#include "BLI_ghash.h" #include "BLI_sys_types.h" #include "DNA_windowmanager_types.h" @@ -81,6 +82,8 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) if (BKE_lib_query_foreachid_iter_stop(data)) { return; } + + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, win->unpinned_scene, IDWALK_CB_NOP); } if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { @@ -248,6 +251,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) BLI_listbase_clear(&wm->operators); BLI_listbase_clear(&wm->paintcursors); BLI_listbase_clear(&wm->notifier_queue); + wm->notifier_queue_set = NULL; BKE_reports_init(&wm->reports, RPT_STORE); BLI_listbase_clear(&wm->keyconfigs); @@ -285,6 +289,7 @@ static void lib_link_workspace_instance_hook(BlendLibReader *reader, { WorkSpace *workspace = BKE_workspace_active_get(hook); BLO_read_id_address(reader, id->lib, &workspace); + BKE_workspace_active_set(hook, workspace); } @@ -300,6 +305,11 @@ static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id) /* deprecated, but needed for versioning (will be NULL'ed then) */ BLO_read_id_address(reader, NULL, &win->screen); + /* The unpinned scene is a UI->Scene-data pointer, and should be NULL'ed on linking (like + * WorkSpace.pin_scene). But the WindowManager ID (owning the window) is never linked. */ + BLI_assert(!ID_IS_LINKED(id)); + BLO_read_id_address(reader, id->lib, &win->unpinned_scene); + LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { BKE_screen_area_blend_read_lib(reader, &wm->id, area); } @@ -310,7 +320,7 @@ static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id) IDTypeInfo IDType_ID_WM = { .id_code = ID_WM, - .id_filter = 0, + .id_filter = FILTER_ID_WM, .main_listbase_index = INDEX_ID_WM, .struct_size = sizeof(wmWindowManager), .name = "WindowManager", @@ -633,6 +643,10 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) } BLI_freelistN(&wm->notifier_queue); + if (wm->notifier_queue_set) { + BLI_gset_free(wm->notifier_queue_set, NULL); + wm->notifier_queue_set = NULL; + } if (wm->message_bus != NULL) { WM_msgbus_destroy(wm->message_bus); @@ -663,7 +677,10 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist) while ((wm = wmlist->first)) { wm_close_and_free(C, wm); BLI_remlink(wmlist, wm); - BKE_libblock_free_data(&wm->id, true); + /* Don't handle user counts as this is only ever called once #G_MAIN has already been freed via + * #BKE_main_free so any ID's referenced by the window-manager (from ID properties) will crash. + * See: T100703. */ + BKE_libblock_free_data(&wm->id, false); BKE_libblock_free_data_py(&wm->id); MEM_freeN(wm); } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index fc992ef069d..43be87fce39 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -228,11 +228,11 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4]) /* Only grab cursor when not running debug. * It helps not to get a stuck WM when hitting a break-point. */ GHOST_TGrabCursorMode mode = GHOST_kGrabNormal; - GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kGrabAxisY; + GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kAxisY; if (bounds) { - wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]); - wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]); + wm_cursor_position_to_ghost_screen_coords(win, &bounds[0], &bounds[1]); + wm_cursor_position_to_ghost_screen_coords(win, &bounds[2], &bounds[3]); } if (hide) { @@ -245,7 +245,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4]) mode_axis = GHOST_kAxisX; } else if (wrap == WM_CURSOR_WRAP_Y) { - mode_axis = GHOST_kGrabAxisY; + mode_axis = GHOST_kAxisY; } } @@ -266,12 +266,11 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2]) if (win && win->ghostwin) { if (mouse_ungrab_xy) { int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]}; - wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]); - GHOST_SetCursorGrab( - win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, mouse_xy); + wm_cursor_position_to_ghost_screen_coords(win, &mouse_xy[0], &mouse_xy[1]); + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kAxisNone, NULL, mouse_xy); } else { - GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, NULL); + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kAxisNone, NULL, NULL); } win->grabcursor = GHOST_kGrabDisable; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.cc index 09ef4e15012..94bd33a9765 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -7,7 +7,7 @@ * Our own drag-and-drop, drag state and drop boxes. */ -#include <string.h> +#include <cstring> #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -57,7 +57,7 @@ /* ****************************************************** */ -static ListBase dropboxes = {NULL, NULL}; +static ListBase dropboxes = {nullptr, nullptr}; static void wm_drag_free_asset_data(wmDragAsset **asset_data); @@ -65,14 +65,13 @@ static void wm_drag_free_asset_data(wmDragAsset **asset_data); /* these are part of blender's UI/space specs, and not like keymaps */ /* when editors become configurable, they can add own dropbox definitions */ -typedef struct wmDropBoxMap { +struct wmDropBoxMap { struct wmDropBoxMap *next, *prev; ListBase dropboxes; short spaceid, regionid; char idname[KMAP_MAX_NAME]; - -} wmDropBoxMap; +}; ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) { @@ -84,7 +83,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) } } - wmDropBoxMap *dm = MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list"); + wmDropBoxMap *dm = MEM_cnew<wmDropBoxMap>(__func__); BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME); dm->spaceid = spaceid; dm->regionid = regionid; @@ -97,20 +96,20 @@ wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, bool (*poll)(bContext *, wmDrag *, const wmEvent *), void (*copy)(bContext *, wmDrag *, wmDropBox *), - void (*cancel)(struct Main *, wmDrag *, wmDropBox *), + void (*cancel)(Main *, wmDrag *, wmDropBox *), WMDropboxTooltipFunc tooltip) { - wmDropBox *drop = MEM_callocN(sizeof(wmDropBox), "wmDropBox"); + wmDropBox *drop = MEM_cnew<wmDropBox>(__func__); drop->poll = poll; drop->copy = copy; drop->cancel = cancel; drop->tooltip = tooltip; - drop->ot = WM_operatortype_find(idname, 0); + drop->ot = WM_operatortype_find(idname, false); - if (drop->ot == NULL) { + if (drop->ot == nullptr) { MEM_freeN(drop); printf("Error: dropbox with unknown operator: %s\n", idname); - return NULL; + return nullptr; } WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname); @@ -170,27 +169,25 @@ static void wm_dropbox_invoke(bContext *C, wmDrag *drag) if (drop->on_drag_start) { drop->on_drag_start(C, drag); } - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); } } } -wmDrag *WM_event_start_drag( - struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags) +wmDrag *WM_drag_data_create( + bContext *C, int icon, int type, void *poin, double value, unsigned int flags) { - wmWindowManager *wm = CTX_wm_manager(C); - wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag"); + wmDrag *drag = MEM_cnew<wmDrag>(__func__); /* Keep track of future multi-touch drag too, add a mouse-pointer id or so. */ /* if multiple drags are added, they're drawn as list */ - BLI_addtail(&wm->drags, drag); - drag->flags = flags; + drag->flags = static_cast<eWM_DragFlags>(flags); drag->icon = icon; drag->type = type; switch (type) { case WM_DRAG_PATH: - BLI_strncpy(drag->path, poin, FILE_MAX); + BLI_strncpy(drag->path, static_cast<const char *>(poin), FILE_MAX); /* As the path is being copied, free it immediately as `drag` won't "own" the data. */ if (flags & WM_DRAG_FREE_DATA) { MEM_freeN(poin); @@ -198,7 +195,7 @@ wmDrag *WM_event_start_drag( break; case WM_DRAG_ID: if (poin) { - WM_drag_add_local_ID(drag, poin, NULL); + WM_drag_add_local_ID(drag, static_cast<ID *>(poin), nullptr); } break; case WM_DRAG_ASSET: @@ -213,7 +210,7 @@ wmDrag *WM_event_start_drag( const AssetLibraryReference *asset_library = CTX_wm_asset_library_ref(C); ListBase asset_file_links = CTX_data_collection_get(C, "selected_asset_files"); LISTBASE_FOREACH (const CollectionPointerLink *, link, &asset_file_links) { - const FileDirEntry *asset_file = link->ptr.data; + const FileDirEntry *asset_file = static_cast<const FileDirEntry *>(link->ptr.data); const AssetHandle asset_handle = {asset_file}; WM_drag_add_asset_list_item(drag, C, asset_library, &asset_handle); } @@ -226,9 +223,22 @@ wmDrag *WM_event_start_drag( } drag->value = value; + return drag; +} + +void WM_event_start_prepared_drag(bContext *C, wmDrag *drag) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + BLI_addtail(&wm->drags, drag); wm_dropbox_invoke(C, drag); +} - return drag; +void WM_event_start_drag( + bContext *C, int icon, int type, void *poin, double value, unsigned int flags) +{ + wmDrag *drag = WM_drag_data_create(C, icon, type, poin, value, flags); + WM_event_start_prepared_drag(C, drag); } void wm_drags_exit(wmWindowManager *wm, wmWindow *win) @@ -255,12 +265,12 @@ static bContextStore *wm_drop_ui_context_create(const bContext *C) { uiBut *active_but = UI_region_active_but_get(CTX_wm_region(C)); if (!active_but) { - return NULL; + return nullptr; } bContextStore *but_context = UI_but_context_get(active_but); if (!but_context) { - return NULL; + return nullptr; } return CTX_store_copy(but_context); @@ -272,7 +282,7 @@ static void wm_drop_ui_context_free(bContextStore **context_store) return; } CTX_store_free(*context_store); - *context_store = NULL; + *context_store = nullptr; } void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale) @@ -283,14 +293,14 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale) void WM_drag_data_free(int dragtype, void *poin) { - /* Don't require all the callers to have a NULL-check, just allow passing NULL. */ + /* Don't require all the callers to have a nullptr-check, just allow passing nullptr. */ if (!poin) { return; } /* Not too nice, could become a callback. */ if (dragtype == WM_DRAG_ASSET) { - wmDragAsset *asset_data = poin; + wmDragAsset *asset_data = static_cast<wmDragAsset *>(poin); wm_drag_free_asset_data(&asset_data); } else { @@ -320,17 +330,17 @@ void WM_drag_free(wmDrag *drag) MEM_freeN(drag); } -void WM_drag_free_list(struct ListBase *lb) +void WM_drag_free_list(ListBase *lb) { wmDrag *drag; - while ((drag = BLI_pophead(lb))) { + while ((drag = static_cast<wmDrag *>(BLI_pophead(lb)))) { WM_drag_free(drag); } } static char *dropbox_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox *drop) { - char *tooltip = NULL; + char *tooltip = nullptr; if (drop->tooltip) { tooltip = drop->tooltip(C, drag, xy, drop); } @@ -350,7 +360,7 @@ static wmDropBox *dropbox_active(bContext *C, if (drag->drop_state.free_disabled_info) { MEM_SAFE_FREE(drag->drop_state.disabled_info); } - drag->drop_state.disabled_info = NULL; + drag->drop_state.disabled_info = nullptr; LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) { if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) { @@ -370,7 +380,7 @@ static wmDropBox *dropbox_active(bContext *C, const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); if (WM_operator_poll_context(C, drop->ot, opcontext)) { - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); return drop; } @@ -386,8 +396,8 @@ static wmDropBox *dropbox_active(bContext *C, } } } - CTX_store_set(C, NULL); - return NULL; + CTX_store_set(C, nullptr); + return nullptr; } /* return active operator tooltip/name when mouse is in box */ @@ -430,14 +440,14 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even if (drop != drop_prev) { if (drop_prev && drop_prev->draw_deactivate) { drop_prev->draw_deactivate(drop_prev, drag); - BLI_assert(drop_prev->draw_data == NULL); + BLI_assert(drop_prev->draw_data == nullptr); } if (drop && drop->draw_activate) { drop->draw_activate(drop, drag); } drag->drop_state.active_dropbox = drop; - drag->drop_state.area_from = drop ? CTX_wm_area(C) : NULL; - drag->drop_state.region_from = drop ? CTX_wm_region(C) : NULL; + drag->drop_state.area_from = drop ? CTX_wm_area(C) : nullptr; + drag->drop_state.region_from = drop ? CTX_wm_region(C) : nullptr; } if (!drag->drop_state.active_dropbox) { @@ -465,7 +475,7 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) void wm_drop_end(bContext *C, wmDrag *UNUSED(drag), wmDropBox *UNUSED(drop)) { - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); } void wm_drags_check_ops(bContext *C, const wmEvent *event) @@ -500,7 +510,7 @@ void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) /* Don't drag the same ID twice. */ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { if (drag_id->id == id) { - if (drag_id->from_parent == NULL) { + if (drag_id->from_parent == nullptr) { drag_id->from_parent = from_parent; } return; @@ -512,7 +522,7 @@ void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) } /* Add to list. */ - wmDragID *drag_id = MEM_callocN(sizeof(wmDragID), __func__); + wmDragID *drag_id = MEM_cnew<wmDragID>(__func__); drag_id->id = id; drag_id->from_parent = from_parent; BLI_addtail(&drag->ids, drag_id); @@ -521,26 +531,26 @@ void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) ID *WM_drag_get_local_ID(const wmDrag *drag, short idcode) { if (drag->type != WM_DRAG_ID) { - return NULL; + return nullptr; } - wmDragID *drag_id = drag->ids.first; + wmDragID *drag_id = static_cast<wmDragID *>(drag->ids.first); if (!drag_id) { - return NULL; + return nullptr; } ID *id = drag_id->id; - return (idcode == 0 || GS(id->name) == idcode) ? id : NULL; + return (idcode == 0 || GS(id->name) == idcode) ? id : nullptr; } ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode) { if (event->custom != EVT_DATA_DRAGDROP) { - return NULL; + return nullptr; } - ListBase *lb = event->customdata; - return WM_drag_get_local_ID(lb->first, idcode); + ListBase *lb = static_cast<ListBase *>(event->customdata); + return WM_drag_get_local_ID(static_cast<const wmDrag *>(lb->first), idcode); } bool WM_drag_is_ID_type(const wmDrag *drag, int idcode) @@ -553,7 +563,7 @@ wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type) { - wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset"); + wmDragAsset *asset_drag = MEM_new<wmDragAsset>(__func__); BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name)); asset_drag->metadata = metadata; @@ -573,14 +583,14 @@ static void wm_drag_free_asset_data(wmDragAsset **asset_data) wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode) { if (drag->type != WM_DRAG_ASSET) { - return NULL; + return nullptr; } - wmDragAsset *asset_drag = drag->poin; - return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL; + wmDragAsset *asset_drag = static_cast<wmDragAsset *>(drag->poin); + return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : nullptr; } -struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode) +AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode) { wmDragAsset *drag_asset = WM_drag_get_asset_data(drag, idcode); if (drag_asset) { @@ -592,17 +602,18 @@ struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode return local_id->asset_data; } - return NULL; + return nullptr; } ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra) { /* Only support passing in limited flags. */ BLI_assert(flag_extra == (flag_extra & FILE_AUTOSELECT)); - eFileSel_Params_Flag flag = flag_extra | FILE_ACTIVE_COLLECTION; + eFileSel_Params_Flag flag = static_cast<eFileSel_Params_Flag>(flag_extra) | + FILE_ACTIVE_COLLECTION; const char *name = asset_drag->name; - ID_Type idtype = asset_drag->id_type; + ID_Type idtype = static_cast<ID_Type>(asset_drag->id_type); /* FIXME: Link/Append should happens in the operator called at the end of drop process, not from * here. */ @@ -640,7 +651,7 @@ ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra) } BLI_assert_unreachable(); - return NULL; + return nullptr; } bool WM_drag_asset_will_import_linked(const wmDrag *drag) @@ -656,7 +667,7 @@ bool WM_drag_asset_will_import_linked(const wmDrag *drag) ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode) { if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) { - return NULL; + return nullptr; } if (drag->type == WM_DRAG_ID) { @@ -665,14 +676,14 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode) wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, idcode); if (!asset_drag) { - return NULL; + return nullptr; } /* Link/append the asset. */ return WM_drag_asset_id_import(asset_drag, 0); } -void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop) +void WM_drag_free_imported_drag_ID(Main *bmain, wmDrag *drag, wmDropBox *drop) { if (drag->type != WM_DRAG_ASSET) { return; @@ -686,8 +697,8 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox * /* Try to find the imported ID. For this to work either a "session_uuid" or "name" property must * have been defined (see #WM_operator_properties_id_lookup()). */ ID *id = WM_operator_properties_id_lookup_from_name_or_session_uuid( - bmain, drop->ptr, asset_drag->id_type); - if (id != NULL) { + bmain, drop->ptr, static_cast<ID_Type>(asset_drag->id_type)); + if (id != nullptr) { /* Do not delete the dragged ID if it has any user, otherwise if it is a 're-used' ID it will * cause T95636. Note that we need first to add the user that we want to remove in * #BKE_id_free_us. */ @@ -699,10 +710,10 @@ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox * wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag) { if (drag->type != WM_DRAG_ASSET_CATALOG) { - return NULL; + return nullptr; } - return drag->poin; + return static_cast<wmDragAssetCatalog *>(drag->poin); } void WM_drag_add_asset_list_item( @@ -712,14 +723,12 @@ void WM_drag_add_asset_list_item( const AssetLibraryReference *asset_library_ref, const AssetHandle *asset) { - if (drag->type != WM_DRAG_ASSET_LIST) { - return; - } + BLI_assert(drag->type == WM_DRAG_ASSET_LIST); /* No guarantee that the same asset isn't added twice. */ /* Add to list. */ - wmDragAssetListItem *drag_asset = MEM_callocN(sizeof(*drag_asset), __func__); + wmDragAssetListItem *drag_asset = MEM_cnew<wmDragAssetListItem>(__func__); ID *local_id = ED_asset_handle_get_local_id(asset); if (local_id) { drag_asset->is_external = false; @@ -739,7 +748,7 @@ void WM_drag_add_asset_list_item( const ListBase *WM_drag_asset_list_get(const wmDrag *drag) { if (drag->type != WM_DRAG_ASSET_LIST) { - return NULL; + return nullptr; } return &drag->asset_items; @@ -828,7 +837,7 @@ static void wm_drag_draw_icon(bContext *UNUSED(C), y = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2); const float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR); immDrawPixelsTexTiled_scaling(&state, x, y, @@ -880,7 +889,7 @@ static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const int iconsize = UI_DPI_ICON_SIZE; int padding = 4 * UI_DPI_FAC; - char *tooltip = NULL; + char *tooltip = nullptr; if (drag->drop_state.active_dropbox) { tooltip = dropbox_tooltip(C, drag, xy, drag->drop_state.active_dropbox); } @@ -1004,7 +1013,7 @@ void wm_drags_draw(bContext *C, wmWindow *win) wm_drag_draw_default(C, win, drag, xy); } GPU_blend(GPU_BLEND_NONE); - CTX_wm_area_set(C, NULL); - CTX_wm_region_set(C, NULL); - CTX_store_set(C, NULL); + CTX_wm_area_set(C, nullptr); + CTX_wm_region_set(C, nullptr); + CTX_store_set(C, nullptr); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 63a7fb5ddaa..a3334c79ba0 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -41,6 +41,7 @@ #include "GPU_debug.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "GPU_texture.h" #include "GPU_viewport.h" @@ -158,9 +159,13 @@ static bool wm_software_cursor_needed_for_window(const wmWindow *win, struct Gra if (GHOST_GetCursorVisibility(win->ghostwin)) { /* NOTE: The value in `win->grabcursor` can't be used as it * doesn't always match GHOST's value in the case of tablet events. */ - GHOST_GetCursorGrabState( - win->ghostwin, &grab_state->mode, &grab_state->wrap_axis, grab_state->bounds); - if (grab_state->mode == GHOST_kGrabWrap) { + bool use_software_cursor; + GHOST_GetCursorGrabState(win->ghostwin, + &grab_state->mode, + &grab_state->wrap_axis, + grab_state->bounds, + &use_software_cursor); + if (use_software_cursor) { return true; } } @@ -189,52 +194,138 @@ static void wm_software_cursor_motion_clear(void) g_software_cursor.xy[1] = -1; } -static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state) +static void wm_software_cursor_draw_bitmap(const int event_xy[2], + const GHOST_CursorBitmapRef *bitmap) { - int x = win->eventstate->xy[0]; - int y = win->eventstate->xy[1]; + GPU_blend(GPU_BLEND_ALPHA); - if (grab_state->wrap_axis & GHOST_kAxisX) { - const int min = grab_state->bounds[0]; - const int max = grab_state->bounds[2]; - if (min != max) { - x = mod_i(x - min, max - min) + min; - } - } - if (grab_state->wrap_axis & GHOST_kGrabAxisY) { - const int height = WM_window_pixels_y(win); - const int min = height - grab_state->bounds[1]; - const int max = height - grab_state->bounds[3]; - if (min != max) { - y = mod_i(y - max, min - max) + max; - } - } + float gl_matrix[4][4]; + GPUTexture *texture = GPU_texture_create_2d( + "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, NULL); + GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data); + GPU_texture_filter_mode(texture, false); + + GPU_matrix_push(); + + const int scale = (int)U.pixelsize; + + unit_m4(gl_matrix); + + gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale); + gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale); + + gl_matrix[0][0] = bitmap->data_size[0] * scale; + gl_matrix[1][1] = bitmap->data_size[1] * scale; + + GPU_matrix_mul(gl_matrix); + + GPUVertFormat *imm_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint texCoord = GPU_vertformat_attr_add( + imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + /* Use 3D image for correct display of planar tracked images. */ + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE); + + immBindTexture("image", texture); + + immBegin(GPU_PRIM_TRI_FAN, 4); + + immAttr2f(texCoord, 0.0f, 1.0f); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 1.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 0.0f); + immVertex3f(pos, 1.0f, 1.0f, 0.0f); + + immAttr2f(texCoord, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + + immEnd(); + + immUnbindProgram(); + + GPU_matrix_pop(); + GPU_texture_unbind(texture); + GPU_texture_free(texture); + + GPU_blend(GPU_BLEND_NONE); +} +static void wm_software_cursor_draw_crosshair(const int event_xy[2]) +{ /* Draw a primitive cross-hair cursor. * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors * are set by the operating-system, where the pixel information isn't easily available. */ const float unit = max_ff(U.dpi_fac, 1.0f); uint pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4f(1, 1, 1, 1); { const int ofs_line = (8 * unit); const int ofs_size = (2 * unit); - immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size); - immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); } immUniformColor4f(0, 0, 0, 1); { const int ofs_line = (7 * unit); const int ofs_size = (1 * unit); - immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size); - immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); } immUnbindProgram(); } +static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state) +{ + int event_xy[2] = {UNPACK2(win->eventstate->xy)}; + + if (grab_state->wrap_axis & GHOST_kAxisX) { + const int min = grab_state->bounds[0]; + const int max = grab_state->bounds[2]; + if (min != max) { + event_xy[0] = mod_i(event_xy[0] - min, max - min) + min; + } + } + if (grab_state->wrap_axis & GHOST_kAxisY) { + const int height = WM_window_pixels_y(win); + const int min = height - grab_state->bounds[1]; + const int max = height - grab_state->bounds[3]; + if (min != max) { + event_xy[1] = mod_i(event_xy[1] - max, min - max) + max; + } + } + + GHOST_CursorBitmapRef bitmap = {0}; + if (GHOST_GetCursorBitmap(win->ghostwin, &bitmap) == GHOST_kSuccess) { + wm_software_cursor_draw_bitmap(event_xy, &bitmap); + } + else { + wm_software_cursor_draw_crosshair(event_xy); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -865,7 +956,7 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) GPU_debug_group_end(); } - /* Draw menus into their own framebuffer. */ + /* Draw menus into their own frame-buffer. */ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { if (!region->visible) { continue; @@ -902,7 +993,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) GPU_debug_group_begin("Window Redraw"); - /* Draw into the window framebuffer, in full window coordinates. */ + /* Draw into the window frame-buffer, in full window coordinates. */ wmWindowViewport(win); /* We draw on all pixels of the windows so we don't need to clear them before. @@ -1006,23 +1097,25 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) static void wm_draw_window(bContext *C, wmWindow *win) { + GPU_context_begin_frame(win->gpuctx); + bScreen *screen = WM_window_get_active_screen(win); bool stereo = WM_stereo3d_enabled(win, false); /* Avoid any BGL call issued before this to alter the window drawin. */ GPU_bgl_end(); - /* Draw area regions into their own framebuffer. This way we can redraw - * the areas that need it, and blit the rest from existing framebuffers. */ + /* Draw area regions into their own frame-buffer. This way we can redraw + * the areas that need it, and blit the rest from existing frame-buffers. */ wm_draw_window_offscreen(C, win, stereo); - /* Now we draw into the window framebuffer, in full window coordinates. */ + /* Now we draw into the window frame-buffer, in full window coordinates. */ if (!stereo) { /* Regular mono drawing. */ wm_draw_window_onscreen(C, win, -1); } else if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) { - /* For pageflip we simply draw to both back buffers. */ + /* For page-flip we simply draw to both back buffers. */ GPU_backbuffer_bind(GPU_BACKBUFFER_RIGHT); wm_draw_window_onscreen(C, win, 1); @@ -1031,12 +1124,12 @@ static void wm_draw_window(bContext *C, wmWindow *win) } else if (ELEM(win->stereo3d_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) { /* For anaglyph and interlace, we draw individual regions with - * stereo framebuffers using different shaders. */ + * stereo frame-buffers using different shaders. */ wm_draw_window_onscreen(C, win, -1); } else { /* For side-by-side and top-bottom, we need to render each view to an - * an offscreen texture and then draw it. This used to happen for all + * an off-screen texture and then draw it. This used to happen for all * stereo methods, but it's less efficient than drawing directly. */ const int width = WM_window_pixels_x(win); const int height = WM_window_pixels_y(win); @@ -1075,6 +1168,8 @@ static void wm_draw_window(bContext *C, wmWindow *win) } screen->do_draw = false; + + GPU_context_end_frame(win->gpuctx); } /** @@ -1085,12 +1180,49 @@ static void wm_draw_surface(bContext *C, wmSurface *surface) wm_window_clear_drawable(CTX_wm_manager(C)); wm_surface_make_drawable(surface); + GPU_context_begin_frame(surface->gpu_ctx); + surface->draw(C); + GPU_context_end_frame(surface->gpu_ctx); + /* Avoid interference with window drawable */ wm_surface_clear_drawable(); } +uint *WM_window_pixels_read_offscreen(bContext *C, wmWindow *win, int r_size[2]) +{ + /* NOTE(@campbellbarton): There is a problem reading the windows front-buffer after redrawing + * the window in some cases (typically to clear UI elements such as menus or search popup). + * With EGL `eglSurfaceAttrib(..)` may support setting the `EGL_SWAP_BEHAVIOR` attribute to + * `EGL_BUFFER_PRESERVED` however not all implementations support this. + * Requesting the ability with `EGL_SWAP_BEHAVIOR_PRESERVED_BIT` can even cause the EGL context + * not to initialize at all. + * Confusingly there are some cases where this *does* work, depending on the state of the window + * and prior calls to swap-buffers, however ensuring the state exactly as needed to satisfy a + * particular GPU back-end is fragile, see T98462. + * + * So provide an alternative to #WM_window_pixels_read that avoids using the front-buffer. */ + + /* Draw into an off-screen buffer and read it's contents. */ + r_size[0] = WM_window_pixels_x(win); + r_size[1] = WM_window_pixels_y(win); + + GPUOffScreen *offscreen = GPU_offscreen_create(r_size[0], r_size[1], false, GPU_RGBA8, NULL); + if (UNLIKELY(!offscreen)) { + return NULL; + } + + const uint rect_len = r_size[0] * r_size[1]; + uint *rect = MEM_mallocN(sizeof(*rect) * rect_len, __func__); + GPU_offscreen_bind(offscreen, false); + wm_draw_window_onscreen(C, win, -1); + GPU_offscreen_unbind(offscreen, false); + GPU_offscreen_read_pixels(offscreen, GPU_DATA_UBYTE, rect); + GPU_offscreen_free(offscreen); + return rect; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index b732bc91569..a1d94c33f27 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -112,7 +112,7 @@ void WM_event_print(const wmEvent *event) "wmEvent type:%d/%s, val:%d/%s, " "prev_type:%d/%s, prev_val:%d/%s, " "modifier=%s, keymodifier:%d, flag:%s, " - "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p", + "mouse:(%d,%d), utf8:'%.*s', pointer:%p", event->type, type_id, event->val, @@ -126,7 +126,6 @@ void WM_event_print(const wmEvent *event) flag_id, event->xy[0], event->xy[1], - event->ascii, BLI_str_utf8_size(event->utf8_buf), event->utf8_buf, (const void *)event); @@ -254,16 +253,6 @@ bool WM_event_is_modal_drag_exit(const wmEvent *event, return 0; } -bool WM_event_is_last_mousemove(const wmEvent *event) -{ - while ((event = event->next)) { - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - return false; - } - } - return true; -} - bool WM_event_is_mouse_drag(const wmEvent *event) { return (ISMOUSE_BUTTON(event->type) && (event->val == KM_CLICK_DRAG)); @@ -357,8 +346,8 @@ bool WM_cursor_test_motion_and_update(const int mval[2]) int WM_event_drag_threshold(const struct wmEvent *event) { int drag_threshold; - if (ISMOUSE(event->prev_press_type)) { - BLI_assert(event->prev_press_type != MOUSEMOVE); + BLI_assert(event->prev_press_type != MOUSEMOVE); + if (ISMOUSE_BUTTON(event->prev_press_type)) { /* Using the previous type is important is we want to check the last pressed/released button, * The `event->type` would include #MOUSEMOVE which is always the case when dragging * and does not help us know which threshold to use. */ @@ -411,6 +400,20 @@ void WM_event_drag_start_xy(const wmEvent *event, int r_xy[2]) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Event Text Queries + * \{ */ + +char WM_event_utf8_to_ascii(const struct wmEvent *event) +{ + if (BLI_str_utf8_size(event->utf8_buf) == 1) { + return event->utf8_buf[0]; + } + return '\0'; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Event Preference Mapping * \{ */ diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index d3ae4177e4d..bc19e2c09c3 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -27,6 +27,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" +#include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_timer.h" #include "BLI_utildefines.h" @@ -90,6 +91,7 @@ #define USE_GIZMO_MOUSE_PRIORITY_HACK static void wm_notifier_clear(wmNotifier *note); +static bool wm_notifier_is_clear(const wmNotifier *note); static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, @@ -190,7 +192,7 @@ void wm_event_free(wmEvent *event) printf("%s: 'is_repeat=true' for non-keyboard event, this should not happen.\n", __func__); WM_event_print(event); } - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) && (event->val != KM_NOTHING)) { + if (ISMOUSE_MOTION(event->type) && (event->val != KM_NOTHING)) { printf("%s: 'val != NOTHING' for a cursor motion event, this should not happen.\n", __func__); WM_event_print(event); } @@ -252,36 +254,67 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event) /** \name Notifiers & Listeners * \{ */ -static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference) +/** + * Hash for #wmWindowManager.notifier_queue_set, ignores `window`. + */ +static uint note_hash_for_queue_fn(const void *ptr) { - LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) { - if ((note->category | note->data | note->subtype | note->action) == type && - note->reference == reference) { - return true; - } - } + const wmNotifier *note = static_cast<const wmNotifier *>(ptr); + return (BLI_ghashutil_ptrhash(note->reference) ^ + (note->category | note->data | note->subtype | note->action)); +} - return false; +/** + * Comparison for #wmWindowManager.notifier_queue_set + * + * \note This is not an exact equality function as the `window` is ignored. + */ +static bool note_cmp_for_queue_fn(const void *a, const void *b) +{ + const wmNotifier *note_a = static_cast<const wmNotifier *>(a); + const wmNotifier *note_b = static_cast<const wmNotifier *>(b); + return !(((note_a->category | note_a->data | note_a->subtype | note_a->action) == + (note_b->category | note_b->data | note_b->subtype | note_b->action)) && + (note_a->reference == note_b->reference)); } void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference) { - if (wm_test_duplicate_notifier(wm, type, reference)) { + if (wm == nullptr) { + /* There may be some cases where e.g. `G_MAIN` is not actually the real current main, but some + * other temporary one (e.g. during liboverride processing over linked data), leading to null + * window manager. + * + * This is fairly bad and weak, but unfortunately RNA does not have any way to operate over + * another main than G_MAIN currently. */ return; } - wmNotifier *note = MEM_cnew<wmNotifier>(__func__); + wmNotifier note_test = {nullptr}; - BLI_addtail(&wm->notifier_queue, note); + note_test.window = win; - note->window = win; + note_test.category = type & NOTE_CATEGORY; + note_test.data = type & NOTE_DATA; + note_test.subtype = type & NOTE_SUBTYPE; + note_test.action = type & NOTE_ACTION; + note_test.reference = reference; - note->category = type & NOTE_CATEGORY; - note->data = type & NOTE_DATA; - note->subtype = type & NOTE_SUBTYPE; - note->action = type & NOTE_ACTION; + BLI_assert(!wm_notifier_is_clear(¬e_test)); - note->reference = reference; + if (wm->notifier_queue_set == nullptr) { + wm->notifier_queue_set = BLI_gset_new_ex( + note_hash_for_queue_fn, note_cmp_for_queue_fn, __func__, 1024); + } + + void **note_p; + if (BLI_gset_ensure_p_ex(wm->notifier_queue_set, ¬e_test, ¬e_p)) { + return; + } + wmNotifier *note = MEM_new<wmNotifier>(__func__); + *note = note_test; + *note_p = note; + BLI_addtail(&wm->notifier_queue, note); } /* XXX: in future, which notifiers to send to other windows? */ @@ -295,20 +328,7 @@ void WM_main_add_notifier(unsigned int type, void *reference) Main *bmain = G_MAIN; wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); - if (!wm || wm_test_duplicate_notifier(wm, type, reference)) { - return; - } - - wmNotifier *note = MEM_cnew<wmNotifier>(__func__); - - BLI_addtail(&wm->notifier_queue, note); - - note->category = type & NOTE_CATEGORY; - note->data = type & NOTE_DATA; - note->subtype = type & NOTE_SUBTYPE; - note->action = type & NOTE_ACTION; - - note->reference = reference; + WM_event_add_notifier_ex(wm, nullptr, type, reference); } void WM_main_remove_notifier_reference(const void *reference) @@ -319,6 +339,9 @@ void WM_main_remove_notifier_reference(const void *reference) if (wm) { LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { if (note->reference == reference) { + const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr); + BLI_assert(removed); + UNUSED_VARS_NDEBUG(removed); /* Don't remove because this causes problems for #wm_event_do_notifiers * which may be looping on the data (deleting screens). */ wm_notifier_clear(note); @@ -374,6 +397,12 @@ static void wm_notifier_clear(wmNotifier *note) { /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */ memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link)); + note->category = NOTE_CATEGORY_TAG_CLEARED; +} + +static bool wm_notifier_is_clear(const wmNotifier *note) +{ + return note->category == NOTE_CATEGORY_TAG_CLEARED; } void wm_event_do_depsgraph(bContext *C, bool is_after_open_file) @@ -473,7 +502,7 @@ void wm_event_do_notifiers(bContext *C) CTX_wm_window_set(C, win); - LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { + LISTBASE_FOREACH_MUTABLE (const wmNotifier *, note, &wm->notifier_queue) { if (note->category == NC_WM) { if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) { wm->file_saved = 1; @@ -565,8 +594,15 @@ void wm_event_do_notifiers(bContext *C) } /* The notifiers are sent without context, to keep it clean. */ - wmNotifier *note; - while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) { + const wmNotifier *note; + while ((note = static_cast<const wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) { + if (wm_notifier_is_clear(note)) { + MEM_freeN((void *)note); + continue; + } + const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr); + BLI_assert(removed); + UNUSED_VARS_NDEBUG(removed); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { Scene *scene = WM_window_get_active_scene(win); bScreen *screen = WM_window_get_active_screen(win); @@ -630,7 +666,7 @@ void wm_event_do_notifiers(bContext *C) } } - MEM_freeN(note); + MEM_freeN((void *)note); } #endif /* If 1 (postpone disabling for in favor of message-bus), eventually. */ @@ -657,7 +693,7 @@ void wm_event_do_notifiers(bContext *C) wm_test_autorun_warning(C); } -static int wm_event_always_pass(const wmEvent *event) +static bool wm_event_always_pass(const wmEvent *event) { /* Some events we always pass on, to ensure proper communication. */ return ISTIMER(event->type) || (event->type == WINDEACTIVATE); @@ -667,14 +703,23 @@ static int wm_event_always_pass(const wmEvent *event) * Debug only sanity check for the return value of event handlers. Checks that "always pass" events * don't cause non-passing handler return values, and thus actually pass. * - * Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)` - * returning `nullptr`), because the event will have been freed then. + * \param C: Pass in the context to check if it's "window" was cleared. + * The event check can't be executed if the handler just loaded a file or closed the window. + * (typically identified by `CTX_wm_window(C)` returning null), + * because the event will have been freed then. + * When null, always check the event (assume the caller knows the event was not freed). */ -BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action) +BLI_INLINE void wm_event_handler_return_value_check(const bContext *C, + const wmEvent *event, + const int action) { - BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK), - "Return value for events that should always pass should never be BREAK."); - UNUSED_VARS_NDEBUG(event, action); +#ifndef NDEBUG + if (C == nullptr || CTX_wm_window(C)) { + BLI_assert_msg(!wm_event_always_pass(event) || (action != WM_HANDLER_BREAK), + "Return value for events that should always pass should never be BREAK."); + } +#endif + UNUSED_VARS_NDEBUG(C, event, action); } /** \} */ @@ -1378,22 +1423,20 @@ static int wm_operator_invoke(bContext *C, } if (op->type->invoke && event) { - /* Temporarily write into `mval` (not technically `const` correct) but this is restored. */ - const int mval_prev[2] = {UNPACK2(event->mval)}; - wm_region_mouse_co(C, (wmEvent *)event); + /* Make a copy of the event as it's `const` and the #wmEvent.mval to be written into. */ + wmEvent event_temp = *event; + wm_region_mouse_co(C, &event_temp); if (op->type->flag & OPTYPE_UNDO) { wm->op_undo_depth++; } - retval = op->type->invoke(C, op, event); + retval = op->type->invoke(C, op, &event_temp); OPERATOR_RETVAL_CHECK(retval); if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) { wm->op_undo_depth--; } - - copy_v2_v2_int(((wmEvent *)event)->mval, mval_prev); } else if (op->type->exec) { if (op->type->flag & OPTYPE_UNDO) { @@ -1548,6 +1591,7 @@ static int wm_operator_call_internal(bContext *C, case WM_OP_EXEC_AREA: case WM_OP_EXEC_SCREEN: event = nullptr; + break; default: break; } @@ -2088,9 +2132,7 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi) /* The matching rules. */ if (kmitype == KM_TEXTINPUT) { if (winevent->val == KM_PRESS) { /* Prevent double clicks. */ - /* Not using #ISTEXTINPUT anymore because (at least on Windows) some key codes above 255 - * could have printable ascii keys, See T30479. */ - if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) { + if (ISKEYBOARD(winevent->type) && winevent->utf8_buf[0]) { return true; } } @@ -2355,7 +2397,7 @@ static int wm_handler_operator_call(bContext *C, } } - /* Important to run 'wm_operator_finished' before nullptr-ing the context members. */ + /* Important to run 'wm_operator_finished' before setting the context members to null. */ if (retval & OPERATOR_FINISHED) { wm_operator_finished(C, op, false, true); handler->op = nullptr; @@ -2735,7 +2777,7 @@ static int wm_handler_fileselect_call(bContext *C, return wm_handler_fileselect_do(C, handlers, handler, event->val); } -static int wm_action_not_handled(int action) +static bool wm_action_not_handled(int action) { return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL); } @@ -3099,13 +3141,13 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) && /* Comment this out to flood the console! (if you really want to test). */ - !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE); + !ISMOUSE_MOTION(event->type); wmWindowManager *wm = CTX_wm_manager(C); int action = WM_HANDLER_CONTINUE; if (handlers == nullptr) { - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3271,9 +3313,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis } /* Do some extra sanity checking before returning the action. */ - if (CTX_wm_window(C) != nullptr) { - wm_event_handler_return_value_check(event, action); - } + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3290,7 +3330,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) return action; } - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (ISMOUSE_MOTION(event->type)) { /* Test for #KM_CLICK_DRAG events. */ /* NOTE(@campbellbarton): Needed so drag can be used for editors that support both click @@ -3376,9 +3416,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } - if (event->prev_press_type == event->type) { - - if (event->val == KM_RELEASE) { + if (event->val == KM_RELEASE) { + if (event->prev_press_type == event->type) { if (event->prev_val == KM_PRESS) { if (win->event_queue_check_click) { if (WM_event_drag_test(event, event->prev_press_xy)) { @@ -3408,15 +3447,15 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } } - else if (event->val == KM_DBL_CLICK) { - /* The underlying event is a press, so try and handle this. */ - event->val = KM_PRESS; - action |= wm_handlers_do_intern(C, win, event, handlers); + } + else if (event->val == KM_DBL_CLICK) { + /* The underlying event is a press, so try and handle this. */ + event->val = KM_PRESS; + action |= wm_handlers_do_intern(C, win, event, handlers); - /* Revert value if not handled. */ - if (wm_action_not_handled(action)) { - event->val = KM_DBL_CLICK; - } + /* Revert value if not handled. */ + if (wm_action_not_handled(action)) { + event->val = KM_DBL_CLICK; } } } @@ -3445,7 +3484,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3573,7 +3612,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv /* Clear drop icon. */ screen->do_draw_drag = true; - /* Restore cursor (disabled, see `wm_dragdrop.c`) */ + /* Restore cursor (disabled, see `wm_dragdrop.cc`) */ // WM_cursor_modal_restore(win); } } @@ -3722,7 +3761,7 @@ static int wm_event_do_handlers_area_regions(bContext *C, wmEvent *event, ScrAre action |= wm_event_do_region_handlers(C, event, region); } - wm_event_handler_return_value_check(event, action); + wm_event_handler_return_value_check(C, event, action); return action; } @@ -3826,15 +3865,14 @@ void wm_event_do_handlers(bContext *C) /* Active screen might change during handlers, update pointer. */ screen = WM_window_get_active_screen(win); - if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && - !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ISMOUSE_MOTION(event->type)) { printf("\n%s: Handling event\n", __func__); WM_event_print(event); } /* Take care of pie event filter. */ if (wm_event_pie_filter(win, event)) { - if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (!ISMOUSE_MOTION(event->type)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed"); } BLI_remlink(&win->event_queue, event); @@ -3856,7 +3894,7 @@ void wm_event_do_handlers(bContext *C) /* Clear tool-tip on mouse move. */ if (screen->tool_tip && screen->tool_tip->exit_on_event) { - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (ISMOUSE_MOTION(event->type)) { if (len_manhattan_v2v2_int(screen->tool_tip->event_xy, event->xy) > WM_EVENT_CURSOR_MOTION_THRESHOLD) { WM_tooltip_clear(C, win); @@ -4980,7 +5018,7 @@ static bool wm_event_is_double_click(const wmEvent *event) { if ((event->type == event->prev_type) && (event->prev_val == KM_RELEASE) && (event->val == KM_PRESS)) { - if (ISMOUSE(event->type) && WM_event_drag_test(event, event->prev_press_xy)) { + if (ISMOUSE_BUTTON(event->type) && WM_event_drag_test(event, event->prev_press_xy)) { /* Pass. */ } else { @@ -5045,7 +5083,6 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win) tevent = *event_last; tevent.flag = (eWM_EventFlag)0; - tevent.ascii = '\0'; tevent.utf8_buf[0] = '\0'; wm_event_custom_clear(&tevent); @@ -5139,6 +5176,53 @@ static void wm_event_state_update_and_click_set(wmEvent *event, wm_event_state_update_and_click_set_ex(event, event_state, is_keyboard, check_double_click); } +/* Returns true when the two events corresponds to a press of the same key with the same modifiers. + */ +static bool wm_event_is_same_key_press(const wmEvent &event_a, const wmEvent &event_b) +{ + if (event_a.val != KM_PRESS || event_b.val != KM_PRESS) { + return false; + } + + if (event_a.modifier != event_b.modifier || event_a.type != event_b.type) { + return false; + } + + return true; +} + +/** + * Returns true if the event is a key press event which is to be ignored and not added to the event + * queue. + * + * A key press event will be ignored if there is already matched key press in the queue. + * This avoids the event queue "clogging" in the situations when there is an operator bound to a + * key press event and the execution time of the operator is longer than the key repeat. + */ +static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent &event) +{ + if (BLI_listbase_is_empty(&win->event_queue)) { + /* If the queue is empty never ignore the event. + * Empty queue at this point means that the events are handled fast enough, and there is no + * reason to ignore anything. */ + return false; + } + + if ((event.flag & WM_EVENT_IS_REPEAT) == 0) { + /* Only ignore repeat events from the keyboard, and allow accumulation of non-repeat events. + * + * The goal of this check is to allow events coming from a keyboard macro software, which can + * generate events quicker than the main loop handles them. In this case we want all events to + * be handled (unless the keyboard macro software tags them as repeat) because otherwise it + * will become impossible to get reliable results of automated events testing. */ + return false; + } + + const wmEvent &last_event = *static_cast<const wmEvent *>(win->event_queue.last); + + return wm_event_is_same_key_press(last_event, event); +} + void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { @@ -5174,6 +5258,13 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.prev_type = event.type; event.prev_val = event.val; + /* Always use modifiers from the active window since + * changes to modifiers aren't sent to inactive windows, see: T66088. */ + if ((wm->winactive != win) && (wm->winactive && wm->winactive->eventstate)) { + event.modifier = wm->winactive->eventstate->modifier; + event.keymodifier = wm->winactive->eventstate->keymodifier; + } + /* Ensure the event state is correct, any deviation from this may cause bugs. * * NOTE: #EVENT_NONE is set when unknown keys are pressed, @@ -5216,6 +5307,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void if (win_other) { wmEvent event_other = *win_other->eventstate; + /* Use the modifier state of this window. */ + event_other.modifier = event.modifier; + event_other.keymodifier = event.keymodifier; + /* See comment for this operation on `event` for details. */ event_other.prev_type = event_other.type; event_other.prev_val = event_other.val; @@ -5305,6 +5400,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void if (win_other) { wmEvent event_other = *win_other->eventstate; + /* Use the modifier state of this window. */ + event_other.modifier = event.modifier; + event_other.keymodifier = event.keymodifier; + /* See comment for this operation on `event` for details. */ event_other.prev_type = event_other.type; event_other.prev_val = event_other.val; @@ -5332,8 +5431,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void break; } - event.ascii = kd->ascii; - /* Might be not nullptr terminated. */ + /* Might be not null terminated. */ memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); if (kd->is_repeat) { event.flag |= WM_EVENT_IS_REPEAT; @@ -5344,8 +5442,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void /* Exclude arrow keys, escape, etc from text input. */ if (type == GHOST_kEventKeyUp) { - event.ascii = '\0'; - /* Ghost should do this already for key up. */ if (event.utf8_buf[0]) { CLOG_ERROR(WM_LOG_EVENTS, @@ -5354,15 +5450,28 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.utf8_buf[0] = '\0'; } else { - if (event.ascii < 32 && event.ascii > 0) { - event.ascii = '\0'; - } if (event.utf8_buf[0] < 32 && event.utf8_buf[0] > 0) { event.utf8_buf[0] = '\0'; } } if (event.utf8_buf[0]) { + /* NOTE(@campbellbarton): Detect non-ASCII characters stored in `utf8_buf`, + * ideally this would never happen but it can't be ruled out for X11 which has + * special handling of Latin1 when building without UTF8 support. + * Avoid regressions by adding this conversions, it should eventually be removed. */ + if ((event.utf8_buf[0] >= 0x80) && (event.utf8_buf[1] == '\0')) { + const uint c = (uint)event.utf8_buf[0]; + int utf8_buf_len = BLI_str_utf8_from_unicode(c, event.utf8_buf, sizeof(event.utf8_buf)); + CLOG_ERROR(WM_LOG_EVENTS, + "ghost detected non-ASCII single byte character '%u', converting to utf8 " + "('%.*s', length=%d)", + c, + utf8_buf_len, + event.utf8_buf, + utf8_buf_len); + } + if (BLI_str_utf8_size(event.utf8_buf) == -1) { CLOG_ERROR(WM_LOG_EVENTS, "ghost detected an invalid unicode character '%d'", @@ -5435,7 +5544,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void G.is_break = true; } - wm_event_add(win, &event); + if (!wm_event_is_ignorable_key_press(win, event)) { + wm_event_add(win, &event); + } break; } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 45d192d227c..99f451d06f8 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -71,6 +71,7 @@ #include "BKE_lib_override.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_main_namemap.h" #include "BKE_packedFile.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -301,6 +302,12 @@ static void wm_window_match_keep_current_wm(const bContext *C, } } + /* we'll be using the current wm list directly; make sure + * the names are validated and in the name map. */ + LISTBASE_FOREACH (wmWindowManager *, wm_item, current_wm_list) { + BKE_main_namemap_get_name(bmain, &wm_item->id, wm_item->id.name + 2); + } + *r_new_wm_list = *current_wm_list; } @@ -704,6 +711,14 @@ static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *p } } + if (is_factory_startup && BLT_translate_new_dataname()) { + /* Translate workspace names */ + LISTBASE_FOREACH_MUTABLE (WorkSpace *, workspace, &bmain->workspaces) { + BKE_libblock_rename( + bmain, &workspace->id, CTX_DATA_(BLT_I18NCONTEXT_ID_WORKSPACE, workspace->id.name + 2)); + } + } + if (use_data) { /* important to do before NULL'ing the context */ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE); @@ -1010,6 +1025,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_cursor_wait(false); + BLI_assert(BKE_main_namemap_validate(CTX_data_main(C))); + return success; } @@ -1771,9 +1788,11 @@ static bool wm_file_write(bContext *C, /* Enforce full override check/generation on file save. */ BKE_lib_override_library_main_operations_create(bmain, true); - /* NOTE: Ideally we would call `WM_redraw_windows` here to remove any open menus. But we - * can crash if saving from a script, see T92704 & T97627. Just checking `!G.background - * && BLI_thread_is_main()` is not sufficient to fix this. */ + /* NOTE: Ideally we would call `WM_redraw_windows` here to remove any open menus. + * But we can crash if saving from a script, see T92704 & T97627. + * Just checking `!G.background && BLI_thread_is_main()` is not sufficient to fix this. + * Additionally some some EGL configurations don't support reading the front-buffer + * immediately after drawing, see: T98462. In that case off-screen drawing is necessary. */ /* don't forget not to return without! */ WM_cursor_wait(true); @@ -1890,9 +1909,6 @@ static void wm_autosave_location(char *filepath) { const int pid = abs(getpid()); char path[1024]; -#ifdef WIN32 - const char *savedir; -#endif /* Normally there is no need to check for this to be NULL, * however this runs on exit when it may be cleared. */ @@ -1918,7 +1934,7 @@ static void wm_autosave_location(char *filepath) * through BLI_windows_get_default_root_dir(). * If there is no C:\tmp autosave fails. */ if (!BLI_exists(BKE_tempdir_base())) { - savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, NULL); + const char *savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, NULL); BLI_make_file_string("/", filepath, savedir, path); return; } @@ -3009,7 +3025,9 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) static void wm_filepath_default(const Main *bmain, char *filepath) { if (bmain->filepath[0] == '\0') { - BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend"); + char filename_untitled[FILE_MAXFILE]; + SNPRINTF(filename_untitled, "%s.blend", DATA_("untitled")); + BLI_path_filename_ensure(filepath, FILE_MAX, filename_untitled); } } @@ -3069,8 +3087,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); char path[FILE_MAX]; const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke); - const bool use_save_as_copy = (RNA_struct_property_is_set(op->ptr, "copy") && - RNA_boolean_get(op->ptr, "copy")); + const bool use_save_as_copy = is_save_as && RNA_boolean_get(op->ptr, "copy"); /* We could expose all options to the users however in most cases remapping * existing relative paths is a good default. @@ -3643,7 +3660,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, BLI_split_file_part(blendfile_path, filename, sizeof(filename)); } else { - STRNCPY(filename, "untitled.blend"); + SNPRINTF(filename, "%s.blend", DATA_("untitled")); } uiItemL(layout, filename, ICON_NONE); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 9b34468ae82..2bc1fb1519a 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -122,7 +122,7 @@ static void wm_gesture_draw_line_active_side(rcti *rect, const bool flip) uint shdr_col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); GPU_blend(GPU_BLEND_ALPHA); - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); const float gradient_length = 150.0f * U.pixelsize; float line_dir[2]; @@ -175,7 +175,7 @@ static void wm_gesture_draw_line(wmGesture *gt) uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -207,7 +207,7 @@ static void wm_gesture_draw_rect(wmGesture *gt) GPU_blend(GPU_BLEND_ALPHA); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f); immRecti(shdr_pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); @@ -218,7 +218,7 @@ static void wm_gesture_draw_rect(wmGesture *gt) shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -248,7 +248,7 @@ static void wm_gesture_draw_circle(wmGesture *gt) const uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f); imm_draw_circle_fill_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40); @@ -257,7 +257,7 @@ static void wm_gesture_draw_circle(wmGesture *gt) GPU_blend(GPU_BLEND_NONE); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -361,7 +361,7 @@ static void wm_gesture_draw_lasso(wmGesture *gt, bool filled) const uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -395,7 +395,7 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt) const uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index f77aad24719..8163b39b3dd 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -166,7 +166,11 @@ void WM_init_opengl(void) if (G.background) { /* Ghost is still not initialized elsewhere in background mode. */ - wm_ghost_init(NULL); + wm_ghost_init_background(); + } + + if (!GPU_backend_supported()) { + return; } /* Needs to be first to have an OpenGL context bound. */ @@ -310,6 +314,7 @@ void WM_init(bContext *C, int argc, const char **argv) IMB_thumb_clear_translations(); if (!G.background) { + GPU_render_begin(); #ifdef WITH_INPUT_NDOF /* Sets 3D mouse dead-zone. */ @@ -322,7 +327,10 @@ void WM_init(bContext *C, int argc, const char **argv) exit(-1); } + GPU_context_begin_frame(GPU_context_active_get()); UI_init(); + GPU_context_end_frame(GPU_context_active_get()); + GPU_render_end(); } BKE_subdiv_init(); @@ -532,7 +540,7 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_vfont_clipboard_free(); BKE_node_clipboard_free(); -#ifdef WITH_COMPOSITOR +#ifdef WITH_COMPOSITOR_CPU COM_deinitialize(); #endif @@ -568,14 +576,6 @@ void WM_exit_ex(bContext *C, const bool do_python) BLF_exit(); - if (opengl_is_init) { - DRW_opengl_context_enable_ex(false); - GPU_pass_cache_free(); - GPU_exit(); - DRW_opengl_context_disable_ex(false); - DRW_opengl_context_destroy(); - } - BLT_lang_free(); ANIM_keyingset_infos_exit(); @@ -600,13 +600,24 @@ void WM_exit_ex(bContext *C, const bool do_python) ED_file_exit(); /* for fsmenu */ - UI_exit(); + /* Delete GPU resources and context. The UI also uses GPU resources and so + * is also deleted with the context active. */ + if (opengl_is_init) { + DRW_opengl_context_enable_ex(false); + UI_exit(); + GPU_pass_cache_free(); + GPU_exit(); + DRW_opengl_context_disable_ex(false); + DRW_opengl_context_destroy(); + } + else { + UI_exit(); + } + BKE_blender_userdef_data_free(&U, false); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ - GPU_backend_exit(); - wm_ghost_exit(); CTX_free(C); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 33c69a23558..18b5461383f 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -81,6 +81,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "UI_interface.h" @@ -638,7 +639,7 @@ char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, i if (lhs == NULL) { /* Fallback to `bpy.data.foo[id]` if we don't find in the context. */ - lhs = RNA_path_full_property_py(CTX_data_main(C), ptr, prop, index); + lhs = RNA_path_full_property_py(ptr, prop, index); } if (!lhs) { @@ -939,7 +940,7 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) return ret_value | OPERATOR_PASS_THROUGH; } - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (ISMOUSE_MOTION(event->type)) { const int drag_delta[2] = { mval[0] - event->mval[0], mval[1] - event->mval[1], @@ -2327,7 +2328,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph GPU_matrix_rotate_2d(RAD2DEGF(rot)); } - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR); immUniformColor3fvAlpha(col, alpha); immBindTexture("image", rc->texture); @@ -2358,7 +2359,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } else { /* flat color if no texture available */ - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor3fvAlpha(col, alpha); imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40); } @@ -2470,7 +2471,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (rc->subtype == PROP_ANGLE) { GPU_matrix_push(); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 3100e6e4fd3..60f3842bc7c 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -482,7 +482,7 @@ static void draw_display_buffer(PlayState *ps, ImBuf *ibuf) GPU_texture_bind(texture, 0); if (!glsl_used) { - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_COLOR); immUniformColor3f(1.0f, 1.0f, 1.0f); } @@ -601,7 +601,7 @@ static void playanim_toscreen( uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor3ub(0, 255, 0); immBegin(GPU_PRIM_LINES, 2); @@ -1217,8 +1217,7 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) GHOST_TEventButtonData *bd = GHOST_GetEventData(evt); int cx, cy, sizex, sizey, inside_window; - GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy); - GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy); + GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy); playanim_window_get_size(&sizex, &sizey); inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey); @@ -1267,15 +1266,15 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) * however the API currently doesn't support this. */ { int x_test, y_test; - GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test); - if (x_test != cd->x || y_test != cd->y) { + GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy); + GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &x_test, &y_test); + + if (cx != x_test || cy != y_test) { /* we're not the last event... skipping */ break; } } - GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy); - tag_change_frame(ps, cx); } break; @@ -1555,6 +1554,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) /* initialize the font */ BLF_init(); + BLF_load_font_stack(); ps.fontid = BLF_load_mono_default(false); BLF_size(ps.fontid, 11.0f, 72); @@ -1807,21 +1807,22 @@ static char *wm_main_playanim_intern(int argc, const char **argv) AUD_Sound_free(source); source = NULL; #endif + /* we still miss freeing a lot!, * but many areas could skip initialization too for anim play */ - GPU_shader_free_builtin_shaders(); + IMB_exit(); + DEG_free_node_types(); + + BLF_exit(); if (g_WS.gpu_context) { GPU_context_active_set(g_WS.gpu_context); + GPU_exit(); GPU_context_discard(g_WS.gpu_context); g_WS.gpu_context = NULL; } - BLF_exit(); - - GPU_exit(); - GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window); /* early exit, IMB and BKE should be exited only in end */ @@ -1830,9 +1831,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv) return filepath; } - IMB_exit(); - DEG_free_node_types(); - totblock = MEM_get_memory_blocks_in_use(); if (totblock != 0) { /* prints many bAKey, bArgument's which are tricky to fix */ @@ -1855,7 +1853,7 @@ void WM_main_playanim(int argc, const char **argv) AUD_DeviceSpecs specs; specs.rate = AUD_RATE_48000; - specs.format = AUD_FORMAT_S16; + specs.format = AUD_FORMAT_FLOAT32; specs.channels = AUD_CHANNELS_STEREO; AUD_initOnce(); diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 2e04a629308..8fca3deef92 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -78,50 +78,51 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) { uchar *rct = (uchar *)ibuf->rect; + if (!rct) { + return; + } - if (rct) { - bTheme *btheme = UI_GetTheme(); - const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; - const int size = roundness * 20; - - if (size < ibuf->x && size < ibuf->y) { - /* Y-axis initial offset. */ - rct += 4 * (ibuf->y - size) * ibuf->x; - - for (int y = 0; y < size; y++) { - for (int x = 0; x < size; x++, rct += 4) { - const float pixel = 1.0 / size; - const float u = pixel * x; - const float v = pixel * y; - const float distance = sqrt(u * u + v * v); - - /* Pointer offset to the alpha value of pixel. */ - /* NOTE: the left corner is flipped in the X-axis. */ - const int offset_l = 4 * (size - x - x - 1) + 3; - const int offset_r = 4 * (ibuf->x - size) + 3; - - if (distance > 1.0) { - rct[offset_l] = 0; - rct[offset_r] = 0; - } - else { - /* Create a single pixel wide transition for anti-aliasing. - * Invert the distance and map its range [0, 1] to [0, pixel]. */ - const float fac = (1.0 - distance) * size; - - if (fac > 1.0) { - continue; - } - - const uchar alpha = unit_float_to_uchar_clamp(fac); - rct[offset_l] = alpha; - rct[offset_r] = alpha; - } + bTheme *btheme = UI_GetTheme(); + const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; + const int size = roundness * 20; + + if (size < ibuf->x && size < ibuf->y) { + /* Y-axis initial offset. */ + rct += 4 * (ibuf->y - size) * ibuf->x; + + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++, rct += 4) { + const float pixel = 1.0 / size; + const float u = pixel * x; + const float v = pixel * y; + const float distance = sqrt(u * u + v * v); + + /* Pointer offset to the alpha value of pixel. */ + /* NOTE: the left corner is flipped in the X-axis. */ + const int offset_l = 4 * (size - x - x - 1) + 3; + const int offset_r = 4 * (ibuf->x - size) + 3; + + if (distance > 1.0) { + rct[offset_l] = 0; + rct[offset_r] = 0; } + else { + /* Create a single pixel wide transition for anti-aliasing. + * Invert the distance and map its range [0, 1] to [0, pixel]. */ + const float fac = (1.0 - distance) * size; - /* X-axis offset to the next row. */ - rct += 4 * (ibuf->x - size); + if (fac > 1.0) { + continue; + } + + const uchar alpha = unit_float_to_uchar_clamp(fac); + rct[offset_l] = alpha; + rct[offset_r] = alpha; + } } + + /* X-axis offset to the next row. */ + rct += 4 * (ibuf->x - size); } } } diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index f85c818cdf3..48a0d47f26a 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -47,7 +47,7 @@ void wm_stereo3d_draw_sidebyside(wmWindow *win, int view) uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE); int soffx = WM_window_pixels_x(win) * 0.5f; if (view == STEREO_LEFT_ID) { @@ -95,7 +95,7 @@ void wm_stereo3d_draw_topbottom(wmWindow *win, int view) uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE); + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE); int soffy; if (view == STEREO_LEFT_ID) { diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 984a8ef41d0..a3aaef6af31 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -26,6 +26,7 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_idprop.h" +#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_paint.h" @@ -367,7 +368,7 @@ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToo Scene *scene = WM_window_get_active_scene(win); ToolSettings *ts = scene->toolsettings; const ViewLayer *view_layer = WM_window_get_active_view_layer(win); - const Object *ob = OBACT(view_layer); + const Object *ob = BKE_view_layer_active_object_get(view_layer); if (ob == NULL) { /* pass */ } @@ -443,7 +444,7 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *area, int switch (space_type) { case SPACE_VIEW3D: { /* 'area' may be NULL in this case. */ - Object *obact = OBACT(view_layer); + Object *obact = BKE_view_layer_active_object_get(view_layer); if (obact != NULL) { Object *obedit = OBEDIT_FROM_OBACT(obact); mode = CTX_data_mode_enum_ex(obedit, obact, obact->mode); @@ -705,7 +706,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case CTX_MODE_VERTEX_GPENCIL: return "builtin_brush.Draw"; case CTX_MODE_SCULPT_CURVES: - return "builtin_brush.Comb"; + return "builtin_brush.density"; /* end temporary hack. */ case CTX_MODE_PARTICLE: diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 104eda220cc..390893ec630 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -83,6 +83,12 @@ # include "BLI_threads.h" #endif +/** + * When windows are activated, simulate modifier press/release to match the current state of + * held modifier keys, see T40317. + */ +#define USE_WIN_ACTIVATE + /* the global to talk to ghost */ static GHOST_SystemHandle g_system = NULL; @@ -155,28 +161,30 @@ static void wm_window_check_size(rcti *rect) static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) { - if (win->ghostwin) { - /* Prevents non-drawable state of main windows (bugs T22967, - * T25071 and possibly T22477 too). Always clear it even if - * this window was not the drawable one, because we mess with - * drawing context to discard the GW context. */ - wm_window_clear_drawable(wm); + if (UNLIKELY(!win->ghostwin)) { + return; + } - if (win == wm->winactive) { - wm->winactive = NULL; - } + /* Prevents non-drawable state of main windows (bugs T22967, + * T25071 and possibly T22477 too). Always clear it even if + * this window was not the drawable one, because we mess with + * drawing context to discard the GW context. */ + wm_window_clear_drawable(wm); - /* We need this window's opengl context active to discard it. */ - GHOST_ActivateWindowDrawingContext(win->ghostwin); - GPU_context_active_set(win->gpuctx); + if (win == wm->winactive) { + wm->winactive = NULL; + } - /* Delete local GPU context. */ - GPU_context_discard(win->gpuctx); + /* We need this window's opengl context active to discard it. */ + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GPU_context_active_set(win->gpuctx); - GHOST_DisposeWindow(g_system, win->ghostwin); - win->ghostwin = NULL; - win->gpuctx = NULL; - } + /* Delete local GPU context. */ + GPU_context_discard(win->gpuctx); + + GHOST_DisposeWindow(g_system, win->ghostwin); + win->ghostwin = NULL; + win->gpuctx = NULL; } void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) @@ -510,7 +518,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, wmWindow *win, bool is_dialog) { - /* a new window is created when pageflip mode is required for a window */ + /* A new window is created when page-flip mode is required for a window. */ GHOST_GLSettings glSettings = {0}; if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) { glSettings.flags |= GHOST_glStereoVisual; @@ -920,25 +928,33 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* ************ events *************** */ -void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y) +void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y) { float fac = GHOST_GetNativePixelSize(win->ghostwin); - - GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y); *x *= fac; *y = (win->sizey - 1) - *y; *y *= fac; } -void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y) +void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y) { float fac = GHOST_GetNativePixelSize(win->ghostwin); *x /= fac; *y /= fac; *y = win->sizey - *y - 1; +} + +void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *x, int *y) +{ + GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y); + wm_cursor_position_from_ghost_client_coords(win, x, y); +} +void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y) +{ + wm_cursor_position_to_ghost_client_coords(win, x, y); GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y); } @@ -949,8 +965,8 @@ void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y) *r_y = win->eventstate->xy[1]; return; } - GHOST_GetCursorPosition(g_system, r_x, r_y); - wm_cursor_position_from_ghost(win, r_x, r_y); + GHOST_GetCursorPosition(g_system, win->ghostwin, r_x, r_y); + wm_cursor_position_from_ghost_client_coords(win, r_x, r_y); } typedef enum { @@ -960,10 +976,10 @@ typedef enum { OS = 'C', } modifierKeyType; -/* check if specified modifier key type is pressed */ -static int query_qual(modifierKeyType qual) +/** Check if specified modifier key type is pressed. */ +static bool query_qual(modifierKeyType qual) { - GHOST_TModifierKeyMask left, right; + GHOST_TModifierKey left, right; switch (qual) { case SHIFT: left = GHOST_kModifierKeyLeftShift; @@ -1109,29 +1125,16 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt case GHOST_kEventWindowDeactivate: wm_event_add_ghostevent(wm, win, type, data); win->active = 0; /* XXX */ - - /* clear modifiers for inactive windows */ - win->eventstate->modifier = 0; - win->eventstate->keymodifier = 0; - break; case GHOST_kEventWindowActivate: { - GHOST_TEventKeyData kdata; const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) | (query_qual(CONTROL) ? KM_CTRL : 0) | (query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0)); - /* Win23/GHOST modifier bug, see T40317 */ -#ifndef WIN32 -//# define USE_WIN_ACTIVATE -#endif - /* No context change! C->wm->windrawable is drawable, or for area queues. */ wm->winactive = win; win->active = 1; - // window_handle(win, INPUTCHANGE, win->active); - /* bad ghost support for modifier keys... so on activate we set the modifiers again */ /* TODO: This is not correct since a modifier may be held when a window is activated... @@ -1139,9 +1142,11 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt * * For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'. */ - kdata.ascii = '\0'; - kdata.utf8_buf[0] = '\0'; - + GHOST_TEventKeyData kdata = { + .key = GHOST_kKeyUnknown, + .utf8_buf = {'\0'}, + .is_repeat = false, + }; if (win->eventstate->modifier & KM_SHIFT) { if ((keymodifier & KM_SHIFT) == 0) { kdata.key = GHOST_kKeyLeftShift; @@ -1353,6 +1358,15 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt event.type = MOUSEMOVE; event.val = KM_NOTHING; copy_v2_v2_int(event.prev_xy, event.xy); + + wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y); + event.xy[0] = ddd->x; + event.xy[1] = ddd->y; + + /* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't) + * Write this into the event state. */ + copy_v2_v2_int(win->eventstate->xy, event.xy); + event.flag = 0; /* No context change! C->wm->windrawable is drawable, or for area queues. */ @@ -1416,14 +1430,14 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt case GHOST_kEventTrackpad: { GHOST_TEventTrackpadData *pd = data; - wm_cursor_position_from_ghost(win, &pd->x, &pd->y); + wm_cursor_position_from_ghost_screen_coords(win, &pd->x, &pd->y); wm_event_add_ghostevent(wm, win, type, data); break; } case GHOST_kEventCursorMove: { GHOST_TEventCursorData *cd = data; - wm_cursor_position_from_ghost(win, &cd->x, &cd->y); + wm_cursor_position_from_ghost_screen_coords(win, &cd->x, &cd->y); wm_event_add_ghostevent(wm, win, type, data); break; } @@ -1537,36 +1551,55 @@ void wm_window_process_events(const bContext *C) void wm_ghost_init(bContext *C) { - if (!g_system) { - GHOST_EventConsumerHandle consumer; + if (g_system) { + return; + } - if (C != NULL) { - consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); - } + BLI_assert(C != NULL); + BLI_assert_msg(!G.background, "Use wm_ghost_init_background instead"); - GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + GHOST_EventConsumerHandle consumer; - g_system = GHOST_CreateSystem(); + consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); - GHOST_Debug debug = {0}; - if (G.debug & G_DEBUG_GHOST) { - debug.flags |= GHOST_kDebugDefault; - } - if (G.debug & G_DEBUG_WINTAB) { - debug.flags |= GHOST_kDebugWintab; - } - GHOST_SystemInitDebug(g_system, debug); + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); - if (C != NULL) { - GHOST_AddEventConsumer(g_system, consumer); - } + g_system = GHOST_CreateSystem(); - if (wm_init_state.native_pixels) { - GHOST_UseNativePixels(); - } + GHOST_Debug debug = {0}; + if (G.debug & G_DEBUG_GHOST) { + debug.flags |= GHOST_kDebugDefault; + } + if (G.debug & G_DEBUG_WINTAB) { + debug.flags |= GHOST_kDebugWintab; + } + GHOST_SystemInitDebug(g_system, debug); - GHOST_UseWindowFocus(wm_init_state.window_focus); + GHOST_AddEventConsumer(g_system, consumer); + + if (wm_init_state.native_pixels) { + GHOST_UseNativePixels(); } + + GHOST_UseWindowFocus(wm_init_state.window_focus); +} + +/* TODO move this to wm_init_exit.c. */ +void wm_ghost_init_background(void) +{ + if (g_system) { + return; + } + + GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace); + + g_system = GHOST_CreateSystemBackground(); + + GHOST_Debug debug = {0}; + if (G.debug & G_DEBUG_GHOST) { + debug.flags |= GHOST_kDebugDefault; + } + GHOST_SystemInitDebug(g_system, debug); } void wm_ghost_exit(void) @@ -1864,7 +1897,7 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv { int tmp[2]; copy_v2_v2_int(tmp, mval); - wm_cursor_position_to_ghost(win, &tmp[0], &tmp[1]); + wm_cursor_position_to_ghost_screen_coords(win, &tmp[0], &tmp[1]); GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, tmp[0], tmp[1]); @@ -1873,7 +1906,7 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv } wmWindow *win_other = GHOST_GetWindowUserData(ghostwin); - wm_cursor_position_from_ghost(win_other, &tmp[0], &tmp[1]); + wm_cursor_position_from_ghost_screen_coords(win_other, &tmp[0], &tmp[1]); copy_v2_v2_int(r_mval, tmp); return win_other; } @@ -1911,6 +1944,9 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm, uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2]) { + /* WARNING: Reading from the front-buffer immediately after drawing may fail, + * for a slower but more reliable version of this function #WM_window_pixels_read_offscreen + * should be preferred. See it's comments for details on why it's needed, see also T98462. */ bool setup_context = wm->windrawable != win; if (setup_context) { @@ -1992,45 +2028,40 @@ void WM_init_native_pixels(bool do_it) void WM_init_tablet_api(void) { - if (g_system) { - switch (U.tablet_api) { - case USER_TABLET_NATIVE: - GHOST_SetTabletAPI(g_system, GHOST_kTabletWinPointer); - break; - case USER_TABLET_WINTAB: - GHOST_SetTabletAPI(g_system, GHOST_kTabletWintab); - break; - case USER_TABLET_AUTOMATIC: - default: - GHOST_SetTabletAPI(g_system, GHOST_kTabletAutomatic); - break; - } + if (UNLIKELY(!g_system)) { + return; + } + + switch (U.tablet_api) { + case USER_TABLET_NATIVE: + GHOST_SetTabletAPI(g_system, GHOST_kTabletWinPointer); + break; + case USER_TABLET_WINTAB: + GHOST_SetTabletAPI(g_system, GHOST_kTabletWintab); + break; + case USER_TABLET_AUTOMATIC: + default: + GHOST_SetTabletAPI(g_system, GHOST_kTabletAutomatic); + break; } } void WM_cursor_warp(wmWindow *win, int x, int y) { - if (win && win->ghostwin) { - int oldx = x, oldy = y; + if (!(win && win->ghostwin)) { + return; + } - wm_cursor_position_to_ghost(win, &x, &y); - GHOST_SetCursorPosition(g_system, x, y); + int oldx = x, oldy = y; - win->eventstate->prev_xy[0] = oldx; - win->eventstate->prev_xy[1] = oldy; + wm_cursor_position_to_ghost_client_coords(win, &x, &y); + GHOST_SetCursorPosition(g_system, win->ghostwin, x, y); - win->eventstate->xy[0] = oldx; - win->eventstate->xy[1] = oldy; - } -} + win->eventstate->prev_xy[0] = oldx; + win->eventstate->prev_xy[1] = oldy; -void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y) -{ - float f = GHOST_GetNativePixelSize(win->ghostwin); - if (f != 1.0f) { - *x = (int)(*x / f) * f; - *y = (int)(*y / f) * f; - } + win->eventstate->xy[0] = oldx; + win->eventstate->xy[1] = oldy; } /** \} */ |