add move window to hyprland service
This commit is contained in:
@@ -54,7 +54,8 @@ target_sources(bar_lib
|
|||||||
src/services/dbus/mpris.cpp
|
src/services/dbus/mpris.cpp
|
||||||
|
|
||||||
src/widgets/tray.cpp
|
src/widgets/tray.cpp
|
||||||
src/widgets/controlCenter.cpp
|
src/widgets/controlCenter/controlCenter.cpp
|
||||||
|
src/widgets/controlCenter/mediaControl.cpp
|
||||||
|
|
||||||
src/components/popover.cpp
|
src/components/popover.cpp
|
||||||
src/components/workspaceIndicator.cpp
|
src/components/workspaceIndicator.cpp
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "widgets/tray.hpp"
|
#include "widgets/tray.hpp"
|
||||||
#include "widgets/volumeWidget.hpp"
|
#include "widgets/volumeWidget.hpp"
|
||||||
#include "widgets/webWidget.hpp"
|
#include "widgets/webWidget.hpp"
|
||||||
#include "widgets/controlCenter.hpp"
|
#include "widgets/controlCenter/controlCenter.hpp"
|
||||||
|
|
||||||
class Bar : public Gtk::Window {
|
class Bar : public Gtk::Window {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct MprisPlayer2Message {
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::string artist;
|
std::string artist;
|
||||||
std::string artwork_url;
|
std::string artwork_url;
|
||||||
uint32_t length_ms;
|
int64_t length_ms;
|
||||||
|
|
||||||
std::function<void()> play_pause;
|
std::function<void()> play_pause;
|
||||||
std::function<void()> next;
|
std::function<void()> next;
|
||||||
|
|||||||
@@ -12,12 +12,15 @@ class MprisController {
|
|||||||
void toggle_play();
|
void toggle_play();
|
||||||
void next_song();
|
void next_song();
|
||||||
void previous_song();
|
void previous_song();
|
||||||
|
void emit_seeked(int64_t position_us);
|
||||||
|
|
||||||
sigc::signal<void(const MprisPlayer2Message &)> &signal_mpris_updated();
|
sigc::signal<void(const MprisPlayer2Message &)> &signal_mpris_updated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MprisController();
|
MprisController();
|
||||||
|
|
||||||
|
bool playerRunning = false;
|
||||||
|
|
||||||
Glib::RefPtr<Gio::DBus::Connection> m_connection;
|
Glib::RefPtr<Gio::DBus::Connection> m_connection;
|
||||||
Glib::RefPtr<Gio::DBus::Proxy> m_proxy;
|
Glib::RefPtr<Gio::DBus::Proxy> m_proxy;
|
||||||
sigc::signal<void(const MprisPlayer2Message &)> mprisUpdatedSignal;
|
sigc::signal<void(const MprisPlayer2Message &)> mprisUpdatedSignal;
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class HyprlandService {
|
|||||||
ACTIVE_WINDOW,
|
ACTIVE_WINDOW,
|
||||||
OPEN_WINDOW,
|
OPEN_WINDOW,
|
||||||
CLOSE_WINDOW,
|
CLOSE_WINDOW,
|
||||||
|
MOVE_WINDOW,
|
||||||
URGENT,
|
URGENT,
|
||||||
|
|
||||||
FOCUSED_MONITOR,
|
FOCUSED_MONITOR,
|
||||||
@@ -78,6 +79,7 @@ class HyprlandService {
|
|||||||
{"activewindowv2", ACTIVE_WINDOW},
|
{"activewindowv2", ACTIVE_WINDOW},
|
||||||
{"openwindow", OPEN_WINDOW},
|
{"openwindow", OPEN_WINDOW},
|
||||||
{"closewindow", CLOSE_WINDOW},
|
{"closewindow", CLOSE_WINDOW},
|
||||||
|
{"movewindowv2", MOVE_WINDOW},
|
||||||
{"urgent", URGENT},
|
{"urgent", URGENT},
|
||||||
{"focusedmon", FOCUSED_MONITOR},
|
{"focusedmon", FOCUSED_MONITOR},
|
||||||
{"monitorremoved", MONITOR_REMOVED},
|
{"monitorremoved", MONITOR_REMOVED},
|
||||||
@@ -86,6 +88,7 @@ class HyprlandService {
|
|||||||
void onFocusedMonitorChanged(std::string monitorData);
|
void onFocusedMonitorChanged(std::string monitorData);
|
||||||
void onOpenWindow(std::string windowData);
|
void onOpenWindow(std::string windowData);
|
||||||
void onCloseWindow(std::string windowData);
|
void onCloseWindow(std::string windowData);
|
||||||
|
void onMoveWindow(std::string windowData);
|
||||||
void onUrgent(std::string windowAddress);
|
void onUrgent(std::string windowAddress);
|
||||||
void onActiveWindowChanged(std::string windowAddress);
|
void onActiveWindowChanged(std::string windowAddress);
|
||||||
void onMonitorRemoved(std::string monitorName);
|
void onMonitorRemoved(std::string monitorName);
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include "components/popover.hpp"
|
|
||||||
#include "gtkmm/box.h"
|
|
||||||
#include "gtkmm/label.h"
|
|
||||||
#include "gtkmm/overlay.h"
|
|
||||||
#include "gtkmm/picture.h"
|
|
||||||
#include "gtkmm/scale.h"
|
|
||||||
#include "gtkmm/scrolledwindow.h"
|
|
||||||
#include "services/dbus/mpris.hpp"
|
|
||||||
|
|
||||||
class ControlCenter : public Popover {
|
|
||||||
public:
|
|
||||||
ControlCenter(std::string icon, std::string name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<MprisController> mprisController = MprisController::getInstance();
|
|
||||||
|
|
||||||
Gtk::Box container;
|
|
||||||
Gtk::Box spotifyContainer;
|
|
||||||
|
|
||||||
// image as background, artist, title
|
|
||||||
Gtk::Overlay topContainer;
|
|
||||||
Gtk::Picture backgroundImage;
|
|
||||||
Gtk::Box infoContainer;
|
|
||||||
Gtk::Label artistLabel;
|
|
||||||
Gtk::Label titleLabel;
|
|
||||||
|
|
||||||
//
|
|
||||||
Gtk::Box seekBarContainer;
|
|
||||||
Gtk::Label currentTimeLabel;
|
|
||||||
Gtk::Scale seekBar;
|
|
||||||
Gtk::Label totalTimeLabel;
|
|
||||||
|
|
||||||
// playback controls
|
|
||||||
Gtk::Box bottomContainer;
|
|
||||||
Gtk::Button previousButton;
|
|
||||||
Gtk::Button playPauseButton;
|
|
||||||
Gtk::Button nextButton;
|
|
||||||
|
|
||||||
Gtk::ScrolledWindow imageWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
void onSpotifyMprisUpdated(const MprisPlayer2Message &message);
|
|
||||||
};
|
|
||||||
15
include/widgets/controlCenter/controlCenter.hpp
Normal file
15
include/widgets/controlCenter/controlCenter.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "components/popover.hpp"
|
||||||
|
#include "gtkmm/box.h"
|
||||||
|
#include "widgets/controlCenter/mediaControl.hpp"
|
||||||
|
|
||||||
|
class ControlCenter : public Popover {
|
||||||
|
public:
|
||||||
|
ControlCenter(std::string icon, std::string name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gtk::Box container;
|
||||||
|
MediaControlWidget mediaControlWidget;
|
||||||
|
|
||||||
|
};
|
||||||
52
include/widgets/controlCenter/mediaControl.hpp
Normal file
52
include/widgets/controlCenter/mediaControl.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "gtkmm/box.h"
|
||||||
|
#include "gtkmm/button.h"
|
||||||
|
#include "gtkmm/label.h"
|
||||||
|
#include "gtkmm/overlay.h"
|
||||||
|
#include "gtkmm/picture.h"
|
||||||
|
#include "gtkmm/scale.h"
|
||||||
|
#include "gtkmm/scrolledwindow.h"
|
||||||
|
|
||||||
|
#include "services/dbus/mpris.hpp"
|
||||||
|
|
||||||
|
class MediaControlWidget : public Gtk::Box {
|
||||||
|
public:
|
||||||
|
MediaControlWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<MprisController> mprisController = MprisController::getInstance();
|
||||||
|
|
||||||
|
int64_t currentPositionUs = 0;
|
||||||
|
int64_t totalLengthUs = 0;
|
||||||
|
sigc::connection seekTimerConnection;
|
||||||
|
|
||||||
|
void setCurrentPosition(int64_t position_us);
|
||||||
|
void setTotalLength(int64_t length_us);
|
||||||
|
void resetSeekTimer(int64_t start_position_us);
|
||||||
|
bool onSeekTick();
|
||||||
|
|
||||||
|
Gtk::Box spotifyContainer;
|
||||||
|
|
||||||
|
// image as background, artist, title
|
||||||
|
Gtk::Overlay topContainer;
|
||||||
|
Gtk::Picture backgroundImage;
|
||||||
|
Gtk::Box infoContainer;
|
||||||
|
Gtk::Label artistLabel;
|
||||||
|
Gtk::Label titleLabel;
|
||||||
|
|
||||||
|
//
|
||||||
|
Gtk::Box seekBarContainer;
|
||||||
|
Gtk::Label currentTimeLabel;
|
||||||
|
Gtk::Scale seekBar;
|
||||||
|
Gtk::Label totalTimeLabel;
|
||||||
|
|
||||||
|
// playback controls
|
||||||
|
Gtk::Box bottomContainer;
|
||||||
|
Gtk::Button previousButton;
|
||||||
|
Gtk::Button playPauseButton;
|
||||||
|
Gtk::Button nextButton;
|
||||||
|
|
||||||
|
Gtk::ScrolledWindow imageWrapper;
|
||||||
|
|
||||||
|
void onSpotifyMprisUpdated(const MprisPlayer2Message &message);
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "services/dbus/mpris.hpp"
|
#include "services/dbus/mpris.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "helpers/string.hpp"
|
#include "helpers/string.hpp"
|
||||||
|
|
||||||
@@ -13,7 +14,6 @@ std::shared_ptr<MprisController> MprisController::getInstance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MprisController::MprisController() {
|
MprisController::MprisController() {
|
||||||
// 1. Connect to the Session Bus
|
|
||||||
Gio::DBus::Connection::get(
|
Gio::DBus::Connection::get(
|
||||||
Gio::DBus::BusType::SESSION,
|
Gio::DBus::BusType::SESSION,
|
||||||
sigc::mem_fun(*this, &MprisController::on_bus_connected));
|
sigc::mem_fun(*this, &MprisController::on_bus_connected));
|
||||||
@@ -44,7 +44,6 @@ void MprisController::on_bus_connected(const Glib::RefPtr<Gio::AsyncResult> &res
|
|||||||
if (m_proxy) {
|
if (m_proxy) {
|
||||||
std::cout << "Connected to: " << player_bus_name << std::endl;
|
std::cout << "Connected to: " << player_bus_name << std::endl;
|
||||||
|
|
||||||
// uncomment if launch notification on start
|
|
||||||
signalNotification();
|
signalNotification();
|
||||||
|
|
||||||
m_proxy->signal_properties_changed().connect(
|
m_proxy->signal_properties_changed().connect(
|
||||||
@@ -69,6 +68,11 @@ void MprisController::signalNotification() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!metadata_var.is_of_type(Glib::VariantType("a{sv}"))) {
|
||||||
|
std::cout << "Unexpected metadata type." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
using MetadataMap = std::map<Glib::ustring, Glib::VariantBase>;
|
using MetadataMap = std::map<Glib::ustring, Glib::VariantBase>;
|
||||||
MetadataMap metadata_map;
|
MetadataMap metadata_map;
|
||||||
|
|
||||||
@@ -78,26 +82,46 @@ void MprisController::signalNotification() {
|
|||||||
metadata_map = variant_dict.get();
|
metadata_map = variant_dict.get();
|
||||||
|
|
||||||
std::string title, artist, artwork_url;
|
std::string title, artist, artwork_url;
|
||||||
|
|
||||||
if (metadata_map.count("xesam:title")) {
|
if (metadata_map.count("xesam:title")) {
|
||||||
auto title_var = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(metadata_map["xesam:title"]);
|
const auto &title_base = metadata_map["xesam:title"];
|
||||||
title = title_var.get();
|
if (title_base.is_of_type(Glib::VariantType("s"))) {
|
||||||
|
auto title_var = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(title_base);
|
||||||
|
title = title_var.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata_map.count("xesam:artist")) {
|
if (metadata_map.count("xesam:artist")) {
|
||||||
auto artist_var = metadata_map["xesam:artist"];
|
const auto &artist_var = metadata_map["xesam:artist"];
|
||||||
|
|
||||||
if (artist_var.is_of_type(Glib::VariantType("as"))) {
|
if (artist_var.is_of_type(Glib::VariantType("as"))) {
|
||||||
auto artists = Glib::VariantBase::cast_dynamic<Glib::Variant<std::vector<Glib::ustring>>>(artist_var).get();
|
auto artists = Glib::VariantBase::cast_dynamic<Glib::Variant<std::vector<Glib::ustring>>>(artist_var).get();
|
||||||
if (!artists.empty()) {
|
if (!artists.empty()) {
|
||||||
artist = artists[0]; // Take the first artist
|
artist = artists[0]; // Take the first artist
|
||||||
}
|
}
|
||||||
|
} else if (artist_var.is_of_type(Glib::VariantType("s"))) {
|
||||||
|
auto artist_str = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(artist_var);
|
||||||
|
artist = artist_str.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata_map.count("mpris:artUrl")) {
|
if (metadata_map.count("mpris:artUrl")) {
|
||||||
auto art_var = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(metadata_map["mpris:artUrl"]);
|
const auto &art_base = metadata_map["mpris:artUrl"];
|
||||||
artwork_url = art_var.get();
|
if (art_base.is_of_type(Glib::VariantType("s"))) {
|
||||||
|
auto art_var = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(art_base);
|
||||||
|
artwork_url = art_var.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t length_us = 0;
|
||||||
|
if (metadata_map.count("mpris:length")) {
|
||||||
|
const auto &length_base = metadata_map["mpris:length"];
|
||||||
|
if (length_base.is_of_type(Glib::VariantType("x"))) {
|
||||||
|
auto length_var = Glib::VariantBase::cast_dynamic<Glib::Variant<gint64>>(length_base);
|
||||||
|
length_us = static_cast<int64_t>(length_var.get());
|
||||||
|
} else if (length_base.is_of_type(Glib::VariantType("t"))) {
|
||||||
|
auto length_var = Glib::VariantBase::cast_dynamic<Glib::Variant<guint64>>(length_base);
|
||||||
|
length_us = static_cast<int64_t>(length_var.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MprisPlayer2Message mpris;
|
MprisPlayer2Message mpris;
|
||||||
@@ -107,6 +131,7 @@ void MprisController::signalNotification() {
|
|||||||
mpris.play_pause = [this]() { this->toggle_play(); };
|
mpris.play_pause = [this]() { this->toggle_play(); };
|
||||||
mpris.next = [this]() { this->next_song(); };
|
mpris.next = [this]() { this->next_song(); };
|
||||||
mpris.previous = [this]() { this->previous_song(); };
|
mpris.previous = [this]() { this->previous_song(); };
|
||||||
|
mpris.length_ms = length_us;
|
||||||
mprisUpdatedSignal.emit(mpris);
|
mprisUpdatedSignal.emit(mpris);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,3 +161,18 @@ void MprisController::next_song() {
|
|||||||
m_proxy->call("Next");
|
m_proxy->call("Next");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MprisController::emit_seeked(int64_t position_us) {
|
||||||
|
if (!m_proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Glib::VariantContainerBase params = Glib::VariantContainerBase::create_tuple(
|
||||||
|
Glib::Variant<gint64>::create(position_us));
|
||||||
|
|
||||||
|
m_proxy->call("Seek", params);
|
||||||
|
} catch (const Glib::Error &ex) {
|
||||||
|
std::cerr << "Error seeking: " << ex.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,24 +29,24 @@ void HyprlandService::init() {
|
|||||||
auto monitorPtr = std::make_shared<Monitor>();
|
auto monitorPtr = std::make_shared<Monitor>();
|
||||||
|
|
||||||
std::string monitorName = item["name"].get<std::string>();
|
std::string monitorName = item["name"].get<std::string>();
|
||||||
int monitorId = item["id"].get<int>();
|
int monitorId = item["id"].get<int>();
|
||||||
|
|
||||||
monitorPtr->id = monitorId;
|
monitorPtr->id = monitorId;
|
||||||
monitorPtr->name = monitorName;
|
monitorPtr->name = monitorName;
|
||||||
monitorPtr->activeWorkspaceId = item["activeWorkspace"]["id"].get<int>();
|
monitorPtr->activeWorkspaceId = item["activeWorkspace"]["id"].get<int>();
|
||||||
monitorPtr->focused = item["focused"].get<bool>();
|
monitorPtr->focused = item["focused"].get<bool>();
|
||||||
this->monitors[monitorPtr->name] = monitorPtr;
|
this->monitors[monitorPtr->name] = monitorPtr;
|
||||||
|
|
||||||
for (int i = 1; i <= NUM_WORKSPACES; i++) {
|
for (int i = 1; i <= NUM_WORKSPACES; i++) {
|
||||||
std::shared_ptr<WorkspaceData> state = std::make_shared<WorkspaceData>();
|
std::shared_ptr<WorkspaceData> state = std::make_shared<WorkspaceData>();
|
||||||
int workspaceId = i + (NUM_WORKSPACES * monitorId);
|
int workspaceId = i + (NUM_WORKSPACES * monitorId);
|
||||||
|
|
||||||
state->id = workspaceId;
|
state->id = workspaceId;
|
||||||
state->monitorName = monitorName;
|
state->monitorName = monitorName;
|
||||||
auto view = std::make_shared<WorkspaceIndicator>(workspaceId, std::to_string(i), onClick);
|
auto view = std::make_shared<WorkspaceIndicator>(workspaceId, std::to_string(i), onClick);
|
||||||
auto workSpace = std::make_shared<Workspace>();
|
auto workSpace = std::make_shared<Workspace>();
|
||||||
workSpace->state = state;
|
workSpace->state = state;
|
||||||
workSpace->view = view;
|
workSpace->view = view;
|
||||||
|
|
||||||
monitorPtr->monitorWorkspaces[workspaceId] = workSpace;
|
monitorPtr->monitorWorkspaces[workspaceId] = workSpace;
|
||||||
this->workspaces[workspaceId] = workSpace;
|
this->workspaces[workspaceId] = workSpace;
|
||||||
@@ -76,7 +76,7 @@ void HyprlandService::init() {
|
|||||||
auto workspacePtr = workspaces[workspace["id"].get<int>()];
|
auto workspacePtr = workspaces[workspace["id"].get<int>()];
|
||||||
auto state = workspacePtr->state;
|
auto state = workspacePtr->state;
|
||||||
|
|
||||||
state->id = workspace["id"].get<int>();
|
state->id = workspace["id"].get<int>();
|
||||||
state->monitorName = workspace["monitor"].get<std::string>();
|
state->monitorName = workspace["monitor"].get<std::string>();
|
||||||
|
|
||||||
refreshIndicator(workspacePtr);
|
refreshIndicator(workspacePtr);
|
||||||
@@ -106,9 +106,9 @@ void HyprlandService::bindHyprlandSocket() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto socket_conditions = static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR); // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
auto socket_conditions = static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR); // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||||
GSource *source = g_unix_fd_source_new(socketFd, socket_conditions);
|
GSource *source = g_unix_fd_source_new(socketFd, socket_conditions);
|
||||||
|
|
||||||
auto onSocketEvent = [](gint fd, GIOCondition , gpointer user_data) -> gboolean {
|
auto onSocketEvent = [](gint fd, GIOCondition, gpointer user_data) -> gboolean {
|
||||||
HyprlandService *self = static_cast<HyprlandService *>(user_data);
|
HyprlandService *self = static_cast<HyprlandService *>(user_data);
|
||||||
auto messages = SocketHelper::parseSocketMessage(fd, ">>");
|
auto messages = SocketHelper::parseSocketMessage(fd, ">>");
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ void HyprlandService::bindHyprlandSocket() {
|
|||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
};
|
};
|
||||||
|
|
||||||
g_source_set_callback(source, reinterpret_cast<GSourceFunc>(reinterpret_cast<void*>(+onSocketEvent)), this, nullptr);
|
g_source_set_callback(source, reinterpret_cast<GSourceFunc>(reinterpret_cast<void *>(+onSocketEvent)), this, nullptr);
|
||||||
g_source_attach(source, g_main_context_default());
|
g_source_attach(source, g_main_context_default());
|
||||||
g_source_unref(source);
|
g_source_unref(source);
|
||||||
}
|
}
|
||||||
@@ -173,11 +173,34 @@ void HyprlandService::onMonitorRemoved(std::string monitorName) {
|
|||||||
this->monitors.erase(monitorName);
|
this->monitors.erase(monitorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HyprlandService::onMoveWindow(std::string windowData) {
|
||||||
|
auto parts = StringHelper::split(windowData, ',');
|
||||||
|
std::string addr = "0x" + parts[0];
|
||||||
|
int newWorkspaceId = std::stoi(parts[1]);
|
||||||
|
|
||||||
|
if (this->clients.find(addr) == this->clients.end()) {
|
||||||
|
std::cerr << "[Hyprland] onMoveWindow: Client not found: " << addr << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clientPtr = this->clients[addr];
|
||||||
|
int oldWorkspaceId = clientPtr->workspaceId;
|
||||||
|
|
||||||
|
auto oldWorkspacePtr = workspaces[oldWorkspaceId];
|
||||||
|
oldWorkspacePtr->state->clients.erase(addr);
|
||||||
|
refreshIndicator(oldWorkspacePtr);
|
||||||
|
|
||||||
|
clientPtr->workspaceId = newWorkspaceId;
|
||||||
|
|
||||||
|
auto newWorkspacePtr = workspaces[newWorkspaceId];
|
||||||
|
newWorkspacePtr->state->clients[addr] = clientPtr;
|
||||||
|
refreshIndicator(newWorkspacePtr);
|
||||||
|
}
|
||||||
|
|
||||||
// void HyprlandService::onMonitorAdded(std::string monitorName) {
|
// void HyprlandService::onMonitorAdded(std::string monitorName) {
|
||||||
// // this->signalMonitorAdded.emit();
|
// // this->signalMonitorAdded.emit();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
void HyprlandService::onOpenWindow(std::string windowData) {
|
void HyprlandService::onOpenWindow(std::string windowData) {
|
||||||
auto parts = StringHelper::split(windowData, ',');
|
auto parts = StringHelper::split(windowData, ',');
|
||||||
std::string addr = "0x" + parts[0];
|
std::string addr = "0x" + parts[0];
|
||||||
@@ -250,6 +273,10 @@ void HyprlandService::handleSocketMessage(SocketHelper::SocketMessage message) {
|
|||||||
this->onMonitorRemoved(eventData);
|
this->onMonitorRemoved(eventData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MOVE_WINDOW: {
|
||||||
|
this->onMoveWindow(eventData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void HyprlandService::onUrgent(std::string windowAddress) {
|
void HyprlandService::onUrgent(std::string windowAddress) {
|
||||||
|
|||||||
20
src/widgets/controlCenter/controlCenter.cpp
Normal file
20
src/widgets/controlCenter/controlCenter.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "widgets/controlCenter/controlCenter.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
ControlCenter::ControlCenter(std::string icon, std::string name)
|
||||||
|
: Popover(icon, name) {
|
||||||
|
this->popover->add_css_class("control-center-popover");
|
||||||
|
this->container.set_orientation(Gtk::Orientation::VERTICAL);
|
||||||
|
this->container.set_spacing(0);
|
||||||
|
this->container.set_margin_top(0);
|
||||||
|
this->container.set_margin_bottom(0);
|
||||||
|
this->container.set_margin_start(0);
|
||||||
|
this->container.set_margin_end(0);
|
||||||
|
|
||||||
|
set_popover_child(this->container);
|
||||||
|
|
||||||
|
|
||||||
|
this->container.append(this->mediaControlWidget);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,37 +1,28 @@
|
|||||||
#include "widgets/controlCenter.hpp"
|
#include "widgets/controlCenter/mediaControl.hpp"
|
||||||
|
|
||||||
#include "services/textureCache.hpp"
|
#include "services/textureCache.hpp"
|
||||||
|
|
||||||
ControlCenter::ControlCenter(std::string icon, std::string name)
|
MediaControlWidget::MediaControlWidget()
|
||||||
: Popover(icon, name) {
|
: Gtk::Box(Gtk::Orientation::VERTICAL) {
|
||||||
this->popover->add_css_class("control-center-popover");
|
|
||||||
this->container.set_orientation(Gtk::Orientation::VERTICAL);
|
|
||||||
this->container.set_spacing(0);
|
|
||||||
this->container.set_margin_top(0);
|
|
||||||
this->container.set_margin_bottom(0);
|
|
||||||
this->container.set_margin_start(0);
|
|
||||||
this->container.set_margin_end(0);
|
|
||||||
this->container.append(this->spotifyContainer);
|
|
||||||
|
|
||||||
set_popover_child(this->container);
|
this->set_orientation(Gtk::Orientation::VERTICAL);
|
||||||
|
this->set_size_request(200, 240);
|
||||||
|
this->set_hexpand(false);
|
||||||
|
this->set_vexpand(false);
|
||||||
|
this->add_css_class("control-center-spotify-container");
|
||||||
|
|
||||||
this->spotifyContainer.set_orientation(Gtk::Orientation::VERTICAL);
|
this->append(this->topContainer);
|
||||||
this->spotifyContainer.set_size_request(200, 240);
|
this->append(this->seekBarContainer);
|
||||||
this->spotifyContainer.set_hexpand(false); // Important: Don't let the main box expand freely
|
this->append(this->bottomContainer);
|
||||||
this->spotifyContainer.set_vexpand(false);
|
|
||||||
this->spotifyContainer.add_css_class("control-center-spotify-container");
|
|
||||||
|
|
||||||
this->spotifyContainer.append(this->topContainer);
|
|
||||||
this->spotifyContainer.append(this->seekBarContainer);
|
|
||||||
this->spotifyContainer.append(this->bottomContainer);
|
|
||||||
|
|
||||||
this->backgroundImage.set_content_fit(Gtk::ContentFit::COVER);
|
this->backgroundImage.set_content_fit(Gtk::ContentFit::COVER);
|
||||||
this->backgroundImage.set_can_shrink(true);
|
this->backgroundImage.set_can_shrink(true);
|
||||||
|
|
||||||
this->imageWrapper.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::NEVER);
|
this->imageWrapper.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::NEVER);
|
||||||
this->imageWrapper.set_child(this->backgroundImage);
|
this->imageWrapper.set_child(this->backgroundImage);
|
||||||
|
|
||||||
this->topContainer.set_child(this->imageWrapper);
|
this->topContainer.set_child(this->imageWrapper);
|
||||||
|
|
||||||
this->topContainer.set_size_request(200, 100);
|
this->topContainer.set_size_request(200, 100);
|
||||||
this->topContainer.set_vexpand(false);
|
this->topContainer.set_vexpand(false);
|
||||||
this->topContainer.set_hexpand(true);
|
this->topContainer.set_hexpand(true);
|
||||||
@@ -44,8 +35,7 @@ ControlCenter::ControlCenter(std::string icon, std::string name)
|
|||||||
this->topContainer.add_overlay(this->infoContainer);
|
this->topContainer.add_overlay(this->infoContainer);
|
||||||
|
|
||||||
this->artistLabel.set_halign(Gtk::Align::START);
|
this->artistLabel.set_halign(Gtk::Align::START);
|
||||||
this->titleLabel.set_halign(Gtk::Align::START);
|
this->titleLabel.set_halign(Gtk::Align::START);
|
||||||
|
|
||||||
|
|
||||||
this->seekBarContainer.set_orientation(Gtk::Orientation::HORIZONTAL);
|
this->seekBarContainer.set_orientation(Gtk::Orientation::HORIZONTAL);
|
||||||
this->seekBarContainer.set_vexpand(false);
|
this->seekBarContainer.set_vexpand(false);
|
||||||
@@ -68,6 +58,13 @@ ControlCenter::ControlCenter(std::string icon, std::string name)
|
|||||||
this->seekBar.set_halign(Gtk::Align::CENTER);
|
this->seekBar.set_halign(Gtk::Align::CENTER);
|
||||||
this->seekBar.add_css_class("control-center-seek-bar");
|
this->seekBar.add_css_class("control-center-seek-bar");
|
||||||
|
|
||||||
|
this->seekBar.signal_value_changed().connect([this]() {
|
||||||
|
double fraction = this->seekBar.get_value() / 100.0;
|
||||||
|
int64_t new_position_us =
|
||||||
|
static_cast<int64_t>(fraction * static_cast<double>(this->totalLengthUs));
|
||||||
|
this->mprisController->emit_seeked(new_position_us); // in ms
|
||||||
|
this->resetSeekTimer(new_position_us);
|
||||||
|
});
|
||||||
|
|
||||||
this->bottomContainer.set_orientation(Gtk::Orientation::HORIZONTAL);
|
this->bottomContainer.set_orientation(Gtk::Orientation::HORIZONTAL);
|
||||||
this->bottomContainer.set_vexpand(false);
|
this->bottomContainer.set_vexpand(false);
|
||||||
@@ -101,20 +98,70 @@ ControlCenter::ControlCenter(std::string icon, std::string name)
|
|||||||
});
|
});
|
||||||
|
|
||||||
this->mprisController->signal_mpris_updated().connect(
|
this->mprisController->signal_mpris_updated().connect(
|
||||||
sigc::mem_fun(*this, &ControlCenter::onSpotifyMprisUpdated)
|
sigc::mem_fun(*this, &MediaControlWidget::onSpotifyMprisUpdated));
|
||||||
);
|
|
||||||
|
|
||||||
this->artistLabel.set_text("Artist Name");
|
this->artistLabel.set_text("Artist Name");
|
||||||
this->artistLabel.add_css_class("control-center-spotify-artist-label");
|
this->artistLabel.add_css_class("control-center-spotify-artist-label");
|
||||||
this->titleLabel.set_text("Song Title");
|
this->titleLabel.set_text("Song Title");
|
||||||
this->titleLabel.add_css_class("control-center-spotify-title-label");
|
this->titleLabel.add_css_class("control-center-spotify-title-label");
|
||||||
|
|
||||||
|
this->resetSeekTimer(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlCenter::onSpotifyMprisUpdated(const MprisPlayer2Message &message) {
|
void MediaControlWidget::onSpotifyMprisUpdated(const MprisPlayer2Message &message) {
|
||||||
this->artistLabel.set_text(message.artist);
|
this->artistLabel.set_text(message.artist);
|
||||||
this->titleLabel.set_text(message.title);
|
this->titleLabel.set_text(message.title);
|
||||||
|
|
||||||
if (auto texture = TextureCacheService::getInstance()->getTexture(message.artwork_url)) {
|
if (auto texture = TextureCacheService::getInstance()->getTexture(message.artwork_url)) {
|
||||||
this->backgroundImage.set_paintable(texture);
|
this->backgroundImage.set_paintable(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->setTotalLength(message.length_ms);
|
||||||
|
this->setCurrentPosition(0);
|
||||||
|
this->resetSeekTimer(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlWidget::setCurrentPosition(int64_t position_us) {
|
||||||
|
this->currentPositionUs = position_us;
|
||||||
|
int64_t seconds = (position_us / 1000000) % 60;
|
||||||
|
int64_t minutes = (position_us / (1000000 * 60)) % 60;
|
||||||
|
this->currentTimeLabel.set_text(
|
||||||
|
std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds));
|
||||||
|
if (totalLengthUs > 0) {
|
||||||
|
double fraction = static_cast<double>(currentPositionUs) / static_cast<double>(totalLengthUs);
|
||||||
|
this->seekBar.set_value(fraction * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlWidget::setTotalLength(int64_t length_us) {
|
||||||
|
this->totalLengthUs = length_us;
|
||||||
|
int64_t seconds = (length_us / 1000000) % 60;
|
||||||
|
int64_t minutes = (length_us / (1000000 * 60)) % 60;
|
||||||
|
this->totalTimeLabel.set_text(
|
||||||
|
std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaControlWidget::resetSeekTimer(int64_t start_position_us) {
|
||||||
|
if (seekTimerConnection.connected()) {
|
||||||
|
seekTimerConnection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentPosition(start_position_us);
|
||||||
|
|
||||||
|
seekTimerConnection = Glib::signal_timeout().connect(
|
||||||
|
sigc::mem_fun(*this, &MediaControlWidget::onSeekTick),
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaControlWidget::onSeekTick() {
|
||||||
|
if (totalLengthUs <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t nextPosition = currentPositionUs + 1000000;
|
||||||
|
if (nextPosition > totalLengthUs) {
|
||||||
|
nextPosition = totalLengthUs;
|
||||||
|
}
|
||||||
|
setCurrentPosition(nextPosition);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user