Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Kim <pk15950@gmail.com>2022-09-08 07:00:12 +0300
committerPeter Kim <pk15950@gmail.com>2022-09-08 07:00:12 +0300
commit00dcfdf916c69672210b006e62d966f1bc2fbeb7 (patch)
tree0cbb1b91fe26c750197126085b74224a795a103c /source/blender/windowmanager/intern
parenta39532670f6b668da7be5810fb1f844b82feeba3 (diff)
parentd5934974219135102f364f57c45a8b1465e2b8d9 (diff)
Merge branch 'master' into xr-devxr-dev
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r--source/blender/windowmanager/intern/wm.c21
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c15
-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.c200
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c31
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc287
-rw-r--r--source/blender/windowmanager/intern/wm_files.c39
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c16
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c37
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c32
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c81
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c4
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c7
-rw-r--r--source/blender/windowmanager/intern/wm_window.c231
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(&note_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, &note_test, &note_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;
}
/** \} */