diff --git a/src/components/channellist/cellrendererchannels.cpp b/src/components/channellist/cellrendererchannels.cpp index b0492528..edbe5bb0 100644 --- a/src/components/channellist/cellrendererchannels.cpp +++ b/src/components/channellist/cellrendererchannels.cpp @@ -122,6 +122,7 @@ void CellRendererChannels::get_preferred_width_vfunc(Gtk::Widget &widget, int &m return get_preferred_width_vfunc_thread(widget, minimum_width, natural_width); #ifdef WITH_VOICE case RenderType::VoiceChannel: + case RenderType::VoiceStage: return get_preferred_width_vfunc_voice_channel(widget, minimum_width, natural_width); case RenderType::VoiceParticipant: return get_preferred_width_vfunc_voice_participant(widget, minimum_width, natural_width); @@ -147,6 +148,7 @@ void CellRendererChannels::get_preferred_width_for_height_vfunc(Gtk::Widget &wid return get_preferred_width_for_height_vfunc_thread(widget, height, minimum_width, natural_width); #ifdef WITH_VOICE case RenderType::VoiceChannel: + case RenderType::VoiceStage: return get_preferred_width_for_height_vfunc_voice_channel(widget, height, minimum_width, natural_width); case RenderType::VoiceParticipant: return get_preferred_width_for_height_vfunc_voice_participant(widget, height, minimum_width, natural_width); @@ -172,6 +174,7 @@ void CellRendererChannels::get_preferred_height_vfunc(Gtk::Widget &widget, int & return get_preferred_height_vfunc_thread(widget, minimum_height, natural_height); #ifdef WITH_VOICE case RenderType::VoiceChannel: + case RenderType::VoiceStage: return get_preferred_height_vfunc_voice_channel(widget, minimum_height, natural_height); case RenderType::VoiceParticipant: return get_preferred_height_vfunc_voice_participant(widget, minimum_height, natural_height); @@ -197,6 +200,7 @@ void CellRendererChannels::get_preferred_height_for_width_vfunc(Gtk::Widget &wid return get_preferred_height_for_width_vfunc_thread(widget, width, minimum_height, natural_height); #ifdef WITH_VOICE case RenderType::VoiceChannel: + case RenderType::VoiceStage: return get_preferred_height_for_width_vfunc_voice_channel(widget, width, minimum_height, natural_height); case RenderType::VoiceParticipant: return get_preferred_height_for_width_vfunc_voice_participant(widget, width, minimum_height, natural_height); @@ -222,7 +226,9 @@ void CellRendererChannels::render_vfunc(const Cairo::RefPtr &cr, return render_vfunc_thread(cr, widget, background_area, cell_area, flags); #ifdef WITH_VOICE case RenderType::VoiceChannel: - return render_vfunc_voice_channel(cr, widget, background_area, cell_area, flags); + return render_vfunc_voice_channel(cr, widget, background_area, cell_area, flags, "\U0001F50A"); + case RenderType::VoiceStage: + return render_vfunc_voice_channel(cr, widget, background_area, cell_area, flags, "\U0001F4E1"); case RenderType::VoiceParticipant: return render_vfunc_voice_participant(cr, widget, background_area, cell_area, flags); #endif @@ -581,7 +587,7 @@ void CellRendererChannels::get_preferred_height_for_width_vfunc_voice_channel(Gt m_renderer_text.get_preferred_height_for_width(widget, width, minimum_height, natural_height); } -void CellRendererChannels::render_vfunc_voice_channel(const Cairo::RefPtr &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) { +void CellRendererChannels::render_vfunc_voice_channel(const Cairo::RefPtr &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags, const char *emoji) { // channel name text Gtk::Requisition minimum_size, natural_size; m_renderer_text.get_preferred_size(widget, minimum_size, natural_size); @@ -598,7 +604,7 @@ void CellRendererChannels::render_vfunc_voice_channel(const Cairo::RefPtrset_font_description(font); layout->set_alignment(Pango::ALIGN_LEFT); cr->set_source_rgba(1.0, 1.0, 1.0, 1.0); diff --git a/src/components/channellist/cellrendererchannels.hpp b/src/components/channellist/cellrendererchannels.hpp index e142b2a2..a1c020ba 100644 --- a/src/components/channellist/cellrendererchannels.hpp +++ b/src/components/channellist/cellrendererchannels.hpp @@ -19,6 +19,7 @@ enum class RenderType : uint8_t { // TODO: maybe enable anyways but without ability to join if no voice support #ifdef WITH_VOICE VoiceChannel, + VoiceStage, // identical to non-stage except for icon VoiceParticipant, #endif @@ -117,7 +118,8 @@ class CellRendererChannels : public Gtk::CellRenderer { Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, - Gtk::CellRendererState flags); + Gtk::CellRendererState flags, + const char *emoji); // voice participant void get_preferred_width_vfunc_voice_participant(Gtk::Widget &widget, int &minimum_width, int &natural_width) const; diff --git a/src/components/channellist/channellisttree.cpp b/src/components/channellist/channellisttree.cpp index 4816b423..8b313a37 100644 --- a/src/components/channellist/channellisttree.cpp +++ b/src/components/channellist/channellisttree.cpp @@ -29,6 +29,8 @@ ChannelListTree::ChannelListTree() #ifdef WITH_VOICE , m_menu_voice_channel_join("_Join", true) , m_menu_voice_channel_disconnect("_Disconnect", true) + , m_menu_voice_stage_join("_Join", true) + , m_menu_voice_stage_disconnect("_Disconnect", true) #endif , m_menu_dm_copy_id("_Copy ID", true) , m_menu_dm_close("") // changes depending on if group or not @@ -212,6 +214,19 @@ ChannelListTree::ChannelListTree() m_menu_voice_channel.append(m_menu_voice_channel_join); m_menu_voice_channel.append(m_menu_voice_channel_disconnect); m_menu_voice_channel.show_all(); + + m_menu_voice_stage_join.signal_activate().connect([this]() { + const auto id = static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]); + m_signal_action_join_voice_channel.emit(id); + }); + + m_menu_voice_stage_disconnect.signal_activate().connect([this]() { + m_signal_action_disconnect_voice.emit(); + }); + + m_menu_voice_stage.append(m_menu_voice_stage_join); + m_menu_voice_stage.append(m_menu_voice_stage_disconnect); + m_menu_voice_stage.show_all(); #endif m_menu_dm_copy_id.signal_activate().connect([this] { @@ -356,8 +371,8 @@ int ChannelListTree::SortFunc(const Gtk::TreeModel::iterator &a, const Gtk::Tree if (a_type == RenderType::DMHeader) return -1; if (b_type == RenderType::DMHeader) return 1; #ifdef WITH_VOICE - if (a_type == RenderType::TextChannel && b_type == RenderType::VoiceChannel) return -1; - if (b_type == RenderType::TextChannel && a_type == RenderType::VoiceChannel) return 1; + if (a_type == RenderType::TextChannel && (b_type == RenderType::VoiceChannel || b_type == RenderType::VoiceStage)) return -1; + if (b_type == RenderType::TextChannel && (a_type == RenderType::VoiceChannel || a_type == RenderType::VoiceStage)) return 1; #endif return static_cast(std::clamp(a_sort - b_sort, int64_t(-1), int64_t(1))); } @@ -624,6 +639,7 @@ void ChannelListTree::OnThreadListSync(const ThreadListSyncData &data) { #ifdef WITH_VOICE void ChannelListTree::OnVoiceUserConnect(Snowflake user_id, Snowflake channel_id) { auto parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::VoiceChannel); + if (!parent_iter) parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::VoiceStage); if (!parent_iter) parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::DM); if (!parent_iter) return; const auto user = Abaddon::Get().GetDiscordClient().GetUser(user_id); @@ -906,7 +922,7 @@ Gtk::TreeModel::iterator ChannelListTree::AddGuild(const GuildData &guild, const const auto channel = discord.GetChannel(channel_.ID); if (!channel.has_value()) continue; #ifdef WITH_VOICE - if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS || channel->Type == ChannelType::GUILD_VOICE) { + if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS || channel->Type == ChannelType::GUILD_VOICE || channel->Type == ChannelType::GUILD_STAGE_VOICE) { #else if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS) { #endif @@ -953,10 +969,14 @@ Gtk::TreeModel::iterator ChannelListTree::AddGuild(const GuildData &guild, const channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name); } #ifdef WITH_VOICE - else { + else if (channel.Type == ChannelType::GUILD_VOICE) { channel_row[m_columns.m_type] = RenderType::VoiceChannel; channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name); add_voice_participants(channel, channel_row->children()); + } else if (channel.Type == ChannelType::GUILD_STAGE_VOICE) { + channel_row[m_columns.m_type] = RenderType::VoiceStage; + channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name); + add_voice_participants(channel, channel_row->children()); } #endif channel_row[m_columns.m_id] = channel.ID; @@ -985,10 +1005,14 @@ Gtk::TreeModel::iterator ChannelListTree::AddGuild(const GuildData &guild, const channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name); } #ifdef WITH_VOICE - else { + else if (channel.Type == ChannelType::GUILD_VOICE) { channel_row[m_columns.m_type] = RenderType::VoiceChannel; channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name); add_voice_participants(channel, channel_row->children()); + } else if (channel.Type == ChannelType::GUILD_STAGE_VOICE) { + channel_row[m_columns.m_type] = RenderType::VoiceStage; + channel_row[m_columns.m_name] = Glib::Markup::escape_text(*channel.Name); + add_voice_participants(channel, channel_row->children()); } #endif channel_row[m_columns.m_id] = channel.ID; @@ -1333,6 +1357,10 @@ bool ChannelListTree::OnButtonPressEvent(GdkEventButton *ev) { OnVoiceChannelSubmenuPopup(); m_menu_voice_channel.popup_at_pointer(reinterpret_cast(ev)); break; + case RenderType::VoiceStage: + OnVoiceStageSubmenuPopup(); + m_menu_voice_stage.popup_at_pointer(reinterpret_cast(ev)); + break; #endif case RenderType::DM: { OnDMSubmenuPopup(); @@ -1440,6 +1468,20 @@ void ChannelListTree::OnVoiceChannelSubmenuPopup() { m_menu_voice_channel_disconnect.set_sensitive(false); } } + +void ChannelListTree::OnVoiceStageSubmenuPopup() { + const auto iter = m_model->get_iter(m_path_for_menu); + if (!iter) return; + const auto id = static_cast((*iter)[m_columns.m_id]); + auto &discord = Abaddon::Get().GetDiscordClient(); + if (discord.IsVoiceConnected() || discord.IsVoiceConnecting()) { + m_menu_voice_stage_join.set_sensitive(false); + m_menu_voice_stage_disconnect.set_sensitive(discord.GetVoiceChannelID() == id); + } else { + m_menu_voice_stage_join.set_sensitive(true); + m_menu_voice_stage_disconnect.set_sensitive(false); + } +} #endif void ChannelListTree::OnDMSubmenuPopup() { diff --git a/src/components/channellist/channellisttree.hpp b/src/components/channellist/channellisttree.hpp index 136522b5..3841e3c4 100644 --- a/src/components/channellist/channellisttree.hpp +++ b/src/components/channellist/channellisttree.hpp @@ -165,6 +165,10 @@ class ChannelListTree : public Gtk::ScrolledWindow { Gtk::Menu m_menu_voice_channel; Gtk::MenuItem m_menu_voice_channel_join; Gtk::MenuItem m_menu_voice_channel_disconnect; + + Gtk::Menu m_menu_voice_stage; + Gtk::MenuItem m_menu_voice_stage_join; + Gtk::MenuItem m_menu_voice_stage_disconnect; #endif Gtk::Menu m_menu_dm; @@ -196,6 +200,7 @@ class ChannelListTree : public Gtk::ScrolledWindow { #ifdef WITH_VOICE void OnVoiceChannelSubmenuPopup(); + void OnVoiceStageSubmenuPopup(); #endif bool m_updating_listing = false; diff --git a/src/discord/channel.hpp b/src/discord/channel.hpp index cac8b4ca..ebf67b08 100644 --- a/src/discord/channel.hpp +++ b/src/discord/channel.hpp @@ -27,22 +27,6 @@ enum class ChannelType : int { GUILD_MEDIA = 16, }; -enum class StagePrivacy { - PUBLIC = 1, - GUILD_ONLY = 2, -}; - -constexpr const char *GetStagePrivacyDisplayString(StagePrivacy e) { - switch (e) { - case StagePrivacy::PUBLIC: - return "Public"; - case StagePrivacy::GUILD_ONLY: - return "Guild Only"; - default: - return "Unknown"; - } -} - // should be moved somewhere? struct ThreadMetadataData { diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 385d6b7e..e99cb5f7 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -1646,6 +1646,15 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::GUILD_MEMBERS_CHUNK: { HandleGatewayGuildMembersChunk(m); } break; + case GatewayEvent::STAGE_INSTANCE_CREATE: { + HandleGatewayStageInstanceCreate(m); + } break; + case GatewayEvent::STAGE_INSTANCE_UPDATE: { + HandleGatewayStageInstanceUpdate(m); + } break; + case GatewayEvent::STAGE_INSTANCE_DELETE: { + HandleGatewayStageInstanceDelete(m); + } break; #ifdef WITH_VOICE case GatewayEvent::VOICE_STATE_UPDATE: { HandleGatewayVoiceStateUpdate(m); @@ -2296,6 +2305,29 @@ void DiscordClient::HandleGatewayGuildMembersChunk(const GatewayMessage &msg) { m_store.EndTransaction(); } +void DiscordClient::HandleGatewayStageInstanceCreate(const GatewayMessage &msg) { + StageInstance data = msg.Data; + spdlog::get("discord")->debug("STAGE_INSTANCE_CREATE: {} in {}", data.ID, data.ChannelID); + m_stage_instances[data.ID] = data; + m_channel_to_stage_instance[data.ChannelID] = data.ID; + m_signal_stage_instance_create.emit(data); +} + +void DiscordClient::HandleGatewayStageInstanceUpdate(const GatewayMessage &msg) { + StageInstance data = msg.Data; + spdlog::get("discord")->debug("STAGE_INSTANCE_UPDATE: {} in {}", data.ID, data.ChannelID); + m_stage_instances[data.ID] = data; + m_signal_stage_instance_update.emit(data); +} + +void DiscordClient::HandleGatewayStageInstanceDelete(const GatewayMessage &msg) { + StageInstance data = msg.Data; + spdlog::get("discord")->debug("STAGE_INSTANCE_DELETE: {} in {}", data.ID, data.ChannelID); + m_stage_instances.erase(data.ID); + m_channel_to_stage_instance.erase(data.ChannelID); + m_signal_stage_instance_delete.emit(data); +} + #ifdef WITH_VOICE /* @@ -3001,6 +3033,9 @@ void DiscordClient::LoadEventMap() { m_event_map["VOICE_STATE_UPDATE"] = GatewayEvent::VOICE_STATE_UPDATE; m_event_map["VOICE_SERVER_UPDATE"] = GatewayEvent::VOICE_SERVER_UPDATE; m_event_map["CALL_CREATE"] = GatewayEvent::CALL_CREATE; + m_event_map["STAGE_INSTANCE_CREATE"] = GatewayEvent::STAGE_INSTANCE_CREATE; + m_event_map["STAGE_INSTANCE_UPDATE"] = GatewayEvent::STAGE_INSTANCE_UPDATE; + m_event_map["STAGE_INSTANCE_DELETE"] = GatewayEvent::STAGE_INSTANCE_DELETE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -3179,6 +3214,18 @@ DiscordClient::type_signal_guild_members_chunk DiscordClient::signal_guild_membe return m_signal_guild_members_chunk; } +DiscordClient::type_signal_stage_instance_create DiscordClient::signal_stage_instance_create() { + return m_signal_stage_instance_create; +} + +DiscordClient::type_signal_stage_instance_update DiscordClient::signal_stage_instance_update() { + return m_signal_stage_instance_update; +} + +DiscordClient::type_signal_stage_instance_delete DiscordClient::signal_stage_instance_delete() { + return m_signal_stage_instance_delete; +} + DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() { return m_signal_added_to_thread; } diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp index 21eaa822..a74b5f63 100644 --- a/src/discord/discord.hpp +++ b/src/discord/discord.hpp @@ -294,12 +294,16 @@ class DiscordClient { void HandleGatewayMessageAck(const GatewayMessage &msg); void HandleGatewayUserGuildSettingsUpdate(const GatewayMessage &msg); void HandleGatewayGuildMembersChunk(const GatewayMessage &msg); + void HandleGatewayStageInstanceCreate(const GatewayMessage &msg); + void HandleGatewayStageInstanceUpdate(const GatewayMessage &msg); + void HandleGatewayStageInstanceDelete(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); #ifdef WITH_VOICE - void HandleGatewayVoiceStateUpdate(const GatewayMessage &msg); + void + HandleGatewayVoiceStateUpdate(const GatewayMessage &msg); void HandleGatewayVoiceServerUpdate(const GatewayMessage &msg); void HandleGatewayCallCreate(const GatewayMessage &msg); @@ -341,6 +345,8 @@ class DiscordClient { std::unordered_set m_muted_channels; std::unordered_map m_unread; std::unordered_set m_channel_muted_parent; + std::map m_stage_instances; + std::map m_channel_to_stage_instance; UserData m_user_data; UserSettings m_user_settings; @@ -441,6 +447,9 @@ class DiscordClient { typedef sigc::signal type_signal_thread_member_list_update; typedef sigc::signal type_signal_message_ack; typedef sigc::signal type_signal_guild_members_chunk; + typedef sigc::signal type_signal_stage_instance_create; + typedef sigc::signal type_signal_stage_instance_update; + typedef sigc::signal type_signal_stage_instance_delete; // not discord dispatch events typedef sigc::signal type_signal_added_to_thread; @@ -513,6 +522,9 @@ class DiscordClient { type_signal_thread_member_list_update signal_thread_member_list_update(); type_signal_message_ack signal_message_ack(); type_signal_guild_members_chunk signal_guild_members_chunk(); + type_signal_stage_instance_create signal_stage_instance_create(); + type_signal_stage_instance_update signal_stage_instance_update(); + type_signal_stage_instance_delete signal_stage_instance_delete(); type_signal_added_to_thread signal_added_to_thread(); type_signal_removed_from_thread signal_removed_from_thread(); @@ -582,6 +594,9 @@ class DiscordClient { type_signal_thread_member_list_update m_signal_thread_member_list_update; type_signal_message_ack m_signal_message_ack; type_signal_guild_members_chunk m_signal_guild_members_chunk; + type_signal_stage_instance_create m_signal_stage_instance_create; + type_signal_stage_instance_update m_signal_stage_instance_update; + type_signal_stage_instance_delete m_signal_stage_instance_delete; type_signal_removed_from_thread m_signal_removed_from_thread; type_signal_added_to_thread m_signal_added_to_thread; diff --git a/src/discord/objects.hpp b/src/discord/objects.hpp index dfe99f06..67474a31 100644 --- a/src/discord/objects.hpp +++ b/src/discord/objects.hpp @@ -20,6 +20,7 @@ #include "auditlog.hpp" #include "relationship.hpp" #include "errors.hpp" +#include "stage.hpp" // most stuff below should just be objects that get processed and thrown away immediately @@ -110,6 +111,9 @@ enum class GatewayEvent : int { VOICE_STATE_UPDATE, VOICE_SERVER_UPDATE, CALL_CREATE, + STAGE_INSTANCE_CREATE, + STAGE_INSTANCE_UPDATE, + STAGE_INSTANCE_DELETE, }; enum class GatewayCloseCode : uint16_t { diff --git a/src/discord/stage.cpp b/src/discord/stage.cpp new file mode 100644 index 00000000..428e1f3b --- /dev/null +++ b/src/discord/stage.cpp @@ -0,0 +1,12 @@ +#include "stage.hpp" + +#include "json.hpp" + +void from_json(const nlohmann::json &j, StageInstance &m) { + JS_D("id", m.ID); + JS_D("guild_id", m.GuildID); + JS_D("channel_id", m.ChannelID); + JS_N("topic", m.Topic); + JS_N("privacy_level", m.PrivacyLevel); + JS_N("guild_scheduled_event_id", m.GuildScheduledEventID); +} diff --git a/src/discord/stage.hpp b/src/discord/stage.hpp new file mode 100644 index 00000000..3df44335 --- /dev/null +++ b/src/discord/stage.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "snowflake.hpp" + +enum class StagePrivacy { + PUBLIC = 1, + GUILD_ONLY = 2, +}; + +constexpr const char *GetStagePrivacyDisplayString(StagePrivacy e) { + switch (e) { + case StagePrivacy::PUBLIC: + return "Public"; + case StagePrivacy::GUILD_ONLY: + return "Guild Only"; + default: + return "Unknown"; + } +} + +struct StageInstance { + Snowflake ID; + Snowflake GuildID; + Snowflake ChannelID; + std::string Topic; + StagePrivacy PrivacyLevel; + Snowflake GuildScheduledEventID; + + friend void from_json(const nlohmann::json &j, StageInstance &m); +}; diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp index e4b56bda..164033fa 100644 --- a/src/discord/voiceclient.cpp +++ b/src/discord/voiceclient.cpp @@ -96,11 +96,11 @@ std::vector UDPSocket::Receive() { } void UDPSocket::Stop() { - #ifdef _WIN32 +#ifdef _WIN32 closesocket(m_socket); - #else +#else close(m_socket); - #endif +#endif m_running = false; if (m_thread.joinable()) m_thread.join(); } @@ -250,6 +250,7 @@ bool DiscordVoiceClient::IsConnecting() const noexcept { } void DiscordVoiceClient::OnGatewayMessage(const std::string &str) { + m_log->trace("IN: {}", str); VoiceGatewayMessage msg = nlohmann::json::parse(str); switch (msg.Opcode) { case VoiceGatewayOp::Hello: diff --git a/src/discord/voiceclient.hpp b/src/discord/voiceclient.hpp index 0112749f..aa1014cf 100644 --- a/src/discord/voiceclient.hpp +++ b/src/discord/voiceclient.hpp @@ -43,6 +43,23 @@ enum class VoiceGatewayOp : int { Hello = 8, Resumed = 9, ClientDisconnect = 13, + SessionUpdate = 14, + MediaSinkWants = 15, + VoiceBackendVersion = 16, + ChannelOptionsUpdate = 17, + Flags = 18, + SpeedTest = 19, + Platform = 20, + SecureFramesPrepareProtocolTransition = 21, + SecureFramesExecuteTransition = 22, + SecureFramesReadyForTransition = 23, + SecureFramesPrepareEpoch = 24, + MlsExternalSenderPackage = 25, + MlsKeyPackage = 26, + MlsProposals = 27, + MlsCommitWelcome = 28, + MlsPrepareCommitTransition = 29, + MlsWelcome = 30, }; struct VoiceGatewayMessage { @@ -156,11 +173,11 @@ class UDPSocket { private: void ReadThread(); - #ifdef _WIN32 +#ifdef _WIN32 SOCKET m_socket; - #else +#else int m_socket; - #endif +#endif sockaddr_in m_server; std::atomic m_running = false; diff --git a/src/windows/voicewindow.cpp b/src/windows/voicewindow.cpp index 18f4a416..90338574 100644 --- a/src/windows/voicewindow.cpp +++ b/src/windows/voicewindow.cpp @@ -248,12 +248,26 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) combos_combos->pack_start(m_playback_combo); combos_combos->pack_start(m_capture_combo); + discord.signal_stage_instance_create().connect([this](const StageInstance &instance) { + m_TMP_stagelabel.show(); + m_TMP_stagelabel.set_markup("" + instance.Topic + ""); + }); + + discord.signal_stage_instance_update().connect([this](const StageInstance &instance) { + m_TMP_stagelabel.set_markup("" + instance.Topic + ""); + }); + + discord.signal_stage_instance_delete().connect([this](const StageInstance &instance) { + m_TMP_stagelabel.hide(); + }); + m_scroll.add(m_user_list); m_controls.add(m_mute); m_controls.add(m_deafen); m_controls.add(m_noise_suppression); m_controls.add(m_mix_mono); m_main.pack_start(m_menu_bar, false, true); + m_main.pack_start(m_TMP_stagelabel, false, true); m_main.pack_start(m_controls, false, true); m_main.pack_start(m_vad_value, false, true); m_main.pack_start(*Gtk::make_managed("Input Settings"), false, true); @@ -263,6 +277,8 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) add(m_main); show_all_children(); + m_TMP_stagelabel.hide(); + Glib::signal_timeout().connect(sigc::mem_fun(*this, &VoiceWindow::UpdateVoiceMeters), 40); } diff --git a/src/windows/voicewindow.hpp b/src/windows/voicewindow.hpp index 018934b2..6d460849 100644 --- a/src/windows/voicewindow.hpp +++ b/src/windows/voicewindow.hpp @@ -69,6 +69,8 @@ class VoiceWindow : public Gtk::Window { Gtk::Menu m_menu_view_sub; Gtk::MenuItem m_menu_view_settings; + Gtk::Label m_TMP_stagelabel; + public: using type_signal_mute = sigc::signal; using type_signal_deafen = sigc::signal;