diff --git a/src/Utils.cpp b/src/Utils.cpp index 062e707c..43abf217 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -185,7 +185,7 @@ obs_sceneitem_t* Utils::GetSceneItemFromItem(obs_scene_t* scene, obs_data_t* ite const char* name = obs_data_item_get_string(nameInfoItem); if (idInfoItem) { - obs_sceneitem_t* sceneItem = obs_scene_find_sceneitem_by_id(scene, id); + obs_sceneitem_t* sceneItem = GetSceneItemFromId(scene, id); obs_source_t* sceneItemSource = obs_sceneitem_get_source(sceneItem); QString sceneItemName = obs_source_get_name(sceneItemSource); @@ -215,7 +215,6 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_scene_t* scene, QString name) { current_search search; search.query = name; search.result = nullptr; - search.enumCallback = nullptr; search.enumCallback = []( obs_scene_t* scene, @@ -248,6 +247,49 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_scene_t* scene, QString name) { return search.result; } +obs_sceneitem_t* Utils::GetSceneItemFromId(obs_scene_t* scene, int64_t id) { + if (!scene) { + return nullptr; + } + + struct current_search { + int query; + obs_sceneitem_t* result; + bool (*enumCallback)(obs_scene_t*, obs_sceneitem_t*, void*); + }; + + current_search search; + search.query = id; + search.result = nullptr; + + search.enumCallback = []( + obs_scene_t* scene, + obs_sceneitem_t* currentItem, + void* param) + { + current_search* search = reinterpret_cast(param); + + if (obs_sceneitem_is_group(currentItem)) { + obs_sceneitem_group_enum_items(currentItem, search->enumCallback, search); + if (search->result) { + return false; + } + } + + if (obs_sceneitem_get_id(currentItem) == search->query) { + search->result = currentItem; + obs_sceneitem_addref(search->result); + return false; + } + + return true; + }; + + obs_scene_enum_items(scene, search.enumCallback, &search); + + return search.result; +} + bool Utils::IsValidAlignment(const uint32_t alignment) { switch (alignment) { case OBS_ALIGN_CENTER: diff --git a/src/Utils.h b/src/Utils.h index 3a8da207..6a446a7c 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -37,7 +37,10 @@ class Utils { static obs_data_array_t* GetSceneItems(obs_source_t* source); static obs_data_t* GetSceneItemData(obs_sceneitem_t* item); + // These two functions support nested lookup into groups static obs_sceneitem_t* GetSceneItemFromName(obs_scene_t* scene, QString name); + static obs_sceneitem_t* GetSceneItemFromId(obs_scene_t* scene, int64_t id); + static obs_sceneitem_t* GetSceneItemFromItem(obs_scene_t* scene, obs_data_t* item); static obs_scene_t* GetSceneFromNameOrCurrent(QString sceneName); static obs_data_t* GetSceneItemPropertiesData(obs_sceneitem_t* item); diff --git a/src/WSRequestHandler_Scenes.cpp b/src/WSRequestHandler_Scenes.cpp index cd7f8c25..3a8754b4 100644 --- a/src/WSRequestHandler_Scenes.cpp +++ b/src/WSRequestHandler_Scenes.cpp @@ -104,26 +104,46 @@ HandlerResponse WSRequestHandler::HandleReorderSceneItems(WSRequestHandler* req) return req->SendErrorResponse("sceneItem order not specified"); } - QVector orderList; - struct obs_sceneitem_order_info info; + struct reorder_context { + obs_data_array_t* items; + bool success; + QString errorMessage; + }; - size_t itemCount = obs_data_array_count(items); - for (int i = 0; i < itemCount; i++) { - OBSDataAutoRelease item = obs_data_array_item(items, i); + struct reorder_context ctx; + ctx.success = false; + ctx.items = items; - OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item); - if (!sceneItem) { - return req->SendErrorResponse("Invalid sceneItem id or name specified"); + obs_scene_atomic_update(scene, [](void* param, obs_scene_t* scene) { + auto ctx = reinterpret_cast(param); + + QVector orderList; + struct obs_sceneitem_order_info info; + + size_t itemCount = obs_data_array_count(ctx->items); + for (int i = 0; i < itemCount; i++) { + OBSDataAutoRelease item = obs_data_array_item(ctx->items, i); + + OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item); + if (!sceneItem) { + ctx->success = false; + ctx->errorMessage = "Invalid sceneItem id or name specified"; + return; + } + + info.group = nullptr; + info.item = sceneItem; + orderList.insert(0, info); } - info.group = nullptr; - info.item = sceneItem; - orderList.insert(0, info); - } + ctx->success = obs_scene_reorder_items2(scene, orderList.data(), orderList.size()); + if (!ctx->success) { + ctx->errorMessage = "Invalid sceneItem order"; + } + }, &ctx); - bool success = obs_scene_reorder_items2(scene, orderList.data(), orderList.size()); - if (!success) { - return req->SendErrorResponse("Invalid sceneItem order"); + if (!ctx.success) { + return req->SendErrorResponse(ctx.errorMessage); } return req->SendOKResponse();