mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-21 18:52:49 +00:00
Add active window title widget
This widget called "Title" is a simple text with the title of the currently active window. To prevent clipping the size of the title is capped by the config variable "MaxTitleLength". Implements https://github.com/scorpion-26/gBar/issues/77
This commit is contained in:
parent
3a7fd719a2
commit
70594dae44
11 changed files with 147 additions and 3 deletions
|
@ -20,6 +20,10 @@
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.reboot-button {
|
||||
font-size: 28px;
|
||||
color: #6272a4;
|
||||
|
|
|
@ -45,6 +45,10 @@ $textsize: 16px;
|
|||
font-size: $textsize;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: $textsize;
|
||||
}
|
||||
|
||||
.reboot-button {
|
||||
font-size: 28px;
|
||||
|
||||
|
|
|
@ -119,6 +119,10 @@ DateTimeStyle: %a %D - %H:%M:%S %Z
|
|||
# Set datetime locale (defaults to system locale if not set or set to empty string)
|
||||
#DateTimeLocale: de_DE.utf8
|
||||
|
||||
# How many characters of the title can be displayed. Note that higher values *will* cause styling issues, especially when it is in the center.
|
||||
# If you have the title in the center, consider also increasing "CenterSpace"
|
||||
MaxTitleLength: 30
|
||||
|
||||
# Adds a audio input(aka. microphone) widget
|
||||
AudioInput: false
|
||||
|
||||
|
|
11
meson.build
11
meson.build
|
@ -23,6 +23,15 @@ ext_workspace_header = custom_target('generate-ext-workspace-header',
|
|||
output: ['ext-workspace-unstable-v1.h'],
|
||||
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])
|
||||
|
||||
wlr_foreign_toplevel_src = custom_target('generate-wlr-foreign-toplevel-src',
|
||||
input: ['protocols/wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||
output: ['wlr-foreign-toplevel-management-unstable-v1.c'],
|
||||
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'])
|
||||
|
||||
wlr_foreign_toplevel_header = custom_target('generate-wlr-foreign-toplevel-header',
|
||||
input: ['protocols/wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||
output: ['wlr-foreign-toplevel-management-unstable-v1.h'],
|
||||
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])
|
||||
gtk = dependency('gtk+-3.0')
|
||||
gtk_layer_shell = dependency('gtk-layer-shell-0')
|
||||
|
||||
|
@ -46,6 +55,8 @@ headers = [
|
|||
sources = [
|
||||
ext_workspace_src,
|
||||
ext_workspace_header,
|
||||
wlr_foreign_toplevel_src,
|
||||
wlr_foreign_toplevel_header,
|
||||
'src/Window.cpp',
|
||||
'src/Widget.cpp',
|
||||
'src/Wayland.cpp',
|
||||
|
|
35
src/Bar.cpp
35
src/Bar.cpp
|
@ -4,8 +4,8 @@
|
|||
#include "Common.h"
|
||||
#include "Config.h"
|
||||
#include "SNI.h"
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Bar
|
||||
{
|
||||
|
@ -389,6 +389,20 @@ namespace Bar
|
|||
return TimerResult::Ok;
|
||||
}
|
||||
|
||||
TimerResult UpdateTitle(Text& text)
|
||||
{
|
||||
std::string title = System::GetActiveWindowTitle();
|
||||
if (title.size() > Config::Get().maxTitleLength)
|
||||
{
|
||||
constexpr std::string_view ellipsis = "...";
|
||||
uint32_t newLength = std::max(Config::Get().maxTitleLength - ellipsis.size(), (size_t)0);
|
||||
title.resize(newLength);
|
||||
title += ellipsis;
|
||||
}
|
||||
text.SetText(title);
|
||||
return TimerResult::Ok;
|
||||
}
|
||||
|
||||
#ifdef WITH_WORKSPACES
|
||||
static std::vector<Button*> workspaces;
|
||||
TimerResult UpdateWorkspaces(Box&)
|
||||
|
@ -1085,6 +1099,18 @@ namespace Bar
|
|||
parent.AddChild(std::move(time));
|
||||
}
|
||||
|
||||
void WidgetTitle(Widget& parent, Side side)
|
||||
{
|
||||
auto title = Widget::Create<Text>();
|
||||
Utils::SetTransform(*title, {-1, side == Side::Center, SideToAlignment(side)});
|
||||
title->SetAngle(Utils::GetAngle());
|
||||
title->SetClass("widget");
|
||||
title->AddClass("title-text");
|
||||
title->SetText("Uninitialized");
|
||||
title->AddTimer<Text>(DynCtx::UpdateTitle, DynCtx::updateTimeFast);
|
||||
parent.AddChild(std::move(title));
|
||||
}
|
||||
|
||||
void ChooseWidgetToDraw(const std::string& widgetName, Widget& parent, Side side)
|
||||
{
|
||||
if (widgetName == "Workspaces")
|
||||
|
@ -1102,6 +1128,11 @@ namespace Bar
|
|||
WidgetTime(parent, side);
|
||||
return;
|
||||
}
|
||||
if (widgetName == "Title")
|
||||
{
|
||||
WidgetTitle(parent, side);
|
||||
return;
|
||||
}
|
||||
if (widgetName == "Tray")
|
||||
{
|
||||
#ifdef WITH_SNI
|
||||
|
@ -1184,7 +1215,7 @@ namespace Bar
|
|||
}
|
||||
LOG("Warning: Unkwown widget name " << widgetName << "!"
|
||||
<< "\n\tKnown names are: Workspaces, Time, Tray, Packages, Audio, Bluetooth, Network, Sensors, Disk, "
|
||||
"VRAM, GPU, RAM, CPU, Battery, Power");
|
||||
"VRAM, GPU, RAM, CPU, Battery, Power, Title");
|
||||
}
|
||||
|
||||
void Create(Window& window, const std::string& monitorName)
|
||||
|
|
|
@ -302,6 +302,7 @@ void Config::Load(const std::string& overrideConfigLocation)
|
|||
|
||||
AddConfigVar("CheckUpdateInterval", config.checkUpdateInterval, lineView, foundProperty);
|
||||
AddConfigVar("CenterSpace", config.centerSpace, lineView, foundProperty);
|
||||
AddConfigVar("MaxTitleLength", config.maxTitleLength, lineView, foundProperty);
|
||||
AddConfigVar("NumWorkspaces", config.numWorkspaces, lineView, foundProperty);
|
||||
AddConfigVar("AudioScrollSpeed", config.audioScrollSpeed, lineView, foundProperty);
|
||||
AddConfigVar("SensorSize", config.sensorSize, lineView, foundProperty);
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
uint32_t audioScrollSpeed = 5; // 5% each scroll
|
||||
uint32_t checkUpdateInterval = 5 * 60; // Interval to run the "checkPackagesCommand". In seconds
|
||||
uint32_t centerSpace = 300; // How much space should be reserved for the center widgets.
|
||||
uint32_t maxTitleLength = 30; // Maximum chars of the title widget. Longer titles will be shortened
|
||||
uint32_t numWorkspaces = 9; // How many workspaces to display
|
||||
uint32_t sensorSize = 24; // The size of the circular sensors
|
||||
uint32_t networkIconSize = 24; // The size of the two network arrows
|
||||
|
|
|
@ -647,6 +647,16 @@ namespace System
|
|||
return str.str();
|
||||
}
|
||||
|
||||
std::string GetActiveWindowTitle()
|
||||
{
|
||||
Wayland::PollEvents();
|
||||
const Wayland::Window* activeWindow = Wayland::GetActiveWindow();
|
||||
if (!activeWindow)
|
||||
return "No Active Window"; // TODO Customize!!
|
||||
|
||||
return activeWindow->title;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
system("shutdown 0");
|
||||
|
|
|
@ -113,6 +113,8 @@ namespace System
|
|||
|
||||
std::string GetTime();
|
||||
|
||||
std::string GetActiveWindowTitle();
|
||||
|
||||
void Shutdown();
|
||||
void Reboot();
|
||||
void ExitWM();
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "Config.h"
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-client.h>
|
||||
#include <ext-workspace-unstable-v1.h>
|
||||
#include <wlr-foreign-toplevel-management-unstable-v1.h>
|
||||
|
||||
namespace Wayland
|
||||
{
|
||||
|
@ -11,10 +13,12 @@ namespace Wayland
|
|||
static std::unordered_map<wl_output*, Monitor> monitors;
|
||||
static std::unordered_map<zext_workspace_group_handle_v1*, WorkspaceGroup> workspaceGroups;
|
||||
static std::unordered_map<zext_workspace_handle_v1*, Workspace> workspaces;
|
||||
static std::unordered_map<zwlr_foreign_toplevel_handle_v1*, Window> windows;
|
||||
|
||||
static wl_display* display;
|
||||
static wl_registry* registry;
|
||||
static zext_workspace_manager_v1* workspaceManager;
|
||||
static zwlr_foreign_toplevel_manager_v1* toplevelManager;
|
||||
|
||||
static bool registeredMonitor = false;
|
||||
static bool registeredGroup = false;
|
||||
|
@ -127,6 +131,52 @@ namespace Wayland
|
|||
}
|
||||
zext_workspace_manager_v1_listener workspaceManagerListener = {OnWSManagerNewGroup, OnWSManagerDone, OnWSManagerFinished};
|
||||
|
||||
// zwlr_foreign_toplevel_handle_v1
|
||||
static void OnTLTitle(void*, zwlr_foreign_toplevel_handle_v1* toplevel, const char* title)
|
||||
{
|
||||
auto window = windows.find(toplevel);
|
||||
ASSERT(window != windows.end(), "Wayland: OnTLTile called on unknwon toplevel!");
|
||||
window->second.title = title;
|
||||
}
|
||||
static void OnTLOutputEnter(void*, UNUSED zwlr_foreign_toplevel_handle_v1* toplevel, UNUSED wl_output* output) {}
|
||||
static void OnTLOutputLeave(void*, UNUSED zwlr_foreign_toplevel_handle_v1* toplevel, UNUSED wl_output* output) {}
|
||||
static void OnTLState(void*, zwlr_foreign_toplevel_handle_v1* toplevel, wl_array* state)
|
||||
{
|
||||
auto window = windows.find(toplevel);
|
||||
ASSERT(window != windows.end(), "Wayland: OnTLState called on unknwon toplevel!");
|
||||
// Unrolled from wl_array_for_each, but with types defined to compile under C++
|
||||
// There doesn't seem to be any documentation on the element size of the state, so use wlr's internally used uint32_t
|
||||
bool activated = false;
|
||||
for (uint32_t* curPtr = (uint32_t*)state->data; (uint8_t*)curPtr < (uint8_t*)state->data + state->size; curPtr++)
|
||||
{
|
||||
switch (*curPtr)
|
||||
{
|
||||
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: activated = true; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
window->second.activated = activated;
|
||||
}
|
||||
static void OnTLAppID(void*, zwlr_foreign_toplevel_handle_v1* toplevel, const char* appId) {}
|
||||
static void OnTLDone(void*, zwlr_foreign_toplevel_handle_v1*) {}
|
||||
static void OnTLClosed(void*, zwlr_foreign_toplevel_handle_v1* toplevel)
|
||||
{
|
||||
windows.erase(toplevel);
|
||||
zwlr_foreign_toplevel_handle_v1_destroy(toplevel);
|
||||
}
|
||||
static void OnTLParent(void*, zwlr_foreign_toplevel_handle_v1*, zwlr_foreign_toplevel_handle_v1*) {}
|
||||
zwlr_foreign_toplevel_handle_v1_listener toplevelListener = {OnTLTitle, OnTLAppID, OnTLOutputEnter, OnTLOutputLeave,
|
||||
OnTLState, OnTLDone, OnTLClosed, OnTLParent};
|
||||
|
||||
// zwlr_foreign_toplevel_manager_v1
|
||||
static void OnToplevel(void*, zwlr_foreign_toplevel_manager_v1*, zwlr_foreign_toplevel_handle_v1* toplevel)
|
||||
{
|
||||
windows.emplace(toplevel, Window{});
|
||||
zwlr_foreign_toplevel_handle_v1_add_listener(toplevel, &toplevelListener, nullptr);
|
||||
}
|
||||
static void OnTLManagerFinished(void*, zwlr_foreign_toplevel_manager_v1*) {}
|
||||
zwlr_foreign_toplevel_manager_v1_listener toplevelManagerListener = {OnToplevel, OnTLManagerFinished};
|
||||
|
||||
// Output Callbacks
|
||||
// Very bloated, indeed
|
||||
static void OnOutputGeometry(void*, wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) {}
|
||||
|
@ -162,11 +212,17 @@ namespace Wayland
|
|||
LOG("Wayland: Register <pending> at ID " << mon.ID);
|
||||
wl_output_add_listener(output, &outputListener, nullptr);
|
||||
}
|
||||
if (strcmp(interface, "zext_workspace_manager_v1") == 0 && !Config::Get().useHyprlandIPC)
|
||||
else if (strcmp(interface, "zext_workspace_manager_v1") == 0 && !Config::Get().useHyprlandIPC)
|
||||
{
|
||||
workspaceManager = (zext_workspace_manager_v1*)wl_registry_bind(registry, name, &zext_workspace_manager_v1_interface, version);
|
||||
zext_workspace_manager_v1_add_listener(workspaceManager, &workspaceManagerListener, nullptr);
|
||||
}
|
||||
else if (strcmp(interface, "zwlr_foreign_toplevel_manager_v1") == 0)
|
||||
{
|
||||
toplevelManager = (zwlr_foreign_toplevel_manager_v1*)wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface,
|
||||
version);
|
||||
zwlr_foreign_toplevel_manager_v1_add_listener(toplevelManager, &toplevelManagerListener, nullptr);
|
||||
}
|
||||
}
|
||||
static void OnRegistryRemove(void*, wl_registry*, uint32_t name)
|
||||
{
|
||||
|
@ -305,6 +361,18 @@ namespace Wayland
|
|||
return it->second.ID;
|
||||
}
|
||||
|
||||
const Window* GetActiveWindow()
|
||||
{
|
||||
auto it = std::find_if(windows.begin(), windows.end(),
|
||||
[&](const std::pair<zwlr_foreign_toplevel_handle_v1*, Window>& el)
|
||||
{
|
||||
return el.second.activated == true;
|
||||
});
|
||||
if (it == windows.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
const std::unordered_map<wl_output*, Monitor>& GetMonitors()
|
||||
{
|
||||
return monitors;
|
||||
|
|
|
@ -29,6 +29,12 @@ namespace Wayland
|
|||
zext_workspace_handle_v1* lastActiveWorkspace;
|
||||
};
|
||||
|
||||
struct Window
|
||||
{
|
||||
std::string title;
|
||||
bool activated;
|
||||
};
|
||||
|
||||
void Init();
|
||||
void PollEvents();
|
||||
|
||||
|
@ -61,5 +67,7 @@ namespace Wayland
|
|||
});
|
||||
}
|
||||
|
||||
const Window* GetActiveWindow();
|
||||
|
||||
void Shutdown();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue