فهرست منبع

Plumb menu item activation events from WindowServer to clients.

GMenu now has an "on_item_activation" callback that fires whenever one
of its items are activated. The menu item identifier is used to distinguish
between items.

Use this to implement font switching in Terminal. :^)
Andreas Kling 6 سال پیش
والد
کامیت
db98327bdc

+ 8 - 0
Applications/Terminal/Terminal.cpp

@@ -749,3 +749,11 @@ void Terminal::flush_dirty_lines()
     }
     update(rect);
 }
+
+void Terminal::force_repaint()
+{
+    for (int i = 0; i < m_rows; ++i)
+        line(i).dirty = true;
+    m_need_full_flush = true;
+    update();
+}

+ 1 - 0
Applications/Terminal/Terminal.h

@@ -19,6 +19,7 @@ public:
     void on_char(byte);
 
     void flush_dirty_lines();
+    void force_repaint();
 
 private:
     virtual void event(GEvent&) override;

+ 17 - 3
Applications/Terminal/main.cpp

@@ -80,9 +80,23 @@ int main(int argc, char** argv)
     menubar->add_menu(move(app_menu));
 
     auto font_menu = make<GMenu>("Font");
-    font_menu->add_item(30, "Liza 8x10");
-    font_menu->add_item(31, "LizaRegular 8x10");
-    font_menu->add_item(32, "LizaBold 8x10");
+    font_menu->add_item(30, "Liza Thin");
+    font_menu->add_item(31, "Liza Regular");
+    font_menu->add_item(32, "Liza Bold");
+    font_menu->on_item_activation = [&terminal] (unsigned identifier) {
+        switch (identifier) {
+        case 30:
+            terminal.set_font(Font::load_from_file("/res/fonts/Liza8x10.font"));
+            break;
+        case 31:
+            terminal.set_font(Font::load_from_file("/res/fonts/LizaRegular8x10.font"));
+            break;
+        case 32:
+            terminal.set_font(Font::load_from_file("/res/fonts/LizaBold8x10.font"));
+            break;
+        }
+        terminal.force_repaint();
+    };
     menubar->add_menu(move(font_menu));
 
     auto help_menu = make<GMenu>("Help");

+ 5 - 0
Kernel/GUITypes.h

@@ -67,6 +67,7 @@ struct GUI_Event {
         WindowActivated,
         WindowDeactivated,
         WindowCloseRequest,
+        MenuItemActivated,
     };
     Type type { Invalid };
     int window_id { -1 };
@@ -88,6 +89,10 @@ struct GUI_Event {
             bool alt : 1;
             bool shift : 1;
         } key;
+        struct {
+            int menu_id;
+            unsigned identifier;
+        } menu;
     };
 };
 

+ 25 - 0
LibGUI/GEventLoop.cpp

@@ -3,6 +3,7 @@
 #include "GObject.h"
 #include "GWindow.h"
 #include <LibGUI/GNotifier.h>
+#include <LibGUI/GMenu.h>
 #include <LibC/unistd.h>
 #include <LibC/stdio.h>
 #include <LibC/fcntl.h>
@@ -147,6 +148,21 @@ void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
     post_event(&window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button));
 }
 
+void GEventLoop::handle_menu_event(const GUI_Event& event)
+{
+    if (event.type == GUI_Event::Type::MenuItemActivated) {
+        auto* menu = GMenu::from_menu_id(event.menu.menu_id);
+        if (!menu) {
+            dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
+            return;
+        }
+        if (menu->on_item_activation)
+            menu->on_item_activation(event.menu.identifier);
+        return;
+    }
+    ASSERT_NOT_REACHED();
+}
+
 void GEventLoop::wait_for_event()
 {
     fd_set rfds;
@@ -219,6 +235,13 @@ void GEventLoop::wait_for_event()
         if (nread == 0)
             break;
         assert(nread == sizeof(event));
+
+        switch (event.type) {
+        case GUI_Event::MenuItemActivated:
+            handle_menu_event(event);
+            continue;
+        }
+
         auto* window = GWindow::from_window_id(event.window_id);
         if (!window) {
             dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
@@ -244,6 +267,8 @@ void GEventLoop::wait_for_event()
         case GUI_Event::Type::KeyUp:
             handle_key_event(event, *window);
             break;
+        default:
+            break;
         }
     }
 }

+ 1 - 0
LibGUI/GEventLoop.h

@@ -41,6 +41,7 @@ private:
     void handle_key_event(const GUI_Event&, GWindow&);
     void handle_window_activation_event(const GUI_Event&, GWindow&);
     void handle_window_close_request_event(const GUI_Event&, GWindow&);
+    void handle_menu_event(const GUI_Event&);
 
     void get_next_timer_expiration(timeval&);
 

+ 19 - 0
LibGUI/GMenu.cpp

@@ -1,5 +1,22 @@
 #include <LibGUI/GMenu.h>
 #include <LibC/gui.h>
+#include <AK/HashMap.h>
+
+static HashMap<int, GMenu*>& all_menus()
+{
+    static HashMap<int, GMenu*>* map;
+    if (!map)
+        map = new HashMap<int, GMenu*>();
+    return *map;
+}
+
+GMenu* GMenu::from_menu_id(int menu_id)
+{
+    auto it = all_menus().find(menu_id);
+    if (it == all_menus().end())
+        return nullptr;
+    return (*it).value;
+}
 
 GMenu::GMenu(const String& name)
     : m_name(name)
@@ -9,6 +26,7 @@ GMenu::GMenu(const String& name)
 GMenu::~GMenu()
 {
     if (m_menu_id) {
+        all_menus().remove(m_menu_id);
         gui_menu_destroy(m_menu_id);
         m_menu_id = 0;
     }
@@ -34,5 +52,6 @@ int GMenu::realize_menu()
         else if (item.type() == GMenuItem::Text)
             gui_menu_add_item(m_menu_id, item.identifier(), item.text().characters());
     }
+    all_menus().set(m_menu_id, this);
     return m_menu_id;
 }

+ 5 - 0
LibGUI/GMenu.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <LibGUI/GMenuItem.h>
+#include <AK/Function.h>
 #include <AK/Vector.h>
 
 class GMenu {
@@ -8,9 +9,13 @@ public:
     explicit GMenu(const String& name);
     ~GMenu();
 
+    static GMenu* from_menu_id(int);
+
     void add_item(unsigned identifier, const String& text);
     void add_separator();
 
+    Function<void(unsigned)> on_item_activation;
+
 private:
     friend class GMenuBar;
     int menu_id() const { return m_menu_id; }

+ 1 - 0
LibGUI/GWidget.cpp

@@ -234,6 +234,7 @@ void GWidget::set_font(RetainPtr<Font>&& font)
         m_font = Font::default_font();
     else
         m_font = move(font);
+    update();
 }
 
 void GWidget::set_global_cursor_tracking(bool enabled)

+ 11 - 0
WindowServer/WSMenu.cpp

@@ -137,7 +137,18 @@ void WSMenu::did_activate(WSMenuItem& item)
 {
     if (on_item_activation)
         on_item_activation(item);
+
     close();
+
+    GUI_Event gui_event;
+    gui_event.type = GUI_Event::Type::MenuItemActivated;
+    gui_event.menu.menu_id = m_menu_id;
+    gui_event.menu.identifier = item.identifier();
+
+    if (!m_process)
+        return;
+    LOCKER(m_process->gui_events_lock());
+    m_process->gui_events().append(move(gui_event));
 }
 
 WSMenuItem* WSMenu::item_at(const Point& position)