diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index ea0560c2d6..b922ee6b5c 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -3,47 +3,52 @@ #include #include #include +#include #include #include #include #include #include "DirectoryView.h" -static GWindow* make_window(); - int main(int argc, char** argv) { GApplication app(argc, argv); + auto mkdir_action = GAction::create("New directory...", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/mkdir16.rgb", { 16, 16 }), [] (const GAction&) { + dbgprintf("'New directory' action activated!\n"); + }); + + auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/copyfile16.rgb", { 16, 16 }), [] (const GAction&) { + dbgprintf("'Copy' action activated!\n"); + }); + + auto delete_action = GAction::create("Delete", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/trash16.rgb", { 16, 16 }), [] (const GAction&) { + dbgprintf("'Delete' action activated!\n"); + }); + auto menubar = make(); auto app_menu = make("FileManager"); - app_menu->add_action(make("Quit", String(), [] (const GAction&) { + app_menu->add_action(GAction::create("Quit", String(), [] (const GAction&) { GApplication::the().quit(0); return; })); menubar->add_menu(move(app_menu)); auto file_menu = make("File"); + file_menu->add_action(mkdir_action.copy_ref()); + file_menu->add_action(copy_action.copy_ref()); + file_menu->add_action(delete_action.copy_ref()); menubar->add_menu(move(file_menu)); auto help_menu = make("Help"); - help_menu->add_action(make("About", [] (const GAction&) { + help_menu->add_action(GAction::create("About", [] (const GAction&) { dbgprintf("FIXME: Implement Help/About\n"); })); menubar->add_menu(move(help_menu)); app.set_menubar(move(menubar)); - auto* window = make_window(); - window->set_should_exit_app_on_close(true); - window->show(); - - return app.exec(); -} - -GWindow* make_window() -{ auto* window = new GWindow; window->set_title("FileManager"); window->set_rect(20, 200, 240, 300); @@ -53,6 +58,11 @@ GWindow* make_window() widget->set_layout(make(Orientation::Vertical)); + auto* toolbar = new GToolBar(widget); + toolbar->add_action(mkdir_action.copy_ref()); + toolbar->add_action(copy_action.copy_ref()); + toolbar->add_action(delete_action.copy_ref()); + auto* directory_view = new DirectoryView(widget); auto* statusbar = new GStatusBar(widget); @@ -68,6 +78,8 @@ GWindow* make_window() directory_view->open("/"); - return window; -} + window->set_should_exit_app_on_close(true); + window->show(); + return app.exec(); +} diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index e27d2c0f35..a63970a7ee 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -97,7 +97,7 @@ int main(int argc, char** argv) auto menubar = make(); auto app_menu = make("Terminal"); - app_menu->add_action(make("Quit", String(), [] (const GAction&) { + app_menu->add_action(GAction::create("Quit", String(), [] (const GAction&) { dbgprintf("Terminal: Quit menu activated!\n"); GApplication::the().quit(0); return; @@ -106,7 +106,7 @@ int main(int argc, char** argv) auto font_menu = make("Font"); GFontDatabase::the().for_each_font([&] (const String& font_name) { - font_menu->add_action(make(font_name, [&terminal] (const GAction& action) { + font_menu->add_action(GAction::create(font_name, [&terminal] (const GAction& action) { terminal.set_font(GFontDatabase::the().get_by_name(action.text())); terminal.force_repaint(); })); @@ -114,7 +114,7 @@ int main(int argc, char** argv) menubar->add_menu(move(font_menu)); auto help_menu = make("Help"); - help_menu->add_action(make("About", [] (const GAction&) { + help_menu->add_action(GAction::create("About", [] (const GAction&) { dbgprintf("FIXME: Implement Help/About\n"); })); menubar->add_menu(move(help_menu)); diff --git a/Base/res/icons/copyfile16.data b/Base/res/icons/copyfile16.data new file mode 100644 index 0000000000..3d772ced7c Binary files /dev/null and b/Base/res/icons/copyfile16.data differ diff --git a/Base/res/icons/copyfile16.png b/Base/res/icons/copyfile16.png new file mode 100644 index 0000000000..cfdeaf1016 Binary files /dev/null and b/Base/res/icons/copyfile16.png differ diff --git a/Base/res/icons/copyfile16.rgb b/Base/res/icons/copyfile16.rgb new file mode 100644 index 0000000000..3d772ced7c Binary files /dev/null and b/Base/res/icons/copyfile16.rgb differ diff --git a/Base/res/icons/mkdir16.data b/Base/res/icons/mkdir16.data new file mode 100644 index 0000000000..31b5b29590 Binary files /dev/null and b/Base/res/icons/mkdir16.data differ diff --git a/Base/res/icons/mkdir16.png b/Base/res/icons/mkdir16.png new file mode 100644 index 0000000000..d24903b955 Binary files /dev/null and b/Base/res/icons/mkdir16.png differ diff --git a/Base/res/icons/mkdir16.rgb b/Base/res/icons/mkdir16.rgb new file mode 100644 index 0000000000..4e0073f4d5 Binary files /dev/null and b/Base/res/icons/mkdir16.rgb differ diff --git a/Base/res/icons/trash16.data b/Base/res/icons/trash16.data new file mode 100644 index 0000000000..b42feef7c5 Binary files /dev/null and b/Base/res/icons/trash16.data differ diff --git a/Base/res/icons/trash16.png b/Base/res/icons/trash16.png new file mode 100644 index 0000000000..531df59348 Binary files /dev/null and b/Base/res/icons/trash16.png differ diff --git a/Base/res/icons/trash16.rgb b/Base/res/icons/trash16.rgb new file mode 100644 index 0000000000..99f10a1b81 Binary files /dev/null and b/Base/res/icons/trash16.rgb differ diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp index ccf27c9f33..9cb38f1921 100644 --- a/Kernel/i386.cpp +++ b/Kernel/i386.cpp @@ -195,6 +195,36 @@ void exception_7_handler(RegisterDump& regs) } +// 0: Divide error +EH_ENTRY_NO_CODE(0); +void exception_0_handler(RegisterDump& regs) +{ + kprintf("%s DIVIDE ERROR: %u(%s)\n", current->is_ring0() ? "Kernel" : "User", current->pid(), current->name().characters()); + + word ss; + dword esp; + if (current->is_ring0()) { + ss = regs.ds; + esp = regs.esp; + } else { + ss = regs.ss_if_crossRing; + esp = regs.esp_if_crossRing; + } + + kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); + kprintf("stk=%w:%x\n", ss, esp); + kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); + kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); + + if (current->is_ring0()) { + kprintf("Oh shit, we've crashed in ring 0 :(\n"); + hang(); + } + + current->crash(); +} + + // 13: General Protection Fault EH_ENTRY(13); void exception_13_handler(RegisterDumpWithExceptionCode& regs) @@ -316,7 +346,6 @@ void exception_14_handler(RegisterDumpWithExceptionCode& regs) hang(); \ } -EH(0, "Divide error") EH(1, "Debug exception") EH(2, "Unknown error") EH(3, "Breakpoint") @@ -442,7 +471,7 @@ void idt_init() for (byte i = 0xff; i > 0x10; --i) register_interrupt_handler(i, unimp_trap); - register_interrupt_handler(0x00, _exception0); + register_interrupt_handler(0x00, exception_0_entry); register_interrupt_handler(0x01, _exception1); register_interrupt_handler(0x02, _exception2); register_interrupt_handler(0x03, _exception3); diff --git a/LibGUI/GAction.cpp b/LibGUI/GAction.cpp index 1d04ea1bcb..aa6e52c5df 100644 --- a/LibGUI/GAction.cpp +++ b/LibGUI/GAction.cpp @@ -1,8 +1,8 @@ #include GAction::GAction(const String& text, const String& custom_data, Function on_activation_callback) - : m_text(text) - , on_activation(move(on_activation_callback)) + : on_activation(move(on_activation_callback)) + , m_text(text) , m_custom_data(custom_data) { } @@ -12,6 +12,13 @@ GAction::GAction(const String& text, Function on_activatio { } +GAction::GAction(const String& text, RetainPtr&& icon, Function on_activation_callback) + : on_activation(move(on_activation_callback)) + , m_text(text) + , m_icon(move(icon)) +{ +} + GAction::~GAction() { } diff --git a/LibGUI/GAction.h b/LibGUI/GAction.h index 6e2bea0404..64797fedf7 100644 --- a/LibGUI/GAction.h +++ b/LibGUI/GAction.h @@ -2,22 +2,41 @@ #include #include +#include +#include +#include -class GAction { +class GAction : public Retainable { public: - GAction(const String& text, Function = nullptr); - GAction(const String& text, const String& custom_data = String(), Function = nullptr); + static RetainPtr create(const String& text, Function callback) + { + return adopt(*new GAction(text, move(callback))); + } + static RetainPtr create(const String& text, const String& custom_data, Function callback) + { + return adopt(*new GAction(text, custom_data, move(callback))); + } + static RetainPtr create(const String& text, RetainPtr&& icon, Function callback) + { + return adopt(*new GAction(text, move(icon), move(callback))); + } ~GAction(); String text() const { return m_text; } String custom_data() const { return m_custom_data; } + const GraphicsBitmap* icon() const { return m_icon.ptr(); } Function on_activation; void activate(); private: + GAction(const String& text, Function = nullptr); + GAction(const String& text, RetainPtr&& icon, Function = nullptr); + GAction(const String& text, const String& custom_data = String(), Function = nullptr); + String m_text; String m_custom_data; + RetainPtr m_icon; }; diff --git a/LibGUI/GBoxLayout.cpp b/LibGUI/GBoxLayout.cpp index 273617daee..84ac0abc0b 100644 --- a/LibGUI/GBoxLayout.cpp +++ b/LibGUI/GBoxLayout.cpp @@ -52,12 +52,14 @@ void GBoxLayout::run(GWidget& widget) Size automatic_size; - if (m_orientation == Orientation::Horizontal) { - automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size); - automatic_size.set_height(widget.height()); - } else { - automatic_size.set_width(widget.width()); - automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size); + if (number_of_entries_with_automatic_size) { + if (m_orientation == Orientation::Horizontal) { + automatic_size.set_width(available_size.width() / number_of_entries_with_automatic_size); + automatic_size.set_height(widget.height()); + } else { + automatic_size.set_width(widget.width()); + automatic_size.set_height(available_size.height() / number_of_entries_with_automatic_size); + } } #ifdef GBOXLAYOUT_DEBUG diff --git a/LibGUI/GMenu.cpp b/LibGUI/GMenu.cpp index 105b9a93ba..0a859d5978 100644 --- a/LibGUI/GMenu.cpp +++ b/LibGUI/GMenu.cpp @@ -29,7 +29,7 @@ GMenu::~GMenu() unrealize_menu(); } -void GMenu::add_action(OwnPtr&& action) +void GMenu::add_action(RetainPtr&& action) { m_items.append(make(move(action))); } diff --git a/LibGUI/GMenu.h b/LibGUI/GMenu.h index 5d56ac0994..6a93f03f0b 100644 --- a/LibGUI/GMenu.h +++ b/LibGUI/GMenu.h @@ -15,7 +15,7 @@ public: GAction* action_at(size_t); - void add_action(OwnPtr&&); + void add_action(RetainPtr&&); void add_separator(); Function on_item_activation; diff --git a/LibGUI/GMenuItem.cpp b/LibGUI/GMenuItem.cpp index 42900548ae..ba877a927b 100644 --- a/LibGUI/GMenuItem.cpp +++ b/LibGUI/GMenuItem.cpp @@ -6,7 +6,7 @@ GMenuItem::GMenuItem(Type type) { } -GMenuItem::GMenuItem(OwnPtr&& action) +GMenuItem::GMenuItem(RetainPtr&& action) : m_type(Action) , m_action(move(action)) { diff --git a/LibGUI/GMenuItem.h b/LibGUI/GMenuItem.h index 383c1b00fe..a26dea394c 100644 --- a/LibGUI/GMenuItem.h +++ b/LibGUI/GMenuItem.h @@ -9,7 +9,7 @@ public: enum Type { Invalid, Action, Separator }; explicit GMenuItem(Type); - explicit GMenuItem(OwnPtr&&); + explicit GMenuItem(RetainPtr&&); ~GMenuItem(); Type type() const { return m_type; } @@ -21,6 +21,6 @@ public: private: Type m_type { Invalid }; unsigned m_identifier { 0 }; - OwnPtr m_action; + RetainPtr m_action; }; diff --git a/LibGUI/GToolBar.cpp b/LibGUI/GToolBar.cpp new file mode 100644 index 0000000000..81593a758c --- /dev/null +++ b/LibGUI/GToolBar.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +GToolBar::GToolBar(GWidget* parent) + : GWidget(parent) +{ + set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + set_preferred_size({ 0, 24 }); + set_layout(make(Orientation::Horizontal)); +} + +GToolBar::~GToolBar() +{ +} + +void GToolBar::add_action(RetainPtr&& action) +{ + ASSERT(action); + GAction* raw_action_ptr = action.ptr(); + auto item = make(); + item->type = Item::Action; + item->action = move(action); + + auto* button = new GButton(this); + if (item->action->icon()) + button->set_icon(item->action->icon()); + else + button->set_caption(item->action->text()); + button->on_click = [raw_action_ptr] (const GButton&) { + raw_action_ptr->activate(); + }; + +#if 0 + // FIXME: Gotta fix GBoxLayout for this to work. + button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + button->set_preferred_size({ 16, 16 }); +#endif + + m_items.append(move(item)); +} + +void GToolBar::add_separator() +{ + auto item = make(); + item->type = Item::Separator; + m_items.append(move(item)); +} + +void GToolBar::paint_event(GPaintEvent& event) +{ + Painter painter(*this); + painter.set_clip_rect(event.rect()); + painter.fill_rect({ 0, 0, width(), height() - 1 }, Color::LightGray); + painter.draw_line({ 0, rect().bottom() }, { width() - 1, rect().bottom() }, Color::DarkGray); +} diff --git a/LibGUI/GToolBar.h b/LibGUI/GToolBar.h new file mode 100644 index 0000000000..3338c3d55a --- /dev/null +++ b/LibGUI/GToolBar.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +class GAction; + +class GToolBar : public GWidget { +public: + explicit GToolBar(GWidget* parent); + virtual ~GToolBar() override; + + void add_action(RetainPtr&&); + void add_separator(); + +private: + virtual const char* class_name() const override { return "GToolBar"; } + virtual void paint_event(GPaintEvent&) override; + + struct Item { + enum Type { Invalid, Separator, Action }; + Type type { Invalid }; + RetainPtr action; + }; + Vector> m_items; +}; diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index 3bf6cc8934..b17eb9aa48 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -73,6 +73,13 @@ void GWidget::handle_paint_event(GPaintEvent& event) if (fill_with_background_color()) { Painter painter(*this); painter.fill_rect(event.rect(), background_color()); + } else { +#ifdef DEBUG_WIDGET_UNDERDRAW + // FIXME: This is a bit broken. + // If the widget is not opaque, let's not mess it up with debugging color. + Painter painter(*this); + painter.fill_rect(rect(), Color::Red); +#endif } paint_event(event); for (auto* ch : children()) { diff --git a/LibGUI/Makefile b/LibGUI/Makefile index cc1c2d779e..ec8abacc1b 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -27,6 +27,7 @@ LIBGUI_OBJS = \ GApplication.o \ GAction.o \ GFontDatabase.o \ + GToolBar.o \ GWindow.o OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS) diff --git a/SharedGraphics/Painter.cpp b/SharedGraphics/Painter.cpp index b9f55a2af3..21ee3af872 100644 --- a/SharedGraphics/Painter.cpp +++ b/SharedGraphics/Painter.cpp @@ -14,8 +14,6 @@ #include #endif -#define DEBUG_WIDGET_UNDERDRAW - Painter::Painter(GraphicsBitmap& bitmap) { m_font = &Font::default_font(); @@ -42,12 +40,6 @@ Painter::Painter(GWidget& widget) // NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store. m_clip_rect = widget.window_relative_rect(); m_clip_rect.intersect(m_target->rect()); - -#ifdef DEBUG_WIDGET_UNDERDRAW - // If the widget is not opaque, let's not mess it up with debugging color. - if (widget.fill_with_background_color() && m_window->main_widget() != &widget) - fill_rect(widget.rect(), Color::Red); -#endif } #endif