mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
WindowServer+MenuApplets: Move the "Audio" applet to its own program
This patch introduces the second MenuApplet: Audio. To make this work, menu applet windows now also receive mouse events. There's still some problem with mute/unmute via clicking not actually working, but the call goes from the applet program over IPC to the AudioServer, where something goes wrong with the state change message. Need to look at that separately. Anyways, it's pretty cool to have more applets running in their own separate processes. :^)
This commit is contained in:
parent
df129bbe0e
commit
e1940f365b
Notes:
sideshowbarker
2024-07-19 10:50:30 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e1940f365be
11 changed files with 98 additions and 46 deletions
|
@ -28,6 +28,10 @@ User=anon
|
||||||
KeepAlive=1
|
KeepAlive=1
|
||||||
User=anon
|
User=anon
|
||||||
|
|
||||||
|
[Audio.MenuApplet]
|
||||||
|
KeepAlive=1
|
||||||
|
User=anon
|
||||||
|
|
||||||
[AudioServer]
|
[AudioServer]
|
||||||
Socket=/tmp/portal/audio
|
Socket=/tmp/portal/audio
|
||||||
# TODO: we may want to start it lazily, but right now WindowServer connects to it immediately on startup
|
# TODO: we may want to start it lazily, but right now WindowServer connects to it immediately on startup
|
||||||
|
|
|
@ -109,6 +109,7 @@ cp ../Servers/TTYServer/TTYServer mnt/bin/TTYServer
|
||||||
cp ../Servers/TelnetServer/TelnetServer mnt/bin/TelnetServer
|
cp ../Servers/TelnetServer/TelnetServer mnt/bin/TelnetServer
|
||||||
cp ../Servers/ProtocolServer/ProtocolServer mnt/bin/ProtocolServer
|
cp ../Servers/ProtocolServer/ProtocolServer mnt/bin/ProtocolServer
|
||||||
cp ../Shell/Shell mnt/bin/Shell
|
cp ../Shell/Shell mnt/bin/Shell
|
||||||
|
cp ../MenuApplets/Audio/Audio.MenuApplet mnt/bin/
|
||||||
cp ../MenuApplets/CPUGraph/CPUGraph.MenuApplet mnt/bin/
|
cp ../MenuApplets/CPUGraph/CPUGraph.MenuApplet mnt/bin/
|
||||||
echo "done"
|
echo "done"
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ build_targets="$build_targets ../Shell"
|
||||||
|
|
||||||
build_targets="$build_targets ../Userland"
|
build_targets="$build_targets ../Userland"
|
||||||
|
|
||||||
|
build_targets="$build_targets ../MenuApplets/Audio"
|
||||||
build_targets="$build_targets ../MenuApplets/CPUGraph"
|
build_targets="$build_targets ../MenuApplets/CPUGraph"
|
||||||
|
|
||||||
build_targets="$build_targets ." # the kernel
|
build_targets="$build_targets ." # the kernel
|
||||||
|
|
BIN
MenuApplets/Audio/Audio.MenuApplet
Executable file
BIN
MenuApplets/Audio/Audio.MenuApplet
Executable file
Binary file not shown.
7
MenuApplets/Audio/Makefile
Executable file
7
MenuApplets/Audio/Makefile
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
include ../../Makefile.common
|
||||||
|
|
||||||
|
OBJS = main.o
|
||||||
|
|
||||||
|
APP = Audio.MenuApplet
|
||||||
|
|
||||||
|
include ../Makefile.common
|
65
MenuApplets/Audio/main.cpp
Normal file
65
MenuApplets/Audio/main.cpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include <LibAudio/AClientConnection.h>
|
||||||
|
#include <LibGUI/GApplication.h>
|
||||||
|
#include <LibGUI/GPainter.h>
|
||||||
|
#include <LibGUI/GWidget.h>
|
||||||
|
#include <LibGUI/GWindow.h>
|
||||||
|
|
||||||
|
class AudioWidget final : public GWidget {
|
||||||
|
C_OBJECT(AudioWidget)
|
||||||
|
public:
|
||||||
|
AudioWidget()
|
||||||
|
: GWidget(nullptr)
|
||||||
|
{
|
||||||
|
m_audio_client = make<AClientConnection>();
|
||||||
|
m_audio_client->on_muted_state_change = [this](bool muted) {
|
||||||
|
dbg() << "Muted state changed: " << muted;
|
||||||
|
if (m_audio_muted == muted)
|
||||||
|
return;
|
||||||
|
m_audio_muted = muted;
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
m_unmuted_bitmap = GraphicsBitmap::load_from_file("/res/icons/audio-unmuted.png");
|
||||||
|
m_muted_bitmap = GraphicsBitmap::load_from_file("/res/icons/audio-muted.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~AudioWidget() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void mousedown_event(GMouseEvent& event) override
|
||||||
|
{
|
||||||
|
if (event.button() != GMouseButton::Left)
|
||||||
|
return;
|
||||||
|
dbg() << "set_muted: " << !m_audio_muted;
|
||||||
|
m_audio_client->set_muted(!m_audio_muted);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void paint_event(GPaintEvent& event) override
|
||||||
|
{
|
||||||
|
GPainter painter(*this);
|
||||||
|
painter.add_clip_rect(event.rect());
|
||||||
|
painter.clear_rect(event.rect(), Color::from_rgba(0));
|
||||||
|
auto& audio_bitmap = m_audio_muted ? *m_muted_bitmap : *m_unmuted_bitmap;
|
||||||
|
painter.blit({}, audio_bitmap, audio_bitmap.rect());
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnPtr<AClientConnection> m_audio_client;
|
||||||
|
RefPtr<GraphicsBitmap> m_muted_bitmap;
|
||||||
|
RefPtr<GraphicsBitmap> m_unmuted_bitmap;
|
||||||
|
bool m_audio_muted { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
GApplication app(argc, argv);
|
||||||
|
|
||||||
|
auto window = GWindow::construct();
|
||||||
|
window->set_has_alpha_channel(true);
|
||||||
|
window->set_window_type(GWindowType::MenuApplet);
|
||||||
|
window->resize(12, 16);
|
||||||
|
|
||||||
|
auto widget = AudioWidget::construct();
|
||||||
|
window->set_main_widget(widget);
|
||||||
|
window->show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ public:
|
||||||
void for_each_menu(Callback callback)
|
void for_each_menu(Callback callback)
|
||||||
{
|
{
|
||||||
for (auto& menu : m_menus) {
|
for (auto& menu : m_menus) {
|
||||||
if (!callback(*menu))
|
if (callback(*menu) == IterationDecision::Break)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <LibAudio/AClientConnection.h>
|
|
||||||
#include <LibCore/CTimer.h>
|
#include <LibCore/CTimer.h>
|
||||||
#include <LibDraw/Font.h>
|
#include <LibDraw/Font.h>
|
||||||
#include <LibDraw/Painter.h>
|
#include <LibDraw/Painter.h>
|
||||||
|
@ -10,20 +9,6 @@
|
||||||
|
|
||||||
WSMenuManager::WSMenuManager()
|
WSMenuManager::WSMenuManager()
|
||||||
{
|
{
|
||||||
m_audio_client = make<AClientConnection>();
|
|
||||||
m_audio_client->on_muted_state_change = [this](bool muted) {
|
|
||||||
if (m_audio_muted == muted)
|
|
||||||
return;
|
|
||||||
m_audio_muted = muted;
|
|
||||||
if (m_window) {
|
|
||||||
draw();
|
|
||||||
m_window->invalidate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
m_unmuted_bitmap = GraphicsBitmap::load_from_file("/res/icons/audio-unmuted.png");
|
|
||||||
m_muted_bitmap = GraphicsBitmap::load_from_file("/res/icons/audio-muted.png");
|
|
||||||
|
|
||||||
m_username = getlogin();
|
m_username = getlogin();
|
||||||
m_needs_window_resize = true;
|
m_needs_window_resize = true;
|
||||||
|
|
||||||
|
@ -71,7 +56,6 @@ void WSMenuManager::draw()
|
||||||
menubar_rect.height()
|
menubar_rect.height()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int time_width = Font::default_font().width("2222-22-22 22:22:22");
|
int time_width = Font::default_font().width("2222-22-22 22:22:22");
|
||||||
m_time_rect = {
|
m_time_rect = {
|
||||||
m_username_rect.left() - menubar_menu_margin() / 2 - time_width,
|
m_username_rect.left() - menubar_menu_margin() / 2 - time_width,
|
||||||
|
@ -80,11 +64,9 @@ void WSMenuManager::draw()
|
||||||
menubar_rect.height()
|
menubar_rect.height()
|
||||||
};
|
};
|
||||||
|
|
||||||
m_audio_rect = { m_time_rect.right() - time_width - 20, m_time_rect.y() + 1, 12, 16 };
|
int right_edge_x = m_time_rect.left() - 4;
|
||||||
|
|
||||||
int right_edge_x = m_audio_rect.x() - 4;
|
|
||||||
for (auto& existing_applet : m_applets) {
|
for (auto& existing_applet : m_applets) {
|
||||||
if (! existing_applet)
|
if (!existing_applet)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Rect new_applet_rect(right_edge_x - existing_applet->size().width(), 0, existing_applet->size().width(), existing_applet->size().height());
|
Rect new_applet_rect(right_edge_x - existing_applet->size().width(), 0, existing_applet->size().width(), existing_applet->size().height());
|
||||||
|
@ -118,7 +100,7 @@ void WSMenuManager::draw()
|
||||||
TextAlignment::CenterLeft,
|
TextAlignment::CenterLeft,
|
||||||
text_color);
|
text_color);
|
||||||
++index;
|
++index;
|
||||||
return true;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
painter.draw_text(m_username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
painter.draw_text(m_username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
||||||
|
@ -133,12 +115,8 @@ void WSMenuManager::draw()
|
||||||
tm->tm_min,
|
tm->tm_min,
|
||||||
tm->tm_sec);
|
tm->tm_sec);
|
||||||
|
|
||||||
|
|
||||||
painter.draw_text(m_time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black);
|
painter.draw_text(m_time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black);
|
||||||
|
|
||||||
auto& audio_bitmap = m_audio_muted ? *m_muted_bitmap : *m_unmuted_bitmap;
|
|
||||||
painter.blit(m_audio_rect.location(), audio_bitmap, audio_bitmap.rect());
|
|
||||||
|
|
||||||
for (auto& applet : m_applets) {
|
for (auto& applet : m_applets) {
|
||||||
if (!applet)
|
if (!applet)
|
||||||
continue;
|
continue;
|
||||||
|
@ -165,21 +143,23 @@ void WSMenuManager::event(CEvent& event)
|
||||||
return CObject::event(event);
|
return CObject::event(event);
|
||||||
|
|
||||||
if (event.type() == WSEvent::MouseMove || event.type() == WSEvent::MouseUp || event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseWheel) {
|
if (event.type() == WSEvent::MouseMove || event.type() == WSEvent::MouseUp || event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseWheel) {
|
||||||
|
|
||||||
auto& mouse_event = static_cast<WSMouseEvent&>(event);
|
auto& mouse_event = static_cast<WSMouseEvent&>(event);
|
||||||
WSWindowManager::the().for_each_active_menubar_menu([&](WSMenu& menu) {
|
WSWindowManager::the().for_each_active_menubar_menu([&](WSMenu& menu) {
|
||||||
if (menu.rect_in_menubar().contains(mouse_event.position())) {
|
if (menu.rect_in_menubar().contains(mouse_event.position())) {
|
||||||
handle_menu_mouse_event(menu, mouse_event);
|
handle_menu_mouse_event(menu, mouse_event);
|
||||||
return false;
|
return IterationDecision::Break;
|
||||||
}
|
}
|
||||||
return true;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mouse_event.type() == WSEvent::MouseDown
|
for (auto& applet : m_applets) {
|
||||||
&& mouse_event.button() == MouseButton::Left
|
if (!applet)
|
||||||
&& m_audio_rect.contains(mouse_event.position())) {
|
continue;
|
||||||
m_audio_client->set_muted(!m_audio_muted);
|
if (!applet->rect_in_menubar().contains(mouse_event.position()))
|
||||||
draw();
|
continue;
|
||||||
m_window->invalidate();
|
auto local_event = mouse_event.translated(-applet->rect_in_menubar().location());
|
||||||
|
applet->event(local_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CObject::event(event);
|
return CObject::event(event);
|
||||||
|
@ -300,7 +280,7 @@ void WSMenuManager::close_bar()
|
||||||
|
|
||||||
void WSMenuManager::add_applet(WSWindow& applet)
|
void WSMenuManager::add_applet(WSWindow& applet)
|
||||||
{
|
{
|
||||||
int right_edge_x = m_audio_rect.x() - 4;
|
int right_edge_x = m_time_rect.left() - 4;
|
||||||
for (auto& existing_applet : m_applets) {
|
for (auto& existing_applet : m_applets) {
|
||||||
if (existing_applet)
|
if (existing_applet)
|
||||||
right_edge_x = existing_applet->rect_in_menubar().x() - 4;
|
right_edge_x = existing_applet->rect_in_menubar().x() - 4;
|
||||||
|
|
|
@ -58,18 +58,11 @@ private:
|
||||||
WeakPtr<WSMenu> m_current_menu;
|
WeakPtr<WSMenu> m_current_menu;
|
||||||
Vector<WeakPtr<WSMenu>> m_open_menu_stack;
|
Vector<WeakPtr<WSMenu>> m_open_menu_stack;
|
||||||
|
|
||||||
RefPtr<GraphicsBitmap> m_muted_bitmap;
|
|
||||||
RefPtr<GraphicsBitmap> m_unmuted_bitmap;
|
|
||||||
|
|
||||||
Vector<WeakPtr<WSWindow>> m_applets;
|
Vector<WeakPtr<WSWindow>> m_applets;
|
||||||
|
|
||||||
OwnPtr<AClientConnection> m_audio_client;
|
|
||||||
|
|
||||||
Rect m_audio_rect;
|
|
||||||
Rect m_username_rect;
|
Rect m_username_rect;
|
||||||
Rect m_time_rect;
|
Rect m_time_rect;
|
||||||
|
|
||||||
bool m_needs_window_resize { false };
|
bool m_needs_window_resize { false };
|
||||||
bool m_bar_open { false };
|
bool m_bar_open { false };
|
||||||
bool m_audio_muted { false };
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -260,7 +260,7 @@ void WSWindowManager::set_current_menubar(WSMenuBar* menubar)
|
||||||
menu.set_text_rect_in_menubar({ next_menu_location, { text_width, menubar_rect().height() } });
|
menu.set_text_rect_in_menubar({ next_menu_location, { text_width, menubar_rect().height() } });
|
||||||
next_menu_location.move_by(menu.rect_in_menubar().width(), 0);
|
next_menu_location.move_by(menu.rect_in_menubar().width(), 0);
|
||||||
++index;
|
++index;
|
||||||
return true;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
m_menu_manager.refresh();
|
m_menu_manager.refresh();
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,8 @@ public:
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_active_menubar_menu(Callback callback)
|
void for_each_active_menubar_menu(Callback callback)
|
||||||
{
|
{
|
||||||
callback(*m_system_menu);
|
if (callback(*m_system_menu) == IterationDecision::Break)
|
||||||
|
return;
|
||||||
if (m_current_menubar)
|
if (m_current_menubar)
|
||||||
m_current_menubar->for_each_menu(callback);
|
m_current_menubar->for_each_menu(callback);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue