Add API's and plumbing for WindowServer clients to make menus.

This commit is contained in:
Andreas Kling 2019-02-12 00:52:19 +01:00
parent bb31d961b4
commit 133706d697
Notes: sideshowbarker 2024-07-19 15:46:57 +09:00
17 changed files with 322 additions and 24 deletions

View file

@ -81,7 +81,7 @@ int main(int argc, char** argv)
auto help_menu = make<GMenu>("?");
help_menu->add_item(2, "About");
menubar->add_menu(move(app_menu));
menubar->add_menu(move(help_menu));
app.set_menubar(move(menubar));

View file

@ -230,6 +230,14 @@ public:
int gui$get_window_rect(int window_id, GUI_Rect*);
int gui$set_window_rect(int window_id, const GUI_Rect*);
int gui$set_global_cursor_tracking_enabled(int window_id, bool enabled);
int gui$menubar_create();
int gui$menubar_destroy(int menubar_id);
int gui$menubar_add_menu(int menubar_id, int menu_id);
int gui$menu_create(const char* name);
int gui$menu_destroy(int menu_id);
int gui$menu_add_separator(int menu_id);
int gui$menu_add_item(int menu_id, unsigned identifier, const char* text);
int gui$set_menubar(int menubar_id);
DisplayInfo set_video_resolution(int width, int height);

View file

@ -6,6 +6,7 @@
#include <WindowServer/WSMessageLoop.h>
#include <WindowServer/WSWindow.h>
#include <WindowServer/WSWindowManager.h>
#include <WindowServer/WSMenuBar.h>
#include <Kernel/BochsVGADevice.h>
//#define LOG_GUI_SYSCALLS
@ -284,3 +285,48 @@ DisplayInfo Process::set_video_resolution(int width, int height)
BochsVGADevice::the().set_resolution(width, height);
return info;
}
int Process::gui$menubar_create()
{
return WSWindowManager::the().api$menubar_create();
}
int Process::gui$menubar_destroy(int menubar_id)
{
return WSWindowManager::the().api$menubar_destroy(menubar_id);
}
int Process::gui$menubar_add_menu(int menubar_id, int menu_id)
{
return WSWindowManager::the().api$menubar_add_menu(menubar_id, menu_id);
}
int Process::gui$menu_create(const char* name)
{
if (!validate_read_str(name))
return -EFAULT;
return WSWindowManager::the().api$menu_create(String(name));
}
int Process::gui$menu_destroy(int menu_id)
{
return WSWindowManager::the().api$menu_destroy(menu_id);
}
int Process::gui$menu_add_separator(int menu_id)
{
return WSWindowManager::the().api$menu_add_separator(menu_id);
}
int Process::gui$menu_add_item(int menu_id, unsigned identifier, const char* text)
{
if (!validate_read_str(text))
return -EFAULT;
return WSWindowManager::the().api$menu_add_item(menu_id, identifier, String(text));
}
int Process::gui$set_menubar(int menubar_id)
{
kprintf("gui$set_menubar %d\n", menubar_id);
return WSWindowManager::the().api$app_set_menubar(menubar_id);
}

View file

@ -223,6 +223,22 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
return current->sys$rmdir((const char*)arg1);
case Syscall::SC_chmod:
return current->sys$chmod((const char*)arg1, (mode_t)arg2);
case Syscall::SC_gui_menubar_create:
return current->gui$menubar_create();
case Syscall::SC_gui_menubar_destroy:
return current->gui$menubar_destroy((int)arg1);
case Syscall::SC_gui_menubar_add_menu:
return current->gui$menubar_add_menu((int)arg1, (int)arg2);
case Syscall::SC_gui_menu_create:
return current->gui$menu_create((const char*)arg1);
case Syscall::SC_gui_menu_destroy:
return current->gui$menu_destroy((int)arg1);
case Syscall::SC_gui_menu_add_separator:
return current->gui$menu_add_separator((int)arg1);
case Syscall::SC_gui_menu_add_item:
return current->gui$menu_add_item((int)arg1, (unsigned)arg2, (const char*)arg3);
case Syscall::SC_gui_app_set_menubar:
return current->gui$set_menubar((int)arg1);
default:
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
break;

View file

@ -85,6 +85,14 @@
__ENUMERATE_SYSCALL(rmdir) \
__ENUMERATE_SYSCALL(chmod) \
__ENUMERATE_SYSCALL(usleep) \
__ENUMERATE_SYSCALL(gui_menubar_create) \
__ENUMERATE_SYSCALL(gui_menubar_destroy) \
__ENUMERATE_SYSCALL(gui_menubar_add_menu) \
__ENUMERATE_SYSCALL(gui_menu_create) \
__ENUMERATE_SYSCALL(gui_menu_destroy) \
__ENUMERATE_SYSCALL(gui_menu_add_separator) \
__ENUMERATE_SYSCALL(gui_menu_add_item) \
__ENUMERATE_SYSCALL(gui_app_set_menubar) \
#ifdef SERENITY

View file

@ -46,6 +46,8 @@
__ERROR(EBADWINDOW, "Bad window ID") \
__ERROR(EBADBACKING, "Bad backing store ID") \
__ERROR(ENOTEMPTY, "Directory not empty") \
__ERROR(EBADMENUBAR, "Bad menubar ID") \
__ERROR(EBADMENU, "Bad menu ID") \
enum __errno_values {

View file

@ -68,3 +68,51 @@ int gui_set_global_cursor_tracking_enabled(int window_id, bool enabled)
int rc = syscall(SC_gui_set_global_cursor_tracking_enabled, window_id, enabled);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menubar_create()
{
int rc = syscall(SC_gui_menubar_create);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menubar_destroy(int menubar_id)
{
int rc = syscall(SC_gui_menubar_destroy, menubar_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menubar_add_menu(int menubar_id, int menu_id)
{
int rc = syscall(SC_gui_menubar_add_menu, menubar_id, menu_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_create(const char* name)
{
int rc = syscall(SC_gui_menu_create, name);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_destroy(int menu_id)
{
int rc = syscall(SC_gui_menu_destroy, menu_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_add_separator(int menu_id)
{
int rc = syscall(SC_gui_menu_add_separator, menu_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_add_item(int menu_id, unsigned identifier, const char* text)
{
int rc = syscall(SC_gui_menu_add_item, menu_id, identifier, text);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_app_set_menubar(int menubar_id)
{
int rc = syscall(SC_gui_app_set_menubar, menubar_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}

View file

@ -16,6 +16,14 @@ int gui_set_window_title(int window_id, const char*, size_t);
int gui_get_window_rect(int window_id, GUI_Rect*);
int gui_set_window_rect(int window_id, const GUI_Rect*);
int gui_set_global_cursor_tracking_enabled(int window_id, bool);
int gui_menubar_create();
int gui_menubar_destroy(int menubar_id);
int gui_menubar_add_menu(int menubar_id, int menu_id);
int gui_menu_create(const char* name);
int gui_menu_destroy(int menu_id);
int gui_menu_add_separator(int menu_id);
int gui_menu_add_item(int menu_id, unsigned identifier, const char* text);
int gui_app_set_menubar(int menubar_id);
__END_DECLS

View file

@ -1,4 +1,5 @@
#include <LibGUI/GMenu.h>
#include <LibC/gui.h>
GMenu::GMenu(const String& name)
: m_name(name)
@ -7,6 +8,10 @@ GMenu::GMenu(const String& name)
GMenu::~GMenu()
{
if (m_menu_id) {
gui_menu_destroy(m_menu_id);
m_menu_id = 0;
}
}
void GMenu::add_item(unsigned identifier, const String& text)
@ -18,3 +23,16 @@ void GMenu::add_separator()
{
m_items.append(GMenuItem(GMenuItem::Separator));
}
int GMenu::realize_menu()
{
m_menu_id = gui_menu_create(m_name.characters());
ASSERT(m_menu_id > 0);
for (auto& item : m_items) {
if (item.type() == GMenuItem::Separator)
gui_menu_add_separator(m_menu_id);
else if (item.type() == GMenuItem::Text)
gui_menu_add_item(m_menu_id, item.identifier(), item.text().characters());
}
return m_menu_id;
}

View file

@ -12,6 +12,11 @@ public:
void add_separator();
private:
friend class GMenuBar;
int menu_id() const { return m_menu_id; }
int realize_menu();
int m_menu_id { 0 };
String m_name;
Vector<GMenuItem> m_items;
};

View file

@ -1,4 +1,5 @@
#include <LibGUI/GMenuBar.h>
#include <LibC/gui.h>
GMenuBar::GMenuBar()
{
@ -15,8 +16,22 @@ void GMenuBar::add_menu(OwnPtr<GMenu>&& menu)
void GMenuBar::notify_added_to_application(Badge<GApplication>)
{
ASSERT(!m_menubar_id);
m_menubar_id = gui_menubar_create();
ASSERT(m_menubar_id > 0);
for (auto& menu : m_menus) {
ASSERT(menu);
int menu_id = menu->realize_menu();
ASSERT(menu_id > 0);
int rc = gui_menubar_add_menu(m_menubar_id, menu_id);
ASSERT(rc == 0);
}
gui_app_set_menubar(m_menubar_id);
}
void GMenuBar::notify_removed_from_application(Badge<GApplication>)
{
ASSERT(m_menubar_id);
gui_menubar_destroy(m_menubar_id);
m_menubar_id = 0;
}

View file

@ -18,5 +18,6 @@ public:
void notify_removed_from_application(Badge<GApplication>);
private:
int m_menubar_id { 0 };
Vector<OwnPtr<GMenu>> m_menus;
};

View file

@ -7,8 +7,9 @@
#include <SharedGraphics/Painter.h>
#include <SharedGraphics/Font.h>
WSMenu::WSMenu(const String& name)
: m_name(name)
WSMenu::WSMenu(int menu_id, String&& name)
: m_menu_id(menu_id)
, m_name(move(name))
{
}

View file

@ -12,9 +12,11 @@ class Font;
class WSMenu {
public:
WSMenu(const String& name);
WSMenu(int menu_id, String&& name);
~WSMenu();
int menu_id() const { return m_menu_id; }
WSMenuBar* menu_bar() { return m_menubar; }
const WSMenuBar* menu_bar() const { return m_menubar; }
@ -70,6 +72,7 @@ public:
private:
void did_activate(WSMenuItem&);
int m_menu_id { 0 };
String m_name;
Rect m_rect_in_menubar;
Rect m_text_rect_in_menubar;

View file

@ -8,7 +8,7 @@ public:
WSMenuBar();
~WSMenuBar();
void add_menu(OwnPtr<WSMenu>&& menu) { m_menus.append(move(menu)); }
void add_menu(WSMenu* menu) { m_menus.append(menu); }
template<typename Callback>
void for_each_menu(Callback callback)
@ -20,5 +20,5 @@ public:
}
private:
Vector<OwnPtr<WSMenu>> m_menus;
Vector<WSMenu*> m_menus;
};

View file

@ -10,6 +10,7 @@
#include <SharedGraphics/CharacterBitmap.h>
#include <AK/StdLibExtras.h>
#include <Kernel/BochsVGADevice.h>
#include <LibC/errno_numbers.h>
#include "WSMenu.h"
#include "WSMenuBar.h"
#include "WSMenuItem.h"
@ -185,28 +186,28 @@ WSWindowManager::WSWindowManager()
{
byte system_menu_name[] = { 0xfc, 0 };
auto menu = make<WSMenu>(String((const char*)system_menu_name));
menu->add_item(make<WSMenuItem>(0, "Launch Terminal"));
menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
menu->add_item(make<WSMenuItem>(1, "Hello again"));
menu->add_item(make<WSMenuItem>(2, "To all my friends"));
menu->add_item(make<WSMenuItem>(3, "Together we can play some rock&roll"));
menu->add_item(make<WSMenuItem>(WSMenuItem::Separator));
menu->add_item(make<WSMenuItem>(4, "About..."));
menu->on_item_activation = [] (WSMenuItem& item) {
auto& menu = create_menu(String((const char*)system_menu_name));
menu.add_item(make<WSMenuItem>(0, "Launch Terminal"));
menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
menu.add_item(make<WSMenuItem>(1, "Hello again"));
menu.add_item(make<WSMenuItem>(2, "To all my friends"));
menu.add_item(make<WSMenuItem>(3, "Together we can play some rock&roll"));
menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
menu.add_item(make<WSMenuItem>(4, "About..."));
menu.on_item_activation = [] (WSMenuItem& item) {
kprintf("WSMenu 1 item activated: '%s'\n", item.text().characters());
};
menubar->add_menu(move(menu));
menubar->add_menu(&menu);
}
{
auto menu = make<WSMenu>("Dummy");
menu->add_item(make<WSMenuItem>(5, "Foo."));
menu->add_item(make<WSMenuItem>(6, "Bar?"));
menu->add_item(make<WSMenuItem>(7, "Baz!"));
menu->on_item_activation = [] (WSMenuItem& item) {
auto& menu = create_menu("Dummy");
menu.add_item(make<WSMenuItem>(5, "Foo."));
menu.add_item(make<WSMenuItem>(6, "Bar?"));
menu.add_item(make<WSMenuItem>(7, "Baz!"));
menu.on_item_activation = [] (WSMenuItem& item) {
kprintf("WSMenu 2 item activated: '%s'\n", item.text().characters());
};
menubar->add_menu(move(menu));
menubar->add_menu(&menu);
}
set_current_menubar(menubar.ptr());
@ -223,11 +224,10 @@ WSWindowManager::~WSWindowManager()
void WSWindowManager::set_current_menubar(WSMenuBar* menubar)
{
LOCKER(m_lock);
if (m_current_menubar == menubar)
return;
m_current_menubar = menubar;
if (!m_current_menubar)
return;
int menu_margin = 16;
Point next_menu_location { menu_margin / 2, 3 };
m_current_menubar->for_each_menu([&] (WSMenu& menu) {
@ -237,6 +237,7 @@ void WSWindowManager::set_current_menubar(WSMenuBar* menubar)
next_menu_location.move_by(menu.rect_in_menubar().width(), 0);
return true;
});
invalidate();
}
static const char* s_close_button_bitmap_data = {
@ -445,6 +446,7 @@ void WSWindowManager::handle_close_button_mouse_event(WSWindow& window, WSMouseE
void WSWindowManager::process_mouse_event(WSMouseEvent& event)
{
LOCKER(m_lock);
if (event.type() == WSMessage::MouseUp && event.button() == MouseButton::Left) {
if (m_drag_window) {
#ifdef DRAG_DEBUG
@ -770,3 +772,106 @@ void WSWindowManager::close_menu(WSMenu& menu)
ASSERT(m_current_menu == &menu);
close_current_menu();
}
WSMenu& WSWindowManager::create_menu(String&& name)
{
int menu_id = m_next_menu_id++;
auto menu = make<WSMenu>(menu_id, move(name));
auto* menu_ptr = menu.ptr();
m_menus.set(menu_id, move(menu));
return *menu_ptr;
}
int WSWindowManager::api$menubar_create()
{
LOCKER(m_lock);
auto menubar = make<WSMenuBar>();
int menubar_id = m_next_menubar_id++;
m_menubars.set(menubar_id, move(menubar));
return menubar_id;
}
int WSWindowManager::api$menubar_destroy(int menubar_id)
{
LOCKER(m_lock);
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end())
return -EBADMENUBAR;
auto& menubar = *(*it).value;
if (&menubar == m_current_menubar)
ASSERT_NOT_REACHED();
m_menubars.remove(it);
return 0;
}
int WSWindowManager::api$menubar_add_menu(int menubar_id, int menu_id)
{
LOCKER(m_lock);
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end())
return -EBADMENUBAR;
auto& menubar = *(*it).value;
auto jt = m_menus.find(menu_id);
if (jt == m_menus.end())
return -EBADMENU;
auto& menu = *(*jt).value;
menubar.add_menu(&menu);
return 0;
}
int WSWindowManager::api$menu_create(String&& name)
{
LOCKER(m_lock);
return create_menu(move(name)).menu_id();
}
int WSWindowManager::api$menu_destroy(int menu_id)
{
LOCKER(m_lock);
auto it = m_menus.find(menu_id);
if (it == m_menus.end())
return -EBADMENU;
m_menus.remove(it);
return 0;
}
int WSWindowManager::api$menu_add_separator(int menu_id)
{
LOCKER(m_lock);
auto it = m_menus.find(menu_id);
if (it == m_menus.end())
return -EBADMENU;
auto& menu = *(*it).value;
menu.add_item(make<WSMenuItem>(WSMenuItem::Separator));
return 0;
}
int WSWindowManager::api$menu_add_item(int menu_id, unsigned identifier, String&& text)
{
LOCKER(m_lock);
auto it = m_menus.find(menu_id);
if (it == m_menus.end())
return -EBADMENU;
auto& menu = *(*it).value;
menu.add_item(make<WSMenuItem>(identifier, move(text)));
return 0;
}
int WSWindowManager::api$app_set_menubar(int menubar_id)
{
LOCKER(m_lock);
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end())
return -EBADMENUBAR;
auto& menubar = *(*it).value;
if (&menubar == m_current_menubar)
return 0;
set_current_menubar(&menubar);
// FIXME: Maybe leave the system menu even if the app menu changes?
close_current_menu();
invalidate();
return 0;
}

View file

@ -53,6 +53,15 @@ public:
void close_menu(WSMenu&);
int api$menubar_create();
int api$menubar_destroy(int menubar_id);
int api$menubar_add_menu(int menubar_id, int menu_id);
int api$menu_create(String&&);
int api$menu_destroy(int menu_id);
int api$menu_add_separator(int menu_id);
int api$menu_add_item(int menu_id, unsigned identifier, String&& text);
int api$app_set_menubar(int menubar_id);
private:
WSWindowManager();
virtual ~WSWindowManager() override;
@ -66,6 +75,7 @@ private:
void set_active_window(WSWindow*);
void close_current_menu();
WSMenu& create_menu(String&& name);
virtual void on_message(WSMessage&) override;
@ -128,7 +138,11 @@ private:
Lockable<bool> m_flash_flush;
bool m_buffers_are_flipped { false };
int m_next_menubar_id = 100;
int m_next_menu_id = 900;
WSMenuBar* m_current_menubar { nullptr };
WSMenu* m_current_menu { nullptr };
HashMap<int, OwnPtr<WSMenuBar>> m_menubars;
HashMap<int, OwnPtr<WSMenu>> m_menus;
};